⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xircom_tulip_cb.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
			break;		} else if (link == 0) {			break;		}	}}/* * locate the MII interfaces and initialize them. * we disable full-duplex modes here, * because we don't know how to handle them. */static void find_mii_transceivers(struct net_device *dev){	struct xircom_private *tp = netdev_priv(dev);	int phy, phy_idx;	if (media_cap[tp->default_port] & MediaIsMII) {		u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };		tp->to_advertise = media2advert[tp->default_port - 9];	} else		tp->to_advertise =			/*ADVERTISE_100BASE4 | ADVERTISE_100FULL |*/ ADVERTISE_100HALF |			/*ADVERTISE_10FULL |*/ ADVERTISE_10HALF | ADVERTISE_CSMA;	/* Find the connected MII xcvrs.	   Doing this in open() would allow detecting external xcvrs later,	   but takes much time. */	for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) {		int mii_status = mdio_read(dev, phy, MII_BMSR);		if ((mii_status & (BMSR_100BASE4 | BMSR_100HALF | BMSR_10HALF)) == BMSR_100BASE4 ||			((mii_status & BMSR_100BASE4) == 0 &&			 (mii_status & (BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | BMSR_10HALF)) != 0)) {			int mii_reg0 = mdio_read(dev, phy, MII_BMCR);			int mii_advert = mdio_read(dev, phy, MII_ADVERTISE);			int reg4 = ((mii_status >> 6) & tp->to_advertise) | ADVERTISE_CSMA;			tp->phys[phy_idx] = phy;			tp->advertising[phy_idx++] = reg4;			printk(KERN_INFO "%s:  MII transceiver #%d "				   "config %4.4x status %4.4x advertising %4.4x.\n",				   dev->name, phy, mii_reg0, mii_status, mii_advert);		}	}	tp->mii_cnt = phy_idx;	if (phy_idx == 0) {		printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",			   dev->name);		tp->phys[0] = 0;	}}/* * To quote Arjan van de Ven: *   transceiver_voodoo() enables the external UTP plug thingy. *   it's called voodoo as I stole this code and cannot cross-reference *   it with the specification. * Actually it seems to go like this: * - GPIO2 enables the MII itself so we can talk to it. The MII gets reset *   so any prior MII settings are lost. * - GPIO0 enables the TP port so the MII can talk to the network. * - a software reset will reset both GPIO pins. * I also moved the software reset here, because doing it in xircom_up() * required enabling the GPIO pins each time, which reset the MII each time. * Thus we couldn't control the MII -- which sucks because we don't know * how to handle full-duplex modes so we *must* disable them. */static void transceiver_voodoo(struct net_device *dev){	struct xircom_private *tp = netdev_priv(dev);	long ioaddr = dev->base_addr;	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */	outl(SoftwareReset, ioaddr + CSR0);	udelay(2);	/* Deassert reset. */	outl(tp->csr0, ioaddr + CSR0);	/* Reset the xcvr interface and turn on heartbeat. */	outl(0x0008, ioaddr + CSR15);	udelay(5);  /* The delays are Xircom-recommended to give the				 * chipset time to reset the actual hardware				 * on the PCMCIA card				 */	outl(0xa8050000, ioaddr + CSR15);	udelay(5);	outl(0xa00f0000, ioaddr + CSR15);	udelay(5);	outl_CSR6(0, ioaddr);	//outl_CSR6(FullDuplexBit, ioaddr);}static int __devinit xircom_init_one(struct pci_dev *pdev, const struct pci_device_id *id){	struct net_device *dev;	struct xircom_private *tp;	static int board_idx = -1;	int chip_idx = id->driver_data;	long ioaddr;	int i;	u8 chip_rev;/* when built into the kernel, we only print version if device is found */#ifndef MODULE	static int printed_version;	if (!printed_version++)		printk(version);#endif	//printk(KERN_INFO "xircom_init_one(%s)\n", pci_name(pdev));	board_idx++;	if (pci_enable_device(pdev))		return -ENODEV;	pci_set_master(pdev);	ioaddr = pci_resource_start(pdev, 0);	dev = alloc_etherdev(sizeof(*tp));	if (!dev) {		printk (KERN_ERR DRV_NAME "%d: cannot alloc etherdev, aborting\n", board_idx);		return -ENOMEM;	}	SET_MODULE_OWNER(dev);	SET_NETDEV_DEV(dev, &pdev->dev);	dev->base_addr = ioaddr;	dev->irq = pdev->irq;	if (pci_request_regions(pdev, dev->name)) {		printk (KERN_ERR DRV_NAME " %d: cannot reserve PCI resources, aborting\n", board_idx);		goto err_out_free_netdev;	}	/* Bring the chip out of sleep mode.	   Caution: Snooze mode does not work with some boards! */	if (xircom_tbl[chip_idx].flags & HAS_ACPI)		pci_write_config_dword(pdev, PCI_POWERMGMT, 0);	/* Stop the chip's Tx and Rx processes. */	outl_CSR6(inl(ioaddr + CSR6) & ~EnableTxRx, ioaddr);	/* Clear the missed-packet counter. */	(volatile int)inl(ioaddr + CSR8);	tp = netdev_priv(dev);	spin_lock_init(&tp->lock);	tp->pdev = pdev;	tp->chip_id = chip_idx;	/* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. */	/* XXX: is this necessary for Xircom? */	tp->csr0 = csr0 & ~EnableMWI;	pci_set_drvdata(pdev, dev);	/* The lower four bits are the media type. */	if (board_idx >= 0 && board_idx < MAX_UNITS) {		tp->default_port = options[board_idx] & 15;		if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)			tp->full_duplex = 1;		if (mtu[board_idx] > 0)			dev->mtu = mtu[board_idx];	}	if (dev->mem_start)		tp->default_port = dev->mem_start;	if (tp->default_port) {		if (media_cap[tp->default_port] & MediaAlwaysFD)			tp->full_duplex = 1;	}	if (tp->full_duplex)		tp->autoneg = 0;	else		tp->autoneg = 1;	tp->speed100 = 1;	/* The Xircom-specific entries in the device structure. */	dev->open = &xircom_open;	dev->hard_start_xmit = &xircom_start_xmit;	dev->stop = &xircom_close;	dev->get_stats = &xircom_get_stats;	dev->do_ioctl = &xircom_ioctl;#ifdef HAVE_MULTICAST	dev->set_multicast_list = &set_rx_mode;#endif	dev->tx_timeout = xircom_tx_timeout;	dev->watchdog_timeo = TX_TIMEOUT;	SET_ETHTOOL_OPS(dev, &ops);	transceiver_voodoo(dev);	read_mac_address(dev);	if (register_netdev(dev))		goto err_out_cleardev;	pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);	printk(KERN_INFO "%s: %s rev %d at %#3lx,",	       dev->name, xircom_tbl[chip_idx].chip_name, chip_rev, ioaddr);	for (i = 0; i < 6; i++)		printk("%c%2.2X", i ? ':' : ' ', dev->dev_addr[i]);	printk(", IRQ %d.\n", dev->irq);	if (xircom_tbl[chip_idx].flags & HAS_MII) {		find_mii_transceivers(dev);		check_duplex(dev);	}	return 0;err_out_cleardev:	pci_set_drvdata(pdev, NULL);	pci_release_regions(pdev);err_out_free_netdev:	free_netdev(dev);	return -ENODEV;}/* 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 or future 66Mhz PCI. */#define mdio_delay() inl(mdio_addr)/* Read and write the MII registers using software-generated serial   MDIO protocol.  It is just different enough from the EEPROM protocol   to not share code.  The maxium data clock rate is 2.5 Mhz. */#define MDIO_SHIFT_CLK	0x10000#define MDIO_DATA_WRITE0 0x00000#define MDIO_DATA_WRITE1 0x20000#define MDIO_ENB		0x00000		/* Ignore the 0x02000 databook setting. */#define MDIO_ENB_IN		0x40000#define MDIO_DATA_READ	0x80000static int mdio_read(struct net_device *dev, int phy_id, int location){	int i;	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;	int retval = 0;	long ioaddr = dev->base_addr;	long mdio_addr = ioaddr + CSR9;	/* Establish sync by sending at least 32 logic ones. */	for (i = 32; i >= 0; i--) {		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);		mdio_delay();		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);		mdio_delay();	}	/* Shift the read command bits out. */	for (i = 15; i >= 0; i--) {		int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;		outl(MDIO_ENB | dataval, mdio_addr);		mdio_delay();		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);		mdio_delay();	}	/* Read the two transition, 16 data, and wire-idle bits. */	for (i = 19; i > 0; i--) {		outl(MDIO_ENB_IN, mdio_addr);		mdio_delay();		retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);		mdio_delay();	}	return (retval>>1) & 0xffff;}static void mdio_write(struct net_device *dev, int phy_id, int location, int value){	int i;	int cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;	long ioaddr = dev->base_addr;	long mdio_addr = ioaddr + CSR9;	/* Establish sync by sending 32 logic ones. */	for (i = 32; i >= 0; i--) {		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);		mdio_delay();		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);		mdio_delay();	}	/* Shift the command bits out. */	for (i = 31; i >= 0; i--) {		int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;		outl(MDIO_ENB | dataval, mdio_addr);		mdio_delay();		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);		mdio_delay();	}	/* Clear out extra bits. */	for (i = 2; i > 0; i--) {		outl(MDIO_ENB_IN, mdio_addr);		mdio_delay();		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);		mdio_delay();	}	return;}static voidxircom_up(struct net_device *dev){	struct xircom_private *tp = netdev_priv(dev);	long ioaddr = dev->base_addr;	int i;	xircom_init_ring(dev);	/* Clear the tx ring */	for (i = 0; i < TX_RING_SIZE; i++) {		tp->tx_skbuff[i] = NULL;		tp->tx_ring[i].status = 0;	}	if (xircom_debug > 1)		printk(KERN_DEBUG "%s: xircom_up() irq %d.\n", dev->name, dev->irq);	outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);	outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);	tp->saved_if_port = dev->if_port;	if (dev->if_port == 0)		dev->if_port = tp->default_port;	tp->csr6 = TxThresh10 /*| FullDuplexBit*/;						/* XXX: why 10 and not 100? */	set_rx_mode(dev);	/* Start the chip's Tx to process setup frame. */	outl_CSR6(tp->csr6, ioaddr);	outl_CSR6(tp->csr6 | EnableTx, ioaddr);	/* Acknowledge all outstanding interrupts sources */	outl(xircom_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);	/* Enable interrupts by setting the interrupt mask. */	outl(xircom_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);	/* Enable Rx */	outl_CSR6(tp->csr6 | EnableTxRx, ioaddr);	/* Rx poll demand */	outl(0, ioaddr + CSR2);	/* Tell the net layer we're ready */	netif_start_queue (dev);	/* Check current media state */	xircom_media_change(dev);	if (xircom_debug > 2) {		printk(KERN_DEBUG "%s: Done xircom_up(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",			   dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5),			   inl(ioaddr + CSR6));	}}static intxircom_open(struct net_device *dev){	struct xircom_private *tp = netdev_priv(dev);	if (request_irq(dev->irq, &xircom_interrupt, SA_SHIRQ, dev->name, dev))		return -EAGAIN;	xircom_up(dev);	tp->open = 1;	return 0;}static void xircom_tx_timeout(struct net_device *dev){	struct xircom_private *tp = netdev_priv(dev);	long ioaddr = dev->base_addr;	if (media_cap[dev->if_port] & MediaIsMII) {		/* Do nothing -- the media monitor should handle this. */		if (xircom_debug > 1)			printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",				   dev->name);	}#if defined(way_too_many_messages)	if (xircom_debug > 3) {		int i;		for (i = 0; i < RX_RING_SIZE; i++) {			u8 *buf = (u8 *)(tp->rx_ring[i].buffer1);			int j;			printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x  "				   "%2.2x %2.2x %2.2x.\n",				   i, (unsigned int)tp->rx_ring[i].status,				   (unsigned int)tp->rx_ring[i].length,				   (unsigned int)tp->rx_ring[i].buffer1,				   (unsigned int)tp->rx_ring[i].buffer2,				   buf[0], buf[1], buf[2]);			for (j = 0; buf[j] != 0xee && j < 1600; j++)				if (j < 100) printk(" %2.2x", buf[j]);			printk(" j=%d.\n", j);		}		printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)tp->rx_ring);		for (i = 0; i < RX_RING_SIZE; i++)			printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);		printk("\n" KERN_DEBUG "  Tx ring %8.8x: ", (int)tp->tx_ring);		for (i = 0; i < TX_RING_SIZE; i++)			printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);		printk("\n");	}#endif	/* Stop and restart the chip's Tx/Rx processes . */	outl_CSR6(tp->csr6 | EnableRx, ioaddr);	outl_CSR6(tp->csr6 | EnableTxRx, ioaddr);	/* Trigger an immediate transmit demand. */	outl(0, ioaddr + CSR1);	dev->trans_start = jiffies;	netif_wake_queue (dev);	tp->stats.tx_errors++;}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void xircom_init_ring(struct net_device *dev){	struct xircom_private *tp = netdev_priv(dev);	int i;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -