📄 starfire.c
字号:
enum intr_status_bits { IntrLinkChange=0xf0000000, IntrStatsMax=0x08000000, IntrAbnormalSummary=0x02000000, IntrGeneralTimer=0x01000000, IntrSoftware=0x800000, IntrRxComplQ1Low=0x400000, IntrTxComplQLow=0x200000, IntrPCI=0x100000, IntrDMAErr=0x080000, IntrTxDataLow=0x040000, IntrRxComplQ2Low=0x020000, IntrRxDescQ1Low=0x010000, IntrNormalSummary=0x8000, IntrTxDone=0x4000, IntrTxDMADone=0x2000, IntrTxEmpty=0x1000, IntrEarlyRxQ2=0x0800, IntrEarlyRxQ1=0x0400, IntrRxQ2Done=0x0200, IntrRxQ1Done=0x0100, IntrRxGFPDead=0x80, IntrRxDescQ2Low=0x40, IntrNoTxCsum=0x20, IntrTxBadID=0x10, IntrHiPriTxBadID=0x08, IntrRxGfp=0x04, IntrTxGfp=0x02, IntrPCIPad=0x01, /* not quite bits */ IntrRxDone=IntrRxQ2Done | IntrRxQ1Done, IntrRxEmpty=IntrRxDescQ1Low | IntrRxDescQ2Low, IntrNormalMask=0xff00, IntrAbnormalMask=0x3ff00fe,};/* Bits in the RxFilterMode register. */enum rx_mode_bits { AcceptBroadcast=0x04, AcceptAllMulticast=0x02, AcceptAll=0x01, AcceptMulticast=0x10, AcceptMyPhys=0xE040,};/* Bits in the TxDescCtrl register. */enum tx_ctrl_bits { TxDescSpaceUnlim=0x00, TxDescSpace32=0x10, TxDescSpace64=0x20, TxDescSpace128=0x30, TxDescSpace256=0x40, TxDescType0=0x00, TxDescType1=0x01, TxDescType2=0x02, TxDescType3=0x03, TxDescType4=0x04, TxNoDMACompletion=0x08, TxDescQ64bit=0x80, TxHiPriFIFOThreshShift=24, TxPadLenShift=16, TxDMABurstSizeShift=8,};/* Bits in the RxDescQCtrl register. */enum rx_ctrl_bits { RxBufferLenShift=16, RxMinDescrThreshShift=0, RxPrefetchMode=0x8000, Rx2048QEntries=0x4000, RxVariableQ=0x2000, RxDesc64bit=0x1000, RxDescQAddr64bit=0x0100, RxDescSpace4=0x000, RxDescSpace8=0x100, RxDescSpace16=0x200, RxDescSpace32=0x300, RxDescSpace64=0x400, RxDescSpace128=0x500, RxConsumerWrEn=0x80,};/* Bits in the RxCompletionAddr register */enum rx_compl_bits { RxComplQAddr64bit=0x80, TxComplProducerWrEn=0x40, RxComplType0=0x00, RxComplType1=0x10, RxComplType2=0x20, RxComplType3=0x30, RxComplThreshShift=0,};/* The Rx and Tx buffer descriptors. */struct starfire_rx_desc { u32 rxaddr; /* Optionally 64 bits. */};enum rx_desc_bits { RxDescValid=1, RxDescEndRing=2,};/* Completion queue entry. You must update the page allocation, init_ring and the shift count in rx() if using a larger format. */#ifdef HAS_FIRMWARE#define csum_rx_status#endif /* HAS_FIRMWARE */struct rx_done_desc { u32 status; /* Low 16 bits is length. */#ifdef csum_rx_status u32 status2; /* Low 16 bits is csum */#endif /* csum_rx_status */#ifdef full_rx_status u32 status2; u16 vlanid; u16 csum; /* partial checksum */ u32 timestamp;#endif /* full_rx_status */};enum rx_done_bits { RxOK=0x20000000, RxFIFOErr=0x10000000, RxBufQ2=0x08000000,};#ifdef ZEROCOPY/* Type 0 Tx descriptor. *//* If more fragments are needed, don't forget to change the descriptor spacing as well! */struct starfire_tx_desc { u32 status; u32 nbufs; u32 first_addr; u16 first_len; u16 total_len; struct { u32 addr; u32 len; } frag[MAX_STARFIRE_FRAGS];};#else /* not ZEROCOPY *//* Type 1 Tx descriptor. */struct starfire_tx_desc { u32 status; /* Upper bits are status, lower 16 length. */ u32 first_addr;};#endif /* not ZEROCOPY */enum tx_desc_bits { TxDescID=0xB0000000, TxCRCEn=0x01000000, TxDescIntr=0x08000000, TxRingWrap=0x04000000, TxCalTCP=0x02000000,};struct tx_done_report { u32 status; /* timestamp, index. */#if 0 u32 intrstatus; /* interrupt status */#endif};struct rx_ring_info { struct sk_buff *skb; dma_addr_t mapping;};struct tx_ring_info { struct sk_buff *skb; dma_addr_t first_mapping;#ifdef ZEROCOPY dma_addr_t frag_mapping[MAX_STARFIRE_FRAGS];#endif /* ZEROCOPY */};#define PHY_CNT 2struct netdev_private { /* Descriptor rings first for alignment. */ struct starfire_rx_desc *rx_ring; struct starfire_tx_desc *tx_ring; dma_addr_t rx_ring_dma; dma_addr_t tx_ring_dma; /* The addresses of rx/tx-in-place skbuffs. */ struct rx_ring_info rx_info[RX_RING_SIZE]; struct tx_ring_info tx_info[TX_RING_SIZE]; /* Pointers to completion queues (full pages). */ struct rx_done_desc *rx_done_q; dma_addr_t rx_done_q_dma; unsigned int rx_done; struct tx_done_report *tx_done_q; dma_addr_t tx_done_q_dma; unsigned int tx_done; struct net_device_stats stats; struct pci_dev *pci_dev; /* Frequently used values: keep some adjacent for cache effect. */ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ unsigned int tx_full:1, /* The Tx queue is full. */ /* These values keep track of the transceiver/media in use. */ autoneg:1, /* Autonegotiation allowed. */ full_duplex:1, /* Full-duplex operation. */ speed100:1; /* Set if speed == 100MBit. */ unsigned int intr_mitigation; u32 tx_mode; u8 tx_threshold; /* MII transceiver section. */ u16 advertising; /* NWay media advertisement */ int phy_cnt; /* MII device addresses. */ unsigned char phys[PHY_CNT]; /* 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 void check_duplex(struct net_device *dev);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 void netdev_media_change(struct net_device *dev);static int __devinit starfire_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){ struct netdev_private *np; int i, irq, option, chip_idx = ent->driver_data; struct net_device *dev; static int card_idx = -1; long ioaddr; int drv_flags, io_size; int boguscnt; u8 cache;/* 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 card_idx++; if (pci_enable_device (pdev)) return -EIO; ioaddr = pci_resource_start(pdev, 0); io_size = pci_resource_len(pdev, 0); if (!ioaddr || ((pci_resource_flags(pdev, 0) & IORESOURCE_MEM) == 0)) { printk (KERN_ERR DRV_NAME " %d: no PCI MEM resources, aborting\n", card_idx); return -ENODEV; } dev = alloc_etherdev(sizeof(*np)); if (!dev) { printk (KERN_ERR DRV_NAME " %d: cannot alloc etherdev, aborting\n", card_idx); return -ENOMEM; } SET_MODULE_OWNER(dev); irq = pdev->irq; if (pci_request_regions (pdev, dev->name)) { printk (KERN_ERR DRV_NAME " %d: cannot reserve PCI resources, aborting\n", card_idx); goto err_out_free_netdev; } ioaddr = (long) ioremap (ioaddr, io_size); if (!ioaddr) { printk (KERN_ERR DRV_NAME " %d: cannot remap 0x%x @ 0x%lx, aborting\n", card_idx, io_size, ioaddr); goto err_out_free_res; } pci_set_master (pdev); /* set PCI cache size */ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache); if ((cache << 2) != SMP_CACHE_BYTES) { printk(KERN_INFO " PCI cache line size set incorrectly " "(%i bytes) by BIOS/FW, correcting to %i\n", (cache << 2), SMP_CACHE_BYTES); pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, SMP_CACHE_BYTES >> 2); }#ifdef ZEROCOPY /* Starfire can do SG and TCP/UDP checksumming */ dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;#endif /* ZEROCOPY */ /* Serial EEPROM reads are hidden by the hardware. */ for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20-i);#if ! defined(final_version) /* Dump the EEPROM contents during development. */ if (debug > 4) for (i = 0; i < 0x20; i++) printk("%2.2x%s", (unsigned int)readb(ioaddr + EEPROMCtrl + i), i % 16 != 15 ? " " : "\n");#endif /* Issue soft reset */ writel(0x8000, ioaddr + TxMode); udelay(1000); writel(0, ioaddr + TxMode); /* Reset the chip to erase previous misconfiguration. */ writel(1, ioaddr + PCIDeviceConfig); boguscnt = 1000; while (--boguscnt > 0) { udelay(10); if ((readl(ioaddr + PCIDeviceConfig) & 1) == 0) break; } if (boguscnt == 0) printk("%s: chipset reset never completed!\n", dev->name); /* wait a little longer */ udelay(1000); dev->base_addr = ioaddr; dev->irq = irq; np = dev->priv; pci_set_drvdata(pdev, dev); np->pci_dev = pdev; drv_flags = netdrv_tbl[chip_idx].drv_flags; option = card_idx < MAX_UNITS ? options[card_idx] : 0; if (dev->mem_start) option = dev->mem_start; /* The lower four bits are the media type. */ if (option & 0x200) np->full_duplex = 1; if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) np->full_duplex = 1; if (np->full_duplex) np->autoneg = 0; else np->autoneg = 1; np->speed100 = 1; /* The chip-specific entries in the device structure. */ dev->open = &netdev_open; dev->hard_start_xmit = &start_tx; init_tx_timer(dev, tx_timeout, TX_TIMEOUT); dev->stop = &netdev_close; dev->get_stats = &get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &netdev_ioctl; if (mtu) dev->mtu = mtu; i = register_netdev(dev); if (i) goto err_out_cleardev; printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, netdrv_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 (drv_flags & CanHaveMII) { int phy, phy_idx = 0; int mii_status; for (phy = 0; phy < 32 && phy_idx < PHY_CNT; phy++) { mdio_write(dev, phy, MII_BMCR, BMCR_RESET); mdelay(100); boguscnt = 1000; while (--boguscnt > 0) if ((mdio_read(dev, phy, MII_BMCR) & BMCR_RESET) == 0) break; if (boguscnt == 0) { printk("%s: PHY reset never completed!\n", dev->name); continue; } mii_status = mdio_read(dev, phy, MII_BMSR); if (mii_status != 0) { np->phys[phy_idx++] = phy; np->advertising = mdio_read(dev, phy, MII_ADVERTISE); 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); /* there can be only one PHY on-board */ break; } } np->phy_cnt = phy_idx; }#ifdef ZEROCOPY printk(KERN_INFO "%s: scatter-gather and hardware TCP cksumming enabled.\n", dev->name);#else /* not ZEROCOPY */ printk(KERN_INFO "%s: scatter-gather and hardware TCP cksumming disabled.\n", dev->name);#endif /* not ZEROCOPY */ return 0;err_out_cleardev: pci_set_drvdata(pdev, NULL); iounmap((void *)ioaddr);err_out_free_res: pci_release_regions (pdev);err_out_free_netdev: unregister_netdev(dev); kfree(dev); return -ENODEV;}/* 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); if (boguscnt == 0) return 0; if ((result & 0xffff) == 0xffff) return 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -