sundance.c

来自「linux 内核源代码」· C语言 代码 · 共 1,781 行 · 第 1/4 页

C
1,781
字号
		udelay(100);	}}static int __devinit sundance_probe1 (struct pci_dev *pdev,				      const struct pci_device_id *ent){	struct net_device *dev;	struct netdev_private *np;	static int card_idx;	int chip_idx = ent->driver_data;	int irq;	int i;	void __iomem *ioaddr;	u16 mii_ctl;	void *ring_space;	dma_addr_t ring_dma;#ifdef USE_IO_OPS	int bar = 0;#else	int bar = 1;#endif	int phy, phy_end, phy_idx = 0;	DECLARE_MAC_BUF(mac);/* 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	if (pci_enable_device(pdev))		return -EIO;	pci_set_master(pdev);	irq = pdev->irq;	dev = alloc_etherdev(sizeof(*np));	if (!dev)		return -ENOMEM;	SET_NETDEV_DEV(dev, &pdev->dev);	if (pci_request_regions(pdev, DRV_NAME))		goto err_out_netdev;	ioaddr = pci_iomap(pdev, bar, netdev_io_size);	if (!ioaddr)		goto err_out_res;	for (i = 0; i < 3; i++)		((__le16 *)dev->dev_addr)[i] =			cpu_to_le16(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET));	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);	dev->base_addr = (unsigned long)ioaddr;	dev->irq = irq;	np = netdev_priv(dev);	np->base = ioaddr;	np->pci_dev = pdev;	np->chip_id = chip_idx;	np->msg_enable = (1 << debug) - 1;	spin_lock_init(&np->lock);	tasklet_init(&np->rx_tasklet, rx_poll, (unsigned long)dev);	tasklet_init(&np->tx_tasklet, tx_poll, (unsigned long)dev);	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);	if (!ring_space)		goto err_out_cleardev;	np->tx_ring = (struct netdev_desc *)ring_space;	np->tx_ring_dma = ring_dma;	ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);	if (!ring_space)		goto err_out_unmap_tx;	np->rx_ring = (struct netdev_desc *)ring_space;	np->rx_ring_dma = ring_dma;	np->mii_if.dev = dev;	np->mii_if.mdio_read = mdio_read;	np->mii_if.mdio_write = mdio_write;	np->mii_if.phy_id_mask = 0x1f;	np->mii_if.reg_num_mask = 0x1f;	/* The chip-specific entries in the device structure. */	dev->open = &netdev_open;	dev->hard_start_xmit = &start_tx;	dev->stop = &netdev_close;	dev->get_stats = &get_stats;	dev->set_multicast_list = &set_rx_mode;	dev->do_ioctl = &netdev_ioctl;	SET_ETHTOOL_OPS(dev, &ethtool_ops);	dev->tx_timeout = &tx_timeout;	dev->watchdog_timeo = TX_TIMEOUT;	dev->change_mtu = &change_mtu;	pci_set_drvdata(pdev, dev);	i = register_netdev(dev);	if (i)		goto err_out_unmap_rx;	printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",	       dev->name, pci_id_tbl[chip_idx].name, ioaddr,	       print_mac(mac, dev->dev_addr), irq);	np->phys[0] = 1;		/* Default setting */	np->mii_preamble_required++;	/*	 * It seems some phys doesn't deal well with address 0 being accessed	 * first	 */	if (sundance_pci_tbl[np->chip_id].device == 0x0200) {		phy = 0;		phy_end = 31;	} else {		phy = 1;		phy_end = 32;	/* wraps to zero, due to 'phy & 0x1f' */	}	for (; phy <= phy_end && phy_idx < MII_CNT; phy++) {		int phyx = phy & 0x1f;		int mii_status = mdio_read(dev, phyx, MII_BMSR);		if (mii_status != 0xffff  &&  mii_status != 0x0000) {			np->phys[phy_idx++] = phyx;			np->mii_if.advertising = mdio_read(dev, phyx, MII_ADVERTISE);			if ((mii_status & 0x0040) == 0)				np->mii_preamble_required++;			printk(KERN_INFO "%s: MII PHY found at address %d, status "				   "0x%4.4x advertising %4.4x.\n",				   dev->name, phyx, mii_status, np->mii_if.advertising);		}	}	np->mii_preamble_required--;	if (phy_idx == 0) {		printk(KERN_INFO "%s: No MII transceiver found, aborting.  ASIC status %x\n",			   dev->name, ioread32(ioaddr + ASICCtrl));		goto err_out_unregister;	}	np->mii_if.phy_id = np->phys[0];	/* Parse override configuration */	np->an_enable = 1;	if (card_idx < MAX_UNITS) {		if (media[card_idx] != NULL) {			np->an_enable = 0;			if (strcmp (media[card_idx], "100mbps_fd") == 0 ||			    strcmp (media[card_idx], "4") == 0) {				np->speed = 100;				np->mii_if.full_duplex = 1;			} else if (strcmp (media[card_idx], "100mbps_hd") == 0				   || strcmp (media[card_idx], "3") == 0) {				np->speed = 100;				np->mii_if.full_duplex = 0;			} else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||				   strcmp (media[card_idx], "2") == 0) {				np->speed = 10;				np->mii_if.full_duplex = 1;			} else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||				   strcmp (media[card_idx], "1") == 0) {				np->speed = 10;				np->mii_if.full_duplex = 0;			} else {				np->an_enable = 1;			}		}		if (flowctrl == 1)			np->flowctrl = 1;	}	/* Fibre PHY? */	if (ioread32 (ioaddr + ASICCtrl) & 0x80) {		/* Default 100Mbps Full */		if (np->an_enable) {			np->speed = 100;			np->mii_if.full_duplex = 1;			np->an_enable = 0;		}	}	/* Reset PHY */	mdio_write (dev, np->phys[0], MII_BMCR, BMCR_RESET);	mdelay (300);	/* If flow control enabled, we need to advertise it.*/	if (np->flowctrl)		mdio_write (dev, np->phys[0], MII_ADVERTISE, np->mii_if.advertising | 0x0400);	mdio_write (dev, np->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);	/* Force media type */	if (!np->an_enable) {		mii_ctl = 0;		mii_ctl |= (np->speed == 100) ? BMCR_SPEED100 : 0;		mii_ctl |= (np->mii_if.full_duplex) ? BMCR_FULLDPLX : 0;		mdio_write (dev, np->phys[0], MII_BMCR, mii_ctl);		printk (KERN_INFO "Override speed=%d, %s duplex\n",			np->speed, np->mii_if.full_duplex ? "Full" : "Half");	}	/* Perhaps move the reset here? */	/* Reset the chip to erase previous misconfiguration. */	if (netif_msg_hw(np))		printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl));	sundance_reset(dev, 0x00ff << 16);	if (netif_msg_hw(np))		printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl));	card_idx++;	return 0;err_out_unregister:	unregister_netdev(dev);err_out_unmap_rx:        pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);err_out_unmap_tx:        pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma);err_out_cleardev:	pci_set_drvdata(pdev, NULL);	pci_iounmap(pdev, ioaddr);err_out_res:	pci_release_regions(pdev);err_out_netdev:	free_netdev (dev);	return -ENODEV;}static int change_mtu(struct net_device *dev, int new_mtu){	if ((new_mtu < 68) || (new_mtu > 8191)) /* Set by RxDMAFrameLen */		return -EINVAL;	if (netif_running(dev))		return -EBUSY;	dev->mtu = new_mtu;	return 0;}#define eeprom_delay(ee_addr)	ioread32(ee_addr)/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */static int __devinit eeprom_read(void __iomem *ioaddr, int location){	int boguscnt = 10000;		/* Typical 1900 ticks. */	iowrite16(0x0200 | (location & 0xff), ioaddr + EECtrl);	do {		eeprom_delay(ioaddr + EECtrl);		if (! (ioread16(ioaddr + EECtrl) & 0x8000)) {			return ioread16(ioaddr + EEData);		}	} while (--boguscnt > 0);	return 0;}/*  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 33Mhz PCI cycles. */#define mdio_delay() ioread8(mdio_addr)enum mii_reg_bits {	MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004,};#define MDIO_EnbIn  (0)#define MDIO_WRITE0 (MDIO_EnbOutput)#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)/* Generate the preamble required for initial synchronization and   a few older transceivers. */static void mdio_sync(void __iomem *mdio_addr){	int bits = 32;	/* Establish sync by sending at least 32 logic ones. */	while (--bits >= 0) {		iowrite8(MDIO_WRITE1, mdio_addr);		mdio_delay();		iowrite8(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);		mdio_delay();	}}static int mdio_read(struct net_device *dev, int phy_id, int location){	struct netdev_private *np = netdev_priv(dev);	void __iomem *mdio_addr = np->base + MIICtrl;	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;	int i, retval = 0;	if (np->mii_preamble_required)		mdio_sync(mdio_addr);	/* Shift the read command bits out. */	for (i = 15; i >= 0; i--) {		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;		iowrite8(dataval, mdio_addr);		mdio_delay();		iowrite8(dataval | MDIO_ShiftClk, mdio_addr);		mdio_delay();	}	/* Read the two transition, 16 data, and wire-idle bits. */	for (i = 19; i > 0; i--) {		iowrite8(MDIO_EnbIn, mdio_addr);		mdio_delay();		retval = (retval << 1) | ((ioread8(mdio_addr) & MDIO_Data) ? 1 : 0);		iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);		mdio_delay();	}	return (retval>>1) & 0xffff;}static void mdio_write(struct net_device *dev, int phy_id, int location, int value){	struct netdev_private *np = netdev_priv(dev);	void __iomem *mdio_addr = np->base + MIICtrl;	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;	int i;	if (np->mii_preamble_required)		mdio_sync(mdio_addr);	/* Shift the command bits out. */	for (i = 31; i >= 0; i--) {		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;		iowrite8(dataval, mdio_addr);		mdio_delay();		iowrite8(dataval | MDIO_ShiftClk, mdio_addr);		mdio_delay();	}	/* Clear out extra bits. */	for (i = 2; i > 0; i--) {		iowrite8(MDIO_EnbIn, mdio_addr);		mdio_delay();		iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);		mdio_delay();	}	return;}static int netdev_open(struct net_device *dev){	struct netdev_private *np = netdev_priv(dev);	void __iomem *ioaddr = np->base;	unsigned long flags;	int i;	/* Do we need to reset the chip??? */	i = request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev);	if (i)		return i;	if (netif_msg_ifup(np))		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",			   dev->name, dev->irq);	init_ring(dev);	iowrite32(np->rx_ring_dma, ioaddr + RxListPtr);	/* The Tx list pointer is written as packets are queued. */	/* Initialize other registers. */	__set_mac_addr(dev);#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)	iowrite16(dev->mtu + 18, ioaddr + MaxFrameSize);#else	iowrite16(dev->mtu + 14, ioaddr + MaxFrameSize);#endif	if (dev->mtu > 2047)		iowrite32(ioread32(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl);	/* Configure the PCI bus bursts and FIFO thresholds. */	if (dev->if_port == 0)		dev->if_port = np->default_port;	spin_lock_init(&np->mcastlock);	set_rx_mode(dev);	iowrite16(0, ioaddr + IntrEnable);	iowrite16(0, ioaddr + DownCounter);	/* Set the chip to poll every N*320nsec. */	iowrite8(100, ioaddr + RxDMAPollPeriod);	iowrite8(127, ioaddr + TxDMAPollPeriod);	/* Fix DFE-580TX packet drop issue */	if (np->pci_dev->revision >= 0x14)		iowrite8(0x01, ioaddr + DebugCtrl1);	netif_start_queue(dev);	spin_lock_irqsave(&np->lock, flags);	reset_tx(dev);	spin_unlock_irqrestore(&np->lock, flags);	iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);	if (netif_msg_ifup(np))		printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x "			   "MAC Control %x, %4.4x %4.4x.\n",			   dev->name, ioread32(ioaddr + RxStatus), ioread8(ioaddr + TxStatus),			   ioread32(ioaddr + MACCtrl0),			   ioread16(ioaddr + MACCtrl1), ioread16(ioaddr + MACCtrl0));	/* Set the timer to check for link beat. */	init_timer(&np->timer);	np->timer.expires = jiffies + 3*HZ;	np->timer.data = (unsigned long)dev;	np->timer.function = &netdev_timer;				/* timer handler */	add_timer(&np->timer);	/* Enable interrupts by setting the interrupt mask. */	iowrite16(DEFAULT_INTR, ioaddr + IntrEnable);	return 0;}static void check_duplex(struct net_device *dev){	struct netdev_private *np = netdev_priv(dev);	void __iomem *ioaddr = np->base;	int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);	int negotiated = mii_lpa & np->mii_if.advertising;	int duplex;	/* Force media */	if (!np->an_enable || mii_lpa == 0xffff) {		if (np->mii_if.full_duplex)			iowrite16 (ioread16 (ioaddr + MACCtrl0) | EnbFullDuplex,				ioaddr + MACCtrl0);		return;	}	/* Autonegotiation */	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;	if (np->mii_if.full_duplex != duplex) {		np->mii_if.full_duplex = duplex;		if (netif_msg_link(np))			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d "				   "negotiated capability %4.4x.\n", dev->name,				   duplex ? "full" : "half", np->phys[0], negotiated);		iowrite16(ioread16(ioaddr + MACCtrl0) | duplex ? 0x20 : 0, ioaddr + MACCtrl0);	}}static void netdev_timer(unsigned long data){

⌨️ 快捷键说明

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