]> 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 ac6fc1ced2a60ea8aed02a15804aad5f0a35eea5..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>
@@ -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) },
        { }
 };