📄 forcedeth.c
字号:
*/enum { NV_OPTIMIZATION_MODE_THROUGHPUT, NV_OPTIMIZATION_MODE_CPU};static int optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT;/* * Poll interval for timer irq * * This interval determines how frequent an interrupt is generated. * The is value is determined by [(time_in_micro_secs * 100) / (2^10)] * Min = 0, and Max = 65535 */static int poll_interval = -1;/* * MSI interrupts */enum { NV_MSI_INT_DISABLED, NV_MSI_INT_ENABLED};static int msi = NV_MSI_INT_ENABLED;/* * MSIX interrupts */enum { NV_MSIX_INT_DISABLED, NV_MSIX_INT_ENABLED};static int msix = NV_MSIX_INT_DISABLED;/* * DMA 64bit */enum { NV_DMA_64BIT_DISABLED, NV_DMA_64BIT_ENABLED};static int dma_64bit = NV_DMA_64BIT_ENABLED;static inline struct fe_priv *get_nvpriv(struct net_device *dev){ return netdev_priv(dev);}static inline u8 __iomem *get_hwbase(struct net_device *dev){ return ((struct fe_priv *)netdev_priv(dev))->base;}static inline void pci_push(u8 __iomem *base){ /* force out pending posted writes */ readl(base);}static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v){ return le32_to_cpu(prd->flaglen) & ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);}static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v){ return le32_to_cpu(prd->flaglen) & LEN_MASK_V2;}static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target, int delay, int delaymax, const char *msg){ u8 __iomem *base = get_hwbase(dev); pci_push(base); do { udelay(delay); delaymax -= delay; if (delaymax < 0) { if (msg) printk(msg); return 1; } } while ((readl(base + offset) & mask) != target); return 0;}#define NV_SETUP_RX_RING 0x01#define NV_SETUP_TX_RING 0x02static void setup_hw_rings(struct net_device *dev, int rxtx_flags){ struct fe_priv *np = get_nvpriv(dev); u8 __iomem *base = get_hwbase(dev); if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { if (rxtx_flags & NV_SETUP_RX_RING) { writel((u32) cpu_to_le64(np->ring_addr), base + NvRegRxRingPhysAddr); } if (rxtx_flags & NV_SETUP_TX_RING) { writel((u32) cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); } } else { if (rxtx_flags & NV_SETUP_RX_RING) { writel((u32) cpu_to_le64(np->ring_addr), base + NvRegRxRingPhysAddr); writel((u32) (cpu_to_le64(np->ring_addr) >> 32), base + NvRegRxRingPhysAddrHigh); } if (rxtx_flags & NV_SETUP_TX_RING) { writel((u32) cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); writel((u32) (cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)) >> 32), base + NvRegTxRingPhysAddrHigh); } }}static void free_rings(struct net_device *dev){ struct fe_priv *np = get_nvpriv(dev); if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { if (np->rx_ring.orig) pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (np->rx_ring_size + np->tx_ring_size), np->rx_ring.orig, np->ring_addr); } else { if (np->rx_ring.ex) pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (np->rx_ring_size + np->tx_ring_size), np->rx_ring.ex, np->ring_addr); } if (np->rx_skb) kfree(np->rx_skb); if (np->tx_skb) kfree(np->tx_skb);}static int using_multi_irqs(struct net_device *dev){ struct fe_priv *np = get_nvpriv(dev); if (!(np->msi_flags & NV_MSI_X_ENABLED) || ((np->msi_flags & NV_MSI_X_ENABLED) && ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) return 0; else return 1;}static void nv_enable_irq(struct net_device *dev){ struct fe_priv *np = get_nvpriv(dev); if (!using_multi_irqs(dev)) { if (np->msi_flags & NV_MSI_X_ENABLED) enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); else enable_irq(np->pci_dev->irq); } else { enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); }}static void nv_disable_irq(struct net_device *dev){ struct fe_priv *np = get_nvpriv(dev); if (!using_multi_irqs(dev)) { if (np->msi_flags & NV_MSI_X_ENABLED) disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); else disable_irq(np->pci_dev->irq); } else { disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); }}/* In MSIX mode, a write to irqmask behaves as XOR */static void nv_enable_hw_interrupts(struct net_device *dev, u32 mask){ u8 __iomem *base = get_hwbase(dev); writel(mask, base + NvRegIrqMask);}static void nv_disable_hw_interrupts(struct net_device *dev, u32 mask){ struct fe_priv *np = get_nvpriv(dev); u8 __iomem *base = get_hwbase(dev); if (np->msi_flags & NV_MSI_X_ENABLED) { writel(mask, base + NvRegIrqMask); } else { if (np->msi_flags & NV_MSI_ENABLED) writel(0, base + NvRegMSIIrqMask); writel(0, base + NvRegIrqMask); }}#define MII_READ (-1)/* mii_rw: read/write a register on the PHY. * * Caller must guarantee serialization */static int mii_rw(struct net_device *dev, int addr, int miireg, int value){ u8 __iomem *base = get_hwbase(dev); u32 reg; int retval; writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); reg = readl(base + NvRegMIIControl); if (reg & NVREG_MIICTL_INUSE) { writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl); udelay(NV_MIIBUSY_DELAY); } reg = (addr << NVREG_MIICTL_ADDRSHIFT) | miireg; if (value != MII_READ) { writel(value, base + NvRegMIIData); reg |= NVREG_MIICTL_WRITE; } writel(reg, base + NvRegMIIControl); if (reg_delay(dev, NvRegMIIControl, NVREG_MIICTL_INUSE, 0, NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, NULL)) { dprintk(KERN_DEBUG "%s: mii_rw of reg %d at PHY %d timed out.\n", dev->name, miireg, addr); retval = -1; } else if (value != MII_READ) { /* it was a write operation - fewer failures are detectable */ dprintk(KERN_DEBUG "%s: mii_rw wrote 0x%x to reg %d at PHY %d\n", dev->name, value, miireg, addr); retval = 0; } else if (readl(base + NvRegMIIStatus) & NVREG_MIISTAT_ERROR) { dprintk(KERN_DEBUG "%s: mii_rw of reg %d at PHY %d failed.\n", dev->name, miireg, addr); retval = -1; } else { retval = readl(base + NvRegMIIData); dprintk(KERN_DEBUG "%s: mii_rw read from reg %d at PHY %d: 0x%x.\n", dev->name, miireg, addr, retval); } return retval;}static int phy_reset(struct net_device *dev, u32 bmcr_setup){ struct fe_priv *np = netdev_priv(dev); u32 miicontrol; unsigned int tries = 0; miicontrol = BMCR_RESET | bmcr_setup; if (mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol)) { return -1; } /* wait for 500ms */ msleep(500); /* must wait till reset is deasserted */ while (miicontrol & BMCR_RESET) { msleep(10); miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); /* FIXME: 100 tries seem excessive */ if (tries++ > 100) return -1; } return 0;}static int phy_init(struct net_device *dev){ struct fe_priv *np = get_nvpriv(dev); u8 __iomem *base = get_hwbase(dev); u32 phyinterface, phy_reserved, mii_status, mii_control, mii_control_1000,reg; /* phy errata for E3016 phy */ if (np->phy_model == PHY_MODEL_MARVELL_E3016) { reg = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ); reg &= ~PHY_MARVELL_E3016_INITMASK; if (mii_rw(dev, np->phyaddr, MII_NCONFIG, reg)) { printk(KERN_INFO "%s: phy write to errata reg failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } } if (np->phy_oui == PHY_OUI_REALTEK) { if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } } /* set advertise register */ reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); reg |= (ADVERTISE_10HALF|ADVERTISE_10FULL|ADVERTISE_100HALF|ADVERTISE_100FULL|ADVERTISE_PAUSE_ASYM|ADVERTISE_PAUSE_CAP); if (mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg)) { printk(KERN_INFO "%s: phy write to advertise failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } /* get phy interface type */ phyinterface = readl(base + NvRegPhyInterface); /* see if gigabit phy */ mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ); if (mii_status & PHY_GIGABIT) { np->gigabit = PHY_GIGABIT; mii_control_1000 = mii_rw(dev, np->phyaddr, MII_CTRL1000, MII_READ); mii_control_1000 &= ~ADVERTISE_1000HALF; if (phyinterface & PHY_RGMII) mii_control_1000 |= ADVERTISE_1000FULL; else mii_control_1000 &= ~ADVERTISE_1000FULL; if (mii_rw(dev, np->phyaddr, MII_CTRL1000, mii_control_1000)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } } else np->gigabit = 0; mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); mii_control |= BMCR_ANENABLE; /* reset the phy * (certain phys need bmcr to be setup with reset) */ if (phy_reset(dev, mii_control)) { printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev)); return PHY_ERROR; } /* phy vendor specific configuration */ if ((np->phy_oui == PHY_OUI_CICADA) && (phyinterface & PHY_RGMII) ) { phy_reserved = mii_rw(dev, np->phyaddr, MII_RESV1, MII_READ); phy_reserved &= ~(PHY_CICADA_INIT1 | PHY_CICADA_INIT2); phy_reserved |= (PHY_CICADA_INIT3 | PHY_CICADA_INIT4); if (mii_rw(dev, np->phyaddr, MII_RESV1, phy_reserved)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } phy_reserved = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ); phy_reserved |= PHY_CICADA_INIT5; if (mii_rw(dev, np->phyaddr, MII_NCONFIG, phy_reserved)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } } if (np->phy_oui == PHY_OUI_CICADA) { phy_reserved = mii_rw(dev, np->phyaddr, MII_SREVISION, MII_READ); phy_reserved |= PHY_CICADA_INIT6; if (mii_rw(dev, np->phyaddr, MII_SREVISION, phy_reserved)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } } if (np->phy_oui == PHY_OUI_VITESSE) { if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG1, PHY_VITESSE_INIT1)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT2)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, MII_READ); if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, MII_READ); phy_reserved &= ~PHY_VITESSE_INIT_MSK1; phy_reserved |= PHY_VITESSE_INIT3; if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, phy_reserved)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT4)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT5)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, MII_READ); phy_reserved &= ~PHY_VITESSE_INIT_MSK1; phy_reserved |= PHY_VITESSE_INIT3; if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, MII_READ); if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, phy_reserved)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); return PHY_ERROR; } if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT6)) { printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -