]> bbs.cooldavid.org Git - jme.git/blobdiff - jme.c
Import jme 0.9d-msix source
[jme.git] / jme.c
diff --git a/jme.c b/jme.c
index 612a0585240201ed719add5d8cfe3ca27ef5f846..f7350d56acd1ea7bc33dc7bb8458f15f5d7ce3b8 100644 (file)
--- a/jme.c
+++ b/jme.c
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/irq.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
@@ -37,6 +38,7 @@
 #include <linux/crc32.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
+#include <linux/net.h>
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
@@ -98,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;
        }
 
@@ -119,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,
@@ -331,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;
@@ -613,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;
@@ -1052,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)
        )) {
@@ -1329,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;
@@ -1361,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
         */
@@ -1420,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)
@@ -1440,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)
 {
@@ -1448,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;
@@ -1476,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
@@ -1794,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;
 }
@@ -2454,14 +2716,21 @@ 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;
+       int i, offset = eeprom->offset, len = eeprom->len, idx;
 
        /*
-        * ethtool will check boundary for us
+        * ethtool will check the boundary for us
         */
+       memset(data, 0xFF, len);
        eeprom->magic = JME_EEPROM_MAGIC;
-       for(i = 0 ; i < len ; ++i)
-               data[i] = jme_smb_read(jme, i + offset);
+       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;
 }
@@ -2477,7 +2746,7 @@ jme_set_eeprom(struct net_device *netdev,
                return -EINVAL;
 
        /*
-        * ethtool will check boundary for us
+        * ethtool will check the boundary for us
         */
        for(i = 0 ; i < len ; ++i)
                jme_smb_write(jme, i + offset, data[i]);
@@ -2689,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;
@@ -2740,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;
 
@@ -2914,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) },
        { }
 };