Skip to content
Snippets Groups Projects
3c59x.c 102 KiB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
	if(VORTEX_PCI(vp))
		state = VORTEX_PCI(vp)->current_state;

	/* The kernel core really should have pci_get_power_state() */

	if(state != 0)
		pci_set_power_state(VORTEX_PCI(vp), PCI_D0);
	err = generic_mii_ioctl(&vp->mii, if_mii(rq), cmd, NULL);
	if(state != 0)
		pci_set_power_state(VORTEX_PCI(vp), state);

	return err;
}
#endif


/* Pre-Cyclone chips have no documented multicast filter, so the only
   multicast setting is to receive all multicast frames.  At least
   the chip has a very clean way to set the mode, unlike many others. */
static void set_rx_mode(struct net_device *dev)
{
	struct vortex_private *vp = netdev_priv(dev);
	void __iomem *ioaddr = vp->ioaddr;
Linus Torvalds's avatar
Linus Torvalds committed
	int new_mode;

	if (dev->flags & IFF_PROMISC) {
		if (vortex_debug > 3)
			pr_notice("%s: Setting promiscuous mode.\n", dev->name);
Linus Torvalds's avatar
Linus Torvalds committed
		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
	} else	if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) {
Linus Torvalds's avatar
Linus Torvalds committed
		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
	} else
		new_mode = SetRxFilter | RxStation | RxBroadcast;

	iowrite16(new_mode, ioaddr + EL3_CMD);
Linus Torvalds's avatar
Linus Torvalds committed
}

#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
/* Setup the card so that it can receive frames with an 802.1q VLAN tag.
   Note that this must be done after each RxReset due to some backwards
   compatibility logic in the Cyclone and Tornado ASICs */

/* The Ethernet Type used for 802.1q tagged frames */
#define VLAN_ETHER_TYPE 0x8100

static void set_8021q_mode(struct net_device *dev, int enable)
{
	struct vortex_private *vp = netdev_priv(dev);
	int mac_ctrl;

	if ((vp->drv_flags&IS_CYCLONE) || (vp->drv_flags&IS_TORNADO)) {
		/* cyclone and tornado chipsets can recognize 802.1q
		 * tagged frames and treat them correctly */

		int max_pkt_size = dev->mtu+14;	/* MTU+Ethernet header */
		if (enable)
			max_pkt_size += 4;	/* 802.1Q VLAN tag */

		window_write16(vp, max_pkt_size, 3, Wn3_MaxPktSize);
Linus Torvalds's avatar
Linus Torvalds committed

		/* set VlanEtherType to let the hardware checksumming
		   treat tagged frames correctly */
		window_write16(vp, VLAN_ETHER_TYPE, 7, Wn7_VlanEtherType);
Linus Torvalds's avatar
Linus Torvalds committed
	} else {
		/* on older cards we have to enable large frames */

		vp->large_frames = dev->mtu > 1500 || enable;

		mac_ctrl = window_read16(vp, 3, Wn3_MAC_Ctrl);
Linus Torvalds's avatar
Linus Torvalds committed
		if (vp->large_frames)
			mac_ctrl |= 0x40;
		else
			mac_ctrl &= ~0x40;
		window_write16(vp, mac_ctrl, 3, Wn3_MAC_Ctrl);
Linus Torvalds's avatar
Linus Torvalds committed
	}
}
#else

static void set_8021q_mode(struct net_device *dev, int enable)
{
}


#endif

/* MII transceiver control section.
   Read and write the MII registers using software-generated serial
   MDIO protocol.  See the MII specifications or DP83840A data sheet
   for details. */

/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
   "overclocking" issues. */
static void mdio_delay(struct vortex_private *vp)
{
	window_read32(vp, 4, Wn4_PhysicalMgmt);
}
Linus Torvalds's avatar
Linus Torvalds committed

#define MDIO_SHIFT_CLK	0x01
#define MDIO_DIR_WRITE	0x04
#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
#define MDIO_DATA_READ	0x02
#define MDIO_ENB_IN		0x00

/* Generate the preamble required for initial synchronization and
   a few older transceivers. */
static void mdio_sync(struct vortex_private *vp, int bits)
Linus Torvalds's avatar
Linus Torvalds committed
{
	/* Establish sync by sending at least 32 logic ones. */
	while (-- bits >= 0) {
		window_write16(vp, MDIO_DATA_WRITE1, 4, Wn4_PhysicalMgmt);
		mdio_delay(vp);
		window_write16(vp, MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK,
			       4, Wn4_PhysicalMgmt);
		mdio_delay(vp);
Linus Torvalds's avatar
Linus Torvalds committed
	}
}

static int mdio_read(struct net_device *dev, int phy_id, int location)
{
	int i;
	struct vortex_private *vp = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
	unsigned int retval = 0;

Linus Torvalds's avatar
Linus Torvalds committed
	if (mii_preamble_required)
Linus Torvalds's avatar
Linus Torvalds committed

	/* Shift the read command bits out. */
	for (i = 14; i >= 0; i--) {
		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
		window_write16(vp, dataval, 4, Wn4_PhysicalMgmt);
		mdio_delay(vp);
		window_write16(vp, dataval | MDIO_SHIFT_CLK,
			       4, Wn4_PhysicalMgmt);
		mdio_delay(vp);
Linus Torvalds's avatar
Linus Torvalds committed
	}
	/* Read the two transition, 16 data, and wire-idle bits. */
	for (i = 19; i > 0; i--) {
		window_write16(vp, MDIO_ENB_IN, 4, Wn4_PhysicalMgmt);
		mdio_delay(vp);
		retval = (retval << 1) |
			((window_read16(vp, 4, Wn4_PhysicalMgmt) &
			  MDIO_DATA_READ) ? 1 : 0);
		window_write16(vp, MDIO_ENB_IN | MDIO_SHIFT_CLK,
			       4, Wn4_PhysicalMgmt);
		mdio_delay(vp);
Linus Torvalds's avatar
Linus Torvalds committed
	}
Linus Torvalds's avatar
Linus Torvalds committed
	return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
}

static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
{
	struct vortex_private *vp = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
	int i;

Linus Torvalds's avatar
Linus Torvalds committed
	if (mii_preamble_required)
Linus Torvalds's avatar
Linus Torvalds committed

	/* Shift the command bits out. */
	for (i = 31; i >= 0; i--) {
		int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
		window_write16(vp, dataval, 4, Wn4_PhysicalMgmt);
		mdio_delay(vp);
		window_write16(vp, dataval | MDIO_SHIFT_CLK,
			       4, Wn4_PhysicalMgmt);
		mdio_delay(vp);
Linus Torvalds's avatar
Linus Torvalds committed
	}
	/* Leave the interface idle. */
	for (i = 1; i >= 0; i--) {
		window_write16(vp, MDIO_ENB_IN, 4, Wn4_PhysicalMgmt);
		mdio_delay(vp);
		window_write16(vp, MDIO_ENB_IN | MDIO_SHIFT_CLK,
			       4, Wn4_PhysicalMgmt);
		mdio_delay(vp);
Linus Torvalds's avatar
Linus Torvalds committed
	}
Linus Torvalds's avatar
Linus Torvalds committed
}
Linus Torvalds's avatar
Linus Torvalds committed
/* ACPI: Advanced Configuration and Power Interface. */
/* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */
static void acpi_set_WOL(struct net_device *dev)
{
	struct vortex_private *vp = netdev_priv(dev);
	void __iomem *ioaddr = vp->ioaddr;
Linus Torvalds's avatar
Linus Torvalds committed

	device_set_wakeup_enable(vp->gendev, vp->enable_wol);

Linus Torvalds's avatar
Linus Torvalds committed
	if (vp->enable_wol) {
		/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
		window_write16(vp, 2, 7, 0x0c);
Linus Torvalds's avatar
Linus Torvalds committed
		/* The RxFilter must accept the WOL frames. */
		iowrite16(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
		iowrite16(RxEnable, ioaddr + EL3_CMD);
Linus Torvalds's avatar
Linus Torvalds committed

Steffen Klassert's avatar
Steffen Klassert committed
		if (pci_enable_wake(VORTEX_PCI(vp), PCI_D3hot, 1)) {
			pr_info("%s: WOL not supported.\n", pci_name(VORTEX_PCI(vp)));
Steffen Klassert's avatar
Steffen Klassert committed

			vp->enable_wol = 0;
			return;
		}
		if (VORTEX_PCI(vp)->current_state < PCI_D3hot)
			return;

		/* Change the power state to D3; RxEnable doesn't take effect. */
		pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot);
static void __devexit vortex_remove_one(struct pci_dev *pdev)
Linus Torvalds's avatar
Linus Torvalds committed
{
	struct net_device *dev = pci_get_drvdata(pdev);
	struct vortex_private *vp;

	if (!dev) {
		pr_err("vortex_remove_one called for Compaq device!\n");
Linus Torvalds's avatar
Linus Torvalds committed
		BUG();
	}

	vp = netdev_priv(dev);

	if (vp->cb_fn_base)
		pci_iounmap(VORTEX_PCI(vp), vp->cb_fn_base);

Linus Torvalds's avatar
Linus Torvalds committed
	unregister_netdev(dev);

	if (VORTEX_PCI(vp)) {
		pci_set_power_state(VORTEX_PCI(vp), PCI_D0);	/* Go active */
		if (vp->pm_state_valid)
			pci_restore_state(VORTEX_PCI(vp));
		pci_disable_device(VORTEX_PCI(vp));
	}
	/* Should really use issue_and_wait() here */
	iowrite16(TotalReset | ((vp->drv_flags & EEPROM_RESET) ? 0x04 : 0x14),
	     vp->ioaddr + EL3_CMD);

	pci_iounmap(VORTEX_PCI(vp), vp->ioaddr);
Linus Torvalds's avatar
Linus Torvalds committed

	pci_free_consistent(pdev,
						sizeof(struct boom_rx_desc) * RX_RING_SIZE
							+ sizeof(struct boom_tx_desc) * TX_RING_SIZE,
						vp->rx_ring,
						vp->rx_ring_dma);
	if (vp->must_free_region)
		release_region(dev->base_addr, vp->io_size);
	free_netdev(dev);
}


static struct pci_driver vortex_driver = {
	.name		= "3c59x",
	.probe		= vortex_init_one,
	.remove		= __devexit_p(vortex_remove_one),
	.id_table	= vortex_pci_tbl,
	.driver.pm	= VORTEX_PM_OPS,
Linus Torvalds's avatar
Linus Torvalds committed
};


static int vortex_have_pci;
static int vortex_have_eisa;


static int __init vortex_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
{
	int pci_rc, eisa_rc;

	pci_rc = pci_register_driver(&vortex_driver);
Linus Torvalds's avatar
Linus Torvalds committed
	eisa_rc = vortex_eisa_init();

	if (pci_rc == 0)
		vortex_have_pci = 1;
	if (eisa_rc > 0)
		vortex_have_eisa = 1;

	return (vortex_have_pci + vortex_have_eisa) ? 0 : -ENODEV;
}


static void __exit vortex_eisa_cleanup(void)
Linus Torvalds's avatar
Linus Torvalds committed
{
	struct vortex_private *vp;
	void __iomem *ioaddr;
Linus Torvalds's avatar
Linus Torvalds committed

#ifdef CONFIG_EISA
	/* Take care of the EISA devices */
	eisa_driver_unregister(&vortex_eisa_driver);
Linus Torvalds's avatar
Linus Torvalds committed
#endif
Linus Torvalds's avatar
Linus Torvalds committed
	if (compaq_net_device) {
		vp = netdev_priv(compaq_net_device);
		ioaddr = ioport_map(compaq_net_device->base_addr,
		                    VORTEX_TOTAL_SIZE);
Linus Torvalds's avatar
Linus Torvalds committed

		unregister_netdev(compaq_net_device);
		iowrite16(TotalReset, ioaddr + EL3_CMD);
		release_region(compaq_net_device->base_addr,
		               VORTEX_TOTAL_SIZE);
Linus Torvalds's avatar
Linus Torvalds committed

		free_netdev(compaq_net_device);
static void __exit vortex_cleanup(void)
Linus Torvalds's avatar
Linus Torvalds committed
{
	if (vortex_have_pci)
		pci_unregister_driver(&vortex_driver);
Linus Torvalds's avatar
Linus Torvalds committed
	if (vortex_have_eisa)
		vortex_eisa_cleanup();
Linus Torvalds's avatar
Linus Torvalds committed
}


module_init(vortex_init);
module_exit(vortex_cleanup);