📄 sundance.c
字号:
DescEndRing=0x2000, LastFrag=0x80000000, DescIntrOnTx=0x8000, DescIntrOnDMADone=0x80000000, DisableAlign = 0x00000001,};#define PRIV_ALIGN 15 /* Required alignment mask *//* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment within the structure. */#define MII_CNT 4struct netdev_private { /* Descriptor rings first for alignment. */ struct netdev_desc *rx_ring; struct netdev_desc *tx_ring; struct sk_buff* rx_skbuff[RX_RING_SIZE]; struct sk_buff* tx_skbuff[TX_RING_SIZE]; dma_addr_t tx_ring_dma; dma_addr_t rx_ring_dma; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ /* Frequently used values: keep some adjacent for cache effect. */ spinlock_t lock; int chip_id, drv_flags; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int rx_buf_sz; /* Based on MTU+slack. */ spinlock_t txlock; /* Group with Tx control cache line. */ struct netdev_desc *last_tx; /* Last Tx descriptor used. */ unsigned int cur_tx, dirty_tx; unsigned int tx_full:1; /* The Tx queue is full. */ /* These values are keep track of the transceiver/media in use. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int medialock:1; /* Do not sense media. */ unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int an_enable:1; unsigned int speed; /* Multicast and receive mode. */ spinlock_t mcastlock; /* SMP lock multicast updates. */ u16 mcast_filter[4]; /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ u16 advertising; /* NWay media advertisement */ unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ struct pci_dev *pci_dev;};/* The station address location in the EEPROM. */#define EEPROM_SA_OFFSET 0x10static int eeprom_read(long ioaddr, int location);static int mdio_read(struct net_device *dev, int phy_id, int location);static void mdio_write(struct net_device *dev, int phy_id, int location, int value);static int netdev_open(struct net_device *dev);static void check_duplex(struct net_device *dev);static void netdev_timer(unsigned long data);static void tx_timeout(struct net_device *dev);static void init_ring(struct net_device *dev);static int start_tx(struct sk_buff *skb, struct net_device *dev);static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);static void netdev_error(struct net_device *dev, int intr_status);static int netdev_rx(struct net_device *dev);static void netdev_error(struct net_device *dev, int intr_status);static void set_rx_mode(struct net_device *dev);static struct net_device_stats *get_stats(struct net_device *dev);static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int netdev_close(struct net_device *dev);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; long ioaddr; u16 mii_ctl; void *ring_space; dma_addr_t ring_dma;/* 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_MODULE_OWNER(dev); if (pci_request_regions(pdev, DRV_NAME)) goto err_out_netdev;#ifdef USE_IO_OPS ioaddr = pci_resource_start(pdev, 0);#else ioaddr = pci_resource_start(pdev, 1); ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size); if (!ioaddr) goto err_out_res;#endif for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); dev->base_addr = ioaddr; dev->irq = irq; np = dev->priv; np->chip_id = chip_idx; np->drv_flags = pci_id_tbl[chip_idx].drv_flags; np->pci_dev = pdev; spin_lock_init(&np->lock); 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; /* 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; dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; pci_set_drvdata(pdev, dev); if (mtu) dev->mtu = mtu; i = register_netdev(dev); if (i) goto err_out_unmap_rx; printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, pci_id_tbl[chip_idx].name, ioaddr); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); if (1) { int phy, phy_idx = 0; np->phys[0] = 1; /* Default setting */ for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; np->advertising = mdio_read(dev, phy, 4); printk(KERN_INFO "%s: MII PHY found at address %d, status " "0x%4.4x advertising %4.4x.\n", dev->name, phy, mii_status, np->advertising); } } np->mii_cnt = phy_idx; if (phy_idx == 0) printk(KERN_INFO "%s: No MII transceiver found!, ASIC status %x\n", dev->name, readl(ioaddr + ASICCtrl)); } /* 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->full_duplex = 1; } else if (strcmp (media[card_idx], "100mbps_hd") == 0 || strcmp (media[card_idx], "3") == 0) { np->speed = 100; np->full_duplex = 0; } else if (strcmp (media[card_idx], "10mbps_fd") == 0 || strcmp (media[card_idx], "2") == 0) { np->speed = 10; np->full_duplex = 1; } else if (strcmp (media[card_idx], "10mbps_hd") == 0 || strcmp (media[card_idx], "1") == 0) { np->speed = 10; np->full_duplex = 0; } else { np->an_enable = 1; } } } /* Fibre PHY? */ if (readl (ioaddr + ASICCtrl) & 0x80) { /* Default 100Mbps Full */ if (np->an_enable) { np->speed = 100; np->full_duplex = 1; np->an_enable = 0; } } /* Reset PHY */ mdio_write (dev, np->phys[0], MII_BMCR, BMCR_RESET); mdelay (300); 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->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->full_duplex ? "Full" : "Half"); } /* Perhaps move the reset here? */ /* Reset the chip to erase previous misconfiguration. */ if (debug > 1) printk("ASIC Control is %x.\n", readl(ioaddr + ASICCtrl)); writew(0x007f, ioaddr + ASICCtrl + 2); if (debug > 1) printk("ASIC Control is now %x.\n", readl(ioaddr + ASICCtrl)); card_idx++; return 0;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);#ifndef USE_IO_OPS iounmap((void *)ioaddr);err_out_res:#endif pci_release_regions(pdev);err_out_netdev: kfree (dev); return -ENODEV;}/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */static int eeprom_read(long ioaddr, int location){ int boguscnt = 1000; /* Typical 190 ticks. */ writew(0x0200 | (location & 0xff), ioaddr + EECtrl); do { if (! (readw(ioaddr + EECtrl) & 0x8000)) { return readw(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() readb(mdio_addr)/* Set iff a MII transceiver on any interface requires mdio preamble. This only set with older tranceivers, so the extra code size of a per-interface flag is not worthwhile. */static const char mii_preamble_required = 1;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(long mdio_addr){ int bits = 32; /* Establish sync by sending at least 32 logic ones. */ while (--bits >= 0) { writeb(MDIO_WRITE1, mdio_addr); mdio_delay(); writeb(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr); mdio_delay(); }}static int mdio_read(struct net_device *dev, int phy_id, int location){ long mdio_addr = dev->base_addr + MIICtrl; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int i, retval = 0; if (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; writeb(dataval, mdio_addr); mdio_delay(); writeb(dataval | MDIO_ShiftClk, mdio_addr); mdio_delay(); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { writeb(MDIO_EnbIn, mdio_addr); mdio_delay(); retval = (retval << 1) | ((readb(mdio_addr) & MDIO_Data) ? 1 : 0); writeb(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){ long mdio_addr = dev->base_addr + MIICtrl; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; int i; if (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; writeb(dataval, mdio_addr); mdio_delay(); writeb(dataval | MDIO_ShiftClk, mdio_addr); mdio_delay(); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { writeb(MDIO_EnbIn, mdio_addr); mdio_delay(); writeb(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); mdio_delay(); } return;}static int netdev_open(struct net_device *dev){ struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int i; /* Do we need to reset the chip??? */ i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); if (i)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -