natsemi.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,270 行 · 第 1/5 页
C
2,270 行
RxOff = 0x08, RxOn = 0x04, TxOff = 0x02, TxOn = 0x01,};enum ChipConfig_bits { CfgPhyDis = 0x200, CfgPhyRst = 0x400, CfgExtPhy = 0x1000, CfgAnegEnable = 0x2000, CfgAneg100 = 0x4000, CfgAnegFull = 0x8000, CfgAnegDone = 0x8000000, CfgFullDuplex = 0x20000000, CfgSpeed100 = 0x40000000, CfgLink = 0x80000000,};enum EECtrl_bits { EE_ShiftClk = 0x04, EE_DataIn = 0x01, EE_ChipSelect = 0x08, EE_DataOut = 0x02, MII_Data = 0x10, MII_Write = 0x20, MII_ShiftClk = 0x40,};enum PCIBusCfg_bits { EepromReload = 0x4,};/* Bits in the interrupt status/mask registers. */enum IntrStatus_bits { IntrRxDone = 0x0001, IntrRxIntr = 0x0002, IntrRxErr = 0x0004, 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};/* * Tx Configuration: * - 256 byte DMA burst length * - fill threshold 512 bytes (i.e. restart DMA when 512 bytes are free) * - 64 bytes initial drain threshold (i.e. begin actual transmission * when 64 byte are in the fifo) * - on tx underruns, increase drain threshold by 64. * - at most use a drain threshold of 1472 bytes: The sum of the fill * threshold and the drain threshold must be less than 2016 bytes. * */#define TX_FLTH_VAL ((512/32) << 8)#define TX_DRTH_VAL_START (64/32)#define TX_DRTH_VAL_INC 2#define TX_DRTH_VAL_LIMIT (1472/32)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};#define RX_DRTH_VAL (128/8)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 = 0x1f,};#define PHY_ADDR_NONE 32#define PHY_ADDR_INTERNAL 1/* values we might find in the silicon revision register */#define SRR_DP83815_C 0x0302#define SRR_DP83815_D 0x0403#define SRR_DP83816_A4 0x0504#define SRR_DP83816_A5 0x0505/* 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]; /* 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; /* Media monitoring timer */ struct timer_list timer; /* Frequently used values: keep some adjacent for cache effect */ struct pci_dev *pci_dev; struct netdev_desc *rx_head_desc; /* Producer/consumer ring indices */ unsigned int cur_rx, dirty_rx; unsigned int cur_tx, dirty_tx; /* Based on MTU+slack. */ unsigned int rx_buf_sz; int oom; /* Do not touch the nic registers */ int hands_off; /* external phy that is used: only valid if dev->if_port != PORT_TP */ int mii; int phy_addr_external; 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; /* expected DSPCFG value */ u16 dspcfg; /* parms saved in ethtool format */ u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */ u8 duplex; /* Duplex, half or full */ u8 autoneg; /* Autonegotiation enabled */ /* MII transceiver section */ u16 advertising; unsigned int iosize; spinlock_t lock; u32 msg_enable;};static void move_int_phy(struct net_device *dev, int addr);static int eeprom_read(void __iomem *ioaddr, int location);static int mdio_read(struct net_device *dev, int reg);static void mdio_write(struct net_device *dev, int reg, u16 data);static void init_phy_fixup(struct net_device *dev);static int miiport_read(struct net_device *dev, int phy_id, int reg);static void miiport_write(struct net_device *dev, int phy_id, int reg, u16 data);static int find_mii(struct net_device *dev);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 do_cable_magic(struct net_device *dev);static void undo_cable_magic(struct net_device *dev);static void check_link(struct net_device *dev);static void netdev_timer(unsigned long data);static void dump_ring(struct net_device *dev);static void tx_timeout(struct net_device *dev);static int alloc_ring(struct net_device *dev);static void refill_rx(struct net_device *dev);static void init_ring(struct net_device *dev);static void drain_tx(struct net_device *dev);static void drain_ring(struct net_device *dev);static void free_ring(struct net_device *dev);static void reinit_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 irqreturn_t 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 int natsemi_change_mtu(struct net_device *dev, int new_mtu);#ifdef CONFIG_NET_POLL_CONTROLLERstatic void natsemi_poll_controller(struct net_device *dev);#endifstatic 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 inline void __iomem *ns_ioaddr(struct net_device *dev){ return (void __iomem *) dev->base_addr;}static void move_int_phy(struct net_device *dev, int addr){ struct netdev_private *np = netdev_priv(dev); void __iomem *ioaddr = ns_ioaddr(dev); int target = 31; /* * The internal phy is visible on the external mii bus. Therefore we must * move it away before we can send commands to an external phy. * There are two addresses we must avoid: * - the address on the external phy that is used for transmission. * - the address that we want to access. User space can access phys * on the mii bus with SIOCGMIIREG/SIOCSMIIREG, independant from the * phy that is used for transmission. */ if (target == addr) target--; if (target == np->phy_addr_external) target--; writew(target, ioaddr + PhyCtrl); readw(ioaddr + PhyCtrl); udelay(1);}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 iostart, iosize; void __iomem *ioaddr; 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++; iostart = 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); SET_NETDEV_DEV(dev, &pdev->dev); i = pci_request_regions(pdev, DRV_NAME); if (i) goto err_pci_request_regions; ioaddr = ioremap(iostart, iosize); if (!ioaddr) { i = -ENOMEM; goto err_ioremap; } /* 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 = (unsigned long __force) ioaddr; dev->irq = irq; np = netdev_priv(dev); np->pci_dev = pdev; pci_set_drvdata(pdev, dev); np->iosize = iosize; spin_lock_init(&np->lock); np->msg_enable = (debug >= 0) ? (1<<debug)-1 : NATSEMI_DEF_MSG; np->hands_off = 0; /* Initial port: * - If the nic was configured to use an external phy and if find_mii * finds a phy: use external port, first phy that replies. * - Otherwise: internal port. * Note that the phy address for the internal phy doesn't matter: * The address would be used to access a phy over the mii bus, but * the internal phy is accessed through mapped registers. */ if (readl(ioaddr + ChipConfig) & CfgExtPhy) dev->if_port = PORT_MII; else dev->if_port = PORT_TP; /* Reset the chip to erase previous misconfiguration. */ natsemi_reload_eeprom(dev); natsemi_reset(dev); if (dev->if_port != PORT_TP) { np->phy_addr_external = find_mii(dev); if (np->phy_addr_external == PHY_ADDR_NONE) { dev->if_port = PORT_TP; np->phy_addr_external = PHY_ADDR_INTERNAL; } } else { np->phy_addr_external = PHY_ADDR_INTERNAL; } option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; if (dev->mem_start)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?