]> bbs.cooldavid.org Git - jme.git/blobdiff - jme.c
Import jme 0.9e source
[jme.git] / jme.c
diff --git a/jme.c b/jme.c
index ac6fc1ced2a60ea8aed02a15804aad5f0a35eea5..799c2d45505c41528b232a75e73d78d29179c888 100644 (file)
--- a/jme.c
+++ b/jme.c
@@ -58,8 +58,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 +78,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 +98,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 +118,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 +209,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 +217,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 +331,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;
@@ -520,9 +522,10 @@ jme_free_tx_resources(struct jme_adapter *jme)
                                dev_kfree_skb(txbi->skb);
                                txbi->skb = NULL;
                        }
-                       txbi->mapping   = 0;
-                       txbi->len       = 0;
-                       txbi->nr_desc   = 0;
+                       txbi->mapping           = 0;
+                       txbi->len               = 0;
+                       txbi->nr_desc           = 0;
+                       txbi->start_xmit        = 0;
                }
 
                dma_free_coherent(&(jme->pdev->dev),
@@ -1327,21 +1330,32 @@ 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)) {
+               /*
+                * Link change event is critical
+                * all other events are ignored
+                */
+               jwrite32(jme, JME_IEVE, intrstat);
                tasklet_schedule(&jme->linkch_task);
                goto out_reenable;
        }
 
-       if(intrstat & INTR_TMINTR)
+       if(intrstat & INTR_TMINTR) {
+               jwrite32(jme, JME_IEVE, INTR_TMINTR);
                tasklet_schedule(&jme->pcc_task);
+       }
 
-       if(intrstat & (INTR_PCCTXTO | INTR_PCCTX))
+       if(intrstat & (INTR_PCCTXTO | INTR_PCCTX)) {
+               jwrite32(jme, JME_IEVE, INTR_PCCTXTO | INTR_PCCTX | INTR_TX0);
                tasklet_schedule(&jme->txclean_task);
+       }
+
+       if((intrstat & (INTR_PCCRX0TO | INTR_PCCRX0 | INTR_RX0EMP))) {
+               jwrite32(jme, JME_IEVE, (intrstat & (INTR_PCCRX0TO |
+                                                    INTR_PCCRX0 |
+                                                    INTR_RX0EMP)) |
+                                       INTR_RX0);
+       }
 
        if(jme->flags & JME_FLAG_POLL) {
                if(intrstat & INTR_RX0EMP)
@@ -1359,8 +1373,7 @@ 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);
        }
 
@@ -1548,6 +1561,20 @@ jme_set_100m_half(struct jme_adapter *jme)
                jwrite32(jme, JME_GHC, GHC_SPEED_100M);
 }
 
+#define JME_WAIT_LINK_TIME 2000 /* 2000ms */
+static void
+jme_wait_link(struct jme_adapter *jme)
+{
+       __u32 phylink, to = JME_WAIT_LINK_TIME;
+
+       mdelay(1000);
+       phylink = jme_linkstat_from_phy(jme);
+       while(!(phylink & PHY_LINK_UP) && (to -= 10) > 0) {
+               mdelay(10);
+               phylink = jme_linkstat_from_phy(jme);
+       }
+}
+
 static void
 jme_phy_off(struct jme_adapter *jme)
 {
@@ -1792,7 +1819,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;
 }
@@ -1820,6 +1847,7 @@ jme_stop_queue_if_full(struct jme_adapter *jme)
                        (jiffies - txbi->start_xmit) >= TX_TIMEOUT &&
                        txbi->skb)) {
                netif_stop_queue(jme->dev);
+               queue_dbg(jme->dev->name, "TX Queue Stopped @(%lu).\n", jiffies);
        }
 }
 
@@ -1859,7 +1887,8 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev)
        jme_map_tx_skb(jme, skb, idx);
        jme_fill_first_tx_desc(jme, skb, idx);
 
-       tx_dbg(jme->dev->name, "Xmit: %d+%d\n", idx, skb_shinfo(skb)->nr_frags + 2);
+       tx_dbg(jme->dev->name, "Xmit: %d+%d @(%lu)\n",
+                       idx, skb_shinfo(skb)->nr_frags + 2, jiffies);
 
        jwrite32(jme, JME_TXCS, jme->reg_txcs |
                                TXCS_SELECT_QUEUE0 |
@@ -1885,13 +1914,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 +2047,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 +2057,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 +2075,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 +2089,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 +2394,124 @@ 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;
+
+       /*
+        * ethtool will check the boundary for us
+        */
+       eeprom->magic = JME_EEPROM_MAGIC;
+       for(i = 0 ; i < len ; ++i)
+               data[i] = jme_smb_read(jme, i + offset);
+
+       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 +2531,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,11 +2716,14 @@ 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;
-       jme->reg_pmcs = PMCS_LFEN | PMCS_LREN | PMCS_MFEN;
+       jme->reg_pmcs = PMCS_MFEN;
        jme->flags = JME_FLAG_TXCSUM | JME_FLAG_TSO;
 
        /*
@@ -2606,7 +2770,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;
 
@@ -2707,7 +2874,7 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state)
        netif_device_detach(netdev);
        netif_stop_queue(netdev);
        jme_stop_irq(jme);
-       jme_free_irq(jme);
+       //jme_free_irq(jme);
 
        while(--timeout > 0 &&
        (
@@ -2723,27 +2890,33 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state)
        jme_disable_shadow(jme);
 
        if(netif_carrier_ok(netdev)) {
+               if(jme->flags & JME_FLAG_POLL)
+                       jme_polling_mode(jme);
+
                jme_stop_pcc_timer(jme);
                jme_reset_mac_processor(jme);
                jme_free_rx_resources(jme);
                jme_free_tx_resources(jme);
                netif_carrier_off(netdev);
                jme->phylink = 0;
-
-               if(jme->flags & JME_FLAG_POLL)
-                       jme_polling_mode(jme);
        }
 
 
        pci_save_state(pdev);
        if(jme->reg_pmcs) {
                jme_set_100m_half(jme);
+
+               if(jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
+                       jme_wait_link(jme);
+
                jwrite32(jme, JME_PMCS, jme->reg_pmcs);
+               pci_enable_wake(pdev, PCI_D1, true);
                pci_enable_wake(pdev, PCI_D3hot, true);
                pci_enable_wake(pdev, PCI_D3cold, true);
        }
        else {
                jme_phy_off(jme);
+               pci_enable_wake(pdev, PCI_D1, false);
                pci_enable_wake(pdev, PCI_D3hot, false);
                pci_enable_wake(pdev, PCI_D3cold, false);
        }
@@ -2768,7 +2941,7 @@ jme_resume(struct pci_dev *pdev)
 
        jme_reset_mac_processor(jme);
        jme_enable_shadow(jme);
-       jme_request_irq(jme);
+       //jme_request_irq(jme);
        jme_start_irq(jme);
        netif_device_attach(netdev);
 
@@ -2780,7 +2953,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) },
        { }
 };