📄 starfire.c
字号:
unsigned int rx_done; struct tx_done_report *tx_done_q __attribute__((aligned (L1_CACHE_BYTES))); unsigned int tx_done; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ int msg_level; int chip_id, drv_flags; struct pci_dev *pci_dev; /* Frequently used values: keep some adjacent for cache effect. */ int max_interrupt_work; int intr_enable; unsigned int restore_intr_enable:1; /* Set if temporarily masked. */ unsigned int polling:1; /* Erk, IRQ err. */ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int rx_buf_sz; /* Based on MTU+slack. */ int rx_copybreak; unsigned int cur_tx, dirty_tx; unsigned int tx_full:1; /* The Tx queue is full. */ /* These values keep track of the transceiver/media in use. */ unsigned int full_duplex:1, /* Full-duplex operation requested. */ medialock:1, /* Xcvr set to fixed speed/duplex. */ rx_flowctrl:1, tx_flowctrl:1; /* Use 802.3x flow control. */ unsigned int default_port; /* Last dev->if_port value. */ u32 tx_mode; u8 tx_threshold; u32 cur_rx_mode; u16 mc_filter[32]; int multicast_filter_limit; /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ u16 advertising; /* NWay media advertisement */ unsigned char phys[2]; /* MII device addresses. */};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 int change_mtu(struct net_device *dev, int new_mtu);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 mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int netdev_close(struct net_device *dev);/* A list of our installed devices, for removing the driver module. */static struct net_device *root_net_dev = NULL;#ifndef MODULEint starfire_probe(struct net_device *dev){ if (pci_drv_register(&starfire_drv_id, dev) < 0) return -ENODEV; printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2); return 0;}#endifstatic void *starfire_probe1(struct pci_dev *pdev, void *init_dev, long ioaddr, int irq, int chip_idx, int card_idx){ struct net_device *dev; struct netdev_private *np; void *priv_mem; int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; dev = init_etherdev(init_dev, 0); if (!dev) return NULL; printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, pci_id_tbl[chip_idx].name, ioaddr); /* Serial EEPROM reads are hidden by the hardware. */ for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20-i); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); /* Make certain elements e.g. descriptor lists are aligned. */ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL); /* Check for the very unlikely case of no memory. */ if (priv_mem == NULL) return NULL; /* Reset the chip to erase previous misconfiguration. */ writel(ChipResetCmd, ioaddr + PCIDeviceConfig); dev->base_addr = ioaddr; dev->irq = irq; dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN); memset(np, 0, sizeof(*np)); np->priv_addr = priv_mem; np->next_module = root_net_dev; root_net_dev = dev; np->pci_dev = pdev; np->chip_id = chip_idx; np->drv_flags = pci_id_tbl[chip_idx].drv_flags; np->msg_level = (1 << debug) - 1; np->rx_copybreak = rx_copybreak; np->max_interrupt_work = max_interrupt_work; np->multicast_filter_limit = multicast_filter_limit; if (dev->mem_start) option = dev->mem_start; if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) np->full_duplex = 1; if (np->full_duplex) { if (np->msg_level & NETIF_MSG_PROBE) printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation" " disabled.\n", dev->name); np->medialock = 1; } /* 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 = &mii_ioctl; dev->change_mtu = &change_mtu; if (np->drv_flags & CanHaveMII) { int phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < 4; 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); if (np->msg_level & NETIF_MSG_PROBE) 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; } /* Force the media type after detecting the transceiver. */ if (option > 0) { if (option & 0x220) np->full_duplex = 1; np->default_port = option & 0x3ff; if (np->default_port & 0x330) { np->medialock = 1; if (np->msg_level & NETIF_MSG_PROBE) printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", (option & 0x300 ? 100 : 10), (np->full_duplex ? "full" : "half")); mdio_write(dev, np->phys[0], 0, ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */ (np->full_duplex ? 0x0100 : 0)); /* Full duplex? */ } } return dev;}/* Read the MII Management Data I/O (MDIO) interfaces. */static int mdio_read(struct net_device *dev, int phy_id, int location){ long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2); int result, boguscnt=1000; /* ??? Should we add a busy-wait here? */ do result = readl(mdio_addr); while ((result & 0xC0000000) != 0x80000000 && --boguscnt >= 0); return result & 0xffff;}static void mdio_write(struct net_device *dev, int phy_id, int location, int value){ long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2); writel(value, mdio_addr); /* The busy-wait will occur before a read. */ return;}static int netdev_open(struct net_device *dev){ struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; int i; MOD_INC_USE_COUNT; if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) { MOD_DEC_USE_COUNT; return -EAGAIN; } /* We have no reports that indicate we need to reset the chip. But to be on the safe side... */ /* Disable the Rx and Tx, and reset the chip. */ writel(0, ioaddr + GenCtrl); writel(ChipResetCmd, ioaddr + PCIDeviceConfig); if (np->msg_level & NETIF_MSG_IFUP) printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", dev->name, dev->irq); /* Allocate the various queues, failing gracefully. */ if (np->tx_done_q == 0) np->tx_done_q = (struct tx_done_report *)get_free_page(GFP_KERNEL); if (np->rx_done_q == 0) np->rx_done_q = (struct rx_done_desc *)get_free_page(GFP_KERNEL); if (np->tx_ring == 0) np->tx_ring = (struct starfire_tx_desc *)get_free_page(GFP_KERNEL); if (np->rx_ring == 0) np->rx_ring = (struct starfire_rx_desc *)get_free_page(GFP_KERNEL); if (np->tx_done_q == 0 || np->rx_done_q == 0 || np->rx_ring == 0 || np->tx_ring == 0) { /* Retain the pages to increase our chances next time. */ MOD_DEC_USE_COUNT; return -ENOMEM; } init_ring(dev); /* Set the size of the Rx buffers. */ writel((np->rx_buf_sz<<16) | 0xA000, ioaddr + RxDescQCtrl); /* Set Tx descriptor to type 1 and padding to 0 bytes. */ writel(0x02000401, ioaddr + TxDescCtrl);#if defined(STARFIRE_ADDR_64BITS) writel(virt_to_bus(np->rx_ring) >> 32, ioaddr + RxDescQHiAddr); writel(virt_to_bus(np->tx_ring) >> 32, ioaddr + TxRingHiAddr);#else writel(0, ioaddr + RxDescQHiAddr); writel(0, ioaddr + TxRingHiAddr); writel(0, ioaddr + CompletionHiAddr);#endif writel(virt_to_bus(np->rx_ring), ioaddr + RxDescQAddr); writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr); writel(virt_to_bus(np->tx_done_q), ioaddr + TxCompletionAddr); writel(virt_to_bus(np->rx_done_q), ioaddr + RxCompletionAddr); if (np->msg_level & NETIF_MSG_IFUP) printk(KERN_DEBUG "%s: Filling in the station address.\n", dev->name); /* Fill both the unused Tx SA register and the Rx perfect filter. */ for (i = 0; i < 6; i++) writeb(dev->dev_addr[i], ioaddr + StationAddr + 5-i); for (i = 0; i < 16; i++) { u16 *eaddrs = (u16 *)dev->dev_addr; long setup_frm = ioaddr + 0x56000 + i*16; writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4; writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4; writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8; } /* Initialize other registers. */ /* Configure the PCI bus bursts and FIFO thresholds. */ np->tx_mode = 0; /* Initialized when TxMode set. */ np->tx_threshold = 4; writel(np->tx_threshold, ioaddr + TxThreshold); writel(interrupt_mitigation, ioaddr + IntrTimerCtrl); if (dev->if_port == 0) dev->if_port = np->default_port; if (np->msg_level & NETIF_MSG_IFUP) printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name); set_rx_mode(dev); np->advertising = mdio_read(dev, np->phys[0], 4); check_duplex(dev); netif_start_tx_queue(dev); /* Set the interrupt mask and enable PCI interrupts. */ np->intr_enable = IntrRxDone | IntrRxEmpty | IntrRxPCIErr | IntrTxDone | IntrTxEmpty | IntrTxPCIErr | StatsMax | LinkChange | IntrNormalSummary | IntrAbnormalSummary | 0x0010; writel(np->intr_enable, ioaddr + IntrEnable); writel(PCIIntEnb | readl(ioaddr + PCIDeviceConfig), ioaddr + PCIDeviceConfig); /* Enable the Rx and Tx units. */ writel(TxEnable|RxEnable, ioaddr + GenCtrl); if (np->msg_level & NETIF_MSG_IFUP) printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name); /* 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); return 0;}/* The starfire can handle frame sizes up to 64KB, but we arbitrarily * limit the size. */static int change_mtu(struct net_device *dev, int new_mtu){ if ((new_mtu < 68) || (new_mtu > 17268)) return -EINVAL; if (netif_running(dev)) return -EBUSY; dev->mtu = new_mtu; return 0;}static void check_duplex(struct net_device *dev){ struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; int new_tx_mode; new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0) | (np->rx_flowctrl ? 0x0400:0); if (np->medialock) { if (np->full_duplex) new_tx_mode |= 2; } else { int mii_reg5 = mdio_read(dev, np->phys[0], 5); int negotiated = mii_reg5 & np->advertising; int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; if (duplex) new_tx_mode |= 2; if (np->full_duplex != duplex) { np->full_duplex = duplex; if (np->msg_level & NETIF_MSG_LINK) 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); } } if (new_tx_mode != np->tx_mode) { np->tx_mode = new_tx_mode; writel(np->tx_mode | 0x8000, ioaddr + TxMode); writel(np->tx_mode, ioaddr + TxMode); }}/* Check for duplex changes, but mostly check for failures. */static void netdev_timer(unsigned long data){ struct net_device *dev = (struct net_device *)data; struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; int status = readl(ioaddr + IntrStatus); static long last_msg = 0; /* Normally we check only every few seconds. */ np->timer.expires = jiffies + 60*HZ; if (np->msg_level & NETIF_MSG_TIMER) { printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n", dev->name, status); } /* Check for a missing chip or failed interrupt line. * The latter may be falsely triggered, so we check twice. */ if (status == 0xffffffff) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -