📄 natsemi.c
字号:
IntrRxEarly = 0x0008, IntrRxIdle = 0x0010, IntrRxOverrun = 0x0020, IntrTxDone = 0x0040, IntrTxIntr = 0x0080, IntrTxErr = 0x0100, IntrTxIdle = 0x0200, IntrTxUnderrun = 0x0400, StatsMax = 0x0800, SWInt = 0x1000, WOLPkt = 0x2000, LinkChange = 0x4000, IntrHighBits = 0x8000, RxStatusFIFOOver = 0x10000, IntrPCIErr = 0xf00000, RxResetDone = 0x1000000, TxResetDone = 0x2000000, IntrAbnormalSummary = 0xCD20,};/* * Default Interrupts: * Rx OK, Rx Packet Error, Rx Overrun, * Tx OK, Tx Packet Error, Tx Underrun, * MIB Service, Phy Interrupt, High Bits, * Rx Status FIFO overrun, * Received Target Abort, Received Master Abort, * Signalled System Error, Received Parity Error */#define DEFAULT_INTR 0x00f1cd65enum TxConfig_bits { TxDrthMask = 0x3f, TxFlthMask = 0x3f00, TxMxdmaMask = 0x700000, TxMxdma_512 = 0x0, TxMxdma_4 = 0x100000, TxMxdma_8 = 0x200000, TxMxdma_16 = 0x300000, TxMxdma_32 = 0x400000, TxMxdma_64 = 0x500000, TxMxdma_128 = 0x600000, TxMxdma_256 = 0x700000, TxCollRetry = 0x800000, TxAutoPad = 0x10000000, TxMacLoop = 0x20000000, TxHeartIgn = 0x40000000, TxCarrierIgn = 0x80000000};enum RxConfig_bits { RxDrthMask = 0x3e, RxMxdmaMask = 0x700000, RxMxdma_512 = 0x0, RxMxdma_4 = 0x100000, RxMxdma_8 = 0x200000, RxMxdma_16 = 0x300000, RxMxdma_32 = 0x400000, RxMxdma_64 = 0x500000, RxMxdma_128 = 0x600000, RxMxdma_256 = 0x700000, RxAcceptLong = 0x8000000, RxAcceptTx = 0x10000000, RxAcceptRunt = 0x40000000, RxAcceptErr = 0x80000000};enum ClkRun_bits { PMEEnable = 0x100, PMEStatus = 0x8000,};enum WolCmd_bits { WakePhy = 0x1, WakeUnicast = 0x2, WakeMulticast = 0x4, WakeBroadcast = 0x8, WakeArp = 0x10, WakePMatch0 = 0x20, WakePMatch1 = 0x40, WakePMatch2 = 0x80, WakePMatch3 = 0x100, WakeMagic = 0x200, WakeMagicSecure = 0x400, SecureHack = 0x100000, WokePhy = 0x400000, WokeUnicast = 0x800000, WokeMulticast = 0x1000000, WokeBroadcast = 0x2000000, WokeArp = 0x4000000, WokePMatch0 = 0x8000000, WokePMatch1 = 0x10000000, WokePMatch2 = 0x20000000, WokePMatch3 = 0x40000000, WokeMagic = 0x80000000, WakeOptsSummary = 0x7ff};enum RxFilterAddr_bits { RFCRAddressMask = 0x3ff, AcceptMulticast = 0x00200000, AcceptMyPhys = 0x08000000, AcceptAllPhys = 0x10000000, AcceptAllMulticast = 0x20000000, AcceptBroadcast = 0x40000000, RxFilterEnable = 0x80000000};enum StatsCtrl_bits { StatsWarn = 0x1, StatsFreeze = 0x2, StatsClear = 0x4, StatsStrobe = 0x8,};enum MIntrCtrl_bits { MICRIntEn = 0x2,};enum PhyCtrl_bits { PhyAddrMask = 0xf,};#define SRR_REV_C 0x0302#define SRR_REV_D 0x0403/* The Rx and Tx buffer descriptors. *//* Note that using only 32 bit fields simplifies conversion to big-endian architectures. */struct netdev_desc { u32 next_desc; s32 cmd_status; u32 addr; u32 software_use;};/* Bits in network_desc.status */enum desc_status_bits { DescOwn=0x80000000, DescMore=0x40000000, DescIntr=0x20000000, DescNoCRC=0x10000000, DescPktOK=0x08000000, DescSizeMask=0xfff, DescTxAbort=0x04000000, DescTxFIFO=0x02000000, DescTxCarrier=0x01000000, DescTxDefer=0x00800000, DescTxExcDefer=0x00400000, DescTxOOWCol=0x00200000, DescTxExcColl=0x00100000, DescTxCollCount=0x000f0000, DescRxAbort=0x04000000, DescRxOver=0x02000000, DescRxDest=0x01800000, DescRxLong=0x00400000, DescRxRunt=0x00200000, DescRxInvalid=0x00100000, DescRxCRC=0x00080000, DescRxAlign=0x00040000, DescRxLoop=0x00020000, DesRxColl=0x00010000,};struct netdev_private { /* Descriptor rings first for alignment. */ dma_addr_t ring_dma; struct netdev_desc* rx_ring; struct netdev_desc* tx_ring; /* The addresses of receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; dma_addr_t rx_dma[RX_RING_SIZE]; /* The saved address of a sent-in-place packet/buffer, for later free(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; dma_addr_t tx_dma[TX_RING_SIZE]; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ /* Frequently used values: keep some adjacent for cache effect. */ struct pci_dev *pci_dev; struct netdev_desc *rx_head_desc; 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. */ /* These values are keep track of the transceiver/media in use. */ unsigned int full_duplex; /* Rx filter. */ u32 cur_rx_mode; u32 rx_filter[16]; /* FIFO and PCI burst thresholds. */ u32 tx_config, rx_config; /* original contents of ClkRun register */ u32 SavedClkRun; /* silicon revision */ u32 srr; /* MII transceiver section. */ u16 advertising; /* NWay media advertisement */ unsigned int iosize; spinlock_t lock; u32 msg_enable;};static int eeprom_read(long ioaddr, int location);static int mdio_read(struct net_device *dev, int phy_id, int reg);static void mdio_write(struct net_device *dev, int phy_id, int reg, u16 data);static void natsemi_reset(struct net_device *dev);static void natsemi_reload_eeprom(struct net_device *dev);static void natsemi_stop_rxtx(struct net_device *dev);static int netdev_open(struct net_device *dev);static void check_link(struct net_device *dev);static void netdev_timer(unsigned long data);static void tx_timeout(struct net_device *dev);static int alloc_ring(struct net_device *dev);static void init_ring(struct net_device *dev);static void drain_ring(struct net_device *dev);static void free_ring(struct net_device *dev);static void init_registers(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 void netdev_rx(struct net_device *dev);static void netdev_tx_done(struct net_device *dev);static void __set_rx_mode(struct net_device *dev);static void set_rx_mode(struct net_device *dev);static void __get_stats(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_set_wol(struct net_device *dev, u32 newval);static int netdev_get_wol(struct net_device *dev, u32 *supported, u32 *cur);static int netdev_set_sopass(struct net_device *dev, u8 *newval);static int netdev_get_sopass(struct net_device *dev, u8 *data);static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd);static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd);static void enable_wol_mode(struct net_device *dev, int enable_intr);static int netdev_close(struct net_device *dev);static int netdev_get_regs(struct net_device *dev, u8 *buf);static int netdev_get_eeprom(struct net_device *dev, u8 *buf);static int __devinit natsemi_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent){ struct net_device *dev; struct netdev_private *np; int i, option, irq, chip_idx = ent->driver_data; static int find_cnt = -1; unsigned long ioaddr, iosize; const int pcibar = 1; /* PCI base address register */ int prev_eedata; u32 tmp;/* 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; /* natsemi has a non-standard PM control register * in PCI config space. Some boards apparently need * to be brought to D0 in this manner. */ pci_read_config_dword(pdev, PCIPM, &tmp); if (tmp & PCI_PM_CTRL_STATE_MASK) { /* D0 state, disable PME assertion */ u32 newtmp = tmp & ~PCI_PM_CTRL_STATE_MASK; pci_write_config_dword(pdev, PCIPM, newtmp); } find_cnt++; ioaddr = pci_resource_start(pdev, pcibar); iosize = pci_resource_len(pdev, pcibar); irq = pdev->irq; if (natsemi_pci_info[chip_idx].flags & PCI_USES_MASTER) pci_set_master(pdev); dev = alloc_etherdev(sizeof (struct netdev_private)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); i = pci_request_regions(pdev, dev->name); if (i) { kfree(dev); return i; } { void *mmio = ioremap (ioaddr, iosize); if (!mmio) { pci_release_regions(pdev); kfree(dev); return -ENOMEM; } ioaddr = (unsigned long) mmio; } /* Work around the dropped serial bit. */ prev_eedata = eeprom_read(ioaddr, 6); for (i = 0; i < 3; i++) { int eedata = eeprom_read(ioaddr, i + 7); dev->dev_addr[i*2] = (eedata << 1) + (prev_eedata >> 15); dev->dev_addr[i*2+1] = eedata >> 7; prev_eedata = eedata; } dev->base_addr = ioaddr; dev->irq = irq; np = dev->priv; np->pci_dev = pdev; pci_set_drvdata(pdev, dev); np->iosize = iosize; spin_lock_init(&np->lock); np->msg_enable = debug; /* Reset the chip to erase previous misconfiguration. */ natsemi_reload_eeprom(dev); natsemi_reset(dev); option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; 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; if (option & 15) printk(KERN_INFO "%s: ignoring user supplied media type %d", dev->name, option & 15); } if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) np->full_duplex = 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 = &netdev_ioctl; dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; if (mtu) dev->mtu = mtu; i = register_netdev(dev); if (i) { pci_release_regions(pdev); unregister_netdev(dev); kfree(dev); pci_set_drvdata(pdev, NULL); return i; } netif_carrier_off(dev); if (netif_msg_drv(np)) { printk(KERN_INFO "%s: %s at %#08lx, ", dev->name, natsemi_pci_info[chip_idx].name, ioaddr); for (i = 0; i < ETH_ALEN-1; i++) printk("%02x:", dev->dev_addr[i]); printk("%02x, IRQ %d.\n", dev->dev_addr[i], irq); } np->advertising = mdio_read(dev, 1, MII_ADVERTISE); if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000 && netif_msg_probe(np)) { u32 chip_config = readl(ioaddr + ChipConfig); printk(KERN_INFO "%s: Transceiver default autonegotiation %s " "10%s %s duplex.\n", dev->name, chip_config & CfgAnegEnable ? "enabled, advertise" : "disabled, force", chip_config & CfgAneg100 ? "0" : "", chip_config & CfgAnegFull ? "full" : "half"); } if (netif_msg_probe(np)) printk(KERN_INFO "%s: Transceiver status %#04x advertising %#04x.\n", dev->name, mdio_read(dev, 1, MII_BMSR), np->advertising); /* save the silicon revision for later querying */ np->srr = readl(ioaddr + SiliconRev); if (netif_msg_hw(np)) printk(KERN_INFO "%s: silicon revision %#04x.\n", dev->name, np->srr); return 0;}/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses. *//* Delay between EEPROM clock transitions. No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need a delay. Note that pre-2.0.34 kernels had a cache-alignment bug that made udelay() unreliable. The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is depricated.*/#define eeprom_delay(ee_addr) readl(ee_addr)#define EE_Write0 (EE_ChipSelect)#define EE_Write1 (EE_ChipSelect | EE_DataIn)/* The EEPROM commands include the alway-set leading bit. */enum EEPROM_Cmds { EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),};static int eeprom_read(long addr, int location){ int i; int retval = 0; long ee_addr = addr + EECtrl; int read_cmd = location | EE_ReadCmd; writel(EE_Write0, ee_addr); /* Shift the read command bits out. */ for (i = 10; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0; writel(dataval, ee_addr); eeprom_delay(ee_addr); writel(dataval | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); } writel(EE_ChipSelect, ee_addr); eeprom_delay(ee_addr); for (i = 0; i < 16; i++) { writel(EE_ChipSelect | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); retval |= (readl(ee_addr) & EE_DataOut) ? 1 << i : 0; writel(EE_ChipSelect, ee_addr); eeprom_delay(ee_addr); } /* Terminate the EEPROM access. */ writel(EE_Write0, ee_addr); writel(0, ee_addr); return retval;}/* MII transceiver control section. The 83815 series has an internal transceiver, and we present the management registers as if they were MII connected. */static int mdio_read(struct net_device *dev, int phy_id, int reg){ if (phy_id == 1 && reg < 32) return readl(dev->base_addr+BasicControl+(reg<<2))&0xffff; else return 0xffff;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -