X-Git-Url: https://bbs.cooldavid.org/git/?p=jme.git;a=blobdiff_plain;f=jme.c;h=f7350d56acd1ea7bc33dc7bb8458f15f5d7ce3b8;hp=ac6fc1ced2a60ea8aed02a15804aad5f0a35eea5;hb=refs%2Fheads%2Fmsix_test;hpb=cdcdc9eb2783c559a7d88c2fd14f433b8a843c59 diff --git a/jme.c b/jme.c index ac6fc1c..f7350d5 100644 --- a/jme.c +++ b/jme.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -58,8 +60,9 @@ static int jme_mdio_read(struct net_device *netdev, int phy, int reg) { struct jme_adapter *jme = netdev_priv(netdev); - int i, val; + int i, val, again = (reg == MII_BMSR)?1:0; +read_again: jwrite32(jme, JME_SMI, SMI_OP_REQ | smi_phy_addr(phy) | smi_reg_addr(reg)); @@ -77,6 +80,9 @@ jme_mdio_read(struct net_device *netdev, int phy, int reg) return 0; } + if(again--) + goto read_again; + return ((val & SMI_DATA_MASK) >> SMI_DATA_SHIFT); } @@ -94,8 +100,7 @@ jme_mdio_write(struct net_device *netdev, wmb(); for (i = JME_PHY_TIMEOUT * 50 ; i > 0 ; --i) { udelay(20); - val = jread32(jme, JME_SMI); - if ((val & SMI_OP_REQ) == 0) + if ((jread32(jme, JME_SMI) & SMI_OP_REQ) == 0) break; } @@ -115,10 +120,11 @@ jme_reset_phy_processor(struct jme_adapter *jme) MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); - jme_mdio_write(jme->dev, - jme->mii_if.phy_id, - MII_CTRL1000, - ADVERTISE_1000FULL | ADVERTISE_1000HALF); + if(jme->pdev->device == JME_GE_DEVICE) + jme_mdio_write(jme->dev, + jme->mii_if.phy_id, + MII_CTRL1000, + ADVERTISE_1000FULL | ADVERTISE_1000HALF); val = jme_mdio_read(jme->dev, jme->mii_if.phy_id, @@ -205,7 +211,7 @@ jme_reload_eeprom(struct jme_adapter *jme) jwrite32(jme, JME_SMBCSR, val); mdelay(12); - for (i = JME_SMB_TIMEOUT; i > 0; --i) + for (i = JME_EEPROM_RELOAD_TIMEOUT; i > 0; --i) { mdelay(1); if ((jread32(jme, JME_SMBCSR) & SMBCSR_RELOAD) == 0) @@ -213,12 +219,10 @@ jme_reload_eeprom(struct jme_adapter *jme) } if(i == 0) { - jeprintk(jme->dev->name, "eeprom reload timeout\n"); + jeprintk("jme", "eeprom reload timeout\n"); return -EIO; } } - else - return -EIO; return 0; } @@ -329,7 +333,7 @@ jme_linkstat_from_phy(struct jme_adapter *jme) phylink = jme_mdio_read(jme->dev, jme->mii_if.phy_id, 17); bmsr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMSR); - if(bmsr & BMCR_ANCOMP) + if(bmsr & BMSR_ANCOMP) phylink |= PHY_LINK_AUTONEG_COMPLETE; return phylink; @@ -611,7 +615,7 @@ jme_disable_tx_engine(struct jme_adapter *jme) static void jme_set_clean_rxdesc(struct jme_adapter *jme, int i) { - struct jme_ring *rxring = jme->rxring; + struct jme_ring *rxring = &(jme->rxring[0]); register volatile struct rxdesc* rxdesc = rxring->desc; struct jme_buffer_info *rxbi = rxring->bufinf; rxdesc += i; @@ -1050,7 +1054,6 @@ jme_pcc_tasklet(unsigned long arg) struct jme_adapter *jme = (struct jme_adapter*)arg; struct net_device *netdev = jme->dev; - if(unlikely(!netif_carrier_ok(netdev) || (atomic_read(&jme->link_changing) != 1) )) { @@ -1327,11 +1330,6 @@ jme_intr_msi(struct jme_adapter *jme, __u32 intrstat) */ jwrite32f(jme, JME_IENC, INTR_ENABLE); - /* - * Write 1 clear interrupt status - */ - jwrite32f(jme, JME_IEVE, intrstat); - if(intrstat & (INTR_LINKCH | INTR_SWINTR)) { tasklet_schedule(&jme->linkch_task); goto out_reenable; @@ -1359,12 +1357,16 @@ jme_intr_msi(struct jme_adapter *jme, __u32 intrstat) atomic_inc(&jme->rx_empty); tasklet_schedule(&jme->rxempty_task); } - - if(intrstat & (INTR_PCCRX0TO | INTR_PCCRX0)) + else if(intrstat & (INTR_PCCRX0TO | INTR_PCCRX0)) tasklet_schedule(&jme->rxclean_task); } out_reenable: + /* + * Write 1 clear interrupt status + */ + jwrite32f(jme, JME_IEVE, intrstat); + /* * Re-enable interrupt */ @@ -1418,6 +1420,130 @@ jme_msi(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t +jme_msix_misc(int irq, void *dev_id) +{ + struct net_device *netdev = dev_id; + struct jme_adapter *jme = netdev_priv(netdev); + __u32 intrstat; + + pci_dma_sync_single_for_cpu(jme->pdev, + jme->shadow_dma, + sizeof(__u32) * SHADOW_REG_NR, + PCI_DMA_FROMDEVICE); + intrstat = jme->shadow_regs[SHADOW_IEVE]; + jme->shadow_regs[SHADOW_IEVE] &= ~INTR_EN_MISC; + + /* + * Disable interrupt + */ + jwrite32f(jme, JME_IENC, INTR_EN_MISC); + + if(intrstat & (INTR_LINKCH | INTR_SWINTR)) { + tasklet_schedule(&jme->linkch_task); + goto out_reenable; + } + + if(intrstat & INTR_TMINTR) + tasklet_schedule(&jme->pcc_task); + +out_reenable: + /* + * Write 1 clear interrupt status + */ + jwrite32f(jme, JME_IEVE, INTR_EN_MISC); + + /* + * Re-enable interrupt + */ + jwrite32f(jme, JME_IENS, INTR_EN_MISC); + + return IRQ_HANDLED; +} + +static irqreturn_t +jme_msix_tx(int irq, void *dev_id) +{ + struct net_device *netdev = dev_id; + struct jme_adapter *jme = netdev_priv(netdev); + + /* + * Disable interrupt + */ + jwrite32f(jme, JME_IENC, INTR_EN_TX); + + if(unlikely(atomic_read(&jme->link_changing) != 1)) + goto out_reenable; + + tasklet_schedule(&jme->txclean_task); + +out_reenable: + /* + * Write 1 clear interrupt status + */ + jwrite32f(jme, JME_IEVE, INTR_EN_TX | INTR_TX0); + + /* + * Re-enable interrupt + */ + jwrite32f(jme, JME_IENS, INTR_EN_TX); + + return IRQ_HANDLED; +} + +static irqreturn_t +jme_msix_rx(int irq, void *dev_id) +{ + struct net_device *netdev = dev_id; + struct jme_adapter *jme = netdev_priv(netdev); + __u32 intrstat; + + pci_dma_sync_single_for_cpu(jme->pdev, + jme->shadow_dma, + sizeof(__u32) * SHADOW_REG_NR, + PCI_DMA_FROMDEVICE); + intrstat = jme->shadow_regs[SHADOW_IEVE]; + jme->shadow_regs[SHADOW_IEVE] &= ~INTR_EN_RX0; + + /* + * Disable interrupt + */ + jwrite32f(jme, JME_IENC, INTR_EN_RX0); + + if(unlikely(atomic_read(&jme->link_changing) != 1)) + goto out_reenable; + + if(jme->flags & JME_FLAG_POLL) { + if(intrstat & INTR_RX0EMP) + atomic_inc(&jme->rx_empty); + + if(likely(JME_RX_SCHEDULE_PREP(jme))) { + jme_polling_mode(jme); + JME_RX_SCHEDULE(jme); + } + } + else { + if(intrstat & INTR_RX0EMP) { + atomic_inc(&jme->rx_empty); + tasklet_schedule(&jme->rxempty_task); + } + else if(intrstat & (INTR_PCCRX0TO | INTR_PCCRX0)) + tasklet_schedule(&jme->rxclean_task); + } + +out_reenable: + /* + * Write 1 clear interrupt status + */ + jwrite32f(jme, JME_IEVE, INTR_EN_RX0 | INTR_RX0); + + /* + * Re-enable interrupt + */ + jwrite32f(jme, JME_IENS, INTR_EN_RX0); + + return IRQ_HANDLED; +} static void jme_reset_link(struct jme_adapter *jme) @@ -1438,6 +1564,132 @@ jme_restart_an(struct jme_adapter *jme) spin_unlock_irqrestore(&jme->phy_lock, flags); } +static void +jme_setup_msix_info(struct jme_adapter *jme, struct msix_entry *msix_ent) +{ + int i; + + for (i = 0; i < JME_MSIX_VEC_NR; i++) { + jme->msix[i].requested = false; + jme->msix[i].vector = msix_ent[i].vector; + strcpy(jme->msix[i].name, jme->dev->name); + } + + jme->msix[0].handler = jme_msix_misc; + jme->msix[1].handler = jme_msix_tx; + jme->msix[2].handler = jme_msix_rx; + + strcat(jme->msix[0].name, "-misc"); + strcat(jme->msix[1].name, "-tx"); + strcat(jme->msix[2].name, "-rx"); +} + +static void +jme_fill_msix_regs(struct jme_adapter *jme) +{ + __u32 mask = 1, reg_msix = 0; + int i, vec; + + for(i = 0 ; i < 32 ; ++i) { + if(mask & INTR_EN_TX) + vec = 1; + else if(mask & INTR_EN_RX0) + vec = 2; + else + vec = 0; + + if(!(i & 7)) + reg_msix = 0; + reg_msix |= (vec & 7) << ((i & 7) << 2); + if((i & 7) == 7) + jwrite32(jme, + JME_MSIX_ENT + ((i >> 3) << 2), + reg_msix); + + mask <<= 1; + } +} + +static int +jme_request_msix_irq(struct jme_adapter *jme) +{ + int i, rc; + struct jme_msix_info *msix_info; + + for (i = 0; i < JME_MSIX_VEC_NR; i++) { + msix_info = jme->msix + i; + rc = request_irq(msix_info->vector, + msix_info->handler, + 0, + msix_info->name, + jme->dev); + if(rc) + break; +#if 0 +#ifdef CONFIG_SMP + /* + * Try to set different cpumask for each irq, + * ignoring assign fail since it has no critical + * effect to the working function. + */ + if(irq_can_set_affinity(msix_info->vector)) + irq_set_affinity(msix_info->vector, + cpumask_of_cpu(i % num_online_cpus())); +#endif +#endif + msix_info->requested = true; + } + + return rc; +} + +static void +jme_free_msix(struct jme_adapter *jme) +{ + int i; + struct jme_msix_info *msix_info; + + for (i = 0; i < JME_MSIX_VEC_NR; i++) { + msix_info = jme->msix + i; + if(msix_info->requested) + free_irq(msix_info->vector, jme->dev); + else + break; + msix_info->requested = false; + } + pci_disable_msix(jme->pdev); +} + +static int +jme_request_msix(struct jme_adapter *jme) +{ + int i, rc; + struct msix_entry msix_ent[JME_MSIX_VEC_NR]; + + for (i = 0; i < JME_MSIX_VEC_NR; i++) { + msix_ent[i].entry = i; + msix_ent[i].vector = 0; + } + + rc = pci_enable_msix(jme->pdev, msix_ent, JME_MSIX_VEC_NR); + if (rc) + goto out; + + jme_setup_msix_info(jme, msix_ent); + jme_fill_msix_regs(jme); + + rc = jme_request_msix_irq(jme); + if(rc) + goto out_free_msix; + + return 0; + +out_free_msix: + jme_free_msix(jme); +out: + return rc; +} + static int jme_request_irq(struct jme_adapter *jme) { @@ -1446,7 +1698,13 @@ jme_request_irq(struct jme_adapter *jme) irq_handler_t handler = jme_intr; int irq_flags = IRQF_SHARED; - if (!pci_enable_msi(jme->pdev)) { + + if(!jme_request_msix(jme)) { + jme->flags |= JME_FLAG_MSIX; + return 0; + } + + if(!pci_enable_msi(jme->pdev)) { jme->flags |= JME_FLAG_MSI; handler = jme_msi; irq_flags = 0; @@ -1474,12 +1732,18 @@ jme_request_irq(struct jme_adapter *jme) static void jme_free_irq(struct jme_adapter *jme) { - free_irq(jme->pdev->irq, jme->dev); - if (jme->flags & JME_FLAG_MSI) { - pci_disable_msi(jme->pdev); - jme->flags &= ~JME_FLAG_MSI; - jme->dev->irq = jme->pdev->irq; - } + if(jme->flags & JME_FLAG_MSIX) { + jme_free_msix(jme); + jme->flags &= ~JME_FLAG_MSIX; + } + else { + free_irq(jme->pdev->irq, jme->dev); + if (jme->flags & JME_FLAG_MSI) { + pci_disable_msi(jme->pdev); + jme->flags &= ~JME_FLAG_MSI; + jme->dev->irq = jme->pdev->irq; + } + } } static int @@ -1792,7 +2056,7 @@ jme_fill_first_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx) txbi->skb = skb; txbi->len = skb->len; if(!(txbi->start_xmit = jiffies)) - txbi->start_xmit = 1; + txbi->start_xmit = (0UL-1); return 0; } @@ -1885,13 +2149,13 @@ jme_set_macaddr(struct net_device *netdev, void *p) spin_lock(&jme->macaddr_lock); memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - val = addr->sa_data[3] << 24 | - addr->sa_data[2] << 16 | - addr->sa_data[1] << 8 | - addr->sa_data[0]; + val = (addr->sa_data[3] & 0xff) << 24 | + (addr->sa_data[2] & 0xff) << 16 | + (addr->sa_data[1] & 0xff) << 8 | + (addr->sa_data[0] & 0xff); jwrite32(jme, JME_RXUMA_LO, val); - val = addr->sa_data[5] << 8 | - addr->sa_data[4]; + val = (addr->sa_data[5] & 0xff) << 8 | + (addr->sa_data[4] & 0xff); jwrite32(jme, JME_RXUMA_HI, val); spin_unlock(&jme->macaddr_lock); @@ -2018,7 +2282,7 @@ jme_get_drvinfo(struct net_device *netdev, static int jme_get_regs_len(struct net_device *netdev) { - return 0x400; + return JME_REG_LEN; } static void @@ -2028,7 +2292,16 @@ mmapio_memcpy(struct jme_adapter *jme, __u32 *p, __u32 reg, int len) for(i = 0 ; i < len ; i += 4) p[i >> 2] = jread32(jme, reg + i); +} + +static void +mdio_memcpy(struct jme_adapter *jme, __u32 *p, int reg_nr) +{ + int i; + __u16 *p16 = (__u16*)p; + for(i = 0 ; i < reg_nr ; ++i) + p16[i] = jme_mdio_read(jme->dev, jme->mii_if.phy_id, i); } static void @@ -2037,7 +2310,7 @@ jme_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) struct jme_adapter *jme = netdev_priv(netdev); __u32 *p32 = (__u32*)p; - memset(p, 0, 0x400); + memset(p, 0xFF, JME_REG_LEN); regs->version = 1; mmapio_memcpy(jme, p32, JME_MAC, JME_MAC_LEN); @@ -2051,6 +2324,8 @@ jme_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) p32 += 0x100 >> 2; mmapio_memcpy(jme, p32, JME_RSS, JME_RSS_LEN); + p32 += 0x100 >> 2; + mdio_memcpy(jme, p32, JME_PHY_REG_NR); } static int @@ -2354,6 +2629,131 @@ jme_nway_reset(struct net_device *netdev) return 0; } +static __u8 +jme_smb_read(struct jme_adapter *jme, unsigned int addr) +{ + __u32 val; + int to; + + val = jread32(jme, JME_SMBCSR); + to = JME_SMB_BUSY_TIMEOUT; + while((val & SMBCSR_BUSY) && --to) { + msleep(1); + val = jread32(jme, JME_SMBCSR); + } + if(!to) { + jeprintk(jme->dev->name, "SMB Bus Busy.\n"); + return 0xFF; + } + + jwrite32(jme, JME_SMBINTF, + ((addr << SMBINTF_HWADDR_SHIFT) & SMBINTF_HWADDR) | + SMBINTF_HWRWN_READ | + SMBINTF_HWCMD); + + val = jread32(jme, JME_SMBINTF); + to = JME_SMB_BUSY_TIMEOUT; + while((val & SMBINTF_HWCMD) && --to) { + msleep(1); + val = jread32(jme, JME_SMBINTF); + } + if(!to) { + jeprintk(jme->dev->name, "SMB Bus Busy.\n"); + return 0xFF; + } + + return (val & SMBINTF_HWDATR) >> SMBINTF_HWDATR_SHIFT; +} + +static void +jme_smb_write(struct jme_adapter *jme, unsigned int addr, __u8 data) +{ + __u32 val; + int to; + + val = jread32(jme, JME_SMBCSR); + to = JME_SMB_BUSY_TIMEOUT; + while((val & SMBCSR_BUSY) && --to) { + msleep(1); + val = jread32(jme, JME_SMBCSR); + } + if(!to) { + jeprintk(jme->dev->name, "SMB Bus Busy.\n"); + return; + } + + jwrite32(jme, JME_SMBINTF, + ((data << SMBINTF_HWDATW_SHIFT) & SMBINTF_HWDATW) | + ((addr << SMBINTF_HWADDR_SHIFT) & SMBINTF_HWADDR) | + SMBINTF_HWRWN_WRITE | + SMBINTF_HWCMD); + + val = jread32(jme, JME_SMBINTF); + to = JME_SMB_BUSY_TIMEOUT; + while((val & SMBINTF_HWCMD) && --to) { + msleep(1); + val = jread32(jme, JME_SMBINTF); + } + if(!to) { + jeprintk(jme->dev->name, "SMB Bus Busy.\n"); + return; + } + + mdelay(2); +} + +static int +jme_get_eeprom_len(struct net_device *netdev) +{ + struct jme_adapter *jme = netdev_priv(netdev); + __u32 val; + val = jread32(jme, JME_SMBCSR); + return (val & SMBCSR_EEPROMD)?JME_SMB_LEN:0; +} + +static int +jme_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct jme_adapter *jme = netdev_priv(netdev); + int i, offset = eeprom->offset, len = eeprom->len, idx; + + /* + * ethtool will check the boundary for us + */ + memset(data, 0xFF, len); + eeprom->magic = JME_EEPROM_MAGIC; + for(i = 0 ; i < len ; ++i) { + idx = i + offset; + data[i] = jme_smb_read(jme, idx); + if(data[i] == 0xFF) + break; + if((idx > 1) && !((idx - 2) % 3) && (data[i] & 0x80)) + len = (len > i + 3)?i + 3:len; + } + + return 0; +} + +static int +jme_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct jme_adapter *jme = netdev_priv(netdev); + int i, offset = eeprom->offset, len = eeprom->len; + + if (eeprom->magic != JME_EEPROM_MAGIC) + return -EINVAL; + + /* + * ethtool will check the boundary for us + */ + for(i = 0 ; i < len ; ++i) + jme_smb_write(jme, i + offset, data[i]); + + return 0; +} + static const struct ethtool_ops jme_ethtool_ops = { .get_drvinfo = jme_get_drvinfo, .get_regs_len = jme_get_regs_len, @@ -2373,6 +2773,9 @@ static const struct ethtool_ops jme_ethtool_ops = { .set_tso = jme_set_tso, .set_sg = ethtool_op_set_sg, .nway_reset = jme_nway_reset, + .get_eeprom_len = jme_get_eeprom_len, + .get_eeprom = jme_get_eeprom, + .set_eeprom = jme_set_eeprom, }; static int @@ -2555,7 +2958,10 @@ jme_init_one(struct pci_dev *pdev, (unsigned long) jme); jme->dpi.cur = PCC_P1; - jme->reg_ghc = GHC_DPX | GHC_SPEED_1000M; + if(pdev->device == JME_GE_DEVICE) + jme->reg_ghc = GHC_DPX | GHC_SPEED_1000M; + else + jme->reg_ghc = GHC_DPX | GHC_SPEED_100M; jme->reg_rxcs = RXCS_DEFAULT; jme->reg_rxmcs = RXMCS_DEFAULT; jme->reg_txpfc = 0; @@ -2606,7 +3012,10 @@ jme_init_one(struct pci_dev *pdev, else { jme->mii_if.phy_id = 1; } - jme->mii_if.supports_gmii = 1; + if(pdev->device == JME_GE_DEVICE) + jme->mii_if.supports_gmii = true; + else + jme->mii_if.supports_gmii = false; jme->mii_if.mdio_read = jme_mdio_read; jme->mii_if.mdio_write = jme_mdio_write; @@ -2780,7 +3189,8 @@ jme_resume(struct pci_dev *pdev) } static struct pci_device_id jme_pci_tbl[] = { - { PCI_VDEVICE(JMICRON, 0x250) }, + { PCI_VDEVICE(JMICRON, JME_GE_DEVICE) }, + { PCI_VDEVICE(JMICRON, JME_FE_DEVICE) }, { } };