📄 yellowfin.c
字号:
/* 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 */ spinlock_t lock;};static int read_eeprom(long ioaddr, int location);static int mdio_read(long ioaddr, int phy_id, int location);static void mdio_write(long ioaddr, int phy_id, int location, int value);static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int yellowfin_open(struct net_device *dev);static void yellowfin_timer(unsigned long data);static void yellowfin_tx_timeout(struct net_device *dev);static void yellowfin_init_ring(struct net_device *dev);static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev);static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *regs);static int yellowfin_rx(struct net_device *dev);static void yellowfin_error(struct net_device *dev, int intr_status);static int yellowfin_close(struct net_device *dev);static struct net_device_stats *yellowfin_get_stats(struct net_device *dev);static void set_rx_mode(struct net_device *dev);static int __devinit yellowfin_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){ struct net_device *dev; struct yellowfin_private *np; int irq; int chip_idx = ent->driver_data; static int find_cnt; long ioaddr, real_ioaddr; int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; int drv_flags = pci_id_tbl[chip_idx].drv_flags; 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 i = pci_enable_device(pdev); if (i) return i; dev = alloc_etherdev(sizeof(*np)); if (!dev) { printk (KERN_ERR PFX "cannot allocate ethernet device\n"); return -ENOMEM; } SET_MODULE_OWNER(dev); np = dev->priv; if (pci_request_regions(pdev, dev->name)) goto err_out_free_netdev; pci_set_master (pdev);#ifdef USE_IO_OPS real_ioaddr = ioaddr = pci_resource_start (pdev, 0);#else real_ioaddr = ioaddr = pci_resource_start (pdev, 1); ioaddr = (long) ioremap(ioaddr, YELLOWFIN_SIZE); if (!ioaddr) goto err_out_free_res;#endif irq = pdev->irq; if (drv_flags & DontUseEeprom) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + StnAddr + i); else { int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0); for (i = 0; i < 6; i++) dev->dev_addr[i] = read_eeprom(ioaddr, ee_offset + i); } /* Reset the chip. */ outl(0x80000000, ioaddr + DMACtrl); dev->base_addr = ioaddr; dev->irq = irq; pci_set_drvdata(pdev, dev); spin_lock_init(&np->lock); np->pci_dev = pdev; np->chip_id = chip_idx; np->drv_flags = drv_flags; ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); if (!ring_space) goto err_out_cleardev; np->tx_ring = (struct yellowfin_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 yellowfin_desc *)ring_space; np->rx_ring_dma = ring_dma; ring_space = pci_alloc_consistent(pdev, STATUS_TOTAL_SIZE, &ring_dma); if (!ring_space) goto err_out_unmap_rx; np->tx_status = (struct tx_status_words *)ring_space; np->tx_status_dma = ring_dma; if (dev->mem_start) option = dev->mem_start; /* The lower four bits are the media type. */ if (option > 0) { if (option & 0x200) np->full_duplex = 1; np->default_port = option & 15; if (np->default_port) np->medialock = 1; } if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) np->full_duplex = 1; if (np->full_duplex) np->duplex_lock = 1; /* The Yellowfin-specific entries in the device structure. */ dev->open = &yellowfin_open; dev->hard_start_xmit = &yellowfin_start_xmit; dev->stop = &yellowfin_close; dev->get_stats = &yellowfin_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &netdev_ioctl; dev->tx_timeout = yellowfin_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; if (mtu) dev->mtu = mtu; i = register_netdev(dev); if (i) goto err_out_unmap_status; printk(KERN_INFO "%s: %s type %8x at 0x%lx, ", dev->name, pci_id_tbl[chip_idx].name, inl(ioaddr + ChipRev), 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 (np->drv_flags & HasMII) { int phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { int mii_status = mdio_read(ioaddr, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; np->advertising = mdio_read(ioaddr, 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; } find_cnt++; return 0;err_out_unmap_status: pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status, np->tx_status_dma);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_free_res:#endif pci_release_regions(pdev);err_out_free_netdev: kfree (dev); return -ENODEV;}static int __devinit read_eeprom(long ioaddr, int location){ int bogus_cnt = 10000; /* Typical 33Mhz: 1050 ticks */ outb(location, ioaddr + EEAddr); outb(0x30 | ((location >> 8) & 7), ioaddr + EECtrl); while ((inb(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0) ; return inb(ioaddr + EERead);}/* MII Managemen Data I/O accesses. These routines assume the MDIO controller is idle, and do not exit until the command is finished. */static int mdio_read(long ioaddr, int phy_id, int location){ int i; outw((phy_id<<8) + location, ioaddr + MII_Addr); outw(1, ioaddr + MII_Cmd); for (i = 10000; i >= 0; i--) if ((inw(ioaddr + MII_Status) & 1) == 0) break; return inw(ioaddr + MII_Rd_Data);}static void mdio_write(long ioaddr, int phy_id, int location, int value){ int i; outw((phy_id<<8) + location, ioaddr + MII_Addr); outw(value, ioaddr + MII_Wr_Data); /* Wait for the command to finish. */ for (i = 10000; i >= 0; i--) if ((inw(ioaddr + MII_Status) & 1) == 0) break; return;}static int yellowfin_open(struct net_device *dev){ struct yellowfin_private *yp = dev->priv; long ioaddr = dev->base_addr; int i; /* Reset the chip. */ outl(0x80000000, ioaddr + DMACtrl); i = request_irq(dev->irq, &yellowfin_interrupt, SA_SHIRQ, dev->name, dev); if (i) return i; if (yellowfin_debug > 1) printk(KERN_DEBUG "%s: yellowfin_open() irq %d.\n", dev->name, dev->irq); yellowfin_init_ring(dev); outl(yp->rx_ring_dma, ioaddr + RxPtr); outl(yp->tx_ring_dma, ioaddr + TxPtr); for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + StnAddr + i); /* Set up various condition 'select' registers. There are no options here. */ outl(0x00800080, ioaddr + TxIntrSel); /* Interrupt on Tx abort */ outl(0x00800080, ioaddr + TxBranchSel); /* Branch on Tx abort */ outl(0x00400040, ioaddr + TxWaitSel); /* Wait on Tx status */ outl(0x00400040, ioaddr + RxIntrSel); /* Interrupt on Rx done */ outl(0x00400040, ioaddr + RxBranchSel); /* Branch on Rx error */ outl(0x00400040, ioaddr + RxWaitSel); /* Wait on Rx done */ /* Initialize other registers: with so many this eventually this will converted to an offset/value list. */ outl(dma_ctrl, ioaddr + DMACtrl); outw(fifo_cfg, ioaddr + FIFOcfg); /* Enable automatic generation of flow control frames, period 0xffff. */ outl(0x0030FFFF, ioaddr + FlowCtrl); yp->tx_threshold = 32; outl(yp->tx_threshold, ioaddr + TxThreshold); if (dev->if_port == 0) dev->if_port = yp->default_port; netif_start_queue(dev); /* Setting the Rx mode will start the Rx process. */ if (yp->drv_flags & IsGigabit) { /* We are always in full-duplex mode with gigabit! */ yp->full_duplex = 1; outw(0x01CF, ioaddr + Cnfg); } else { outw(0x0018, ioaddr + FrameGap0); /* 0060/4060 for non-MII 10baseT */ outw(0x1018, ioaddr + FrameGap1); outw(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); } set_rx_mode(dev); /* Enable interrupts by setting the interrupt mask. */ outw(0x81ff, ioaddr + IntrEnb); /* See enum intr_status_bits */ outw(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */ outl(0x80008000, ioaddr + RxCtrl); /* Start Rx and Tx channels. */ outl(0x80008000, ioaddr + TxCtrl); if (yellowfin_debug > 2) { printk(KERN_DEBUG "%s: Done yellowfin_open().\n", dev->name); } /* Set the timer to check for link beat. */ init_timer(&yp->timer); yp->timer.expires = jiffies + 3*HZ; yp->timer.data = (unsigned long)dev; yp->timer.function = &yellowfin_timer; /* timer handler */ add_timer(&yp->timer); return 0;}static void yellowfin_timer(unsigned long data){ struct net_device *dev = (struct net_device *)data; struct yellowfin_private *yp = dev->priv; long ioaddr = dev->base_addr; int next_tick = 60*HZ; if (yellowfin_debug > 3) { printk(KERN_DEBUG "%s: Yellowfin timer tick, status %8.8x.\n", dev->name, inw(ioaddr + IntrStatus)); } if (yp->mii_cnt) { int bmsr = mdio_read(ioaddr, yp->phys[0], MII_BMSR); int lpa = mdio_read(ioaddr, yp->phys[0], MII_LPA); int negotiated = lpa & yp->advertising; if (yellowfin_debug > 1) printk(KERN_DEBUG "%s: MII #%d status register is %4.4x, " "link partner capability %4.4x.\n", dev->name, yp->phys[0], bmsr, lpa); yp->full_duplex = mii_duplex(yp->duplex_lock, negotiated); outw(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); if (bmsr & BMSR_LSTATUS) next_tick = 60*HZ; else next_tick = 3*HZ; } yp->timer.expires = jiffies + next_tick; add_timer(&yp->timer);}static void yellowfin_tx_timeout(struct net_device *dev){ struct yellowfin_private *yp = dev->priv; long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Yellowfin transmit timed out at %d/%d Tx " "status %4.4x, Rx status %4.4x, resetting...\n", dev->name, yp->cur_tx, yp->dirty_tx, inl(ioaddr + TxStatus), inl(ioaddr + RxStatus)); /* Note: these should be KERN_DEBUG. */ if (yellowfin_debug) { int i; printk(KERN_WARNING " Rx ring %p: ", yp->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) printk(" %8.8x", yp->rx_ring[i].result_status); printk("\n"KERN_WARNING" Tx ring %p: ", yp->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) printk(" %4.4x /%8.8x", yp->tx_status[i].tx_errs, yp->tx_ring[i].result_status); printk("\n"); } /* If the hardware is found to hang regularly, we will update the code to reinitialize the chip here. */ dev->if_port = 0; /* Wake the potentially-idle transmit channel. */ outl(0x10001000, dev->base_addr + TxCtrl); if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE) netif_wake_queue (dev); /* Typical path */ dev->trans_start = jiffies; yp->stats.tx_errors++;}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void yellowfin_init_ring(struct net_device *dev)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -