sky2: only disable 88e8056 on some boards
[powerpc.git] / drivers / net / sky2.c
index ab0ab92..104e204 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/ethtool.h>
 #include <linux/pci.h>
 #include <linux/ip.h>
+#include <net/ip.h>
 #include <linux/tcp.h>
 #include <linux/in.h>
 #include <linux/delay.h>
@@ -39,6 +40,7 @@
 #include <linux/if_vlan.h>
 #include <linux/prefetch.h>
 #include <linux/mii.h>
+#include <linux/dmi.h>
 
 #include <asm/irq.h>
 
@@ -49,7 +51,7 @@
 #include "sky2.h"
 
 #define DRV_NAME               "sky2"
-#define DRV_VERSION            "1.13"
+#define DRV_VERSION            "1.14"
 #define PFX                    DRV_NAME " "
 
 /*
@@ -129,7 +131,7 @@ static const struct pci_device_id sky2_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) }, /* 88EC042 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */
-       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */
+//     { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */
        { 0 }
 };
 
@@ -149,6 +151,8 @@ static const char *yukon2_name[] = {
        "FE",           /* 0xb7 */
 };
 
+static int dmi_blacklisted;
+
 /* Access to external PHY */
 static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val)
 {
@@ -510,9 +514,9 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                ledover &= ~PHY_M_LED_MO_RX;
        }
 
-       if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev == CHIP_REV_YU_EC_A1) {
+       if (hw->chip_id == CHIP_ID_YUKON_EC_U &&
+           hw->chip_rev == CHIP_REV_YU_EC_U_A1) {
                /* apply fixes in PHY AFE */
-               pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
                gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 255);
 
                /* increase differential signal amplitude in 10BASE-T */
@@ -524,7 +528,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                gm_phy_write(hw, port, 0x17, 0x2002);
 
                /* set page register to 0 */
-               gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
+               gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0);
        } else if (hw->chip_id != CHIP_ID_YUKON_EX) {
                gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
 
@@ -740,12 +744,17 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
        if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
                sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
                sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
-               if (hw->dev[port]->mtu > ETH_DATA_LEN) {
-                       /* set Tx GMAC FIFO Almost Empty Threshold */
-                       sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR), 0x180);
-                       /* Disable Store & Forward mode for TX */
-                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_DIS);
-               }
+
+               /* set Tx GMAC FIFO Almost Empty Threshold */
+               sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
+                            (ECU_JUMBO_WM << 16) | ECU_AE_THR);
+
+               if (hw->dev[port]->mtu > ETH_DATA_LEN)
+                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+                                    TX_JUMBO_ENA | TX_STFW_DIS);
+               else
+                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+                                    TX_JUMBO_DIS | TX_STFW_ENA);
        }
 
 }
@@ -1278,7 +1287,7 @@ static int sky2_up(struct net_device *dev)
        /* Set almost empty threshold */
        if (hw->chip_id == CHIP_ID_YUKON_EC_U
            && hw->chip_rev == CHIP_REV_YU_EC_U_A0)
-               sky2_write16(hw, Q_ADDR(txqaddr[port], Q_AL), 0x1a0);
+               sky2_write16(hw, Q_ADDR(txqaddr[port], Q_AL), ECU_TXFF_LEV);
 
        sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
                           TX_RING_SIZE - 1);
@@ -1383,8 +1392,8 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
        /* Check for TCP Segmentation Offload */
        mss = skb_shinfo(skb)->gso_size;
        if (mss != 0) {
-               mss += ((skb->h.th->doff - 5) * 4);     /* TCP options */
-               mss += (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr);
+               mss += tcp_optlen(skb); /* TCP options */
+               mss += ip_hdrlen(skb) + sizeof(struct tcphdr);
                mss += ETH_HLEN;
 
                if (mss != sky2->tx_last_mss) {
@@ -1412,14 +1421,14 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
 
        /* Handle TCP checksum offload */
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               unsigned offset = skb->h.raw - skb->data;
+               const unsigned offset = skb_transport_offset(skb);
                u32 tcpsum;
 
                tcpsum = offset << 16;          /* sum start */
                tcpsum |= offset + skb->csum_offset;    /* sum write */
 
                ctrl = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM;
-               if (skb->nh.iph->protocol == IPPROTO_UDP)
+               if (ip_hdr(skb)->protocol == IPPROTO_UDP)
                        ctrl |= UDPTCP;
 
                if (tcpsum != sky2->tx_tcpsum) {
@@ -1561,6 +1570,7 @@ static int sky2_down(struct net_device *dev)
 
        /* Stop more packets from being queued */
        netif_stop_queue(dev);
+       netif_carrier_off(dev);
 
        /* Disable port IRQ */
        imask = sky2_read32(hw, B0_IMSK);
@@ -1583,13 +1593,6 @@ static int sky2_down(struct net_device *dev)
        sky2_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL),
                     RB_RST_SET | RB_DIS_OP_MD);
 
-       /* WA for dev. #4.209 */
-       if (hw->chip_id == CHIP_ID_YUKON_EC_U
-           && (hw->chip_rev == CHIP_REV_YU_EC_U_A1 || hw->chip_rev == CHIP_REV_YU_EC_U_B0))
-               sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
-                            sky2->speed != SPEED_1000 ?
-                            TX_STFW_ENA : TX_STFW_DIS);
-
        ctrl = gma_read16(hw, port, GM_GP_CTRL);
        ctrl &= ~(GM_GPCR_TX_ENA | GM_GPCR_RX_ENA);
        gma_write16(hw, port, GM_GP_CTRL, ctrl);
@@ -1889,6 +1892,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
        struct sky2_hw *hw = sky2->hw;
+       unsigned port = sky2->port;
        int err;
        u16 ctl, mode;
        u32 imask;
@@ -1896,9 +1900,8 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
        if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
                return -EINVAL;
 
-       /* TSO on Yukon Ultra and MTU > 1500 not supported */
-       if (hw->chip_id == CHIP_ID_YUKON_EC_U && new_mtu > ETH_DATA_LEN)
-               dev->features &= ~NETIF_F_TSO;
+       if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_FE)
+               return -EINVAL;
 
        if (!netif_running(dev)) {
                dev->mtu = new_mtu;
@@ -1914,8 +1917,18 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
 
        synchronize_irq(hw->pdev->irq);
 
-       ctl = gma_read16(hw, sky2->port, GM_GP_CTRL);
-       gma_write16(hw, sky2->port, GM_GP_CTRL, ctl & ~GM_GPCR_RX_ENA);
+       if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
+               if (new_mtu > ETH_DATA_LEN) {
+                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+                                    TX_JUMBO_ENA | TX_STFW_DIS);
+                       dev->features &= NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM;
+               } else
+                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+                                    TX_JUMBO_DIS | TX_STFW_ENA);
+       }
+
+       ctl = gma_read16(hw, port, GM_GP_CTRL);
+       gma_write16(hw, port, GM_GP_CTRL, ctl & ~GM_GPCR_RX_ENA);
        sky2_rx_stop(sky2);
        sky2_rx_clean(sky2);
 
@@ -1927,9 +1940,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
        if (dev->mtu > ETH_DATA_LEN)
                mode |= GM_SMOD_JUMBO_ENA;
 
-       gma_write16(hw, sky2->port, GM_SERIAL_MODE, mode);
+       gma_write16(hw, port, GM_SERIAL_MODE, mode);
 
-       sky2_write8(hw, RB_ADDR(rxqaddr[sky2->port], RB_CTRL), RB_ENA_OP_MD);
+       sky2_write8(hw, RB_ADDR(rxqaddr[port], RB_CTRL), RB_ENA_OP_MD);
 
        err = sky2_rx_start(sky2);
        sky2_write32(hw, B0_IMSK, imask);
@@ -1937,7 +1950,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
        if (err)
                dev_close(dev);
        else {
-               gma_write16(hw, sky2->port, GM_GP_CTRL, ctl);
+               gma_write16(hw, port, GM_GP_CTRL, ctl);
 
                netif_poll_enable(hw->dev[0]);
                netif_wake_queue(dev);
@@ -1958,7 +1971,7 @@ static struct sk_buff *receive_copy(struct sky2_port *sky2,
                skb_reserve(skb, 2);
                pci_dma_sync_single_for_cpu(sky2->hw->pdev, re->data_addr,
                                            length, PCI_DMA_FROMDEVICE);
-               memcpy(skb->data, re->skb->data, length);
+               skb_copy_from_linear_data(re->skb, skb->data, length);
                skb->ip_summed = re->skb->ip_summed;
                skb->csum = re->skb->csum;
                pci_dma_sync_single_for_device(sky2->hw->pdev, re->data_addr,
@@ -2339,26 +2352,22 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port)
        }
 }
 
-/* This should never happen it is a fatal situation */
-static void sky2_descriptor_error(struct sky2_hw *hw, unsigned port,
-                                 const char *rxtx, u32 mask)
+/* This should never happen it is a bug. */
+static void sky2_le_error(struct sky2_hw *hw, unsigned port,
+                         u16 q, unsigned ring_size)
 {
        struct net_device *dev = hw->dev[port];
        struct sky2_port *sky2 = netdev_priv(dev);
-       u32 imask;
-
-       printk(KERN_ERR PFX "%s: %s descriptor error (hardware problem)\n",
-              dev ? dev->name : "<not registered>", rxtx);
+       unsigned idx;
+       const u64 *le = (q == Q_R1 || q == Q_R2)
+               ? (u64 *) sky2->rx_le : (u64 *) sky2->tx_le;
 
-       imask = sky2_read32(hw, B0_IMSK);
-       imask &= ~mask;
-       sky2_write32(hw, B0_IMSK, imask);
+       idx = sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_GET_IDX));
+       printk(KERN_ERR PFX "%s: descriptor error q=%#x get=%u [%llx] put=%u\n",
+              dev->name, (unsigned) q, idx, (unsigned long long) le[idx],
+              (unsigned) sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX)));
 
-       if (dev) {
-               spin_lock(&sky2->phy_lock);
-               sky2_link_down(sky2);
-               spin_unlock(&sky2->phy_lock);
-       }
+       sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_CLR_IRQ_CHK);
 }
 
 /* If idle then force a fake soft NAPI poll once a second
@@ -2382,23 +2391,15 @@ static void sky2_idle(unsigned long arg)
        mod_timer(&hw->idle_timer, jiffies + msecs_to_jiffies(idle_timeout));
 }
 
-
-static int sky2_poll(struct net_device *dev0, int *budget)
+/* Hardware/software error handling */
+static void sky2_err_intr(struct sky2_hw *hw, u32 status)
 {
-       struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw;
-       int work_limit = min(dev0->quota, *budget);
-       int work_done = 0;
-       u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
+       if (net_ratelimit())
+               dev_warn(&hw->pdev->dev, "error interrupt status=%#x\n", status);
 
        if (status & Y2_IS_HW_ERR)
                sky2_hw_intr(hw);
 
-       if (status & Y2_IS_IRQ_PHY1)
-               sky2_phy_intr(hw, 0);
-
-       if (status & Y2_IS_IRQ_PHY2)
-               sky2_phy_intr(hw, 1);
-
        if (status & Y2_IS_IRQ_MAC1)
                sky2_mac_intr(hw, 0);
 
@@ -2406,16 +2407,33 @@ static int sky2_poll(struct net_device *dev0, int *budget)
                sky2_mac_intr(hw, 1);
 
        if (status & Y2_IS_CHK_RX1)
-               sky2_descriptor_error(hw, 0, "receive", Y2_IS_CHK_RX1);
+               sky2_le_error(hw, 0, Q_R1, RX_LE_SIZE);
 
        if (status & Y2_IS_CHK_RX2)
-               sky2_descriptor_error(hw, 1, "receive", Y2_IS_CHK_RX2);
+               sky2_le_error(hw, 1, Q_R2, RX_LE_SIZE);
 
        if (status & Y2_IS_CHK_TXA1)
-               sky2_descriptor_error(hw, 0, "transmit", Y2_IS_CHK_TXA1);
+               sky2_le_error(hw, 0, Q_XA1, TX_RING_SIZE);
 
        if (status & Y2_IS_CHK_TXA2)
-               sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2);
+               sky2_le_error(hw, 1, Q_XA2, TX_RING_SIZE);
+}
+
+static int sky2_poll(struct net_device *dev0, int *budget)
+{
+       struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw;
+       int work_limit = min(dev0->quota, *budget);
+       int work_done = 0;
+       u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
+
+       if (unlikely(status & Y2_IS_ERROR))
+               sky2_err_intr(hw, status);
+
+       if (status & Y2_IS_IRQ_PHY1)
+               sky2_phy_intr(hw, 0);
+
+       if (status & Y2_IS_IRQ_PHY2)
+               sky2_phy_intr(hw, 1);
 
        work_done = sky2_status_intr(hw, work_limit);
        if (work_done < work_limit) {
@@ -2516,6 +2534,17 @@ static int __devinit sky2_init(struct sky2_hw *hw)
                return -EOPNOTSUPP;
        }
 
+
+       /* Some Gigabyte motherboards have 88e8056 but cause problems
+        * There is some unresolved hardware related problem that causes
+        * descriptor errors and receive data corruption.
+        */
+       if (hw->chip_id == CHIP_ID_YUKON_EC_U && dmi_blacklisted) {
+               dev_err(&hw->pdev->dev,
+                       "88E8056 on this motherboard not supported\n");
+               return -EOPNOTSUPP;
+       }
+
        hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
        hw->ports = 1;
        t8 = sky2_read8(hw, B2_Y2_HW_RES);
@@ -2533,16 +2562,14 @@ static void sky2_reset(struct sky2_hw *hw)
        int i;
 
        /* disable ASF */
-       if (hw->chip_id <= CHIP_ID_YUKON_EC) {
-               if (hw->chip_id == CHIP_ID_YUKON_EX) {
-                       status = sky2_read16(hw, HCU_CCSR);
-                       status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE |
-                                   HCU_CCSR_UC_STATE_MSK);
-                       sky2_write16(hw, HCU_CCSR, status);
-               } else
-                       sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
-               sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE);
-       }
+       if (hw->chip_id == CHIP_ID_YUKON_EX) {
+               status = sky2_read16(hw, HCU_CCSR);
+               status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE |
+                           HCU_CCSR_UC_STATE_MSK);
+               sky2_write16(hw, HCU_CCSR, status);
+       } else
+               sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
+       sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE);
 
        /* do a SW reset */
        sky2_write8(hw, B0_CTST, CS_RST_SET);
@@ -3327,6 +3354,36 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
                      regs->len - B3_RI_WTO_R1);
 }
 
+/* In order to do Jumbo packets on these chips, need to turn off the
+ * transmit store/forward. Therefore checksum offload won't work.
+ */
+static int no_tx_offload(struct net_device *dev)
+{
+       const struct sky2_port *sky2 = netdev_priv(dev);
+       const struct sky2_hw *hw = sky2->hw;
+
+       return dev->mtu > ETH_DATA_LEN &&
+               (hw->chip_id == CHIP_ID_YUKON_EX
+                || hw->chip_id == CHIP_ID_YUKON_EC_U);
+}
+
+static int sky2_set_tx_csum(struct net_device *dev, u32 data)
+{
+       if (data && no_tx_offload(dev))
+               return -EINVAL;
+
+       return ethtool_op_set_tx_csum(dev, data);
+}
+
+
+static int sky2_set_tso(struct net_device *dev, u32 data)
+{
+       if (data && no_tx_offload(dev))
+               return -EINVAL;
+
+       return ethtool_op_set_tso(dev, data);
+}
+
 static const struct ethtool_ops sky2_ethtool_ops = {
        .get_settings = sky2_get_settings,
        .set_settings = sky2_set_settings,
@@ -3342,9 +3399,9 @@ static const struct ethtool_ops sky2_ethtool_ops = {
        .get_sg = ethtool_op_get_sg,
        .set_sg = ethtool_op_set_sg,
        .get_tx_csum = ethtool_op_get_tx_csum,
-       .set_tx_csum = ethtool_op_set_tx_csum,
+       .set_tx_csum = sky2_set_tx_csum,
        .get_tso = ethtool_op_get_tso,
-       .set_tso = ethtool_op_set_tso,
+       .set_tso = sky2_set_tso,
        .get_rx_csum = sky2_get_rx_csum,
        .set_rx_csum = sky2_set_rx_csum,
        .get_strings = sky2_get_strings,
@@ -3538,7 +3595,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
        err = pci_request_regions(pdev, DRV_NAME);
        if (err) {
                dev_err(&pdev->dev, "cannot obtain PCI resources\n");
-               goto err_out;
+               goto err_out_disable;
        }
 
        pci_set_master(pdev);
@@ -3675,8 +3732,10 @@ err_out_free_hw:
        kfree(hw);
 err_out_free_regions:
        pci_release_regions(pdev);
+err_out_disable:
        pci_disable_device(pdev);
 err_out:
+       pci_set_drvdata(pdev, NULL);
        return err;
 }
 
@@ -3729,6 +3788,9 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
        struct sky2_hw *hw = pci_get_drvdata(pdev);
        int i, wol = 0;
 
+       if (!hw)
+               return 0;
+
        del_timer_sync(&hw->idle_timer);
        netif_poll_disable(hw->dev[0]);
 
@@ -3760,6 +3822,9 @@ static int sky2_resume(struct pci_dev *pdev)
        struct sky2_hw *hw = pci_get_drvdata(pdev);
        int i, err;
 
+       if (!hw)
+               return 0;
+
        err = pci_set_power_state(pdev, PCI_D0);
        if (err)
                goto out;
@@ -3769,6 +3834,11 @@ static int sky2_resume(struct pci_dev *pdev)
                goto out;
 
        pci_enable_wake(pdev, PCI_D0, 0);
+
+       /* Re-enable all clocks */
+       if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U)
+               sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+
        sky2_reset(hw);
 
        sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
@@ -3801,6 +3871,9 @@ static void sky2_shutdown(struct pci_dev *pdev)
        struct sky2_hw *hw = pci_get_drvdata(pdev);
        int i, wol = 0;
 
+       if (!hw)
+               return;
+
        del_timer_sync(&hw->idle_timer);
        netif_poll_disable(hw->dev[0]);
 
@@ -3837,8 +3910,24 @@ static struct pci_driver sky2_driver = {
        .shutdown = sky2_shutdown,
 };
 
+static struct dmi_system_id __initdata broken_dmi_table[] = {
+       {
+               .ident = "Gigabyte 965P-S3",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Gigabyte Technology Co., Ltd."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "965P-S3"),
+
+               },
+       },
+       { }
+};
+
 static int __init sky2_init_module(void)
 {
+       /* Look for sick motherboards */
+       if (dmi_check_system(broken_dmi_table))
+               dmi_blacklisted = 1;
+
        return pci_register_driver(&sky2_driver);
 }