Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[linux-2.6.git] / drivers / net / sky2.c
index 7650f73..3ee41da 100644 (file)
@@ -22,6 +22,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/crc32.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -31,6 +33,7 @@
 #include <linux/ethtool.h>
 #include <linux/pci.h>
 #include <linux/ip.h>
+#include <linux/slab.h>
 #include <net/ip.h>
 #include <linux/tcp.h>
 #include <linux/in.h>
 
 #include <asm/irq.h>
 
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-#define SKY2_VLAN_TAG_USED 1
-#endif
-
 #include "sky2.h"
 
 #define DRV_NAME               "sky2"
-#define DRV_VERSION            "1.26"
-#define PFX                    DRV_NAME " "
+#define DRV_VERSION            "1.28"
 
 /*
  * The Yukon II chipset takes 64 bit command blocks (called list elements)
    VLAN:GSO + CKSUM + Data + skb_frags * DMA */
 #define MAX_SKB_TX_LE  (2 + (sizeof(dma_addr_t)/sizeof(u32))*(MAX_SKB_FRAGS+1))
 #define TX_MIN_PENDING         (MAX_SKB_TX_LE+1)
-#define TX_MAX_PENDING         4096
+#define TX_MAX_PENDING         1024
 #define TX_DEF_PENDING         127
 
-#define STATUS_RING_SIZE       2048    /* 2 ports * (TX + 2*RX) */
-#define STATUS_LE_BYTES                (STATUS_RING_SIZE*sizeof(struct sky2_status_le))
 #define TX_WATCHDOG            (5 * HZ)
 #define NAPI_WEIGHT            64
 #define PHY_RETRIES            1000
 
 #define SKY2_EEPROM_MAGIC      0x9955aabb
 
-
-#define RING_NEXT(x,s) (((x)+1) & ((s)-1))
+#define RING_NEXT(x, s)        (((x)+1) & ((s)-1))
 
 static const u32 default_msg =
     NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
@@ -173,7 +168,7 @@ static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val)
                udelay(10);
        }
 
-       dev_warn(&hw->pdev->dev,"%s: phy write timeout\n", hw->dev[port]->name);
+       dev_warn(&hw->pdev->dev, "%s: phy write timeout\n", hw->dev[port]->name);
        return -ETIMEDOUT;
 
 io_error:
@@ -225,7 +220,7 @@ static void sky2_power_on(struct sky2_hw *hw)
        /* disable Core Clock Division, */
        sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
 
-       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > CHIP_REV_YU_XL_A1)
                /* enable bits are inverted */
                sky2_write8(hw, B2_Y2_CLK_GATE,
                            Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
@@ -251,6 +246,8 @@ static void sky2_power_on(struct sky2_hw *hw)
 
                sky2_pci_write32(hw, PCI_CFG_REG_1, 0);
 
+               sky2_write16(hw, B0_CTST, Y2_HW_WOL_ON);
+
                /* Enable workaround for dev 4.107 on Yukon-Ultra & Extreme */
                reg = sky2_read32(hw, B2_GP_IO);
                reg |= GLB_GPIO_STAT_RACE_DIS;
@@ -265,7 +262,7 @@ static void sky2_power_on(struct sky2_hw *hw)
 
 static void sky2_power_aux(struct sky2_hw *hw)
 {
-       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > CHIP_REV_YU_XL_A1)
                sky2_write8(hw, B2_Y2_CLK_GATE, 0);
        else
                /* enable bits are inverted */
@@ -644,13 +641,15 @@ static void sky2_phy_power_up(struct sky2_hw *hw, unsigned port)
 {
        u32 reg1;
 
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
        reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
        reg1 &= ~phy_power[port];
 
-       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > CHIP_REV_YU_XL_A1)
                reg1 |= coma_mode[port];
 
        sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
        sky2_pci_read32(hw, PCI_DEV_REG1);
 
        if (hw->chip_id == CHIP_ID_YUKON_FE)
@@ -707,9 +706,23 @@ static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port)
                gm_phy_write(hw, port, PHY_MARV_CTRL, PHY_CT_PDOWN);
        }
 
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
        reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
        reg1 |= phy_power[port];                /* set PHY to PowerDown/COMA Mode */
        sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+}
+
+/* Enable Rx/Tx */
+static void sky2_enable_rx_tx(struct sky2_port *sky2)
+{
+       struct sky2_hw *hw = sky2->hw;
+       unsigned port = sky2->port;
+       u16 reg;
+
+       reg = gma_read16(hw, port, GM_GP_CTRL);
+       reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
+       gma_write16(hw, port, GM_GP_CTRL, reg);
 }
 
 /* Force a renegotiation */
@@ -717,6 +730,7 @@ static void sky2_phy_reinit(struct sky2_port *sky2)
 {
        spin_lock_bh(&sky2->phy_lock);
        sky2_phy_init(sky2->hw, sky2->port);
+       sky2_enable_rx_tx(sky2);
        spin_unlock_bh(&sky2->phy_lock);
 }
 
@@ -727,7 +741,6 @@ static void sky2_wol_init(struct sky2_port *sky2)
        unsigned port = sky2->port;
        enum flow_control save_mode;
        u16 ctrl;
-       u32 reg1;
 
        /* Bring hardware out of reset */
        sky2_write16(hw, B0_CTST, CS_RST_CLR);
@@ -778,14 +791,11 @@ static void sky2_wol_init(struct sky2_port *sky2)
        ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT;
        sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
 
-       /* Turn on legacy PCI-Express PME mode */
-       reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
-       reg1 |= PCI_Y2_PME_LEGACY;
-       sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+       /* Disable PiG firmware */
+       sky2_write16(hw, B0_CTST, Y2_HW_WOL_OFF);
 
        /* block receiver */
        sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
-
 }
 
 static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port)
@@ -796,29 +806,15 @@ static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port)
              hw->chip_rev != CHIP_REV_YU_EX_A0) ||
             hw->chip_id >= CHIP_ID_YUKON_FE_P) {
                /* Yukon-Extreme B0 and further Extreme devices */
-               /* enable Store & Forward mode for TX */
-
-               if (dev->mtu <= ETH_DATA_LEN)
-                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
-                                    TX_JUMBO_DIS | TX_STFW_ENA);
-
-               else
-                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
-                                    TX_JUMBO_ENA| TX_STFW_ENA);
-       } else {
-               if (dev->mtu <= ETH_DATA_LEN)
-                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_ENA);
-               else {
-                       /* set Tx GMAC FIFO Almost Empty Threshold */
-                       sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
-                                    (ECU_JUMBO_WM << 16) | ECU_AE_THR);
+               sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_ENA);
+       } else if (dev->mtu > ETH_DATA_LEN) {
+               /* set Tx GMAC FIFO Almost Empty Threshold */
+               sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
+                            (ECU_JUMBO_WM << 16) | ECU_AE_THR);
 
-                       sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_DIS);
-
-                       /* Can't do offload because of lack of store/forward */
-                       dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM);
-               }
-       }
+               sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_DIS);
+       } else
+               sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_ENA);
 }
 
 static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
@@ -834,7 +830,9 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
 
        sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
 
-       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev == 0 && port == 1) {
+       if (hw->chip_id == CHIP_ID_YUKON_XL &&
+           hw->chip_rev == CHIP_REV_YU_XL_A0 &&
+           port == 1) {
                /* WA DEV_472 -- looks like crossed wires on port 2 */
                /* clear GMAC 1 Control reset */
                sky2_write8(hw, SK_REG(0, GMAC_CTRL), GMC_RST_CLR);
@@ -888,6 +886,10 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
        if (hw->dev[port]->mtu > ETH_DATA_LEN)
                reg |= GM_SMOD_JUMBO_ENA;
 
+       if (hw->chip_id == CHIP_ID_YUKON_EC_U &&
+           hw->chip_rev == CHIP_REV_YU_EC_U_B1)
+               reg |= GM_NEW_FLOW_CTRL;
+
        gma_write16(hw, port, GM_SERIAL_MODE, reg);
 
        /* virtual address for data */
@@ -930,7 +932,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
        sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
        sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
 
-       /* On chips without ram buffer, pause is controled by MAC level */
+       /* On chips without ram buffer, pause is controlled by MAC level */
        if (!(hw->flags & SKY2_HW_RAM_BUFFER)) {
                /* Pause threshold is scaled by 8 in bytes */
                if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
@@ -1021,11 +1023,8 @@ static void sky2_prefetch_init(struct sky2_hw *hw, u32 qaddr,
 static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot)
 {
        struct sky2_tx_le *le = sky2->tx_le + *slot;
-       struct tx_ring_info *re = sky2->tx_ring + *slot;
 
        *slot = RING_NEXT(*slot, sky2->tx_ring_size);
-       re->flags = 0;
-       re->skb = NULL;
        le->ctrl = 0;
        return le;
 }
@@ -1064,8 +1063,42 @@ static inline struct sky2_rx_le *sky2_next_rx(struct sky2_port *sky2)
        return le;
 }
 
+static unsigned sky2_get_rx_threshold(struct sky2_port *sky2)
+{
+       unsigned size;
+
+       /* Space needed for frame data + headers rounded up */
+       size = roundup(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8);
+
+       /* Stopping point for hardware truncation */
+       return (size - 8) / sizeof(u32);
+}
+
+static unsigned sky2_get_rx_data_size(struct sky2_port *sky2)
+{
+       struct rx_ring_info *re;
+       unsigned size;
+
+       /* Space needed for frame data + headers rounded up */
+       size = roundup(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8);
+
+       sky2->rx_nfrags = size >> PAGE_SHIFT;
+       BUG_ON(sky2->rx_nfrags > ARRAY_SIZE(re->frag_addr));
+
+       /* Compute residue after pages */
+       size -= sky2->rx_nfrags << PAGE_SHIFT;
+
+       /* Optimize to handle small packets and headers */
+       if (size < copybreak)
+               size = copybreak;
+       if (size < ETH_HLEN)
+               size = ETH_HLEN;
+
+       return size;
+}
+
 /* Build description to hardware for one receive segment */
-static void sky2_rx_add(struct sky2_port *sky2,  u8 op,
+static void sky2_rx_add(struct sky2_port *sky2, u8 op,
                        dma_addr_t map, unsigned len)
 {
        struct sky2_rx_le *le;
@@ -1102,18 +1135,39 @@ static int sky2_rx_map_skb(struct pci_dev *pdev, struct rx_ring_info *re,
        int i;
 
        re->data_addr = pci_map_single(pdev, skb->data, size, PCI_DMA_FROMDEVICE);
-       if (unlikely(pci_dma_mapping_error(pdev, re->data_addr)))
-               return -EIO;
+       if (pci_dma_mapping_error(pdev, re->data_addr))
+               goto mapping_error;
 
-       pci_unmap_len_set(re, data_size, size);
+       dma_unmap_len_set(re, data_size, size);
 
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-               re->frag_addr[i] = pci_map_page(pdev,
-                                               skb_shinfo(skb)->frags[i].page,
-                                               skb_shinfo(skb)->frags[i].page_offset,
-                                               skb_shinfo(skb)->frags[i].size,
+       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+               skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+               re->frag_addr[i] = pci_map_page(pdev, frag->page,
+                                               frag->page_offset,
+                                               frag->size,
                                                PCI_DMA_FROMDEVICE);
+
+               if (pci_dma_mapping_error(pdev, re->frag_addr[i]))
+                       goto map_page_error;
+       }
        return 0;
+
+map_page_error:
+       while (--i >= 0) {
+               pci_unmap_page(pdev, re->frag_addr[i],
+                              skb_shinfo(skb)->frags[i].size,
+                              PCI_DMA_FROMDEVICE);
+       }
+
+       pci_unmap_single(pdev, re->data_addr, dma_unmap_len(re, data_size),
+                        PCI_DMA_FROMDEVICE);
+
+mapping_error:
+       if (net_ratelimit())
+               dev_warn(&pdev->dev, "%s: rx mapping error\n",
+                        skb->dev->name);
+       return -EIO;
 }
 
 static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re)
@@ -1121,7 +1175,7 @@ static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re)
        struct sk_buff *skb = re->skb;
        int i;
 
-       pci_unmap_single(pdev, re->data_addr, pci_unmap_len(re, data_size),
+       pci_unmap_single(pdev, re->data_addr, dma_unmap_len(re, data_size),
                         PCI_DMA_FROMDEVICE);
 
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
@@ -1144,10 +1198,43 @@ static void rx_set_checksum(struct sky2_port *sky2)
 
        sky2_write32(sky2->hw,
                     Q_ADDR(rxqaddr[sky2->port], Q_CSR),
-                    (sky2->flags & SKY2_FLAG_RX_CHECKSUM)
+                    (sky2->netdev->features & NETIF_F_RXCSUM)
                     ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
 }
 
+/* Enable/disable receive hash calculation (RSS) */
+static void rx_set_rss(struct net_device *dev, u32 features)
+{
+       struct sky2_port *sky2 = netdev_priv(dev);
+       struct sky2_hw *hw = sky2->hw;
+       int i, nkeys = 4;
+
+       /* Supports IPv6 and other modes */
+       if (hw->flags & SKY2_HW_NEW_LE) {
+               nkeys = 10;
+               sky2_write32(hw, SK_REG(sky2->port, RSS_CFG), HASH_ALL);
+       }
+
+       /* Program RSS initial values */
+       if (features & NETIF_F_RXHASH) {
+               u32 key[nkeys];
+
+               get_random_bytes(key, nkeys * sizeof(u32));
+               for (i = 0; i < nkeys; i++)
+                       sky2_write32(hw, SK_REG(sky2->port, RSS_KEY + i * 4),
+                                    key[i]);
+
+               /* Need to turn on (undocumented) flag to make hashing work  */
+               sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T),
+                            RX_STFW_ENA);
+
+               sky2_write32(hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
+                            BMU_ENA_RX_RSS_HASH);
+       } else
+               sky2_write32(hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
+                            BMU_DIS_RX_RSS_HASH);
+}
+
 /*
  * The RX Stop command will not work for Yukon-2 if the BMU does not
  * reach the end of packet and since we can't make sure that we have
@@ -1172,8 +1259,7 @@ static void sky2_rx_stop(struct sky2_port *sky2)
                    == sky2_read8(hw, RB_ADDR(rxq, Q_RL)))
                        goto stopped;
 
-       printk(KERN_WARNING PFX "%s: receiver stop failed\n",
-              sky2->netdev->name);
+       netdev_warn(sky2->netdev, "receiver stop failed\n");
 stopped:
        sky2_write32(hw, Q_ADDR(rxq, Q_CSR), BMU_RST_SET | BMU_FIFO_RST);
 
@@ -1236,39 +1322,34 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return err;
 }
 
-#ifdef SKY2_VLAN_TAG_USED
-static void sky2_set_vlan_mode(struct sky2_hw *hw, u16 port, bool onoff)
+#define SKY2_VLAN_OFFLOADS (NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO)
+
+static void sky2_vlan_mode(struct net_device *dev, u32 features)
 {
-       if (onoff) {
+       struct sky2_port *sky2 = netdev_priv(dev);
+       struct sky2_hw *hw = sky2->hw;
+       u16 port = sky2->port;
+
+       if (features & NETIF_F_HW_VLAN_RX)
                sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
                             RX_VLAN_STRIP_ON);
+       else
+               sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
+                            RX_VLAN_STRIP_OFF);
+
+       if (features & NETIF_F_HW_VLAN_TX) {
                sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
                             TX_VLAN_TAG_ON);
+
+               dev->vlan_features |= SKY2_VLAN_OFFLOADS;
        } else {
-               sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
-                            RX_VLAN_STRIP_OFF);
                sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
                             TX_VLAN_TAG_OFF);
-       }
-}
 
-static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
-{
-       struct sky2_port *sky2 = netdev_priv(dev);
-       struct sky2_hw *hw = sky2->hw;
-       u16 port = sky2->port;
-
-       netif_tx_lock_bh(dev);
-       napi_disable(&hw->napi);
-
-       sky2->vlgrp = grp;
-       sky2_set_vlan_mode(hw, port, grp != NULL);
-
-       sky2_read32(hw, B0_Y2_SP_LISR);
-       napi_enable(&hw->napi);
-       netif_tx_unlock_bh(dev);
+               /* Can't do transmit offload of vlan without hw vlan */
+               dev->vlan_features &= ~SKY2_VLAN_OFFLOADS;
+       }
 }
-#endif
 
 /* Amount of required worst case padding in rx buffer */
 static inline unsigned sky2_rx_pad(const struct sky2_hw *hw)
@@ -1323,8 +1404,32 @@ static inline void sky2_rx_update(struct sky2_port *sky2, unsigned rxq)
        sky2_put_idx(sky2->hw, rxq, sky2->rx_put);
 }
 
+static int sky2_alloc_rx_skbs(struct sky2_port *sky2)
+{
+       struct sky2_hw *hw = sky2->hw;
+       unsigned i;
+
+       sky2->rx_data_size = sky2_get_rx_data_size(sky2);
+
+       /* Fill Rx ring */
+       for (i = 0; i < sky2->rx_pending; i++) {
+               struct rx_ring_info *re = sky2->rx_ring + i;
+
+               re->skb = sky2_rx_alloc(sky2);
+               if (!re->skb)
+                       return -ENOMEM;
+
+               if (sky2_rx_map_skb(hw->pdev, re, sky2->rx_data_size)) {
+                       dev_kfree_skb(re->skb);
+                       re->skb = NULL;
+                       return -ENOMEM;
+               }
+       }
+       return 0;
+}
+
 /*
- * Allocate and setup receiver buffer pool.
+ * Setup receiver buffer pool.
  * Normal case this ends up creating one list element for skb
  * in the receive ring. Worst case if using large MTU and each
  * allocation falls on a different 64 bit region, that results
@@ -1332,12 +1437,12 @@ static inline void sky2_rx_update(struct sky2_port *sky2, unsigned rxq)
  * One element is used for checksum enable/disable, and one
  * extra to avoid wrap.
  */
-static int sky2_rx_start(struct sky2_port *sky2)
+static void sky2_rx_start(struct sky2_port *sky2)
 {
        struct sky2_hw *hw = sky2->hw;
        struct rx_ring_info *re;
        unsigned rxq = rxqaddr[sky2->port];
-       unsigned i, size, thresh;
+       unsigned i, thresh;
 
        sky2->rx_put = sky2->rx_next = 0;
        sky2_qset(hw, rxq);
@@ -1349,8 +1454,7 @@ static int sky2_rx_start(struct sky2_port *sky2)
        /* These chips have no ram buffer?
         * MAC Rx RAM Read is controlled by hardware */
        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))
+           hw->chip_rev > CHIP_REV_YU_EC_U_A0)
                sky2_write32(hw, Q_ADDR(rxq, Q_TEST), F_M_RX_RAM_DIS);
 
        sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1);
@@ -1358,40 +1462,12 @@ static int sky2_rx_start(struct sky2_port *sky2)
        if (!(hw->flags & SKY2_HW_NEW_LE))
                rx_set_checksum(sky2);
 
-       /* Space needed for frame data + headers rounded up */
-       size = roundup(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8);
-
-       /* Stopping point for hardware truncation */
-       thresh = (size - 8) / sizeof(u32);
+       if (!(hw->flags & SKY2_HW_RSS_BROKEN))
+               rx_set_rss(sky2->netdev, sky2->netdev->features);
 
-       sky2->rx_nfrags = size >> PAGE_SHIFT;
-       BUG_ON(sky2->rx_nfrags > ARRAY_SIZE(re->frag_addr));
-
-       /* Compute residue after pages */
-       size -= sky2->rx_nfrags << PAGE_SHIFT;
-
-       /* Optimize to handle small packets and headers */
-       if (size < copybreak)
-               size = copybreak;
-       if (size < ETH_HLEN)
-               size = ETH_HLEN;
-
-       sky2->rx_data_size = size;
-
-       /* Fill Rx ring */
+       /* submit Rx ring */
        for (i = 0; i < sky2->rx_pending; i++) {
                re = sky2->rx_ring + i;
-
-               re->skb = sky2_rx_alloc(sky2);
-               if (!re->skb)
-                       goto nomem;
-
-               if (sky2_rx_map_skb(hw->pdev, re, sky2->rx_data_size)) {
-                       dev_kfree_skb(re->skb);
-                       re->skb = NULL;
-                       goto nomem;
-               }
-
                sky2_rx_submit(sky2, re);
        }
 
@@ -1401,6 +1477,7 @@ static int sky2_rx_start(struct sky2_port *sky2)
         * the register is limited to 9 bits, so if you do frames > 2052
         * you better get the MTU right!
         */
+       thresh = sky2_get_rx_threshold(sky2);
        if (thresh > 0x1ff)
                sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_OFF);
        else {
@@ -1432,13 +1509,6 @@ static int sky2_rx_start(struct sky2_port *sky2)
                sky2_write32(hw, Q_ADDR(txqaddr[sky2->port], Q_TEST),
                             TBMU_TEST_HOME_ADD_FIX_EN | TBMU_TEST_ROUTING_ADD_FIX_EN);
        }
-
-
-
-       return 0;
-nomem:
-       sky2_rx_clean(sky2);
-       return -ENOMEM;
 }
 
 static int sky2_alloc_buffers(struct sky2_port *sky2)
@@ -1469,7 +1539,7 @@ static int sky2_alloc_buffers(struct sky2_port *sky2)
        if (!sky2->rx_ring)
                goto nomem;
 
-       return 0;
+       return sky2_alloc_rx_skbs(sky2);
 nomem:
        return -ENOMEM;
 }
@@ -1478,6 +1548,8 @@ static void sky2_free_buffers(struct sky2_port *sky2)
 {
        struct sky2_hw *hw = sky2->hw;
 
+       sky2_rx_clean(sky2);
+
        if (sky2->rx_le) {
                pci_free_consistent(hw->pdev, RX_LE_BYTES,
                                    sky2->rx_le, sky2->rx_le_map);
@@ -1496,16 +1568,16 @@ static void sky2_free_buffers(struct sky2_port *sky2)
        sky2->rx_ring = NULL;
 }
 
-/* Bring up network interface. */
-static int sky2_up(struct net_device *dev)
+static void sky2_hw_up(struct sky2_port *sky2)
 {
-       struct sky2_port *sky2 = netdev_priv(dev);
        struct sky2_hw *hw = sky2->hw;
        unsigned port = sky2->port;
-       u32 imask, ramsize;
-       int cap, err;
+       u32 ramsize;
+       int cap;
        struct net_device *otherdev = hw->dev[sky2->port^1];
 
+       tx_init(sky2);
+
        /*
         * On dual port PCI-X card, there is an problem where status
         * can be received out of order due to split transactions
@@ -1517,16 +1589,7 @@ static int sky2_up(struct net_device *dev)
                cmd = sky2_pci_read16(hw, cap + PCI_X_CMD);
                cmd &= ~PCI_X_CMD_MAX_SPLIT;
                sky2_pci_write16(hw, cap + PCI_X_CMD, cmd);
-
-       }
-
-       netif_carrier_off(dev);
-
-       err = sky2_alloc_buffers(sky2);
-       if (err)
-               goto err_out;
-
-       tx_init(sky2);
+       }
 
        sky2_mac_init(hw, port);
 
@@ -1535,7 +1598,7 @@ static int sky2_up(struct net_device *dev)
        if (ramsize > 0) {
                u32 rxspace;
 
-               pr_debug(PFX "%s: ram buffer %dK\n", dev->name, ramsize);
+               netdev_dbg(sky2->netdev, "ram buffer %dK\n", ramsize);
                if (ramsize < 16)
                        rxspace = ramsize / 2;
                else
@@ -1563,22 +1626,36 @@ static int sky2_up(struct net_device *dev)
        sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
                           sky2->tx_ring_size - 1);
 
-#ifdef SKY2_VLAN_TAG_USED
-       sky2_set_vlan_mode(hw, port, sky2->vlgrp != NULL);
-#endif
+       sky2_vlan_mode(sky2->netdev, sky2->netdev->features);
+       netdev_update_features(sky2->netdev);
+
+       sky2_rx_start(sky2);
+}
+
+/* Bring up network interface. */
+static int sky2_up(struct net_device *dev)
+{
+       struct sky2_port *sky2 = netdev_priv(dev);
+       struct sky2_hw *hw = sky2->hw;
+       unsigned port = sky2->port;
+       u32 imask;
+       int err;
+
+       netif_carrier_off(dev);
 
-       err = sky2_rx_start(sky2);
+       err = sky2_alloc_buffers(sky2);
        if (err)
                goto err_out;
 
+       sky2_hw_up(sky2);
+
        /* Enable interrupts from phy/mac for port */
        imask = sky2_read32(hw, B0_IMSK);
        imask |= portirq_msk[port];
        sky2_write32(hw, B0_IMSK, imask);
        sky2_read32(hw, B0_IMSK);
 
-       if (netif_msg_ifup(sky2))
-               printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
+       netif_info(sky2, ifup, dev, "enabling interface\n");
 
        return 0;
 
@@ -1618,17 +1695,17 @@ static unsigned tx_le_req(const struct sk_buff *skb)
        return count;
 }
 
-static void sky2_tx_unmap(struct pci_dev *pdev,
-                         const struct tx_ring_info *re)
+static void sky2_tx_unmap(struct pci_dev *pdev, struct tx_ring_info *re)
 {
        if (re->flags & TX_MAP_SINGLE)
-               pci_unmap_single(pdev, pci_unmap_addr(re, mapaddr),
-                                pci_unmap_len(re, maplen),
+               pci_unmap_single(pdev, dma_unmap_addr(re, mapaddr),
+                                dma_unmap_len(re, maplen),
                                 PCI_DMA_TODEVICE);
        else if (re->flags & TX_MAP_PAGE)
-               pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr),
-                              pci_unmap_len(re, maplen),
+               pci_unmap_page(pdev, dma_unmap_addr(re, mapaddr),
+                              dma_unmap_len(re, maplen),
                               PCI_DMA_TODEVICE);
+       re->flags = 0;
 }
 
 /*
@@ -1661,9 +1738,8 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
                goto mapping_error;
 
        slot = sky2->tx_prod;
-       if (unlikely(netif_msg_tx_queued(sky2)))
-               printk(KERN_DEBUG "%s: tx queued, slot %u, len %d\n",
-                      dev->name, slot, skb->len);
+       netif_printk(sky2, tx_queued, KERN_DEBUG, dev,
+                    "tx queued, slot %u, len %d\n", slot, skb->len);
 
        /* Send high bits if needed */
        upper = upper_32_bits(mapping);
@@ -1694,9 +1770,9 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
        }
 
        ctrl = 0;
-#ifdef SKY2_VLAN_TAG_USED
+
        /* Add VLAN tag, can piggyback on LRGLEN or ADDR64 */
-       if (sky2->vlgrp && vlan_tx_tag_present(skb)) {
+       if (vlan_tx_tag_present(skb)) {
                if (!le) {
                        le = get_tx_le(sky2, &slot);
                        le->addr = 0;
@@ -1706,7 +1782,6 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
                le->length = cpu_to_be16(vlan_tx_tag_get(skb));
                ctrl |= INS_VLAN;
        }
-#endif
 
        /* Handle TCP checksum offload */
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -1738,8 +1813,8 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
 
        re = sky2->tx_ring + slot;
        re->flags = TX_MAP_SINGLE;
-       pci_unmap_addr_set(re, mapaddr, mapping);
-       pci_unmap_len_set(re, maplen, len);
+       dma_unmap_addr_set(re, mapaddr, mapping);
+       dma_unmap_len_set(re, maplen, len);
 
        le = get_tx_le(sky2, &slot);
        le->addr = cpu_to_le32(lower_32_bits(mapping));
@@ -1767,8 +1842,8 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
 
                re = sky2->tx_ring + slot;
                re->flags = TX_MAP_PAGE;
-               pci_unmap_addr_set(re, mapaddr, mapping);
-               pci_unmap_len_set(re, maplen, frag->size);
+               dma_unmap_addr_set(re, mapaddr, mapping);
+               dma_unmap_len_set(re, maplen, frag->size);
 
                le = get_tx_le(sky2, &slot);
                le->addr = cpu_to_le32(lower_32_bits(mapping));
@@ -1828,13 +1903,15 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
                sky2_tx_unmap(sky2->hw->pdev, re);
 
                if (skb) {
-                       if (unlikely(netif_msg_tx_done(sky2)))
-                               printk(KERN_DEBUG "%s: tx done %u\n",
-                                      dev->name, idx);
+                       netif_printk(sky2, tx_done, KERN_DEBUG, dev,
+                                    "tx done %u\n", idx);
 
-                       dev->stats.tx_packets++;
-                       dev->stats.tx_bytes += skb->len;
+                       u64_stats_update_begin(&sky2->tx_stats.syncp);
+                       ++sky2->tx_stats.packets;
+                       sky2->tx_stats.bytes += skb->len;
+                       u64_stats_update_end(&sky2->tx_stats.syncp);
 
+                       re->skb = NULL;
                        dev_kfree_skb_any(skb);
 
                        sky2->tx_next = RING_NEXT(idx, sky2->tx_ring_size);
@@ -1843,10 +1920,6 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
 
        sky2->tx_cons = idx;
        smp_mb();
-
-       /* Wake unless it's detached, and called e.g. from sky2_down() */
-       if (tx_avail(sky2) > MAX_SKB_TX_LE + 4 && netif_device_present(dev))
-               netif_wake_queue(dev);
 }
 
 static void sky2_tx_reset(struct sky2_hw *hw, unsigned port)
@@ -1871,21 +1944,11 @@ static void sky2_tx_reset(struct sky2_hw *hw, unsigned port)
        sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
 }
 
-/* Network shutdown */
-static int sky2_down(struct net_device *dev)
+static void sky2_hw_down(struct sky2_port *sky2)
 {
-       struct sky2_port *sky2 = netdev_priv(dev);
        struct sky2_hw *hw = sky2->hw;
        unsigned port = sky2->port;
        u16 ctrl;
-       u32 imask;
-
-       /* Never really got started! */
-       if (!sky2->tx_le)
-               return 0;
-
-       if (netif_msg_ifdown(sky2))
-               printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
 
        /* Force flow control off */
        sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
@@ -1918,15 +1981,6 @@ static int sky2_down(struct net_device *dev)
 
        sky2_rx_stop(sky2);
 
-       /* Disable port IRQ */
-       imask = sky2_read32(hw, B0_IMSK);
-       imask &= ~portirq_msk[port];
-       sky2_write32(hw, B0_IMSK, imask);
-       sky2_read32(hw, B0_IMSK);
-
-       synchronize_irq(hw->pdev->irq);
-       napi_synchronize(&hw->napi);
-
        spin_lock_bh(&sky2->phy_lock);
        sky2_phy_power_down(hw, port);
        spin_unlock_bh(&sky2->phy_lock);
@@ -1935,8 +1989,29 @@ static int sky2_down(struct net_device *dev)
 
        /* Free any pending frames stuck in HW queue */
        sky2_tx_complete(sky2, sky2->tx_prod);
+}
 
-       sky2_rx_clean(sky2);
+/* Network shutdown */
+static int sky2_down(struct net_device *dev)
+{
+       struct sky2_port *sky2 = netdev_priv(dev);
+       struct sky2_hw *hw = sky2->hw;
+
+       /* Never really got started! */
+       if (!sky2->tx_le)
+               return 0;
+
+       netif_info(sky2, ifdown, dev, "disabling interface\n");
+
+       /* Disable port IRQ */
+       sky2_write32(hw, B0_IMSK,
+                    sky2_read32(hw, B0_IMSK) & ~portirq_msk[sky2->port]);
+       sky2_read32(hw, B0_IMSK);
+
+       synchronize_irq(hw->pdev->irq);
+       napi_synchronize(&hw->napi);
+
+       sky2_hw_down(sky2);
 
        sky2_free_buffers(sky2);
 
@@ -1969,7 +2044,6 @@ static void sky2_link_up(struct sky2_port *sky2)
 {
        struct sky2_hw *hw = sky2->hw;
        unsigned port = sky2->port;
-       u16 reg;
        static const char *fc_name[] = {
                [FC_NONE]       = "none",
                [FC_TX]         = "tx",
@@ -1977,10 +2051,7 @@ static void sky2_link_up(struct sky2_port *sky2)
                [FC_BOTH]       = "both",
        };
 
-       /* enable Rx/Tx */
-       reg = gma_read16(hw, port, GM_GP_CTRL);
-       reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
-       gma_write16(hw, port, GM_GP_CTRL, reg);
+       sky2_enable_rx_tx(sky2);
 
        gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
 
@@ -1992,12 +2063,11 @@ 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 (netif_msg_link(sky2))
-               printk(KERN_INFO PFX
-                      "%s: Link is up at %d Mbps, %s duplex, flow control %s\n",
-                      sky2->netdev->name, sky2->speed,
-                      sky2->duplex == DUPLEX_FULL ? "full" : "half",
-                      fc_name[sky2->flow_status]);
+       netif_info(sky2, link, sky2->netdev,
+                  "Link is up at %d Mbps, %s duplex, flow control %s\n",
+                  sky2->speed,
+                  sky2->duplex == DUPLEX_FULL ? "full" : "half",
+                  fc_name[sky2->flow_status]);
 }
 
 static void sky2_link_down(struct sky2_port *sky2)
@@ -2017,8 +2087,7 @@ static void sky2_link_down(struct sky2_port *sky2)
        /* Turn off link LED */
        sky2_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
 
-       if (netif_msg_link(sky2))
-               printk(KERN_INFO PFX "%s: Link is down.\n", sky2->netdev->name);
+       netif_info(sky2, link, sky2->netdev, "Link is down\n");
 
        sky2_phy_init(hw, port);
 }
@@ -2040,13 +2109,12 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
        advert = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV);
        lpa = gm_phy_read(hw, port, PHY_MARV_AUNE_LP);
        if (lpa & PHY_M_AN_RF) {
-               printk(KERN_ERR PFX "%s: remote fault", sky2->netdev->name);
+               netdev_err(sky2->netdev, "remote fault\n");
                return -1;
        }
 
        if (!(aux & PHY_M_PS_SPDUP_RES)) {
-               printk(KERN_ERR PFX "%s: speed/duplex mismatch",
-                      sky2->netdev->name);
+               netdev_err(sky2->netdev, "speed/duplex mismatch\n");
                return -1;
        }
 
@@ -2108,12 +2176,12 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port)
        istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT);
        phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
 
-       if (netif_msg_intr(sky2))
-               printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n",
-                      sky2->netdev->name, istatus, phystat);
+       netif_info(sky2, intr, sky2->netdev, "phy interrupt status 0x%x 0x%x\n",
+                  istatus, phystat);
 
        if (istatus & PHY_M_IS_AN_COMPL) {
-               if (sky2_autoneg_done(sky2, phystat) == 0)
+               if (sky2_autoneg_done(sky2, phystat) == 0 &&
+                   !netif_carrier_ok(dev))
                        sky2_link_up(sky2);
                goto out;
        }
@@ -2149,7 +2217,9 @@ static void sky2_qlink_intr(struct sky2_hw *hw)
 
        /* reset PHY Link Detect */
        phy = sky2_pci_read16(hw, PSM_CONFIG_REG4);
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
        sky2_pci_write16(hw, PSM_CONFIG_REG4, phy | 1);
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
 
        sky2_link_up(sky2);
 }
@@ -2162,13 +2232,12 @@ static void sky2_tx_timeout(struct net_device *dev)
        struct sky2_port *sky2 = netdev_priv(dev);
        struct sky2_hw *hw = sky2->hw;
 
-       if (netif_msg_timer(sky2))
-               printk(KERN_ERR PFX "%s: tx timeout\n", dev->name);
+       netif_err(sky2, timer, dev, "tx timeout\n");
 
-       printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n",
-              dev->name, sky2->tx_cons, sky2->tx_prod,
-              sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX),
-              sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE)));
+       netdev_printk(KERN_DEBUG, dev, "transmit ring %u .. %u report=%u done=%u\n",
+                     sky2->tx_cons, sky2->tx_prod,
+                     sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX),
+                     sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE)));
 
        /* can't restart safely under softirq */
        schedule_work(&hw->restart_work);
@@ -2183,9 +2252,11 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
        u16 ctl, mode;
        u32 imask;
 
+       /* MTU size outside the spec */
        if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
                return -EINVAL;
 
+       /* MTU > 1500 on yukon FE and FE+ not allowed */
        if (new_mtu > ETH_DATA_LEN &&
            (hw->chip_id == CHIP_ID_YUKON_FE ||
             hw->chip_id == CHIP_ID_YUKON_FE_P))
@@ -2193,6 +2264,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
 
        if (!netif_running(dev)) {
                dev->mtu = new_mtu;
+               netdev_update_features(dev);
                return 0;
        }
 
@@ -2200,8 +2272,8 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
        sky2_write32(hw, B0_IMSK, 0);
 
        dev->trans_start = jiffies;     /* prevent tx timeout */
-       netif_stop_queue(dev);
        napi_disable(&hw->napi);
+       netif_tx_disable(dev);
 
        synchronize_irq(hw->pdev->irq);
 
@@ -2214,6 +2286,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
        sky2_rx_clean(sky2);
 
        dev->mtu = new_mtu;
+       netdev_update_features(dev);
 
        mode = DATA_BLIND_VAL(DATA_BLIND_DEF) |
                GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF);
@@ -2225,7 +2298,11 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
 
        sky2_write8(hw, RB_ADDR(rxqaddr[port], RB_CTRL), RB_ENA_OP_MD);
 
-       err = sky2_rx_start(sky2);
+       err = sky2_alloc_rx_skbs(sky2);
+       if (!err)
+               sky2_rx_start(sky2);
+       else
+               sky2_rx_clean(sky2);
        sky2_write32(hw, B0_IMSK, imask);
 
        sky2_read32(hw, B0_Y2_SP_LISR);
@@ -2302,30 +2379,32 @@ static struct sk_buff *receive_new(struct sky2_port *sky2,
                                   struct rx_ring_info *re,
                                   unsigned int length)
 {
-       struct sk_buff *skb, *nskb;
+       struct sk_buff *skb;
+       struct rx_ring_info nre;
        unsigned hdr_space = sky2->rx_data_size;
 
-       /* Don't be tricky about reusing pages (yet) */
-       nskb = sky2_rx_alloc(sky2);
-       if (unlikely(!nskb))
-               return NULL;
+       nre.skb = sky2_rx_alloc(sky2);
+       if (unlikely(!nre.skb))
+               goto nobuf;
+
+       if (sky2_rx_map_skb(sky2->hw->pdev, &nre, hdr_space))
+               goto nomap;
 
        skb = re->skb;
        sky2_rx_unmap_skb(sky2->hw->pdev, re);
-
        prefetch(skb->data);
-       re->skb = nskb;
-       if (sky2_rx_map_skb(sky2->hw->pdev, re, hdr_space)) {
-               dev_kfree_skb(nskb);
-               re->skb = skb;
-               return NULL;
-       }
+       *re = nre;
 
        if (skb_shinfo(skb)->nr_frags)
                skb_put_frags(skb, hdr_space, length);
        else
                skb_put(skb, length);
        return skb;
+
+nomap:
+       dev_kfree_skb(nre.skb);
+nobuf:
+       return NULL;
 }
 
 /*
@@ -2340,15 +2419,12 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
        struct sk_buff *skb = NULL;
        u16 count = (status & GMR_FS_LEN) >> 16;
 
-#ifdef SKY2_VLAN_TAG_USED
-       /* Account for vlan tag */
-       if (sky2->vlgrp && (status & GMR_FS_VLAN))
-               count -= VLAN_HLEN;
-#endif
+       if (status & GMR_FS_VLAN)
+               count -= VLAN_HLEN;     /* Account for vlan tag */
 
-       if (unlikely(netif_msg_rx_status(sky2)))
-               printk(KERN_DEBUG PFX "%s: rx slot %u status 0x%x len %d\n",
-                      dev->name, sky2->rx_next, status, length);
+       netif_printk(sky2, rx_status, KERN_DEBUG, dev,
+                    "rx slot %u status 0x%x len %d\n",
+                    sky2->rx_next, status, length);
 
        sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending;
        prefetch(sky2->rx_ring + sky2->rx_next);
@@ -2370,44 +2446,27 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
 
        /* if length reported by DMA does not match PHY, packet was truncated */
        if (length != count)
-               goto len_error;
+               goto error;
 
 okay:
        if (length < copybreak)
                skb = receive_copy(sky2, re, length);
        else
                skb = receive_new(sky2, re, length);
+
+       dev->stats.rx_dropped += (skb == NULL);
+
 resubmit:
        sky2_rx_submit(sky2, re);
 
        return skb;
 
-len_error:
-       /* Truncation of overlength packets
-          causes PHY length to not match MAC length */
-       ++dev->stats.rx_length_errors;
-       if (netif_msg_rx_err(sky2) && net_ratelimit())
-               pr_info(PFX "%s: rx length error: status %#x length %d\n",
-                       dev->name, status, length);
-       goto resubmit;
-
 error:
        ++dev->stats.rx_errors;
-       if (status & GMR_FS_RX_FF_OV) {
-               dev->stats.rx_over_errors++;
-               goto resubmit;
-       }
 
-       if (netif_msg_rx_err(sky2) && net_ratelimit())
-               printk(KERN_INFO PFX "%s: rx error, status 0x%x length %d\n",
-                      dev->name, status, length);
-
-       if (status & (GMR_FS_LONG_ERR | GMR_FS_UN_SIZE))
-               dev->stats.rx_length_errors++;
-       if (status & GMR_FS_FRAGMENT)
-               dev->stats.rx_frame_errors++;
-       if (status & GMR_FS_CRC_ERR)
-               dev->stats.rx_crc_errors++;
+       if (net_ratelimit())
+               netif_info(sky2, rx_err, dev,
+                          "rx error, status 0x%x length %d\n", status, length);
 
        goto resubmit;
 }
@@ -2417,24 +2476,21 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
 
-       if (netif_running(dev))
+       if (netif_running(dev)) {
                sky2_tx_complete(sky2, last);
+
+               /* Wake unless it's detached, and called e.g. from sky2_down() */
+               if (tx_avail(sky2) > MAX_SKB_TX_LE + 4)
+                       netif_wake_queue(dev);
+       }
 }
 
 static inline void sky2_skb_rx(const struct sky2_port *sky2,
                               u32 status, struct sk_buff *skb)
 {
-#ifdef SKY2_VLAN_TAG_USED
-       u16 vlan_tag = be16_to_cpu(sky2->rx_tag);
-       if (sky2->vlgrp && (status & GMR_FS_VLAN)) {
-               if (skb->ip_summed == CHECKSUM_NONE)
-                       vlan_hwaccel_receive_skb(skb, sky2->vlgrp, vlan_tag);
-               else
-                       vlan_gro_receive(&sky2->hw->napi, sky2->vlgrp,
-                                        vlan_tag, skb);
-               return;
-       }
-#endif
+       if (status & GMR_FS_VLAN)
+               __vlan_hwaccel_put_tag(skb, be16_to_cpu(sky2->rx_tag));
+
        if (skb->ip_summed == CHECKSUM_NONE)
                netif_receive_skb(skb);
        else
@@ -2444,16 +2500,58 @@ static inline void sky2_skb_rx(const struct sky2_port *sky2,
 static inline void sky2_rx_done(struct sky2_hw *hw, unsigned port,
                                unsigned packets, unsigned bytes)
 {
-       if (packets) {
-               struct net_device *dev = hw->dev[port];
+       struct net_device *dev = hw->dev[port];
+       struct sky2_port *sky2 = netdev_priv(dev);
+
+       if (packets == 0)
+               return;
+
+       u64_stats_update_begin(&sky2->rx_stats.syncp);
+       sky2->rx_stats.packets += packets;
+       sky2->rx_stats.bytes += bytes;
+       u64_stats_update_end(&sky2->rx_stats.syncp);
+
+       dev->last_rx = jiffies;
+       sky2_rx_update(netdev_priv(dev), rxqaddr[port]);
+}
+
+static void sky2_rx_checksum(struct sky2_port *sky2, u32 status)
+{
+       /* If this happens then driver assuming wrong format for chip type */
+       BUG_ON(sky2->hw->flags & SKY2_HW_NEW_LE);
 
-               dev->stats.rx_packets += packets;
-               dev->stats.rx_bytes += bytes;
-               dev->last_rx = jiffies;
-               sky2_rx_update(netdev_priv(dev), rxqaddr[port]);
+       /* Both checksum counters are programmed to start at
+        * the same offset, so unless there is a problem they
+        * should match. This failure is an early indication that
+        * hardware receive checksumming won't work.
+        */
+       if (likely((u16)(status >> 16) == (u16)status)) {
+               struct sk_buff *skb = sky2->rx_ring[sky2->rx_next].skb;
+               skb->ip_summed = CHECKSUM_COMPLETE;
+               skb->csum = le16_to_cpu(status);
+       } else {
+               dev_notice(&sky2->hw->pdev->dev,
+                          "%s: receive checksum problem (status = %#x)\n",
+                          sky2->netdev->name, status);
+
+               /* Disable checksum offload
+                * It will be reenabled on next ndo_set_features, but if it's
+                * really broken, will get disabled again
+                */
+               sky2->netdev->features &= ~NETIF_F_RXCSUM;
+               sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
+                            BMU_DIS_RX_CHKSUM);
        }
 }
 
+static void sky2_rx_hash(struct sky2_port *sky2, u32 status)
+{
+       struct sk_buff *skb;
+
+       skb = sky2->rx_ring[sky2->rx_next].skb;
+       skb->rxhash = le32_to_cpu(status);
+}
+
 /* Process status response ring */
 static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
 {
@@ -2475,7 +2573,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
                if (!(opcode & HW_OWNER))
                        break;
 
-               hw->st_idx = RING_NEXT(hw->st_idx, STATUS_RING_SIZE);
+               hw->st_idx = RING_NEXT(hw->st_idx, hw->st_size);
 
                port = le->css & CSS_LINK_BIT;
                dev = hw->dev[port];
@@ -2488,15 +2586,14 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
                case OP_RXSTAT:
                        total_packets[port]++;
                        total_bytes[port] += length;
+
                        skb = sky2_receive(dev, length, status);
-                       if (unlikely(!skb)) {
-                               dev->stats.rx_dropped++;
+                       if (!skb)
                                break;
-                       }
 
                        /* This chip reports checksum status differently */
                        if (hw->flags & SKY2_HW_NEW_LE) {
-                               if ((sky2->flags & SKY2_FLAG_RX_CHECKSUM) &&
+                               if ((dev->features & NETIF_F_RXCSUM) &&
                                    (le->css & (CSS_ISIPV4 | CSS_ISIPV6)) &&
                                    (le->css & CSS_TCPUDPCSOK))
                                        skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -2513,7 +2610,6 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
                                goto exit_loop;
                        break;
 
-#ifdef SKY2_VLAN_TAG_USED
                case OP_RXVLAN:
                        sky2->rx_tag = length;
                        break;
@@ -2521,39 +2617,13 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
                case OP_RXCHKSVLAN:
                        sky2->rx_tag = length;
                        /* fall through */
-#endif
                case OP_RXCHKS:
-                       if (!(sky2->flags & SKY2_FLAG_RX_CHECKSUM))
-                               break;
-
-                       /* If this happens then driver assuming wrong format */
-                       if (unlikely(hw->flags & SKY2_HW_NEW_LE)) {
-                               if (net_ratelimit())
-                                       printk(KERN_NOTICE "%s: unexpected"
-                                              " checksum status\n",
-                                              dev->name);
-                               break;
-                       }
+                       if (likely(dev->features & NETIF_F_RXCSUM))
+                               sky2_rx_checksum(sky2, status);
+                       break;
 
-                       /* Both checksum counters are programmed to start at
-                        * the same offset, so unless there is a problem they
-                        * should match. This failure is an early indication that
-                        * hardware receive checksumming won't work.
-                        */
-                       if (likely(status >> 16 == (status & 0xffff))) {
-                               skb = sky2->rx_ring[sky2->rx_next].skb;
-                               skb->ip_summed = CHECKSUM_COMPLETE;
-                               skb->csum = le16_to_cpu(status);
-                       } else {
-                               printk(KERN_NOTICE PFX "%s: hardware receive "
-                                      "checksum problem (status = %#x)\n",
-                                      dev->name, status);
-                               sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM;
-
-                               sky2_write32(sky2->hw,
-                                            Q_ADDR(rxqaddr[port], Q_CSR),
-                                            BMU_DIS_RX_CHKSUM);
-                       }
+               case OP_RSS_HASH:
+                       sky2_rx_hash(sky2, status);
                        break;
 
                case OP_TXINDEXLE:
@@ -2567,8 +2637,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
 
                default:
                        if (net_ratelimit())
-                               printk(KERN_WARNING PFX
-                                      "unknown status opcode 0x%x\n", opcode);
+                               pr_warning("unknown status opcode 0x%x\n", opcode);
                }
        } while (hw->st_idx != idx);
 
@@ -2587,41 +2656,37 @@ static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status)
        struct net_device *dev = hw->dev[port];
 
        if (net_ratelimit())
-               printk(KERN_INFO PFX "%s: hw error interrupt status 0x%x\n",
-                      dev->name, status);
+               netdev_info(dev, "hw error interrupt status 0x%x\n", status);
 
        if (status & Y2_IS_PAR_RD1) {
                if (net_ratelimit())
-                       printk(KERN_ERR PFX "%s: ram data read parity error\n",
-                              dev->name);
+                       netdev_err(dev, "ram data read parity error\n");
                /* Clear IRQ */
                sky2_write16(hw, RAM_BUFFER(port, B3_RI_CTRL), RI_CLR_RD_PERR);
        }
 
        if (status & Y2_IS_PAR_WR1) {
                if (net_ratelimit())
-                       printk(KERN_ERR PFX "%s: ram data write parity error\n",
-                              dev->name);
+                       netdev_err(dev, "ram data write parity error\n");
 
                sky2_write16(hw, RAM_BUFFER(port, B3_RI_CTRL), RI_CLR_WR_PERR);
        }
 
        if (status & Y2_IS_PAR_MAC1) {
                if (net_ratelimit())
-                       printk(KERN_ERR PFX "%s: MAC parity error\n", dev->name);
+                       netdev_err(dev, "MAC parity error\n");
                sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_CLI_TX_PE);
        }
 
        if (status & Y2_IS_PAR_RX1) {
                if (net_ratelimit())
-                       printk(KERN_ERR PFX "%s: RX parity error\n", dev->name);
+                       netdev_err(dev, "RX parity error\n");
                sky2_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), BMU_CLR_IRQ_PAR);
        }
 
        if (status & Y2_IS_TCP_TXA1) {
                if (net_ratelimit())
-                       printk(KERN_ERR PFX "%s: TCP segmentation error\n",
-                              dev->name);
+                       netdev_err(dev, "TCP segmentation error\n");
                sky2_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), BMU_CLR_IRQ_TCP);
        }
 }
@@ -2640,6 +2705,7 @@ static void sky2_hw_intr(struct sky2_hw *hw)
        if (status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) {
                u16 pci_err;
 
+               sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
                pci_err = sky2_pci_read16(hw, PCI_STATUS);
                if (net_ratelimit())
                        dev_err(&pdev->dev, "PCI hardware error (0x%x)\n",
@@ -2647,12 +2713,14 @@ static void sky2_hw_intr(struct sky2_hw *hw)
 
                sky2_pci_write16(hw, PCI_STATUS,
                                      pci_err | PCI_STATUS_ERROR_BITS);
+               sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
        }
 
        if (status & Y2_IS_PCI_EXP) {
                /* PCI-Express uncorrectable Error occurred */
                u32 err;
 
+               sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
                err = sky2_read32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS);
                sky2_write32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS,
                             0xfffffffful);
@@ -2660,6 +2728,7 @@ static void sky2_hw_intr(struct sky2_hw *hw)
                        dev_err(&pdev->dev, "PCI Express error (0x%x)\n", err);
 
                sky2_read32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS);
+               sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
        }
 
        if (status & Y2_HWE_L1_MASK)
@@ -2675,9 +2744,7 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port)
        struct sky2_port *sky2 = netdev_priv(dev);
        u8 status = sky2_read8(hw, SK_REG(port, GMAC_IRQ_SRC));
 
-       if (netif_msg_intr(sky2))
-               printk(KERN_INFO PFX "%s: mac interrupt status 0x%x\n",
-                      dev->name, status);
+       netif_info(sky2, intr, dev, "mac interrupt status 0x%x\n", status);
 
        if (status & GM_IS_RX_CO_OV)
                gma_read16(hw, port, GM_RX_IRQ_SRC);
@@ -2702,8 +2769,7 @@ static void sky2_le_error(struct sky2_hw *hw, unsigned port, u16 q)
        struct net_device *dev = hw->dev[port];
        u16 idx = sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_GET_IDX));
 
-       dev_err(&hw->pdev->dev, PFX
-               "%s: descriptor error q=%#x get=%u put=%u\n",
+       dev_err(&hw->pdev->dev, "%s: descriptor error q=%#x get=%u put=%u\n",
                dev->name, (unsigned) q, (unsigned) idx,
                (unsigned) sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX)));
 
@@ -2728,9 +2794,10 @@ static int sky2_rx_hung(struct net_device *dev)
             /* Check if the PCI RX hang */
             (fifo_rp == sky2->check.fifo_rp &&
              fifo_lev != 0 && fifo_lev >= sky2->check.fifo_lev))) {
-               printk(KERN_DEBUG PFX "%s: hung mac %d:%d fifo %d (%d:%d)\n",
-                      dev->name, mac_lev, mac_rp, fifo_lev, fifo_rp,
-                      sky2_read8(hw, Q_ADDR(rxq, Q_WP)));
+               netdev_printk(KERN_DEBUG, dev,
+                             "hung mac %d:%d fifo %d (%d:%d)\n",
+                             mac_lev, mac_rp, fifo_lev,
+                             fifo_rp, sky2_read8(hw, Q_ADDR(rxq, Q_WP)));
                return 1;
        } else {
                sky2->check.last = dev->last_rx;
@@ -2761,8 +2828,7 @@ static void sky2_watchdog(unsigned long arg)
                        /* For chips with Rx FIFO, check if stuck */
                        if ((hw->flags & SKY2_HW_RAM_BUFFER) &&
                             sky2_rx_hung(dev)) {
-                               pr_info(PFX "%s: receiver hang detected\n",
-                                       dev->name);
+                               netdev_info(dev, "receiver hang detected\n");
                                schedule_work(&hw->restart_work);
                                return;
                        }
@@ -2911,9 +2977,11 @@ static int __devinit sky2_init(struct sky2_hw *hw)
        hw->chip_id = sky2_read8(hw, B2_CHIP_ID);
        hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
 
-       switch(hw->chip_id) {
+       switch (hw->chip_id) {
        case CHIP_ID_YUKON_XL:
                hw->flags = SKY2_HW_GIGABIT | SKY2_HW_NEWER_PHY;
+               if (hw->chip_rev < CHIP_REV_YU_XL_A2)
+                       hw->flags |= SKY2_HW_RSS_BROKEN;
                break;
 
        case CHIP_ID_YUKON_EC_U:
@@ -2939,10 +3007,11 @@ static int __devinit sky2_init(struct sky2_hw *hw)
                        dev_err(&hw->pdev->dev, "unsupported revision Yukon-EC rev A1\n");
                        return -EOPNOTSUPP;
                }
-               hw->flags = SKY2_HW_GIGABIT;
+               hw->flags = SKY2_HW_GIGABIT | SKY2_HW_RSS_BROKEN;
                break;
 
        case CHIP_ID_YUKON_FE:
+               hw->flags = SKY2_HW_RSS_BROKEN;
                break;
 
        case CHIP_ID_YUKON_FE_P:
@@ -2950,6 +3019,10 @@ static int __devinit sky2_init(struct sky2_hw *hw)
                        | SKY2_HW_NEW_LE
                        | SKY2_HW_AUTO_TX_SUM
                        | SKY2_HW_ADV_POWER_CTL;
+
+               /* The workaround for status conflicts VLAN tag detection. */
+               if (hw->chip_rev == CHIP_REV_YU_FE2_A0)
+                       hw->flags |= SKY2_HW_VLAN_BROKEN;
                break;
 
        case CHIP_ID_YUKON_SUPR:
@@ -3002,11 +3075,20 @@ static void sky2_reset(struct sky2_hw *hw)
        u32 hwe_mask = Y2_HWE_ALL_MASK;
 
        /* disable ASF */
-       if (hw->chip_id == CHIP_ID_YUKON_EX) {
+       if (hw->chip_id == CHIP_ID_YUKON_EX
+           || hw->chip_id == CHIP_ID_YUKON_SUPR) {
+               sky2_write32(hw, CPU_WDOG, 0);
                status = sky2_read16(hw, HCU_CCSR);
                status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE |
                            HCU_CCSR_UC_STATE_MSK);
+               /*
+                * CPU clock divider shouldn't be used because
+                * - ASF firmware may malfunction
+                * - Yukon-Supreme: Parallel FLASH doesn't support divided clocks
+                */
+               status &= ~HCU_CCSR_CPU_CLK_DIVIDE_MSK;
                sky2_write16(hw, HCU_CCSR, status);
+               sky2_write32(hw, CPU_WDOG, 0);
        } else
                sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
        sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE);
@@ -3038,6 +3120,7 @@ static void sky2_reset(struct sky2_hw *hw)
        }
 
        sky2_power_on(hw);
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
 
        for (i = 0; i < hw->ports; i++) {
                sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
@@ -3074,6 +3157,7 @@ static void sky2_reset(struct sky2_hw *hw)
                reg <<= PSM_CONFIG_REG4_TIMER_PHY_LINK_DETECT_BASE;
 
                /* reset PHY Link Detect */
+               sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
                sky2_pci_write16(hw, PSM_CONFIG_REG4,
                                 reg | PSM_CONFIG_REG4_RST_PHY_LINK_DETECT);
                sky2_pci_write16(hw, PSM_CONFIG_REG4, reg);
@@ -3087,10 +3171,11 @@ static void sky2_reset(struct sky2_hw *hw)
                /* check if PSMv2 was running before */
                reg = sky2_pci_read16(hw, PSM_CONFIG_REG3);
                if (reg & PCI_EXP_LNKCTL_ASPMC) {
-                       int cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+                       cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
                        /* restore the PCIe Link Control register */
                        sky2_pci_write16(hw, cap + PCI_EXP_LNKCTL, reg);
                }
+               sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
 
                /* re-enable PEX PM in PEX PHY debug reg. 8 (clear bit 12) */
                sky2_write32(hw, Y2_PEX_PHY_DATA, PEX_DB_ACCESS | (0x08UL << 16));
@@ -3137,7 +3222,7 @@ static void sky2_reset(struct sky2_hw *hw)
        for (i = 0; i < hw->ports; i++)
                sky2_gmac_reset(hw, i);
 
-       memset(hw->st_le, 0, STATUS_LE_BYTES);
+       memset(hw->st_le, 0, hw->st_size * sizeof(struct sky2_status_le));
        hw->st_idx = 0;
 
        sky2_write32(hw, STAT_CTRL, SC_STAT_RST_SET);
@@ -3147,7 +3232,7 @@ static void sky2_reset(struct sky2_hw *hw)
        sky2_write32(hw, STAT_LIST_ADDR_HI, (u64) hw->st_dma >> 32);
 
        /* Set the list last index */
-       sky2_write16(hw, STAT_LAST_IDX, STATUS_RING_SIZE - 1);
+       sky2_write16(hw, STAT_LAST_IDX, hw->st_size - 1);
 
        sky2_write16(hw, STAT_TX_IDX_TH, 10);
        sky2_write8(hw, STAT_FIFO_WM, 16);
@@ -3172,12 +3257,14 @@ static void sky2_reset(struct sky2_hw *hw)
 
 /* Take device down (offline).
  * Equivalent to doing dev_stop() but this does not
- * inform upper layers of the transistion.
+ * inform upper layers of the transition.
  */
 static void sky2_detach(struct net_device *dev)
 {
        if (netif_running(dev)) {
+               netif_tx_lock(dev);
                netif_device_detach(dev);       /* stop txq */
+               netif_tx_unlock(dev);
                sky2_down(dev);
        }
 }
@@ -3190,8 +3277,7 @@ static int sky2_reattach(struct net_device *dev)
        if (netif_running(dev)) {
                err = sky2_up(dev);
                if (err) {
-                       printk(KERN_INFO PFX "%s: could not restart %d\n",
-                              dev->name, err);
+                       netdev_info(dev, "could not restart %d\n", err);
                        dev_close(dev);
                } else {
                        netif_device_attach(dev);
@@ -3202,23 +3288,62 @@ static int sky2_reattach(struct net_device *dev)
        return err;
 }
 
+static void sky2_all_down(struct sky2_hw *hw)
+{
+       int i;
+
+       sky2_read32(hw, B0_IMSK);
+       sky2_write32(hw, B0_IMSK, 0);
+       synchronize_irq(hw->pdev->irq);
+       napi_disable(&hw->napi);
+
+       for (i = 0; i < hw->ports; i++) {
+               struct net_device *dev = hw->dev[i];
+               struct sky2_port *sky2 = netdev_priv(dev);
+
+               if (!netif_running(dev))
+                       continue;
+
+               netif_carrier_off(dev);
+               netif_tx_disable(dev);
+               sky2_hw_down(sky2);
+       }
+}
+
+static void sky2_all_up(struct sky2_hw *hw)
+{
+       u32 imask = Y2_IS_BASE;
+       int i;
+
+       for (i = 0; i < hw->ports; i++) {
+               struct net_device *dev = hw->dev[i];
+               struct sky2_port *sky2 = netdev_priv(dev);
+
+               if (!netif_running(dev))
+                       continue;
+
+               sky2_hw_up(sky2);
+               sky2_set_multicast(dev);
+               imask |= portirq_msk[i];
+               netif_wake_queue(dev);
+       }
+
+       sky2_write32(hw, B0_IMSK, imask);
+       sky2_read32(hw, B0_IMSK);
+
+       sky2_read32(hw, B0_Y2_SP_LISR);
+       napi_enable(&hw->napi);
+}
+
 static void sky2_restart(struct work_struct *work)
 {
        struct sky2_hw *hw = container_of(work, struct sky2_hw, restart_work);
-       int i;
 
        rtnl_lock();
-       for (i = 0; i < hw->ports; i++)
-               sky2_detach(hw->dev[i]);
 
-       napi_disable(&hw->napi);
-       sky2_write32(hw, B0_IMSK, 0);
+       sky2_all_down(hw);
        sky2_reset(hw);
-       sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
-       napi_enable(&hw->napi);
-
-       for (i = 0; i < hw->ports; i++)
-               sky2_reattach(hw->dev[i]);
+       sky2_all_up(hw);
 
        rtnl_unlock();
 }
@@ -3240,6 +3365,8 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
        struct sky2_hw *hw = sky2->hw;
+       bool enable_wakeup = false;
+       int i;
 
        if ((wol->wolopts & ~sky2_wol_supported(sky2->hw)) ||
            !device_can_wakeup(&hw->pdev->dev))
@@ -3247,16 +3374,15 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 
        sky2->wol = wol->wolopts;
 
-       if (hw->chip_id == CHIP_ID_YUKON_EC_U ||
-           hw->chip_id == CHIP_ID_YUKON_EX ||
-           hw->chip_id == CHIP_ID_YUKON_FE_P)
-               sky2_write32(hw, B0_CTST, sky2->wol
-                            ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
+       for (i = 0; i < hw->ports; i++) {
+               struct net_device *dev = hw->dev[i];
+               struct sky2_port *sky2 = netdev_priv(dev);
 
-       device_set_wakeup_enable(&hw->pdev->dev, sky2->wol);
+               if (sky2->wol)
+                       enable_wakeup = true;
+       }
+       device_set_wakeup_enable(&hw->pdev->dev, enable_wakeup);
 
-       if (!netif_running(dev))
-               sky2_wol_init(sky2);
        return 0;
 }
 
@@ -3266,18 +3392,15 @@ static u32 sky2_supported_modes(const struct sky2_hw *hw)
                u32 modes = SUPPORTED_10baseT_Half
                        | SUPPORTED_10baseT_Full
                        | SUPPORTED_100baseT_Half
-                       | SUPPORTED_100baseT_Full
-                       | SUPPORTED_Autoneg | SUPPORTED_TP;
+                       | SUPPORTED_100baseT_Full;
 
                if (hw->flags & SKY2_HW_GIGABIT)
                        modes |= SUPPORTED_1000baseT_Half
                                | SUPPORTED_1000baseT_Full;
                return modes;
        } else
-               return  SUPPORTED_1000baseT_Half
-                       | SUPPORTED_1000baseT_Full
-                       | SUPPORTED_Autoneg
-                       | SUPPORTED_FIBRE;
+               return SUPPORTED_1000baseT_Half
+                       | SUPPORTED_1000baseT_Full;
 }
 
 static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
@@ -3290,10 +3413,12 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
        ecmd->phy_address = PHY_ADDR_MARV;
        if (sky2_is_copper(hw)) {
                ecmd->port = PORT_TP;
-               ecmd->speed = sky2->speed;
+               ethtool_cmd_speed_set(ecmd, sky2->speed);
+               ecmd->supported |=  SUPPORTED_Autoneg | SUPPORTED_TP;
        } else {
-               ecmd->speed = SPEED_1000;
+               ethtool_cmd_speed_set(ecmd, SPEED_1000);
                ecmd->port = PORT_FIBRE;
+               ecmd->supported |=  SUPPORTED_Autoneg | SUPPORTED_FIBRE;
        }
 
        ecmd->advertising = sky2->advertising;
@@ -3310,14 +3435,26 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
        u32 supported = sky2_supported_modes(hw);
 
        if (ecmd->autoneg == AUTONEG_ENABLE) {
+               if (ecmd->advertising & ~supported)
+                       return -EINVAL;
+
+               if (sky2_is_copper(hw))
+                       sky2->advertising = ecmd->advertising |
+                                           ADVERTISED_TP |
+                                           ADVERTISED_Autoneg;
+               else
+                       sky2->advertising = ecmd->advertising |
+                                           ADVERTISED_FIBRE |
+                                           ADVERTISED_Autoneg;
+
                sky2->flags |= SKY2_FLAG_AUTO_SPEED;
-               ecmd->advertising = supported;
                sky2->duplex = -1;
                sky2->speed = -1;
        } else {
                u32 setting;
+               u32 speed = ethtool_cmd_speed(ecmd);
 
-               switch (ecmd->speed) {
+               switch (speed) {
                case SPEED_1000:
                        if (ecmd->duplex == DUPLEX_FULL)
                                setting = SUPPORTED_1000baseT_Full;
@@ -3350,13 +3487,11 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                if ((setting & supported) == 0)
                        return -EINVAL;
 
-               sky2->speed = ecmd->speed;
+               sky2->speed = speed;
                sky2->duplex = ecmd->duplex;
                sky2->flags &= ~SKY2_FLAG_AUTO_SPEED;
        }
 
-       sky2->advertising = ecmd->advertising;
-
        if (netif_running(dev)) {
                sky2_phy_reinit(sky2);
                sky2_set_multicast(dev);
@@ -3420,28 +3555,6 @@ static const struct sky2_stat {
        { "tx_fifo_underrun", GM_TXE_FIFO_UR },
 };
 
-static u32 sky2_get_rx_csum(struct net_device *dev)
-{
-       struct sky2_port *sky2 = netdev_priv(dev);
-
-       return !!(sky2->flags & SKY2_FLAG_RX_CHECKSUM);
-}
-
-static int sky2_set_rx_csum(struct net_device *dev, u32 data)
-{
-       struct sky2_port *sky2 = netdev_priv(dev);
-
-       if (data)
-               sky2->flags |= SKY2_FLAG_RX_CHECKSUM;
-       else
-               sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM;
-
-       sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
-                    data ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
-
-       return 0;
-}
-
 static u32 sky2_get_msglevel(struct net_device *netdev)
 {
        struct sky2_port *sky2 = netdev_priv(netdev);
@@ -3467,13 +3580,11 @@ static void sky2_phy_stats(struct sky2_port *sky2, u64 * data, unsigned count)
        unsigned port = sky2->port;
        int i;
 
-       data[0] = (u64) gma_read32(hw, port, GM_TXO_OK_HI) << 32
-           | (u64) gma_read32(hw, port, GM_TXO_OK_LO);
-       data[1] = (u64) gma_read32(hw, port, GM_RXO_OK_HI) << 32
-           | (u64) gma_read32(hw, port, GM_RXO_OK_LO);
+       data[0] = get_stats64(hw, port, GM_TXO_OK_LO);
+       data[1] = get_stats64(hw, port, GM_RXO_OK_LO);
 
        for (i = 2; i < count; i++)
-               data[i] = (u64) gma_read32(hw, port, sky2_stats[i].offset);
+               data[i] = get_stats32(hw, port, sky2_stats[i].offset);
 }
 
 static void sky2_set_msglevel(struct net_device *netdev, u32 value)
@@ -3538,7 +3649,7 @@ static int sky2_set_mac_address(struct net_device *dev, void *p)
        return 0;
 }
 
-static void inline sky2_add_filter(u8 filter[8], const u8 *addr)
+static inline void sky2_add_filter(u8 filter[8], const u8 *addr)
 {
        u32 bit;
 
@@ -3551,7 +3662,7 @@ static void sky2_set_multicast(struct net_device *dev)
        struct sky2_port *sky2 = netdev_priv(dev);
        struct sky2_hw *hw = sky2->hw;
        unsigned port = sky2->port;
-       struct dev_mc_list *list = dev->mc_list;
+       struct netdev_hw_addr *ha;
        u16 reg;
        u8 filter[8];
        int rx_pause;
@@ -3567,17 +3678,16 @@ static void sky2_set_multicast(struct net_device *dev)
                reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
        else if (dev->flags & IFF_ALLMULTI)
                memset(filter, 0xff, sizeof(filter));
-       else if (dev->mc_count == 0 && !rx_pause)
+       else if (netdev_mc_empty(dev) && !rx_pause)
                reg &= ~GM_RXCR_MCF_ENA;
        else {
-               int i;
                reg |= GM_RXCR_MCF_ENA;
 
                if (rx_pause)
                        sky2_add_filter(filter, pause_mc_addr);
 
-               for (i = 0; list && i < dev->mc_count; i++, list = list->next)
-                       sky2_add_filter(filter, list->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev)
+                       sky2_add_filter(filter, ha->addr);
        }
 
        gma_write16(hw, port, GM_MC_ADDR_H1,
@@ -3592,6 +3702,51 @@ static void sky2_set_multicast(struct net_device *dev)
        gma_write16(hw, port, GM_RX_CTRL, reg);
 }
 
+static struct rtnl_link_stats64 *sky2_get_stats(struct net_device *dev,
+                                               struct rtnl_link_stats64 *stats)
+{
+       struct sky2_port *sky2 = netdev_priv(dev);
+       struct sky2_hw *hw = sky2->hw;
+       unsigned port = sky2->port;
+       unsigned int start;
+       u64 _bytes, _packets;
+
+       do {
+               start = u64_stats_fetch_begin_bh(&sky2->rx_stats.syncp);
+               _bytes = sky2->rx_stats.bytes;
+               _packets = sky2->rx_stats.packets;
+       } while (u64_stats_fetch_retry_bh(&sky2->rx_stats.syncp, start));
+
+       stats->rx_packets = _packets;
+       stats->rx_bytes = _bytes;
+
+       do {
+               start = u64_stats_fetch_begin_bh(&sky2->tx_stats.syncp);
+               _bytes = sky2->tx_stats.bytes;
+               _packets = sky2->tx_stats.packets;
+       } while (u64_stats_fetch_retry_bh(&sky2->tx_stats.syncp, start));
+
+       stats->tx_packets = _packets;
+       stats->tx_bytes = _bytes;
+
+       stats->multicast = get_stats32(hw, port, GM_RXF_MC_OK)
+               + get_stats32(hw, port, GM_RXF_BC_OK);
+
+       stats->collisions = get_stats32(hw, port, GM_TXF_COL);
+
+       stats->rx_length_errors = get_stats32(hw, port, GM_RXF_LNG_ERR);
+       stats->rx_crc_errors = get_stats32(hw, port, GM_RXF_FCS_ERR);
+       stats->rx_frame_errors = get_stats32(hw, port, GM_RXF_SHT)
+               + get_stats32(hw, port, GM_RXE_FRAG);
+       stats->rx_over_errors = get_stats32(hw, port, GM_RXE_FIFO_OV);
+
+       stats->rx_dropped = dev->stats.rx_dropped;
+       stats->rx_fifo_errors = dev->stats.rx_fifo_errors;
+       stats->tx_fifo_errors = dev->stats.tx_fifo_errors;
+
+       return stats;
+}
+
 /* Can have one global because blinking is controlled by
  * ethtool and that is always under RTNL mutex
  */
@@ -3652,23 +3807,24 @@ static void sky2_led(struct sky2_port *sky2, enum led_mode mode)
 }
 
 /* blink LED's for finding board */
-static int sky2_phys_id(struct net_device *dev, u32 data)
+static int sky2_set_phys_id(struct net_device *dev,
+                           enum ethtool_phys_id_state state)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
-       unsigned int i;
-
-       if (data == 0)
-               data = UINT_MAX;
 
-       for (i = 0; i < data; i++) {
+       switch (state) {
+       case ETHTOOL_ID_ACTIVE:
+               return 1;       /* cycle on/off once per second */
+       case ETHTOOL_ID_INACTIVE:
+               sky2_led(sky2, MO_LED_NORM);
+               break;
+       case ETHTOOL_ID_ON:
                sky2_led(sky2, MO_LED_ON);
-               if (msleep_interruptible(500))
-                       break;
+               break;
+       case ETHTOOL_ID_OFF:
                sky2_led(sky2, MO_LED_OFF);
-               if (msleep_interruptible(500))
-                       break;
+               break;
        }
-       sky2_led(sky2, MO_LED_NORM);
 
        return 0;
 }
@@ -3765,7 +3921,7 @@ static int sky2_set_coalesce(struct net_device *dev,
                return -EINVAL;
        if (ecmd->rx_max_coalesced_frames > RX_MAX_PENDING)
                return -EINVAL;
-       if (ecmd->rx_max_coalesced_frames_irq >RX_MAX_PENDING)
+       if (ecmd->rx_max_coalesced_frames_irq > RX_MAX_PENDING)
                return -EINVAL;
 
        if (ecmd->tx_coalesce_usecs == 0)
@@ -3838,6 +3994,50 @@ static int sky2_get_regs_len(struct net_device *dev)
        return 0x4000;
 }
 
+static int sky2_reg_access_ok(struct sky2_hw *hw, unsigned int b)
+{
+       /* This complicated switch statement is to make sure and
+        * only access regions that are unreserved.
+        * Some blocks are only valid on dual port cards.
+        */
+       switch (b) {
+       /* second port */
+       case 5:         /* Tx Arbiter 2 */
+       case 9:         /* RX2 */
+       case 14 ... 15: /* TX2 */
+       case 17: case 19: /* Ram Buffer 2 */
+       case 22 ... 23: /* Tx Ram Buffer 2 */
+       case 25:        /* Rx MAC Fifo 1 */
+       case 27:        /* Tx MAC Fifo 2 */
+       case 31:        /* GPHY 2 */
+       case 40 ... 47: /* Pattern Ram 2 */
+       case 52: case 54: /* TCP Segmentation 2 */
+       case 112 ... 116: /* GMAC 2 */
+               return hw->ports > 1;
+
+       case 0:         /* Control */
+       case 2:         /* Mac address */
+       case 4:         /* Tx Arbiter 1 */
+       case 7:         /* PCI express reg */
+       case 8:         /* RX1 */
+       case 12 ... 13: /* TX1 */
+       case 16: case 18:/* Rx Ram Buffer 1 */
+       case 20 ... 21: /* Tx Ram Buffer 1 */
+       case 24:        /* Rx MAC Fifo 1 */
+       case 26:        /* Tx MAC Fifo 1 */
+       case 28 ... 29: /* Descriptor and status unit */
+       case 30:        /* GPHY 1*/
+       case 32 ... 39: /* Pattern Ram 1 */
+       case 48: case 50: /* TCP Segmentation 1 */
+       case 56 ... 60: /* PCI space */
+       case 80 ... 84: /* GMAC 1 */
+               return 1;
+
+       default:
+               return 0;
+       }
+}
+
 /*
  * Returns copy of control register region
  * Note: ethtool_get_regs always provides full size (16k) buffer
@@ -3852,89 +4052,19 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
        regs->version = 1;
 
        for (b = 0; b < 128; b++) {
-               /* This complicated switch statement is to make sure and
-                * only access regions that are unreserved.
-                * Some blocks are only valid on dual port cards.
-                * and block 3 has some special diagnostic registers that
-                * are poison.
-                */
-               switch (b) {
-               case 3:
-                       /* skip diagnostic ram region */
+               /* skip poisonous diagnostic ram region in block 3 */
+               if (b == 3)
                        memcpy_fromio(p + 0x10, io + 0x10, 128 - 0x10);
-                       break;
-
-               /* dual port cards only */
-               case 5:         /* Tx Arbiter 2 */
-               case 9:         /* RX2 */
-               case 14 ... 15: /* TX2 */
-               case 17: case 19: /* Ram Buffer 2 */
-               case 22 ... 23: /* Tx Ram Buffer 2 */
-               case 25:        /* Rx MAC Fifo 1 */
-               case 27:        /* Tx MAC Fifo 2 */
-               case 31:        /* GPHY 2 */
-               case 40 ... 47: /* Pattern Ram 2 */
-               case 52: case 54: /* TCP Segmentation 2 */
-               case 112 ... 116: /* GMAC 2 */
-                       if (sky2->hw->ports == 1)
-                               goto reserved;
-                       /* fall through */
-               case 0:         /* Control */
-               case 2:         /* Mac address */
-               case 4:         /* Tx Arbiter 1 */
-               case 7:         /* PCI express reg */
-               case 8:         /* RX1 */
-               case 12 ... 13: /* TX1 */
-               case 16: case 18:/* Rx Ram Buffer 1 */
-               case 20 ... 21: /* Tx Ram Buffer 1 */
-               case 24:        /* Rx MAC Fifo 1 */
-               case 26:        /* Tx MAC Fifo 1 */
-               case 28 ... 29: /* Descriptor and status unit */
-               case 30:        /* GPHY 1*/
-               case 32 ... 39: /* Pattern Ram 1 */
-               case 48: case 50: /* TCP Segmentation 1 */
-               case 56 ... 60: /* PCI space */
-               case 80 ... 84: /* GMAC 1 */
+               else if (sky2_reg_access_ok(sky2->hw, b))
                        memcpy_fromio(p, io, 128);
-                       break;
-               default:
-reserved:
+               else
                        memset(p, 0, 128);
-               }
 
                p += 128;
                io += 128;
        }
 }
 
-/* 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_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 int sky2_get_eeprom_len(struct net_device *dev)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
@@ -3952,7 +4082,7 @@ static int sky2_vpd_wait(const struct sky2_hw *hw, int cap, u16 busy)
        while ( (sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F) == busy) {
                /* Can take up to 10.6 ms for write */
                if (time_after(jiffies, start + HZ/4)) {
-                       dev_err(&hw->pdev->dev, PFX "VPD cycle timed out");
+                       dev_err(&hw->pdev->dev, "VPD cycle timed out\n");
                        return -ETIMEDOUT;
                }
                mdelay(1);
@@ -4037,6 +4167,39 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
        return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len);
 }
 
+static u32 sky2_fix_features(struct net_device *dev, u32 features)
+{
+       const struct sky2_port *sky2 = netdev_priv(dev);
+       const struct sky2_hw *hw = sky2->hw;
+
+       /* In order to do Jumbo packets on these chips, need to turn off the
+        * transmit store/forward. Therefore checksum offload won't work.
+        */
+       if (dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U)
+               features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM);
+
+       return features;
+}
+
+static int sky2_set_features(struct net_device *dev, u32 features)
+{
+       struct sky2_port *sky2 = netdev_priv(dev);
+       u32 changed = dev->features ^ features;
+
+       if (changed & NETIF_F_RXCSUM) {
+               u32 on = features & NETIF_F_RXCSUM;
+               sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
+                            on ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
+       }
+
+       if (changed & NETIF_F_RXHASH)
+               rx_set_rss(dev, features);
+
+       if (changed & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX))
+               sky2_vlan_mode(dev, features);
+
+       return 0;
+}
 
 static const struct ethtool_ops sky2_ethtool_ops = {
        .get_settings   = sky2_get_settings,
@@ -4053,11 +4216,6 @@ static const struct ethtool_ops sky2_ethtool_ops = {
        .get_eeprom_len = sky2_get_eeprom_len,
        .get_eeprom     = sky2_get_eeprom,
        .set_eeprom     = sky2_set_eeprom,
-       .set_sg         = ethtool_op_set_sg,
-       .set_tx_csum    = sky2_set_tx_csum,
-       .set_tso        = sky2_set_tso,
-       .get_rx_csum    = sky2_get_rx_csum,
-       .set_rx_csum    = sky2_set_rx_csum,
        .get_strings    = sky2_get_strings,
        .get_coalesce   = sky2_get_coalesce,
        .set_coalesce   = sky2_set_coalesce,
@@ -4065,7 +4223,7 @@ static const struct ethtool_ops sky2_ethtool_ops = {
        .set_ringparam  = sky2_set_ringparam,
        .get_pauseparam = sky2_get_pauseparam,
        .set_pauseparam = sky2_set_pauseparam,
-       .phys_id        = sky2_phys_id,
+       .set_phys_id    = sky2_set_phys_id,
        .get_sset_count = sky2_get_sset_count,
        .get_ethtool_stats = sky2_get_ethtool_stats,
 };
@@ -4178,12 +4336,13 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
        napi_disable(&hw->napi);
        last = sky2_read16(hw, STAT_PUT_IDX);
 
+       seq_printf(seq, "Status ring %u\n", hw->st_size);
        if (hw->st_idx == last)
                seq_puts(seq, "Status ring (empty)\n");
        else {
                seq_puts(seq, "Status ring\n");
-               for (idx = hw->st_idx; idx != last && idx < STATUS_RING_SIZE;
-                    idx = RING_NEXT(idx, STATUS_RING_SIZE)) {
+               for (idx = hw->st_idx; idx != last && idx < hw->st_size;
+                    idx = RING_NEXT(idx, hw->st_size)) {
                        const struct sky2_status_le *le = hw->st_le + idx;
                        seq_printf(seq, "[%d] %#x %d %#x\n",
                                   idx, le->opcode, le->length, le->status);
@@ -4207,7 +4366,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
                        seq_printf(seq, "%u:", idx);
                sop = 0;
 
-               switch(le->opcode & ~HW_OWNER) {
+               switch (le->opcode & ~HW_OWNER) {
                case OP_ADDR64:
                        seq_printf(seq, " %#x:", a);
                        break;
@@ -4276,7 +4435,7 @@ static int sky2_device_event(struct notifier_block *unused,
        if (dev->netdev_ops->ndo_open != sky2_up || !sky2_debug)
                return NOTIFY_DONE;
 
-       switch(event) {
+       switch (event) {
        case NETDEV_CHANGENAME:
                if (sky2->debugfs) {
                        sky2->debugfs = debugfs_rename(sky2_debug, sky2->debugfs,
@@ -4286,8 +4445,7 @@ static int sky2_device_event(struct notifier_block *unused,
 
        case NETDEV_GOING_DOWN:
                if (sky2->debugfs) {
-                       printk(KERN_DEBUG PFX "%s: remove debugfs\n",
-                              dev->name);
+                       netdev_printk(KERN_DEBUG, dev, "remove debugfs\n");
                        debugfs_remove(sky2->debugfs);
                        sky2->debugfs = NULL;
                }
@@ -4347,10 +4505,10 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
        .ndo_set_mac_address    = sky2_set_mac_address,
        .ndo_set_multicast_list = sky2_set_multicast,
        .ndo_change_mtu         = sky2_change_mtu,
+       .ndo_fix_features       = sky2_fix_features,
+       .ndo_set_features       = sky2_set_features,
        .ndo_tx_timeout         = sky2_tx_timeout,
-#ifdef SKY2_VLAN_TAG_USED
-       .ndo_vlan_rx_register   = sky2_vlan_rx_register,
-#endif
+       .ndo_get_stats64        = sky2_get_stats,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = sky2_netpoll,
 #endif
@@ -4364,10 +4522,10 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
        .ndo_set_mac_address    = sky2_set_mac_address,
        .ndo_set_multicast_list = sky2_set_multicast,
        .ndo_change_mtu         = sky2_change_mtu,
+       .ndo_fix_features       = sky2_fix_features,
+       .ndo_set_features       = sky2_set_features,
        .ndo_tx_timeout         = sky2_tx_timeout,
-#ifdef SKY2_VLAN_TAG_USED
-       .ndo_vlan_rx_register   = sky2_vlan_rx_register,
-#endif
+       .ndo_get_stats64        = sky2_get_stats,
   },
 };
 
@@ -4398,7 +4556,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
        /* Auto speed and flow control */
        sky2->flags = SKY2_FLAG_AUTO_SPEED | SKY2_FLAG_AUTO_PAUSE;
        if (hw->chip_id != CHIP_ID_YUKON_XL)
-               sky2->flags |= SKY2_FLAG_RX_CHECKSUM;
+               dev->hw_features |= NETIF_F_RXCSUM;
 
        sky2->flow_mode = FC_BOTH;
 
@@ -4417,17 +4575,21 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
 
        sky2->port = port;
 
-       dev->features |= NETIF_F_TSO | NETIF_F_IP_CSUM | NETIF_F_SG;
+       dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO;
+
        if (highmem)
                dev->features |= NETIF_F_HIGHDMA;
 
-#ifdef SKY2_VLAN_TAG_USED
-       /* The workaround for FE+ status conflicts with VLAN tag detection. */
-       if (!(sky2->hw->chip_id == CHIP_ID_YUKON_FE_P &&
-             sky2->hw->chip_rev == CHIP_REV_YU_FE2_A0)) {
-               dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+       /* Enable receive hashing unless hardware is known broken */
+       if (!(hw->flags & SKY2_HW_RSS_BROKEN))
+               dev->hw_features |= NETIF_F_RXHASH;
+
+       if (!(hw->flags & SKY2_HW_VLAN_BROKEN)) {
+               dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+               dev->vlan_features |= SKY2_VLAN_OFFLOADS;
        }
-#endif
+
+       dev->features |= dev->hw_features;
 
        /* read the mac address */
        memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
@@ -4440,9 +4602,7 @@ static void __devinit sky2_show_addr(struct net_device *dev)
 {
        const struct sky2_port *sky2 = netdev_priv(dev);
 
-       if (netif_msg_probe(sky2))
-               printk(KERN_INFO PFX "%s: addr %pM\n",
-                      dev->name, dev->dev_addr);
+       netif_info(sky2, probe, dev, "addr %pM\n", dev->dev_addr);
 }
 
 /* Handle software interrupt used during MSI test */
@@ -4470,7 +4630,7 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
        struct pci_dev *pdev = hw->pdev;
        int err;
 
-       init_waitqueue_head (&hw->msi_wait);
+       init_waitqueue_head(&hw->msi_wait);
 
        sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW);
 
@@ -4587,7 +4747,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
         * this driver uses software swapping.
         */
        reg &= ~PCI_REV_DESC;
-       err = pci_write_config_dword(pdev,PCI_DEV_REG2, reg);
+       err = pci_write_config_dword(pdev, PCI_DEV_REG2, reg);
        if (err) {
                dev_err(&pdev->dev, "PCI write config failed\n");
                goto err_out_free_regions;
@@ -4614,15 +4774,17 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
                goto err_out_free_hw;
        }
 
-       /* ring for status responses */
-       hw->st_le = pci_alloc_consistent(pdev, STATUS_LE_BYTES, &hw->st_dma);
-       if (!hw->st_le)
-               goto err_out_iounmap;
-
        err = sky2_init(hw);
        if (err)
                goto err_out_iounmap;
 
+       /* ring for status responses */
+       hw->st_size = hw->ports * roundup_pow_of_two(3*RX_MAX_PENDING + TX_MAX_PENDING);
+       hw->st_le = pci_alloc_consistent(pdev, hw->st_size * sizeof(struct sky2_status_le),
+                                        &hw->st_dma);
+       if (!hw->st_le)
+               goto err_out_reset;
+
        dev_info(&pdev->dev, "Yukon-2 %s chip revision %d\n",
                 sky2_name(hw->chip_id, buf1, sizeof(buf1)), hw->chip_rev);
 
@@ -4685,6 +4847,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
        INIT_WORK(&hw->restart_work, sky2_restart);
 
        pci_set_drvdata(pdev, hw);
+       pdev->d3_delay = 150;
 
        return 0;
 
@@ -4695,8 +4858,10 @@ err_out_unregister:
 err_out_free_netdev:
        free_netdev(dev);
 err_out_free_pci:
+       pci_free_consistent(pdev, hw->st_size * sizeof(struct sky2_status_le),
+                           hw->st_le, hw->st_dma);
+err_out_reset:
        sky2_write8(hw, B0_CTST, CS_RST_SET);
-       pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
 err_out_iounmap:
        iounmap(hw->regs);
 err_out_free_hw:
@@ -4734,7 +4899,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
        free_irq(pdev->irq, hw);
        if (hw->flags & SKY2_HW_USE_MSI)
                pci_disable_msi(pdev);
-       pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
+       pci_free_consistent(pdev, hw->st_size * sizeof(struct sky2_status_le),
+                           hw->st_le, hw->st_dma);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
 
@@ -4747,11 +4913,11 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
        pci_set_drvdata(pdev, NULL);
 }
 
-#ifdef CONFIG_PM
-static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
+static int sky2_suspend(struct device *dev)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
        struct sky2_hw *hw = pci_get_drvdata(pdev);
-       int i, wol = 0;
+       int i;
 
        if (!hw)
                return 0;
@@ -4760,105 +4926,64 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
        cancel_work_sync(&hw->restart_work);
 
        rtnl_lock();
+
+       sky2_all_down(hw);
        for (i = 0; i < hw->ports; i++) {
                struct net_device *dev = hw->dev[i];
                struct sky2_port *sky2 = netdev_priv(dev);
 
-               sky2_detach(dev);
-
                if (sky2->wol)
                        sky2_wol_init(sky2);
-
-               wol |= sky2->wol;
        }
 
-       sky2_write32(hw, B0_IMSK, 0);
-       napi_disable(&hw->napi);
        sky2_power_aux(hw);
        rtnl_unlock();
 
-       pci_save_state(pdev);
-       pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
-
        return 0;
 }
 
-static int sky2_resume(struct pci_dev *pdev)
+#ifdef CONFIG_PM_SLEEP
+static int sky2_resume(struct device *dev)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
        struct sky2_hw *hw = pci_get_drvdata(pdev);
-       int i, err;
+       int err;
 
        if (!hw)
                return 0;
 
-       err = pci_set_power_state(pdev, PCI_D0);
-       if (err)
-               goto out;
-
-       err = pci_restore_state(pdev);
-       if (err)
-               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 ||
-           hw->chip_id == CHIP_ID_YUKON_FE_P)
-               sky2_pci_write32(hw, PCI_DEV_REG3, 0);
-
-       sky2_reset(hw);
-       sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
-       napi_enable(&hw->napi);
+       err = pci_write_config_dword(pdev, PCI_DEV_REG3, 0);
+       if (err) {
+               dev_err(&pdev->dev, "PCI write config failed\n");
+               goto out;
+       }
 
        rtnl_lock();
-       for (i = 0; i < hw->ports; i++) {
-               err = sky2_reattach(hw->dev[i]);
-               if (err)
-                       goto out;
-       }
+       sky2_reset(hw);
+       sky2_all_up(hw);
        rtnl_unlock();
 
        return 0;
 out:
-       rtnl_unlock();
 
        dev_err(&pdev->dev, "resume failed (%d)\n", err);
        pci_disable_device(pdev);
        return err;
 }
-#endif
 
-static void sky2_shutdown(struct pci_dev *pdev)
-{
-       struct sky2_hw *hw = pci_get_drvdata(pdev);
-       int i, wol = 0;
-
-       if (!hw)
-               return;
+static SIMPLE_DEV_PM_OPS(sky2_pm_ops, sky2_suspend, sky2_resume);
+#define SKY2_PM_OPS (&sky2_pm_ops)
 
-       rtnl_lock();
-       del_timer_sync(&hw->watchdog_timer);
-
-       for (i = 0; i < hw->ports; i++) {
-               struct net_device *dev = hw->dev[i];
-               struct sky2_port *sky2 = netdev_priv(dev);
-
-               if (sky2->wol) {
-                       wol = 1;
-                       sky2_wol_init(sky2);
-               }
-       }
-
-       if (wol)
-               sky2_power_aux(hw);
-       rtnl_unlock();
+#else
 
-       pci_enable_wake(pdev, PCI_D3hot, wol);
-       pci_enable_wake(pdev, PCI_D3cold, wol);
+#define SKY2_PM_OPS NULL
+#endif
 
-       pci_disable_device(pdev);
+static void sky2_shutdown(struct pci_dev *pdev)
+{
+       sky2_suspend(&pdev->dev);
+       pci_wake_from_d3(pdev, device_may_wakeup(&pdev->dev));
        pci_set_power_state(pdev, PCI_D3hot);
 }
 
@@ -4867,16 +4992,13 @@ static struct pci_driver sky2_driver = {
        .id_table = sky2_id_table,
        .probe = sky2_probe,
        .remove = __devexit_p(sky2_remove),
-#ifdef CONFIG_PM
-       .suspend = sky2_suspend,
-       .resume = sky2_resume,
-#endif
        .shutdown = sky2_shutdown,
+       .driver.pm = SKY2_PM_OPS,
 };
 
 static int __init sky2_init_module(void)
 {
-       pr_info(PFX "driver version " DRV_VERSION "\n");
+       pr_info("driver version " DRV_VERSION "\n");
 
        sky2_debug_init();
        return pci_register_driver(&sky2_driver);