pciehp: make pciehp build for powerpc
[safe/jmp/linux-2.6] / drivers / net / sky2.c
index 9b16c2a..de91609 100644 (file)
@@ -23,7 +23,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/config.h>
 #include <linux/crc32.h>
 #include <linux/kernel.h>
 #include <linux/version.h>
@@ -51,7 +50,7 @@
 #include "sky2.h"
 
 #define DRV_NAME               "sky2"
-#define DRV_VERSION            "1.2"
+#define DRV_VERSION            "1.5"
 #define PFX                    DRV_NAME " "
 
 /*
@@ -66,6 +65,7 @@
 #define RX_MAX_PENDING         (RX_LE_SIZE/2 - 2)
 #define RX_DEF_PENDING         RX_MAX_PENDING
 #define RX_SKB_ALIGN           8
+#define RX_BUF_WRITE           16
 
 #define TX_RING_SIZE           512
 #define TX_DEF_PENDING         (TX_RING_SIZE - 1)
@@ -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) },
@@ -128,6 +129,7 @@ MODULE_DEVICE_TABLE(pci, sky2_id_table);
 /* Avoid conditionals by using array */
 static const unsigned txqaddr[] = { Q_XA1, Q_XA2 };
 static const unsigned rxqaddr[] = { Q_R1, Q_R2 };
+static const u32 portirq_msk[] = { Y2_IS_PORT_1, Y2_IS_PORT_2 };
 
 /* This driver supports yukon2 chipset only */
 static const char *yukon2_name[] = {
@@ -185,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);
@@ -242,6 +243,7 @@ static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
                }
 
                sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+               udelay(100);
 
                break;
 
@@ -254,6 +256,7 @@ static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
                else
                        reg1 |= (PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD);
                sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+               udelay(100);
 
                if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
                        sky2_write8(hw, B2_Y2_CLK_GATE, 0);
@@ -272,12 +275,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)
@@ -304,7 +305,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
        struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
        u16 ctrl, ct1000, adv, pg, ledctrl, ledover;
 
-       if (sky2->autoneg == AUTONEG_ENABLE && hw->chip_id != CHIP_ID_YUKON_XL) {
+       if (sky2->autoneg == AUTONEG_ENABLE &&
+           !(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 |
@@ -332,7 +334,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                        ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO);
 
                        if (sky2->autoneg == AUTONEG_ENABLE &&
-                           hw->chip_id == CHIP_ID_YUKON_XL) {
+                           (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
                                ctrl &= ~PHY_M_PC_DSC_MSK;
                                ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
                        }
@@ -448,10 +450,11 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
 
                /* set LED Function Control register */
-               gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, (PHY_M_LEDC_LOS_CTRL(1) |     /* LINK/ACT */
-                                                          PHY_M_LEDC_INIT_CTRL(7) |    /* 10 Mbps */
-                                                          PHY_M_LEDC_STA1_CTRL(7) |    /* 100 Mbps */
-                                                          PHY_M_LEDC_STA0_CTRL(7)));   /* 1000 Mbps */
+               gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
+                            (PHY_M_LEDC_LOS_CTRL(1) |  /* LINK/ACT */
+                             PHY_M_LEDC_INIT_CTRL(7) | /* 10 Mbps */
+                             PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */
+                             PHY_M_LEDC_STA0_CTRL(7)));        /* 1000 Mbps */
 
                /* set Polarity Control register */
                gm_phy_write(hw, port, PHY_MARV_PHY_STAT,
@@ -465,6 +468,25 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                /* restore page register */
                gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
                break;
+       case CHIP_ID_YUKON_EC_U:
+               pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
+
+               /* select page 3 to access LED control register */
+               gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
+
+               /* set LED Function Control register */
+               gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
+                            (PHY_M_LEDC_LOS_CTRL(1) |  /* LINK/ACT */
+                             PHY_M_LEDC_INIT_CTRL(8) | /* 10 Mbps */
+                             PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */
+                             PHY_M_LEDC_STA0_CTRL(7)));/* 1000 Mbps */
+
+               /* set Blink Rate in LED Timer Control Register */
+               gm_phy_write(hw, port, PHY_MARV_INT_MASK,
+                            ledctrl | PHY_M_LED_BLINK_RT(BLINK_84MS));
+               /* restore page register */
+               gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
+               break;
 
        default:
                /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */
@@ -473,19 +495,21 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
        }
 
-       if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev >= 2) {
+       if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev == CHIP_REV_YU_EC_A1) {
                /* apply fixes in PHY AFE */
-               gm_phy_write(hw, port, 22, 255);
+               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 */
-               gm_phy_write(hw, port, 24, 0xaa99);
-               gm_phy_write(hw, port, 23, 0x2011);
+               gm_phy_write(hw, port, 0x18, 0xaa99);
+               gm_phy_write(hw, port, 0x17, 0x2011);
 
                /* fix for IEEE A/B Symmetry failure in 1000BASE-T */
-               gm_phy_write(hw, port, 24, 0xa204);
-               gm_phy_write(hw, port, 23, 0x2002);
+               gm_phy_write(hw, port, 0x18, 0xa204);
+               gm_phy_write(hw, port, 0x17, 0x2002);
 
                /* set page register to 0 */
-               gm_phy_write(hw, port, 22, 0);
+               gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
        } else {
                gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
 
@@ -559,6 +583,11 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
 
                if (sky2->duplex == DUPLEX_FULL)
                        reg |= GM_GPCR_DUP_FULL;
+
+               /* turn off pause in 10/100mbps half duplex */
+               else if (sky2->speed != SPEED_1000 &&
+                        hw->chip_id != CHIP_ID_YUKON_EC_U)
+                       sky2->tx_pause = sky2->rx_pause = 0;
        } else
                reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL;
 
@@ -948,6 +977,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);
@@ -972,9 +1002,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);
@@ -991,7 +1033,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);
@@ -1056,7 +1116,7 @@ static int sky2_up(struct net_device *dev)
 
        /* Enable interrupts from phy/mac for port */
        imask = sky2_read32(hw, B0_IMSK);
-       imask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2;
+       imask |= portirq_msk[port];
        sky2_write32(hw, B0_IMSK, imask);
 
        return 0;
@@ -1101,7 +1161,7 @@ static unsigned tx_le_req(const struct sk_buff *skb)
        count = sizeof(dma_addr_t) / sizeof(u32);
        count += skb_shinfo(skb)->nr_frags * count;
 
-       if (skb_shinfo(skb)->tso_size)
+       if (skb_is_gso(skb))
                ++count;
 
        if (skb->ip_summed == CHECKSUM_HW)
@@ -1173,7 +1233,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
        }
 
        /* Check for TCP Segmentation Offload */
-       mss = skb_shinfo(skb)->tso_size;
+       mss = skb_shinfo(skb)->gso_size;
        if (mss != 0) {
                /* just drop the packet if non-linear expansion fails */
                if (skb_header_cloned(skb) &&
@@ -1331,7 +1391,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
        }
 
        sky2->tx_cons = put;
-       if (tx_avail(sky2) > MAX_SKB_TX_LE)
+       if (tx_avail(sky2) > MAX_SKB_TX_LE + 4)
                netif_wake_queue(dev);
 }
 
@@ -1407,7 +1467,7 @@ static int sky2_down(struct net_device *dev)
 
        /* Disable port IRQ */
        imask = sky2_read32(hw, B0_IMSK);
-       imask &= ~(sky2->port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2;
+       imask &= ~portirq_msk[port];
        sky2_write32(hw, B0_IMSK, imask);
 
        /* turn off LED's */
@@ -1504,17 +1564,26 @@ static void sky2_link_up(struct sky2_port *sky2)
        sky2_write8(hw, SK_REG(port, LNK_LED_REG),
                    LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF);
 
-       if (hw->chip_id == CHIP_ID_YUKON_XL) {
+       if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) {
                u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
+               u16 led = PHY_M_LEDC_LOS_CTRL(1);       /* link active */
+
+               switch(sky2->speed) {
+               case SPEED_10:
+                       led |= PHY_M_LEDC_INIT_CTRL(7);
+                       break;
+
+               case SPEED_100:
+                       led |= PHY_M_LEDC_STA1_CTRL(7);
+                       break;
+
+               case SPEED_1000:
+                       led |= PHY_M_LEDC_STA0_CTRL(7);
+                       break;
+               }
 
                gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
-               gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, PHY_M_LEDC_LOS_CTRL(1) |      /* LINK/ACT */
-                            PHY_M_LEDC_INIT_CTRL(sky2->speed ==
-                                                 SPEED_10 ? 7 : 0) |
-                            PHY_M_LEDC_STA1_CTRL(sky2->speed ==
-                                                 SPEED_100 ? 7 : 0) |
-                            PHY_M_LEDC_STA0_CTRL(sky2->speed ==
-                                                 SPEED_1000 ? 7 : 0));
+               gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, led);
                gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
        }
 
@@ -1589,7 +1658,7 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
        sky2->speed = sky2_phy_speed(hw, aux);
 
        /* Pause bits are offset (9..8) */
-       if (hw->chip_id == CHIP_ID_YUKON_XL)
+       if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)
                aux >>= 6;
 
        sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0;
@@ -1821,9 +1890,6 @@ resubmit:
        re->skb->ip_summed = CHECKSUM_NONE;
        sky2_rx_add(sky2, re->mapaddr);
 
-       /* Tell receiver about new buffers. */
-       sky2_put_idx(sky2->hw, rxqaddr[sky2->port], sky2->rx_put);
-
        return skb;
 
 oversize:
@@ -1861,10 +1927,18 @@ 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)
 {
+       struct sky2_port *sky2;
        int work_done = 0;
+       unsigned buf_write[2] = { 0, 0 };
        u16 hwidx = sky2_read16(hw, STAT_PUT_IDX);
 
        rmb();
@@ -1872,7 +1946,6 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
        while (hw->st_idx != hwidx) {
                struct sky2_status_le *le  = hw->st_le + hw->st_idx;
                struct net_device *dev;
-               struct sky2_port *sky2;
                struct sk_buff *skb;
                u32 status;
                u16 length;
@@ -1905,6 +1978,14 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
 #endif
                                netif_receive_skb(skb);
 
+                       /* Update receiver after 16 frames */
+                       if (++buf_write[le->link] == RX_BUF_WRITE) {
+                               sky2_put_idx(hw, rxqaddr[le->link],
+                                            sky2->rx_put);
+                               buf_write[le->link] = 0;
+                       }
+
+                       /* Stop after net poll weight */
                        if (++work_done >= to_do)
                                goto exit_loop;
                        break;
@@ -1943,6 +2024,16 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
        }
 
 exit_loop:
+       if (buf_write[0]) {
+               sky2 = netdev_priv(hw->dev[0]);
+               sky2_put_idx(hw, Q_R1, sky2->rx_put);
+       }
+
+       if (buf_write[1]) {
+               sky2 = netdev_priv(hw->dev[1]);
+               sky2_put_idx(hw, Q_R2, sky2->rx_put);
+       }
+
        return work_done;
 }
 
@@ -2087,6 +2178,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;
@@ -2133,19 +2231,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)
+       if (status & Y2_IS_STAT_BMU)
+               sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
+
+       if (sky2_more_work(hw))
                return 1;
 
        netif_rx_complete(dev0);
 
-       status = sky2_read32(hw, B0_Y2_SP_LISR);
+       sky2_read32(hw, B0_Y2_SP_LISR);
        return 0;
 }
 
@@ -2171,8 +2269,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
 
@@ -2201,7 +2301,7 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk)
 }
 
 
-static int __devinit sky2_reset(struct sky2_hw *hw)
+static int sky2_reset(struct sky2_hw *hw)
 {
        u16 status;
        u8 t8, pmd_type;
@@ -2226,13 +2326,6 @@ static int __devinit sky2_reset(struct sky2_hw *hw)
                return -EOPNOTSUPP;
        }
 
-       /* This chip is new and not tested yet */
-       if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
-               pr_info(PFX "%s: is a version of Yukon 2 chipset that has not been tested yet.\n",
-                       pci_name(hw->pdev));
-               pr_info("Please report success/failure to maintainer <shemminger@osdl.org>\n");
-       }
-
        /* disable ASF */
        if (hw->chip_id <= CHIP_ID_YUKON_EC) {
                sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
@@ -3036,12 +3129,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;
@@ -3115,7 +3203,7 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
 
        sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW);
 
-       err = request_irq(pdev->irq, sky2_test_intr, SA_SHIRQ, DRV_NAME, hw);
+       err = request_irq(pdev->irq, sky2_test_intr, IRQF_SHARED, DRV_NAME, hw);
        if (err) {
                printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
                       pci_name(pdev), pdev->irq);
@@ -3237,9 +3325,9 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
        if (err)
                goto err_out_iounmap;
 
-       printk(KERN_INFO PFX "v%s addr 0x%lx irq %d Yukon-%s (0x%x) rev %d\n",
-              DRV_VERSION, pci_resource_start(pdev, 0), pdev->irq,
-              yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
+       printk(KERN_INFO PFX "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n",
+              DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0),
+              pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
               hw->chip_id, hw->chip_rev);
 
        dev = sky2_init_netdev(hw, 0, using_dac);
@@ -3275,7 +3363,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
                        goto err_out_unregister;
        }
 
-       err = request_irq(pdev->irq,  sky2_intr, SA_SHIRQ, DRV_NAME, hw);
+       err = request_irq(pdev->irq,  sky2_intr, IRQF_SHARED, DRV_NAME, hw);
        if (err) {
                printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
                       pci_name(pdev), pdev->irq);
@@ -3285,9 +3373,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);
 
@@ -3360,20 +3446,27 @@ 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);
 
-       for (i = 0; i < 2; i++) {
-               struct net_device *dev = hw->dev[i];
+       if (!(pstate == PCI_D3hot || pstate == PCI_D3cold))
+               return -EINVAL;
 
-               if (dev) {
-                       if (!netif_running(dev))
-                               continue;
+       del_timer_sync(&hw->idle_timer);
+       netif_poll_disable(hw->dev[0]);
+
+       for (i = 0; i < hw->ports; i++) {
+               struct net_device *dev = hw->dev[i];
 
+               if (netif_running(dev)) {
                        sky2_down(dev);
                        netif_device_detach(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)
@@ -3383,27 +3476,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)) {
+               if (netif_running(dev)) {
                        netif_device_attach(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;
                        }
                }
        }
+
+       netif_poll_enable(hw->dev[0]);
+       sky2_idle_start(hw);
 out:
        return err;
 }