prism54: convert to internal net_device_stats
[safe/jmp/linux-2.6] / drivers / net / sky2.c
index 3ebc1b4..d01c56e 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <linux/crc32.h>
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/dma-mapping.h>
@@ -51,7 +50,7 @@
 #include "sky2.h"
 
 #define DRV_NAME               "sky2"
-#define DRV_VERSION            "1.21"
+#define DRV_VERSION            "1.22"
 #define PFX                    DRV_NAME " "
 
 /*
@@ -118,6 +117,7 @@ static DEFINE_PCI_DEVICE_TABLE(sky2_id_table) = {
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4352) }, /* 88E8038 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) }, /* 88E8039 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4354) }, /* 88E8040 */
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4355) }, /* 88E8040T */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4356) }, /* 88EC033 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4357) }, /* 88E8042 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x435A) }, /* 88E8048 */
@@ -136,6 +136,7 @@ static DEFINE_PCI_DEVICE_TABLE(sky2_id_table) = {
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436C) }, /* 88E8072 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436D) }, /* 88E8055 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4370) }, /* 88E8075 */
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4380) }, /* 88E8057 */
        { 0 }
 };
 
@@ -273,86 +274,6 @@ static void sky2_power_aux(struct sky2_hw *hw)
                             PC_VAUX_ON | PC_VCC_OFF));
 }
 
-static void sky2_power_state(struct sky2_hw *hw, pci_power_t state)
-{
-       u16 power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL);
-       int pex = pci_find_capability(hw->pdev, PCI_CAP_ID_EXP);
-       u32 reg;
-
-       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-
-       switch (state) {
-       case PCI_D0:
-               break;
-
-       case PCI_D1:
-               power_control |= 1;
-               break;
-
-       case PCI_D2:
-               power_control |= 2;
-               break;
-
-       case PCI_D3hot:
-       case PCI_D3cold:
-               power_control |= 3;
-               if (hw->flags & SKY2_HW_ADV_POWER_CTL) {
-                       /* additional power saving measurements */
-                       reg = sky2_pci_read32(hw, PCI_DEV_REG4);
-
-                       /* set gating core clock for LTSSM in L1 state */
-                       reg |= P_PEX_LTSSM_STAT(P_PEX_LTSSM_L1_STAT) |
-                               /* auto clock gated scheme controlled by CLKREQ */
-                               P_ASPM_A1_MODE_SELECT |
-                               /* enable Gate Root Core Clock */
-                               P_CLK_GATE_ROOT_COR_ENA;
-
-                       if (pex && (hw->flags & SKY2_HW_CLK_POWER)) {
-                               /* enable Clock Power Management (CLKREQ) */
-                               u16 ctrl = sky2_pci_read16(hw, pex + PCI_EXP_DEVCTL);
-
-                               ctrl |= PCI_EXP_DEVCTL_AUX_PME;
-                               sky2_pci_write16(hw, pex + PCI_EXP_DEVCTL, ctrl);
-                       } else
-                               /* force CLKREQ Enable in Our4 (A1b only) */
-                               reg |= P_ASPM_FORCE_CLKREQ_ENA;
-
-                       /* set Mask Register for Release/Gate Clock */
-                       sky2_pci_write32(hw, PCI_DEV_REG5,
-                                        P_REL_PCIE_EXIT_L1_ST | P_GAT_PCIE_ENTER_L1_ST |
-                                        P_REL_PCIE_RX_EX_IDLE | P_GAT_PCIE_RX_EL_IDLE |
-                                        P_REL_GPHY_LINK_UP | P_GAT_GPHY_LINK_DOWN);
-               } else
-                       sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_CLK_HALT);
-
-               /* put CPU into reset state */
-               sky2_write8(hw,  B28_Y2_ASF_STAT_CMD, HCU_CCSR_ASF_RESET);
-               if (hw->chip_id == CHIP_ID_YUKON_SUPR && hw->chip_rev == CHIP_REV_YU_SU_A0)
-                       /* put CPU into halt state */
-                       sky2_write8(hw, B28_Y2_ASF_STAT_CMD, HCU_CCSR_ASF_HALTED);
-
-               if (pex && !(hw->flags & SKY2_HW_RAM_BUFFER)) {
-                       reg = sky2_pci_read32(hw, PCI_DEV_REG1);
-                       /* force to PCIe L1 */
-                       reg |= PCI_FORCE_PEX_L1;
-                       sky2_pci_write32(hw, PCI_DEV_REG1, reg);
-               }
-               break;
-
-       default:
-               dev_warn(&hw->pdev->dev, PFX "Invalid power state (%d) ",
-                      state);
-               return;
-       }
-
-       power_control |= PCI_PM_CTRL_PME_ENABLE;
-       /* Finally, set the new power state. */
-       sky2_pci_write32(hw, hw->pm_cap + PCI_PM_CTRL, power_control);
-
-       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
-       sky2_pci_read32(hw, B0_CTST);
-}
-
 static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
 {
        u16 reg;
@@ -647,7 +568,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
        }
 
-       if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
+       if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_UL_2) {
                /* apply fixes in PHY AFE */
                gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 255);
 
@@ -655,9 +576,11 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                gm_phy_write(hw, port, 0x18, 0xaa99);
                gm_phy_write(hw, port, 0x17, 0x2011);
 
-               /* fix for IEEE A/B Symmetry failure in 1000BASE-T */
-               gm_phy_write(hw, port, 0x18, 0xa204);
-               gm_phy_write(hw, port, 0x17, 0x2002);
+               if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
+                       /* fix for IEEE A/B Symmetry failure in 1000BASE-T */
+                       gm_phy_write(hw, port, 0x18, 0xa204);
+                       gm_phy_write(hw, port, 0x17, 0x2002);
+               }
 
                /* set page register to 0 */
                gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0);
@@ -705,6 +628,11 @@ static void sky2_phy_power_up(struct sky2_hw *hw, unsigned 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)
+               gm_phy_write(hw, port, PHY_MARV_CTRL, PHY_CT_ANE);
+       else if (hw->flags & SKY2_HW_ADV_POWER_CTL)
+               sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
 }
 
 static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port)
@@ -737,11 +665,16 @@ static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port)
 
        if (hw->chip_id != CHIP_ID_YUKON_EC) {
                if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
-                       ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+                       /* select page 2 to access MAC control register */
+                       gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 2);
 
+                       ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
                        /* enable Power Down */
                        ctrl |= PHY_M_PC_POW_D_ENA;
                        gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+                       /* set page register back to 0 */
+                       gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0);
                }
 
                /* set IEEE compatible Power Down Mode (dev. #4.99) */
@@ -1135,13 +1068,16 @@ static void sky2_rx_submit(struct sky2_port *sky2,
 }
 
 
-static void sky2_rx_map_skb(struct pci_dev *pdev, struct rx_ring_info *re,
+static int sky2_rx_map_skb(struct pci_dev *pdev, struct rx_ring_info *re,
                            unsigned size)
 {
        struct sk_buff *skb = re->skb;
        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;
+
        pci_unmap_len_set(re, data_size, size);
 
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
@@ -1150,6 +1086,7 @@ static void sky2_rx_map_skb(struct pci_dev *pdev, struct rx_ring_info *re,
                                                skb_shinfo(skb)->frags[i].page_offset,
                                                skb_shinfo(skb)->frags[i].size,
                                                PCI_DMA_FROMDEVICE);
+       return 0;
 }
 
 static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re)
@@ -1421,7 +1358,12 @@ static int sky2_rx_start(struct sky2_port *sky2)
                if (!re->skb)
                        goto nomem;
 
-               sky2_rx_map_skb(hw->pdev, re, sky2->rx_data_size);
+               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);
        }
 
@@ -1470,9 +1412,6 @@ static int sky2_up(struct net_device *dev)
 
        }
 
-       if (netif_msg_ifup(sky2))
-               printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
-
        netif_carrier_off(dev);
 
        /* must be power of 2 */
@@ -1551,6 +1490,9 @@ static int sky2_up(struct net_device *dev)
        sky2_write32(hw, B0_IMSK, imask);
 
        sky2_set_multicast(dev);
+
+       if (netif_msg_ifup(sky2))
+               printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
        return 0;
 
 err_out:
@@ -1614,7 +1556,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
        struct sky2_hw *hw = sky2->hw;
        struct sky2_tx_le *le = NULL;
        struct tx_ring_info *re;
-       unsigned i, len;
+       unsigned i, len, first_slot;
        dma_addr_t mapping;
        u16 mss;
        u8 ctrl;
@@ -1622,13 +1564,17 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
        if (unlikely(tx_avail(sky2) < tx_le_req(skb)))
                return NETDEV_TX_BUSY;
 
-       if (unlikely(netif_msg_tx_queued(sky2)))
-               printk(KERN_DEBUG "%s: tx queued, slot %u, len %d\n",
-                      dev->name, sky2->tx_prod, skb->len);
-
        len = skb_headlen(skb);
        mapping = pci_map_single(hw->pdev, skb->data, len, PCI_DMA_TODEVICE);
 
+       if (pci_dma_mapping_error(hw->pdev, mapping))
+               goto mapping_error;
+
+       first_slot = sky2->tx_prod;
+       if (unlikely(netif_msg_tx_queued(sky2)))
+               printk(KERN_DEBUG "%s: tx queued, slot %u, len %d\n",
+                      dev->name, first_slot, skb->len);
+
        /* Send high bits if needed */
        if (sizeof(dma_addr_t) > sizeof(u32)) {
                le = get_tx_le(sky2);
@@ -1715,6 +1661,9 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
                mapping = pci_map_page(hw->pdev, frag->page, frag->page_offset,
                                       frag->size, PCI_DMA_TODEVICE);
 
+               if (pci_dma_mapping_error(hw->pdev, mapping))
+                       goto mapping_unwind;
+
                if (sizeof(dma_addr_t) > sizeof(u32)) {
                        le = get_tx_le(sky2);
                        le->addr = cpu_to_le32(upper_32_bits(mapping));
@@ -1743,6 +1692,34 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
 
        dev->trans_start = jiffies;
        return NETDEV_TX_OK;
+
+mapping_unwind:
+       for (i = first_slot; i != sky2->tx_prod; i = RING_NEXT(i, TX_RING_SIZE)) {
+               le = sky2->tx_le + i;
+               re = sky2->tx_ring + i;
+
+               switch(le->opcode & ~HW_OWNER) {
+               case OP_LARGESEND:
+               case OP_PACKET:
+                       pci_unmap_single(hw->pdev,
+                                        pci_unmap_addr(re, mapaddr),
+                                        pci_unmap_len(re, maplen),
+                                        PCI_DMA_TODEVICE);
+                       break;
+               case OP_BUFFER:
+                       pci_unmap_page(hw->pdev, pci_unmap_addr(re, mapaddr),
+                                      pci_unmap_len(re, maplen),
+                                      PCI_DMA_TODEVICE);
+                       break;
+               }
+       }
+
+       sky2->tx_prod = first_slot;
+mapping_error:
+       if (net_ratelimit())
+               dev_warn(&hw->pdev->dev, "%s: tx mapping error\n", dev->name);
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
 }
 
 /*
@@ -1825,9 +1802,6 @@ static int sky2_down(struct net_device *dev)
        if (netif_msg_ifdown(sky2))
                printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
 
-       /* Stop more packets from being queued */
-       netif_stop_queue(dev);
-
        /* Disable port IRQ */
        imask = sky2_read32(hw, B0_IMSK);
        imask &= ~portirq_msk[port];
@@ -1883,8 +1857,6 @@ static int sky2_down(struct net_device *dev)
 
        sky2_phy_power_down(hw, port);
 
-       netif_carrier_off(dev);
-
        /* turn off LED's */
        sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
 
@@ -2263,7 +2235,11 @@ static struct sk_buff *receive_new(struct sky2_port *sky2,
 
        prefetch(skb->data);
        re->skb = nskb;
-       sky2_rx_map_skb(sky2->hw->pdev, re, hdr_space);
+       if (sky2_rx_map_skb(sky2->hw->pdev, re, hdr_space)) {
+               dev_kfree_skb(nskb);
+               re->skb = skb;
+               return NULL;
+       }
 
        if (skb_shinfo(skb)->nr_frags)
                skb_put_frags(skb, hdr_space, length);
@@ -2759,13 +2735,6 @@ static int sky2_poll(struct napi_struct *napi, int work_limit)
                        goto done;
        }
 
-       /* Bug/Errata workaround?
-        * Need to kick the TX irq moderation timer.
-        */
-       if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) {
-               sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP);
-               sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
-       }
        napi_complete(napi);
        sky2_read32(hw, B0_Y2_SP_LISR);
 done:
@@ -2807,6 +2776,7 @@ static u32 sky2_mhz(const struct sky2_hw *hw)
        case CHIP_ID_YUKON_EC_U:
        case CHIP_ID_YUKON_EX:
        case CHIP_ID_YUKON_SUPR:
+       case CHIP_ID_YUKON_UL_2:
                return 125;
 
        case CHIP_ID_YUKON_FE:
@@ -2855,10 +2825,6 @@ static int __devinit sky2_init(struct sky2_hw *hw)
                hw->flags = SKY2_HW_GIGABIT
                        | SKY2_HW_NEWER_PHY
                        | SKY2_HW_ADV_POWER_CTL;
-
-               /* check for Rev. A1 dev 4200 */
-               if (sky2_read16(hw, Q_ADDR(Q_XA1, Q_WM)) == 0)
-                       hw->flags |= SKY2_HW_CLK_POWER;
                break;
 
        case CHIP_ID_YUKON_EX:
@@ -2899,6 +2865,11 @@ static int __devinit sky2_init(struct sky2_hw *hw)
                        | SKY2_HW_ADV_POWER_CTL;
                break;
 
+       case CHIP_ID_YUKON_UL_2:
+               hw->flags = SKY2_HW_GIGABIT
+                       | SKY2_HW_ADV_POWER_CTL;
+               break;
+
        default:
                dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
                        hw->chip_id);
@@ -2909,12 +2880,6 @@ static int __devinit sky2_init(struct sky2_hw *hw)
        if (hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P')
                hw->flags |= SKY2_HW_FIBRE_PHY;
 
-       hw->pm_cap = pci_find_capability(hw->pdev, PCI_CAP_ID_PM);
-       if (hw->pm_cap == 0) {
-               dev_err(&hw->pdev->dev, "cannot find PowerManagement capability\n");
-               return -EIO;
-       }
-
        hw->ports = 1;
        t8 = sky2_read8(hw, B2_Y2_HW_RES);
        if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
@@ -3110,7 +3075,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;
 
-       if (wol->wolopts & ~sky2_wol_supported(sky2->hw))
+       if ((wol->wolopts & ~sky2_wol_supported(sky2->hw))
+           || !device_can_wakeup(&hw->pdev->dev))
                return -EOPNOTSUPP;
 
        sky2->wol = wol->wolopts;
@@ -3121,6 +3087,8 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
                sky2_write32(hw, B0_CTST, sky2->wol
                             ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
 
+       device_set_wakeup_enable(&hw->pdev->dev, sky2->wol);
+
        if (!netif_running(dev))
                sky2_wol_init(sky2);
        return 0;
@@ -3808,27 +3776,63 @@ static int sky2_get_eeprom_len(struct net_device *dev)
        return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8);
 }
 
-static u32 sky2_vpd_read(struct sky2_hw *hw, int cap, u16 offset)
+static int sky2_vpd_wait(const struct sky2_hw *hw, int cap, u16 busy)
 {
-       u32 val;
+       unsigned long start = jiffies;
 
-       sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset);
+       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");
+                       return -ETIMEDOUT;
+               }
+               mdelay(1);
+       }
 
-       do {
-               offset = sky2_pci_read16(hw, cap + PCI_VPD_ADDR);
-       } while (!(offset & PCI_VPD_ADDR_F));
+       return 0;
+}
+
+static int sky2_vpd_read(struct sky2_hw *hw, int cap, void *data,
+                        u16 offset, size_t length)
+{
+       int rc = 0;
+
+       while (length > 0) {
+               u32 val;
+
+               sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset);
+               rc = sky2_vpd_wait(hw, cap, 0);
+               if (rc)
+                       break;
+
+               val = sky2_pci_read32(hw, cap + PCI_VPD_DATA);
 
-       val = sky2_pci_read32(hw, cap + PCI_VPD_DATA);
-       return val;
+               memcpy(data, &val, min(sizeof(val), length));
+               offset += sizeof(u32);
+               data += sizeof(u32);
+               length -= sizeof(u32);
+       }
+
+       return rc;
 }
 
-static void sky2_vpd_write(struct sky2_hw *hw, int cap, u16 offset, u32 val)
+static int sky2_vpd_write(struct sky2_hw *hw, int cap, const void *data,
+                         u16 offset, unsigned int length)
 {
-       sky2_pci_write16(hw, cap + PCI_VPD_DATA, val);
-       sky2_pci_write32(hw, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F);
-       do {
-               offset = sky2_pci_read16(hw, cap + PCI_VPD_ADDR);
-       } while (offset & PCI_VPD_ADDR_F);
+       unsigned int i;
+       int rc = 0;
+
+       for (i = 0; i < length; i += sizeof(u32)) {
+               u32 val = *(u32 *)(data + i);
+
+               sky2_pci_write32(hw, cap + PCI_VPD_DATA, val);
+               sky2_pci_write32(hw, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F);
+
+               rc = sky2_vpd_wait(hw, cap, PCI_VPD_ADDR_F);
+               if (rc)
+                       break;
+       }
+       return rc;
 }
 
 static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
@@ -3836,24 +3840,13 @@ static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
 {
        struct sky2_port *sky2 = netdev_priv(dev);
        int cap = pci_find_capability(sky2->hw->pdev, PCI_CAP_ID_VPD);
-       int length = eeprom->len;
-       u16 offset = eeprom->offset;
 
        if (!cap)
                return -EINVAL;
 
        eeprom->magic = SKY2_EEPROM_MAGIC;
 
-       while (length > 0) {
-               u32 val = sky2_vpd_read(sky2->hw, cap, offset);
-               int n = min_t(int, length, sizeof(val));
-
-               memcpy(data, &val, n);
-               length -= n;
-               data += n;
-               offset += n;
-       }
-       return 0;
+       return sky2_vpd_read(sky2->hw, cap, data, eeprom->offset, eeprom->len);
 }
 
 static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
@@ -3861,8 +3854,6 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
 {
        struct sky2_port *sky2 = netdev_priv(dev);
        int cap = pci_find_capability(sky2->hw->pdev, PCI_CAP_ID_VPD);
-       int length = eeprom->len;
-       u16 offset = eeprom->offset;
 
        if (!cap)
                return -EINVAL;
@@ -3870,21 +3861,11 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
        if (eeprom->magic != SKY2_EEPROM_MAGIC)
                return -EINVAL;
 
-       while (length > 0) {
-               u32 val;
-               int n = min_t(int, length, sizeof(val));
-
-               if (n < sizeof(val))
-                       val = sky2_vpd_read(sky2->hw, cap, offset);
-               memcpy(&val, data, n);
-
-               sky2_vpd_write(sky2->hw, cap, offset, val);
+       /* Partial writes not supported */
+       if ((eeprom->offset & 3) || (eeprom->len & 3))
+               return -EINVAL;
 
-               length -= n;
-               data += n;
-               offset += n;
-       }
-       return 0;
+       return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len);
 }
 
 
@@ -3924,6 +3905,86 @@ static const struct ethtool_ops sky2_ethtool_ops = {
 
 static struct dentry *sky2_debug;
 
+
+/*
+ * Read and parse the first part of Vital Product Data
+ */
+#define VPD_SIZE       128
+#define VPD_MAGIC      0x82
+
+static const struct vpd_tag {
+       char tag[2];
+       char *label;
+} vpd_tags[] = {
+       { "PN", "Part Number" },
+       { "EC", "Engineering Level" },
+       { "MN", "Manufacturer" },
+       { "SN", "Serial Number" },
+       { "YA", "Asset Tag" },
+       { "VL", "First Error Log Message" },
+       { "VF", "Second Error Log Message" },
+       { "VB", "Boot Agent ROM Configuration" },
+       { "VE", "EFI UNDI Configuration" },
+};
+
+static void sky2_show_vpd(struct seq_file *seq, struct sky2_hw *hw)
+{
+       size_t vpd_size;
+       loff_t offs;
+       u8 len;
+       unsigned char *buf;
+       u16 reg2;
+
+       reg2 = sky2_pci_read16(hw, PCI_DEV_REG2);
+       vpd_size = 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8);
+
+       seq_printf(seq, "%s Product Data\n", pci_name(hw->pdev));
+       buf = kmalloc(vpd_size, GFP_KERNEL);
+       if (!buf) {
+               seq_puts(seq, "no memory!\n");
+               return;
+       }
+
+       if (pci_read_vpd(hw->pdev, 0, vpd_size, buf) < 0) {
+               seq_puts(seq, "VPD read failed\n");
+               goto out;
+       }
+
+       if (buf[0] != VPD_MAGIC) {
+               seq_printf(seq, "VPD tag mismatch: %#x\n", buf[0]);
+               goto out;
+       }
+       len = buf[1];
+       if (len == 0 || len > vpd_size - 4) {
+               seq_printf(seq, "Invalid id length: %d\n", len);
+               goto out;
+       }
+
+       seq_printf(seq, "%.*s\n", len, buf + 3);
+       offs = len + 3;
+
+       while (offs < vpd_size - 4) {
+               int i;
+
+               if (!memcmp("RW", buf + offs, 2))       /* end marker */
+                       break;
+               len = buf[offs + 2];
+               if (offs + len + 3 >= vpd_size)
+                       break;
+
+               for (i = 0; i < ARRAY_SIZE(vpd_tags); i++) {
+                       if (!memcmp(vpd_tags[i].tag, buf + offs, 2)) {
+                               seq_printf(seq, " %s: %.*s\n",
+                                          vpd_tags[i].label, len, buf + offs + 3);
+                               break;
+                       }
+               }
+               offs += len + 3;
+       }
+out:
+       kfree(buf);
+}
+
 static int sky2_debug_show(struct seq_file *seq, void *v)
 {
        struct net_device *dev = seq->private;
@@ -3933,14 +3994,18 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
        unsigned idx, last;
        int sop;
 
-       if (!netif_running(dev))
-               return -ENETDOWN;
+       sky2_show_vpd(seq, hw);
 
-       seq_printf(seq, "IRQ src=%x mask=%x control=%x\n",
+       seq_printf(seq, "\nIRQ src=%x mask=%x control=%x\n",
                   sky2_read32(hw, B0_ISRC),
                   sky2_read32(hw, B0_IMSK),
                   sky2_read32(hw, B0_Y2_SP_ICR));
 
+       if (!netif_running(dev)) {
+               seq_printf(seq, "network not running\n");
+               return 0;
+       }
+
        napi_disable(&hw->napi);
        last = sky2_read16(hw, STAT_PUT_IDX);
 
@@ -4039,7 +4104,7 @@ static int sky2_device_event(struct notifier_block *unused,
        struct net_device *dev = ptr;
        struct sky2_port *sky2 = netdev_priv(dev);
 
-       if (dev->open != sky2_up || !sky2_debug)
+       if (dev->netdev_ops->ndo_open != sky2_up || !sky2_debug)
                return NOTIFY_DONE;
 
        switch(event) {
@@ -4101,6 +4166,41 @@ static __exit void sky2_debug_cleanup(void)
 #define sky2_debug_cleanup()
 #endif
 
+/* Two copies of network device operations to handle special case of
+   not allowing netpoll on second port */
+static const struct net_device_ops sky2_netdev_ops[2] = {
+  {
+       .ndo_open               = sky2_up,
+       .ndo_stop               = sky2_down,
+       .ndo_start_xmit         = sky2_xmit_frame,
+       .ndo_do_ioctl           = sky2_ioctl,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = sky2_set_mac_address,
+       .ndo_set_multicast_list = sky2_set_multicast,
+       .ndo_change_mtu         = sky2_change_mtu,
+       .ndo_tx_timeout         = sky2_tx_timeout,
+#ifdef SKY2_VLAN_TAG_USED
+       .ndo_vlan_rx_register   = sky2_vlan_rx_register,
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = sky2_netpoll,
+#endif
+  },
+  {
+       .ndo_open               = sky2_up,
+       .ndo_stop               = sky2_down,
+       .ndo_start_xmit         = sky2_xmit_frame,
+       .ndo_do_ioctl           = sky2_ioctl,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = sky2_set_mac_address,
+       .ndo_set_multicast_list = sky2_set_multicast,
+       .ndo_change_mtu         = sky2_change_mtu,
+       .ndo_tx_timeout         = sky2_tx_timeout,
+#ifdef SKY2_VLAN_TAG_USED
+       .ndo_vlan_rx_register   = sky2_vlan_rx_register,
+#endif
+  },
+};
 
 /* Initialize network device */
 static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
@@ -4117,20 +4217,9 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
 
        SET_NETDEV_DEV(dev, &hw->pdev->dev);
        dev->irq = hw->pdev->irq;
-       dev->open = sky2_up;
-       dev->stop = sky2_down;
-       dev->do_ioctl = sky2_ioctl;
-       dev->hard_start_xmit = sky2_xmit_frame;
-       dev->set_multicast_list = sky2_set_multicast;
-       dev->set_mac_address = sky2_set_mac_address;
-       dev->change_mtu = sky2_change_mtu;
        SET_ETHTOOL_OPS(dev, &sky2_ethtool_ops);
-       dev->tx_timeout = sky2_tx_timeout;
        dev->watchdog_timeo = TX_WATCHDOG;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       if (port == 0)
-               dev->poll_controller = sky2_netpoll;
-#endif
+       dev->netdev_ops = &sky2_netdev_ops[port];
 
        sky2 = netdev_priv(dev);
        sky2->netdev = dev;
@@ -4164,7 +4253,6 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
        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;
-               dev->vlan_rx_register = sky2_vlan_rx_register;
        }
 #endif
 
@@ -4178,11 +4266,10 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
 static void __devinit sky2_show_addr(struct net_device *dev)
 {
        const struct sky2_port *sky2 = netdev_priv(dev);
-       DECLARE_MAC_BUF(mac);
 
        if (netif_msg_probe(sky2))
-               printk(KERN_INFO PFX "%s: addr %s\n",
-                      dev->name, print_mac(mac, dev->dev_addr));
+               printk(KERN_INFO PFX "%s: addr %pM\n",
+                      dev->name, dev->dev_addr);
 }
 
 /* Handle software interrupt used during MSI test */
@@ -4242,18 +4329,6 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
        return err;
 }
 
-static int __devinit pci_wake_enabled(struct pci_dev *dev)
-{
-       int pm  = pci_find_capability(dev, PCI_CAP_ID_PM);
-       u16 value;
-
-       if (!pm)
-               return 0;
-       if (pci_read_config_word(dev, pm + PCI_PM_CTRL, &value))
-               return 0;
-       return value & PCI_PM_CTRL_PME_ENABLE;
-}
-
 /* This driver supports yukon2 chipset only */
 static const char *sky2_name(u8 chipid, char *buf, int sz)
 {
@@ -4265,9 +4340,10 @@ static const char *sky2_name(u8 chipid, char *buf, int sz)
                "FE",           /* 0xb7 */
                "FE+",          /* 0xb8 */
                "Supreme",      /* 0xb9 */
+               "UL 2",         /* 0xba */
        };
 
-       if (chipid >= CHIP_ID_YUKON_XL && chipid < CHIP_ID_YUKON_SUPR)
+       if (chipid >= CHIP_ID_YUKON_XL && chipid < CHIP_ID_YUKON_UL_2)
                strncpy(buf, name[chipid - CHIP_ID_YUKON_XL], sz);
        else
                snprintf(buf, sz, "(chip %#x)", chipid);
@@ -4280,6 +4356,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
        struct net_device *dev;
        struct sky2_hw *hw;
        int err, using_dac = 0, wol_default;
+       u32 reg;
        char buf1[16];
 
        err = pci_enable_device(pdev);
@@ -4313,7 +4390,35 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
                }
        }
 
-       wol_default = pci_wake_enabled(pdev) ? WAKE_MAGIC : 0;
+       /* Get configuration information
+        * Note: only regular PCI config access once to test for HW issues
+        *       other PCI access through shared memory for speed and to
+        *       avoid MMCONFIG problems.
+        */
+       err = pci_read_config_dword(pdev, PCI_DEV_REG2, &reg);
+       if (err) {
+               dev_err(&pdev->dev, "PCI read config failed\n");
+               goto err_out_free_regions;
+       }
+
+       /* size of available VPD, only impact sysfs */
+       err = pci_vpd_truncate(pdev, 1ul << (((reg & PCI_VPD_ROM_SZ) >> 14) + 8));
+       if (err)
+               dev_warn(&pdev->dev, "Can't set VPD size\n");
+
+#ifdef __BIG_ENDIAN
+       /* The sk98lin vendor driver uses hardware byte swapping but
+        * this driver uses software swapping.
+        */
+       reg &= ~PCI_REV_DESC;
+       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;
+       }
+#endif
+
+       wol_default = device_may_wakeup(&pdev->dev) ? WAKE_MAGIC : 0;
 
        err = -ENOMEM;
        hw = kzalloc(sizeof(*hw), GFP_KERNEL);
@@ -4330,18 +4435,6 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
                goto err_out_free_hw;
        }
 
-#ifdef __BIG_ENDIAN
-       /* The sk98lin vendor driver uses hardware byte swapping but
-        * this driver uses software swapping.
-        */
-       {
-               u32 reg;
-               reg = sky2_pci_read32(hw, PCI_DEV_REG2);
-               reg &= ~PCI_REV_DESC;
-               sky2_pci_write32(hw, PCI_DEV_REG2, reg);
-       }
-#endif
-
        /* ring for status responses */
        hw->st_le = pci_alloc_consistent(pdev, STATUS_LE_BYTES, &hw->st_dma);
        if (!hw->st_le)
@@ -4351,10 +4444,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
        if (err)
                goto err_out_iounmap;
 
-       dev_info(&pdev->dev, "v%s addr 0x%llx irq %d Yukon-2 %s rev %d\n",
-                DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0),
-                pdev->irq, sky2_name(hw->chip_id, buf1, sizeof(buf1)),
-                hw->chip_rev);
+       dev_info(&pdev->dev, "Yukon-2 %s chip revision %d\n",
+                sky2_name(hw->chip_id, buf1, sizeof(buf1)), hw->chip_rev);
 
        sky2_reset(hw);
 
@@ -4506,7 +4597,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
 
        pci_save_state(pdev);
        pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
-       sky2_power_state(hw, pci_choose_state(pdev, state));
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
 
        return 0;
 }
@@ -4519,7 +4610,9 @@ static int sky2_resume(struct pci_dev *pdev)
        if (!hw)
                return 0;
 
-       sky2_power_state(hw, PCI_D0);
+       err = pci_set_power_state(pdev, PCI_D0);
+       if (err)
+               goto out;
 
        err = pci_restore_state(pdev);
        if (err)
@@ -4589,7 +4682,7 @@ static void sky2_shutdown(struct pci_dev *pdev)
        pci_enable_wake(pdev, PCI_D3cold, wol);
 
        pci_disable_device(pdev);
-       sky2_power_state(hw, PCI_D3hot);
+       pci_set_power_state(pdev, PCI_D3hot);
 }
 
 static struct pci_driver sky2_driver = {
@@ -4606,6 +4699,8 @@ static struct pci_driver sky2_driver = {
 
 static int __init sky2_init_module(void)
 {
+       pr_info(PFX "driver version " DRV_VERSION "\n");
+
        sky2_debug_init();
        return pci_register_driver(&sky2_driver);
 }