]> err.no Git - linux-2.6/blobdiff - drivers/net/sky2.c
Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband
[linux-2.6] / drivers / net / sky2.c
index 910c600a6caf592cb0b2cb324045b591f1962683..832fd69a0e59b155f4b28fbf5d502ce363d087b8 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>
@@ -49,7 +50,7 @@
 #include "sky2.h"
 
 #define DRV_NAME               "sky2"
-#define DRV_VERSION            "1.13"
+#define DRV_VERSION            "1.14"
 #define PFX                    DRV_NAME " "
 
 /*
@@ -123,16 +124,13 @@ static const struct pci_device_id sky2_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, /* 88E8050 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) }, /* 88E8053 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) }, /* 88E8055 */
-#ifdef broken
-       /* This device causes data corruption problems that are not resolved */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) }, /* 88E8056 */
-#endif
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */
        { 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 }
 };
 
@@ -306,10 +304,13 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                           PHY_M_EC_MAC_S_MSK);
                ectrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ);
 
+               /* on PHY 88E1040 Rev.D0 (and newer) downshift control changed */
                if (hw->chip_id == CHIP_ID_YUKON_EC)
+                       /* set downshift counter to 3x and enable downshift */
                        ectrl |= PHY_M_EC_DSC_2(2) | PHY_M_EC_DOWN_S_ENA;
                else
-                       ectrl |= PHY_M_EC_M_DSC(2) | PHY_M_EC_S_DSC(3);
+                       /* set master & slave downshift counter to 1x */
+                       ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
 
                gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl);
        }
@@ -326,10 +327,12 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                        /* enable automatic crossover */
                        ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO);
 
+                       /* downshift on PHY 88E1112 and 88E1149 is changed */
                        if (sky2->autoneg == AUTONEG_ENABLE
                            && (hw->chip_id == CHIP_ID_YUKON_XL
                                || hw->chip_id == CHIP_ID_YUKON_EC_U
                                || hw->chip_id == CHIP_ID_YUKON_EX)) {
+                               /* set downshift counter to 3x and enable downshift */
                                ctrl &= ~PHY_M_PC_DSC_MSK;
                                ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
                        }
@@ -743,12 +746,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);
        }
 
 }
@@ -836,10 +844,12 @@ static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2,
 /* Update chip's next pointer */
 static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx)
 {
-       q = Y2_QADDR(q, PREF_UNIT_PUT_IDX);
+       /* Make sure write' to descriptors are complete before we tell hardware */
        wmb();
-       sky2_write16(hw, q, idx);
-       sky2_read16(hw, q);
+       sky2_write16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX), idx);
+
+       /* Synchronize I/O on since next processor may write to tail */
+       mmiowb();
 }
 
 
@@ -971,6 +981,7 @@ stopped:
 
        /* reset the Rx prefetch unit */
        sky2_write32(hw, Y2_QADDR(rxq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET);
+       mmiowb();
 }
 
 /* Clean out receive buffer area, assumes receiver hardware stopped */
@@ -1190,7 +1201,7 @@ static int sky2_rx_start(struct sky2_port *sky2)
        }
 
        /* Tell chip about available buffers */
-       sky2_write16(hw, Y2_QADDR(rxq, PREF_UNIT_PUT_IDX), sky2->rx_put);
+       sky2_put_idx(hw, rxq, sky2->rx_put);
        return 0;
 nomem:
        sky2_rx_clean(sky2);
@@ -1281,7 +1292,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);
@@ -1386,8 +1397,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) {
@@ -1415,14 +1426,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) {
@@ -1532,6 +1543,8 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
        }
 
        sky2->tx_cons = idx;
+       smp_mb();
+
        if (tx_avail(sky2) > MAX_SKB_TX_LE + 4)
                netif_wake_queue(dev);
 }
@@ -1571,13 +1584,6 @@ static int sky2_down(struct net_device *dev)
        imask &= ~portirq_msk[port];
        sky2_write32(hw, B0_IMSK, imask);
 
-       /*
-        * Both ports share the NAPI poll on port 0, so if necessary undo the
-        * the disable that is done in dev_close.
-        */
-       if (sky2->port == 0 && hw->ports > 1)
-               netif_poll_enable(dev);
-
        sky2_gmac_reset(hw, port);
 
        /* Stop transmitter */
@@ -1587,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);
@@ -1893,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;
@@ -1900,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;
@@ -1918,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);
 
@@ -1931,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);
@@ -1941,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);
@@ -1962,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,
@@ -2130,8 +2139,10 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
                switch (le->opcode & ~HW_OWNER) {
                case OP_RXSTAT:
                        skb = sky2_receive(dev, length, status);
-                       if (!skb)
+                       if (unlikely(!skb)) {
+                               sky2->net_stats.rx_dropped++;
                                goto force_update;
+                       }
 
                        skb->protocol = eth_type_trans(skb, dev);
                        sky2->net_stats.rx_packets++;
@@ -2212,6 +2223,7 @@ force_update:
 
        /* Fully processed status ring so clear irq */
        sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
+       mmiowb();
 
 exit_loop:
        if (buf_write[0]) {
@@ -2332,6 +2344,12 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port)
                printk(KERN_INFO PFX "%s: mac interrupt status 0x%x\n",
                       dev->name, status);
 
+       if (status & GM_IS_RX_CO_OV)
+               gma_read16(hw, port, GM_RX_IRQ_SRC);
+
+       if (status & GM_IS_TX_CO_OV)
+               gma_read16(hw, port, GM_TX_IRQ_SRC);
+
        if (status & GM_IS_RX_FF_OR) {
                ++sky2->net_stats.rx_fifo_errors;
                sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_CLI_RX_FO);
@@ -2430,6 +2448,7 @@ static int sky2_poll(struct net_device *dev0, int *budget)
        if (work_done < work_limit) {
                netif_rx_complete(dev0);
 
+               /* end of interrupt, re-enables also acts as I/O synchronization */
                sky2_read32(hw, B0_Y2_SP_LISR);
                return 0;
        } else {
@@ -3334,6 +3353,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,
@@ -3349,9 +3398,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,
@@ -3545,7 +3594,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);
@@ -3682,8 +3731,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;
 }
 
@@ -3736,6 +3787,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]);
 
@@ -3767,6 +3821,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;
@@ -3813,6 +3870,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]);