[ARM] Fix byte order macros for Thumb
[powerpc.git] / drivers / net / sky2.c
index ffd267f..fba1e4d 100644 (file)
@@ -51,7 +51,7 @@
 #include "sky2.h"
 
 #define DRV_NAME               "sky2"
-#define DRV_VERSION            "1.3"
+#define DRV_VERSION            "1.4"
 #define PFX                    DRV_NAME " "
 
 /*
@@ -105,6 +105,7 @@ MODULE_PARM_DESC(idle_timeout, "Idle timeout workaround for lost interrupts (ms)
 static const struct pci_device_id sky2_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) },
        { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) },
+       { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) },    /* DGE-560T */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) },
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) },
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) },
@@ -186,12 +187,11 @@ static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
        return v;
 }
 
-static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
+static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
 {
        u16 power_control;
        u32 reg1;
        int vaux;
-       int ret = 0;
 
        pr_debug("sky2_set_power_state %d\n", state);
        sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
@@ -235,6 +235,7 @@ static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
                }
 
                if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
+                       sky2_write16(hw, B0_CTST, Y2_HW_WOL_ON);
                        sky2_pci_write32(hw, PCI_DEV_REG3, 0);
                        reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
                        reg1 &= P_ASPM_CONTROL_MSK;
@@ -273,12 +274,10 @@ static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
                break;
        default:
                printk(KERN_ERR PFX "Unknown power state %d\n", state);
-               ret = -1;
        }
 
        sky2_pci_write16(hw, hw->pm_cap + PCI_PM_CTRL, power_control);
        sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
-       return ret;
 }
 
 static void sky2_phy_reset(struct sky2_hw *hw, unsigned port)
@@ -306,7 +305,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
        u16 ctrl, ct1000, adv, pg, ledctrl, ledover;
 
        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_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
                u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
 
                ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
@@ -977,6 +976,7 @@ static int sky2_rx_start(struct sky2_port *sky2)
        struct sky2_hw *hw = sky2->hw;
        unsigned rxq = rxqaddr[sky2->port];
        int i;
+       unsigned thresh;
 
        sky2->rx_put = sky2->rx_next = 0;
        sky2_qset(hw, rxq);
@@ -1001,9 +1001,21 @@ static int sky2_rx_start(struct sky2_port *sky2)
                sky2_rx_add(sky2, re->mapaddr);
        }
 
-       /* Truncate oversize frames */
-       sky2_write16(hw, SK_REG(sky2->port, RX_GMF_TR_THR), sky2->rx_bufsize - 8);
-       sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_ON);
+
+       /*
+        * The receiver hangs if it receives frames larger than the
+        * packet buffer. As a workaround, truncate oversize frames, but
+        * the register is limited to 9 bits, so if you do frames > 2052
+        * you better get the MTU right!
+        */
+       thresh = (sky2->rx_bufsize - 8) / sizeof(u32);
+       if (thresh > 0x1ff)
+               sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_OFF);
+       else {
+               sky2_write16(hw, SK_REG(sky2->port, RX_GMF_TR_THR), thresh);
+               sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_ON);
+       }
+
 
        /* Tell chip about available buffers */
        sky2_write16(hw, Y2_QADDR(rxq, PREF_UNIT_PUT_IDX), sky2->rx_put);
@@ -1020,7 +1032,25 @@ static int sky2_up(struct net_device *dev)
        struct sky2_hw *hw = sky2->hw;
        unsigned port = sky2->port;
        u32 ramsize, rxspace, imask;
-       int err = -ENOMEM;
+       int cap, err = -ENOMEM;
+       struct net_device *otherdev = hw->dev[sky2->port^1];
+
+       /*
+        * On dual port PCI-X card, there is an problem where status
+        * can be received out of order due to split transactions
+        */
+       if (otherdev && netif_running(otherdev) &&
+           (cap = pci_find_capability(hw->pdev, PCI_CAP_ID_PCIX))) {
+               struct sky2_port *osky2 = netdev_priv(otherdev);
+               u16 cmd;
+
+               cmd = sky2_pci_read16(hw, cap + PCI_X_CMD);
+               cmd &= ~PCI_X_CMD_MAX_SPLIT;
+               sky2_pci_write16(hw, cap + PCI_X_CMD, cmd);
+
+               sky2->rx_csum = 0;
+               osky2->rx_csum = 0;
+       }
 
        if (netif_msg_ifup(sky2))
                printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
@@ -1899,6 +1929,12 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
        }
 }
 
+/* Is status ring empty or is there more to do? */
+static inline int sky2_more_work(const struct sky2_hw *hw)
+{
+       return (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX));
+}
+
 /* Process status response ring */
 static int sky2_status_intr(struct sky2_hw *hw, int to_do)
 {
@@ -2125,6 +2161,13 @@ static void sky2_descriptor_error(struct sky2_hw *hw, unsigned port,
 /* If idle then force a fake soft NAPI poll once a second
  * to work around cases where sharing an edge triggered interrupt.
  */
+static inline void sky2_idle_start(struct sky2_hw *hw)
+{
+       if (idle_timeout > 0)
+               mod_timer(&hw->idle_timer,
+                         jiffies + msecs_to_jiffies(idle_timeout));
+}
+
 static void sky2_idle(unsigned long arg)
 {
        struct sky2_hw *hw = (struct sky2_hw *) arg;
@@ -2144,6 +2187,9 @@ static int sky2_poll(struct net_device *dev0, int *budget)
        int work_done = 0;
        u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
 
+       if (!~status)
+               goto out;
+
        if (status & Y2_IS_HW_ERR)
                sky2_hw_intr(hw);
 
@@ -2171,19 +2217,19 @@ static int sky2_poll(struct net_device *dev0, int *budget)
        if (status & Y2_IS_CHK_TXA2)
                sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2);
 
-       if (status & Y2_IS_STAT_BMU)
-               sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
-
        work_done = sky2_status_intr(hw, work_limit);
        *budget -= work_done;
        dev0->quota -= work_done;
 
-       if (work_done >= work_limit)
-               return 1;
+       if (status & Y2_IS_STAT_BMU)
+               sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
 
+       if (sky2_more_work(hw))
+               return 1;
+out:
        netif_rx_complete(dev0);
 
-       status = sky2_read32(hw, B0_Y2_SP_LISR);
+       sky2_read32(hw, B0_Y2_SP_LISR);
        return 0;
 }
 
@@ -2209,8 +2255,10 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
 static void sky2_netpoll(struct net_device *dev)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
+       struct net_device *dev0 = sky2->hw->dev[0];
 
-       sky2_intr(sky2->hw->pdev->irq, sky2->hw, NULL);
+       if (netif_running(dev) && __netif_rx_schedule_prep(dev0))
+               __netif_rx_schedule(dev0);
 }
 #endif
 
@@ -3067,12 +3115,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
        sky2->duplex = -1;
        sky2->speed = -1;
        sky2->advertising = sky2_supported_modes(hw);
-
-       /* Receive checksum disabled for Yukon XL
-        * because of observed problems with incorrect
-        * values when multiple packets are received in one interrupt
-        */
-       sky2->rx_csum = (hw->chip_id != CHIP_ID_YUKON_XL);
+       sky2->rx_csum = 1;
 
        spin_lock_init(&sky2->phy_lock);
        sky2->tx_pending = TX_DEF_PENDING;
@@ -3316,9 +3359,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
        sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
 
        setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw);
-       if (idle_timeout > 0)
-               mod_timer(&hw->idle_timer,
-                         jiffies + msecs_to_jiffies(idle_timeout));
+       sky2_idle_start(hw);
 
        pci_set_drvdata(pdev, hw);
 
@@ -3391,8 +3432,14 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct sky2_hw *hw = pci_get_drvdata(pdev);
        int i;
+       pci_power_t pstate = pci_choose_state(pdev, state);
+
+       if (!(pstate == PCI_D3hot || pstate == PCI_D3cold))
+               return -EINVAL;
+
+       del_timer_sync(&hw->idle_timer);
 
-       for (i = 0; i < 2; i++) {
+       for (i = 0; i < hw->ports; i++) {
                struct net_device *dev = hw->dev[i];
 
                if (dev) {
@@ -3401,10 +3448,14 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
 
                        sky2_down(dev);
                        netif_device_detach(dev);
+                       netif_poll_disable(dev);
                }
        }
 
-       return sky2_set_power_state(hw, pci_choose_state(pdev, state));
+       sky2_write32(hw, B0_IMSK, 0);
+       pci_save_state(pdev);
+       sky2_set_power_state(hw, pstate);
+       return 0;
 }
 
 static int sky2_resume(struct pci_dev *pdev)
@@ -3414,27 +3465,31 @@ static int sky2_resume(struct pci_dev *pdev)
 
        pci_restore_state(pdev);
        pci_enable_wake(pdev, PCI_D0, 0);
-       err = sky2_set_power_state(hw, PCI_D0);
-       if (err)
-               goto out;
+       sky2_set_power_state(hw, PCI_D0);
 
        err = sky2_reset(hw);
        if (err)
                goto out;
 
-       for (i = 0; i < 2; i++) {
+       sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
+
+       for (i = 0; i < hw->ports; i++) {
                struct net_device *dev = hw->dev[i];
                if (dev && netif_running(dev)) {
                        netif_device_attach(dev);
+                       netif_poll_enable(dev);
+
                        err = sky2_up(dev);
                        if (err) {
                                printk(KERN_ERR PFX "%s: could not up: %d\n",
                                       dev->name, err);
                                dev_close(dev);
-                               break;
+                               goto out;
                        }
                }
        }
+
+       sky2_idle_start(hw);
 out:
        return err;
 }