Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorDavid S. Miller <davem@davemloft.net>
Fri, 9 Mar 2012 22:34:20 +0000 (14:34 -0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 9 Mar 2012 22:34:20 +0000 (14:34 -0800)
14 files changed:
1  2 
MAINTAINERS
drivers/net/caif/caif_hsi.c
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
drivers/net/ethernet/ibm/ehea/ehea_main.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/usb/usbnet.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
net/ipv4/route.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_netlink.c

diff --combined MAINTAINERS
@@@ -962,7 -962,7 +962,7 @@@ F: drivers/tty/serial/msm_serial.
  F:    drivers/platform/msm/
  F:    drivers/*/pm8???-*
  F:    include/linux/mfd/pm8xxx/
- T:    git git://codeaurora.org/quic/kernel/davidb/linux-msm.git
+ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/davidb/linux-msm.git
  S:    Maintained
  
  ARM/TOSA MACHINE SUPPORT
@@@ -1405,7 -1405,7 +1405,7 @@@ F:      net/ax25
  B43 WIRELESS DRIVER
  M:    Stefano Brivio <stefano.brivio@polimi.it>
  L:    linux-wireless@vger.kernel.org
 -L:    b43-dev@lists.infradead.org (moderated for non-subscribers)
 +L:    b43-dev@lists.infradead.org
  W:    http://linuxwireless.org/en/users/Drivers/b43
  S:    Maintained
  F:    drivers/net/wireless/b43/
@@@ -1414,7 -1414,6 +1414,7 @@@ B43LEGACY WIRELESS DRIVE
  M:    Larry Finger <Larry.Finger@lwfinger.net>
  M:    Stefano Brivio <stefano.brivio@polimi.it>
  L:    linux-wireless@vger.kernel.org
 +L:    b43-dev@lists.infradead.org
  W:    http://linuxwireless.org/en/users/Drivers/b43
  S:    Maintained
  F:    drivers/net/wireless/b43legacy/
@@@ -1568,6 -1567,7 +1568,6 @@@ F:      drivers/net/ethernet/broadcom/tg3.
  
  BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER
  M:    Brett Rudley <brudley@broadcom.com>
 -M:    Henry Ptasinski <henryp@broadcom.com>
  M:    Roland Vossen <rvossen@broadcom.com>
  M:    Arend van Spriel <arend@broadcom.com>
  M:    Franky (Zhenhui) Lin <frankyl@broadcom.com>
@@@ -1797,8 -1797,7 +1797,8 @@@ F:      Documentation/zh_CN
  CISCO VIC ETHERNET NIC DRIVER
  M:    Christian Benvenuti <benve@cisco.com>
  M:    Roopa Prabhu <roprabhu@cisco.com>
 -M:    David Wang <dwang2@cisco.com>
 +M:    Neel Patel <neepatel@cisco.com>
 +M:    Nishank Trivedi <nistrive@cisco.com>
  S:    Supported
  F:    drivers/net/ethernet/cisco/enic/
  
@@@ -4911,6 -4910,8 +4911,6 @@@ F:      fs/ocfs2
  
  ORINOCO DRIVER
  L:    linux-wireless@vger.kernel.org
 -L:    orinoco-users@lists.sourceforge.net
 -L:    orinoco-devel@lists.sourceforge.net
  W:    http://linuxwireless.org/en/users/Drivers/orinoco
  W:    http://www.nongnu.org/orinoco/
  S:    Orphan
@@@ -7457,12 -7458,6 +7457,12 @@@ S:    Supporte
  F:    Documentation/filesystems/xfs.txt
  F:    fs/xfs/
  
 +XILINX AXI ETHERNET DRIVER
 +M:    Ariane Keller <ariane.keller@tik.ee.ethz.ch>
 +M:    Daniel Borkmann <daniel.borkmann@tik.ee.ethz.ch>
 +S:    Maintained
 +F:    drivers/net/ethernet/xilinx/xilinx_axienet*
 +
  XILINX SYSTEMACE DRIVER
  M:    Grant Likely <grant.likely@secretlab.ca>
  W:    http://www.secretlab.ca/
@@@ -426,35 -426,6 +426,35 @@@ static int cfhsi_rx_desc(struct cfhsi_d
        return xfer_sz;
  }
  
 +static int cfhsi_rx_desc_len(struct cfhsi_desc *desc)
 +{
 +      int xfer_sz = 0;
 +      int nfrms = 0;
 +      u16 *plen;
 +
 +      if ((desc->header & ~CFHSI_PIGGY_DESC) ||
 +                      (desc->offset > CFHSI_MAX_EMB_FRM_SZ)) {
 +
 +              pr_err("Invalid descriptor. %x %x\n", desc->header,
 +                              desc->offset);
 +              return -EPROTO;
 +      }
 +
 +      /* Calculate transfer length. */
 +      plen = desc->cffrm_len;
 +      while (nfrms < CFHSI_MAX_PKTS && *plen) {
 +              xfer_sz += *plen;
 +              plen++;
 +              nfrms++;
 +      }
 +
 +      if (xfer_sz % 4) {
 +              pr_err("Invalid payload len: %d, ignored.\n", xfer_sz);
 +              return -EPROTO;
 +      }
 +      return xfer_sz;
 +}
 +
  static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
  {
        int rx_sz = 0;
  static void cfhsi_rx_done(struct cfhsi *cfhsi)
  {
        int res;
 -      int desc_pld_len = 0;
 +      int desc_pld_len = 0, rx_len, rx_state;
        struct cfhsi_desc *desc = NULL;
 +      u8 *rx_ptr, *rx_buf;
 +      struct cfhsi_desc *piggy_desc = NULL;
  
        desc = (struct cfhsi_desc *)cfhsi->rx_buf;
  
        spin_unlock_bh(&cfhsi->lock);
  
        if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) {
 -              desc_pld_len = cfhsi_rx_desc(desc, cfhsi);
 -              if (desc_pld_len == -ENOMEM)
 -                      goto restart;
 -              if (desc_pld_len == -EPROTO)
 +              desc_pld_len = cfhsi_rx_desc_len(desc);
 +
 +              if (desc_pld_len < 0)
                        goto out_of_sync;
 +
 +              rx_buf = cfhsi->rx_buf;
 +              rx_len = desc_pld_len;
 +              if (desc_pld_len > 0 && (desc->header & CFHSI_PIGGY_DESC))
 +                      rx_len += CFHSI_DESC_SZ;
 +              if (desc_pld_len == 0)
 +                      rx_buf = cfhsi->rx_flip_buf;
        } else {
 -              int pld_len;
 +              rx_buf = cfhsi->rx_flip_buf;
  
 -              if (!cfhsi->rx_state.piggy_desc) {
 -                      pld_len = cfhsi_rx_pld(desc, cfhsi);
 -                      if (pld_len == -ENOMEM)
 -                              goto restart;
 -                      if (pld_len == -EPROTO)
 -                              goto out_of_sync;
 -                      cfhsi->rx_state.pld_len = pld_len;
 -              } else {
 -                      pld_len = cfhsi->rx_state.pld_len;
 -              }
 +              rx_len = CFHSI_DESC_SZ;
 +              if (cfhsi->rx_state.pld_len > 0 &&
 +                              (desc->header & CFHSI_PIGGY_DESC)) {
  
 -              if ((pld_len > 0) && (desc->header & CFHSI_PIGGY_DESC)) {
 -                      struct cfhsi_desc *piggy_desc;
                        piggy_desc = (struct cfhsi_desc *)
                                (desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ +
 -                                              pld_len);
 +                                              cfhsi->rx_state.pld_len);
 +
                        cfhsi->rx_state.piggy_desc = true;
  
 -                      /* Extract piggy-backed descriptor. */
 -                      desc_pld_len = cfhsi_rx_desc(piggy_desc, cfhsi);
 -                      if (desc_pld_len == -ENOMEM)
 -                              goto restart;
 +                      /* Extract payload len from piggy-backed descriptor. */
 +                      desc_pld_len = cfhsi_rx_desc_len(piggy_desc);
 +                      if (desc_pld_len < 0)
 +                              goto out_of_sync;
 +
 +                      if (desc_pld_len > 0)
 +                              rx_len = desc_pld_len;
 +
 +                      if (desc_pld_len > 0 &&
 +                                      (piggy_desc->header & CFHSI_PIGGY_DESC))
 +                              rx_len += CFHSI_DESC_SZ;
  
                        /*
                         * Copy needed information from the piggy-backed
                         * descriptor to the descriptor in the start.
                         */
 -                      memcpy((u8 *)desc, (u8 *)piggy_desc,
 +                      memcpy(rx_buf, (u8 *)piggy_desc,
                                        CFHSI_DESC_SHORT_SZ);
 -
 +                      /* Mark no embedded frame here */
 +                      piggy_desc->offset = 0;
                        if (desc_pld_len == -EPROTO)
                                goto out_of_sync;
                }
        }
  
 -      memset(&cfhsi->rx_state, 0, sizeof(cfhsi->rx_state));
        if (desc_pld_len) {
 -              cfhsi->rx_state.state = CFHSI_RX_STATE_PAYLOAD;
 -              cfhsi->rx_ptr = cfhsi->rx_buf + CFHSI_DESC_SZ;
 -              cfhsi->rx_len = desc_pld_len;
 +              rx_state = CFHSI_RX_STATE_PAYLOAD;
 +              rx_ptr = rx_buf + CFHSI_DESC_SZ;
        } else {
 -              cfhsi->rx_state.state = CFHSI_RX_STATE_DESC;
 -              cfhsi->rx_ptr = cfhsi->rx_buf;
 -              cfhsi->rx_len = CFHSI_DESC_SZ;
 +              rx_state = CFHSI_RX_STATE_DESC;
 +              rx_ptr = rx_buf;
 +              rx_len = CFHSI_DESC_SZ;
        }
  
 +      /* Initiate next read */
        if (test_bit(CFHSI_AWAKE, &cfhsi->bits)) {
                /* Set up new transfer. */
                dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n",
 -                      __func__);
 -              res = cfhsi->dev->cfhsi_rx(cfhsi->rx_ptr, cfhsi->rx_len,
 +                              __func__);
 +
 +              res = cfhsi->dev->cfhsi_rx(rx_ptr, rx_len,
                                cfhsi->dev);
                if (WARN_ON(res < 0)) {
                        dev_err(&cfhsi->ndev->dev, "%s: RX error %d.\n",
                        cfhsi->ndev->stats.rx_dropped++;
                }
        }
 -      return;
  
 -restart:
 -      if (++cfhsi->rx_state.retries > CFHSI_MAX_RX_RETRIES) {
 -              dev_err(&cfhsi->ndev->dev, "%s: No memory available "
 -                      "in %d iterations.\n",
 -                      __func__, CFHSI_MAX_RX_RETRIES);
 -              BUG();
 +      if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) {
 +              /* Extract payload from descriptor */
 +              if (cfhsi_rx_desc(desc, cfhsi) < 0)
 +                      goto out_of_sync;
 +      } else {
 +              /* Extract payload */
 +              if (cfhsi_rx_pld(desc, cfhsi) < 0)
 +                      goto out_of_sync;
 +              if (piggy_desc) {
 +                      /* Extract any payload in piggyback descriptor. */
 +                      if (cfhsi_rx_desc(piggy_desc, cfhsi) < 0)
 +                              goto out_of_sync;
 +              }
        }
 -      mod_timer(&cfhsi->rx_slowpath_timer, jiffies + 1);
 +
 +      /* Update state info */
 +      memset(&cfhsi->rx_state, 0, sizeof(cfhsi->rx_state));
 +      cfhsi->rx_state.state = rx_state;
 +      cfhsi->rx_ptr = rx_ptr;
 +      cfhsi->rx_len = rx_len;
 +      cfhsi->rx_state.pld_len = desc_pld_len;
 +      cfhsi->rx_state.piggy_desc = desc->header & CFHSI_PIGGY_DESC;
 +
 +      if (rx_buf != cfhsi->rx_buf)
 +              swap(cfhsi->rx_buf, cfhsi->rx_flip_buf);
        return;
  
  out_of_sync:
@@@ -1031,7 -978,7 +1031,7 @@@ static void cfhsi_setup(struct net_devi
        dev->netdev_ops = &cfhsi_ops;
        dev->type = ARPHRD_CAIF;
        dev->flags = IFF_POINTOPOINT | IFF_NOARP;
-       dev->mtu = CFHSI_MAX_PAYLOAD_SZ;
+       dev->mtu = CFHSI_MAX_CAIF_FRAME_SZ;
        dev->tx_queue_len = 0;
        dev->destructor = free_netdev;
        skb_queue_head_init(&cfhsi->qhead);
@@@ -1093,12 -1040,6 +1093,12 @@@ int cfhsi_probe(struct platform_device 
                goto err_alloc_rx;
        }
  
 +      cfhsi->rx_flip_buf = kzalloc(CFHSI_BUF_SZ_RX, GFP_KERNEL);
 +      if (!cfhsi->rx_flip_buf) {
 +              res = -ENODEV;
 +              goto err_alloc_rx_flip;
 +      }
 +
        /* Pre-calculate inactivity timeout. */
        if (inactivity_timeout != -1) {
                cfhsi->inactivity_timeout =
   err_activate:
        destroy_workqueue(cfhsi->wq);
   err_create_wq:
 +      kfree(cfhsi->rx_flip_buf);
 + err_alloc_rx_flip:
        kfree(cfhsi->rx_buf);
   err_alloc_rx:
        kfree(cfhsi->tx_buf);
@@@ -468,7 -468,6 +468,7 @@@ static int atl1c_set_mac_addr(struct ne
  
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
        memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
 +      netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
  
        atl1c_hw_set_mac_addr(&adapter->hw);
  
@@@ -1711,7 -1710,7 +1711,7 @@@ static irqreturn_t atl1c_intr(int irq, 
                                        "atl1c hardware error (status = 0x%x)\n",
                                        status & ISR_ERROR);
                        /* reset MAC */
-                       adapter->work_event |= ATL1C_WORK_EVENT_RESET;
+                       set_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event);
                        schedule_work(&adapter->common_task);
                        return IRQ_HANDLED;
                }
@@@ -1766,7 -1765,7 +1766,7 @@@ static int atl1c_alloc_rx_buffer(struc
        while (next_info->flags & ATL1C_BUFFER_FREE) {
                rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use);
  
 -              skb = dev_alloc_skb(adapter->rx_buffer_len);
 +              skb = netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len);
                if (unlikely(!skb)) {
                        if (netif_msg_rx_err(adapter))
                                dev_warn(&pdev->dev, "alloc rx buffer failed\n");
@@@ -2686,6 -2685,7 +2686,6 @@@ static int __devinit atl1c_probe(struc
        netdev = alloc_etherdev(sizeof(struct atl1c_adapter));
        if (netdev == NULL) {
                err = -ENOMEM;
 -              dev_err(&pdev->dev, "etherdev alloc failed\n");
                goto err_alloc_etherdev;
        }
  
                err = -EIO;
                goto err_reset;
        }
 -      if (atl1c_read_mac_addr(&adapter->hw) != 0) {
 -              err = -EIO;
 -              dev_err(&pdev->dev, "get mac address failed\n");
 -              goto err_eeprom;
 +      if (atl1c_read_mac_addr(&adapter->hw)) {
 +              /* got a random MAC address, set NET_ADDR_RANDOM to netdev */
 +              netdev->addr_assign_type |= NET_ADDR_RANDOM;
        }
        memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
        memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
  err_reset:
  err_register:
  err_sw_init:
 -err_eeprom:
        iounmap(adapter->hw.hw_addr);
  err_init_netdev:
  err_ioremap:
@@@ -4,7 -4,7 +4,7 @@@
   * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
   * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
   * Copyright (C) 2004 Sun Microsystems Inc.
 - * Copyright (C) 2005-2011 Broadcom Corporation.
 + * Copyright (C) 2005-2012 Broadcom Corporation.
   *
   * Firmware is:
   *    Derived from proprietary unpublished source code,
@@@ -204,7 -204,6 +204,7 @@@ static inline void _tg3_flag_clear(enu
  #define TG3_RAW_IP_ALIGN 2
  
  #define TG3_FW_UPDATE_TIMEOUT_SEC     5
 +#define TG3_FW_UPDATE_FREQ_SEC                (TG3_FW_UPDATE_TIMEOUT_SEC / 2)
  
  #define FIRMWARE_TG3          "tigon/tg3.bin"
  #define FIRMWARE_TG3TSO               "tigon/tg3_tso.bin"
@@@ -1454,23 -1453,33 +1454,23 @@@ static void tg3_wait_for_event_ack(stru
  }
  
  /* tp->lock is held. */
 -static void tg3_ump_link_report(struct tg3 *tp)
 +static void tg3_phy_gather_ump_data(struct tg3 *tp, u32 *data)
  {
 -      u32 reg;
 -      u32 val;
 -
 -      if (!tg3_flag(tp, 5780_CLASS) || !tg3_flag(tp, ENABLE_ASF))
 -              return;
 -
 -      tg3_wait_for_event_ack(tp);
 -
 -      tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE);
 -
 -      tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14);
 +      u32 reg, val;
  
        val = 0;
        if (!tg3_readphy(tp, MII_BMCR, &reg))
                val = reg << 16;
        if (!tg3_readphy(tp, MII_BMSR, &reg))
                val |= (reg & 0xffff);
 -      tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val);
 +      *data++ = val;
  
        val = 0;
        if (!tg3_readphy(tp, MII_ADVERTISE, &reg))
                val = reg << 16;
        if (!tg3_readphy(tp, MII_LPA, &reg))
                val |= (reg & 0xffff);
 -      tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val);
 +      *data++ = val;
  
        val = 0;
        if (!(tp->phy_flags & TG3_PHYFLG_MII_SERDES)) {
                if (!tg3_readphy(tp, MII_STAT1000, &reg))
                        val |= (reg & 0xffff);
        }
 -      tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val);
 +      *data++ = val;
  
        if (!tg3_readphy(tp, MII_PHYADDR, &reg))
                val = reg << 16;
        else
                val = 0;
 -      tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val);
 +      *data++ = val;
 +}
 +
 +/* tp->lock is held. */
 +static void tg3_ump_link_report(struct tg3 *tp)
 +{
 +      u32 data[4];
 +
 +      if (!tg3_flag(tp, 5780_CLASS) || !tg3_flag(tp, ENABLE_ASF))
 +              return;
 +
 +      tg3_phy_gather_ump_data(tp, data);
 +
 +      tg3_wait_for_event_ack(tp);
 +
 +      tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE);
 +      tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14);
 +      tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0x0, data[0]);
 +      tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0x4, data[1]);
 +      tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0x8, data[2]);
 +      tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0xc, data[3]);
  
        tg3_generate_fw_event(tp);
  }
@@@ -1820,13 -1809,13 +1820,13 @@@ static void tg3_adjust_link(struct net_
                      (6 << TX_LENGTHS_IPG_SHIFT) |
                      (32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
  
 -      if ((phydev->link && tp->link_config.active_speed == SPEED_INVALID) ||
 -          (!phydev->link && tp->link_config.active_speed != SPEED_INVALID) ||
 +      if (phydev->link != tp->old_link ||
            phydev->speed != tp->link_config.active_speed ||
            phydev->duplex != tp->link_config.active_duplex ||
            oldflowctrl != tp->link_config.active_flowctrl)
                linkmesg = 1;
  
 +      tp->old_link = phydev->link;
        tp->link_config.active_speed = phydev->speed;
        tp->link_config.active_duplex = phydev->duplex;
  
@@@ -1895,10 -1884,10 +1895,10 @@@ static void tg3_phy_start(struct tg3 *t
  
        if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
                tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER;
 -              phydev->speed = tp->link_config.orig_speed;
 -              phydev->duplex = tp->link_config.orig_duplex;
 -              phydev->autoneg = tp->link_config.orig_autoneg;
 -              phydev->advertising = tp->link_config.orig_advertising;
 +              phydev->speed = tp->link_config.speed;
 +              phydev->duplex = tp->link_config.duplex;
 +              phydev->autoneg = tp->link_config.autoneg;
 +              phydev->advertising = tp->link_config.advertising;
        }
  
        phy_start(phydev);
@@@ -2720,6 -2709,9 +2720,6 @@@ static int tg3_5700_link_polarity(struc
        return 0;
  }
  
 -static int tg3_setup_phy(struct tg3 *, int);
 -static int tg3_halt_cpu(struct tg3 *, u32);
 -
  static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
  {
        u32 val;
@@@ -2986,430 -2978,177 +2986,430 @@@ static int tg3_nvram_read_be32(struct t
        return res;
  }
  
 -#define RX_CPU_SCRATCH_BASE   0x30000
 -#define RX_CPU_SCRATCH_SIZE   0x04000
 -#define TX_CPU_SCRATCH_BASE   0x34000
 -#define TX_CPU_SCRATCH_SIZE   0x04000
 -
 -/* tp->lock is held. */
 -static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
 +static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp,
 +                                  u32 offset, u32 len, u8 *buf)
  {
 -      int i;
 +      int i, j, rc = 0;
 +      u32 val;
  
 -      BUG_ON(offset == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
 +      for (i = 0; i < len; i += 4) {
 +              u32 addr;
 +              __be32 data;
  
 -      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
 -              u32 val = tr32(GRC_VCPU_EXT_CTRL);
 +              addr = offset + i;
  
 -              tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_HALT_CPU);
 -              return 0;
 -      }
 -      if (offset == RX_CPU_BASE) {
 -              for (i = 0; i < 10000; i++) {
 -                      tw32(offset + CPU_STATE, 0xffffffff);
 -                      tw32(offset + CPU_MODE,  CPU_MODE_HALT);
 -                      if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
 -                              break;
 -              }
 +              memcpy(&data, buf + i, 4);
  
 -              tw32(offset + CPU_STATE, 0xffffffff);
 -              tw32_f(offset + CPU_MODE,  CPU_MODE_HALT);
 -              udelay(10);
 -      } else {
 -              for (i = 0; i < 10000; i++) {
 -                      tw32(offset + CPU_STATE, 0xffffffff);
 -                      tw32(offset + CPU_MODE,  CPU_MODE_HALT);
 -                      if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
 +              /*
 +               * The SEEPROM interface expects the data to always be opposite
 +               * the native endian format.  We accomplish this by reversing
 +               * all the operations that would have been performed on the
 +               * data from a call to tg3_nvram_read_be32().
 +               */
 +              tw32(GRC_EEPROM_DATA, swab32(be32_to_cpu(data)));
 +
 +              val = tr32(GRC_EEPROM_ADDR);
 +              tw32(GRC_EEPROM_ADDR, val | EEPROM_ADDR_COMPLETE);
 +
 +              val &= ~(EEPROM_ADDR_ADDR_MASK | EEPROM_ADDR_DEVID_MASK |
 +                      EEPROM_ADDR_READ);
 +              tw32(GRC_EEPROM_ADDR, val |
 +                      (0 << EEPROM_ADDR_DEVID_SHIFT) |
 +                      (addr & EEPROM_ADDR_ADDR_MASK) |
 +                      EEPROM_ADDR_START |
 +                      EEPROM_ADDR_WRITE);
 +
 +              for (j = 0; j < 1000; j++) {
 +                      val = tr32(GRC_EEPROM_ADDR);
 +
 +                      if (val & EEPROM_ADDR_COMPLETE)
                                break;
 +                      msleep(1);
 +              }
 +              if (!(val & EEPROM_ADDR_COMPLETE)) {
 +                      rc = -EBUSY;
 +                      break;
                }
        }
  
 -      if (i >= 10000) {
 -              netdev_err(tp->dev, "%s timed out, %s CPU\n",
 -                         __func__, offset == RX_CPU_BASE ? "RX" : "TX");
 -              return -ENODEV;
 -      }
 -
 -      /* Clear firmware's nvram arbitration. */
 -      if (tg3_flag(tp, NVRAM))
 -              tw32(NVRAM_SWARB, SWARB_REQ_CLR0);
 -      return 0;
 +      return rc;
  }
  
 -struct fw_info {
 -      unsigned int fw_base;
 -      unsigned int fw_len;
 -      const __be32 *fw_data;
 -};
 -
 -/* tp->lock is held. */
 -static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
 -                               u32 cpu_scratch_base, int cpu_scratch_size,
 -                               struct fw_info *info)
 +/* offset and length are dword aligned */
 +static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
 +              u8 *buf)
  {
 -      int err, lock_err, i;
 -      void (*write_op)(struct tg3 *, u32, u32);
 +      int ret = 0;
 +      u32 pagesize = tp->nvram_pagesize;
 +      u32 pagemask = pagesize - 1;
 +      u32 nvram_cmd;
 +      u8 *tmp;
  
 -      if (cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS)) {
 -              netdev_err(tp->dev,
 -                         "%s: Trying to load TX cpu firmware which is 5705\n",
 -                         __func__);
 -              return -EINVAL;
 -      }
 +      tmp = kmalloc(pagesize, GFP_KERNEL);
 +      if (tmp == NULL)
 +              return -ENOMEM;
  
 -      if (tg3_flag(tp, 5705_PLUS))
 -              write_op = tg3_write_mem;
 -      else
 -              write_op = tg3_write_indirect_reg32;
 +      while (len) {
 +              int j;
 +              u32 phy_addr, page_off, size;
  
 -      /* It is possible that bootcode is still loading at this point.
 -       * Get the nvram lock first before halting the cpu.
 -       */
 -      lock_err = tg3_nvram_lock(tp);
 -      err = tg3_halt_cpu(tp, cpu_base);
 -      if (!lock_err)
 -              tg3_nvram_unlock(tp);
 -      if (err)
 -              goto out;
 +              phy_addr = offset & ~pagemask;
  
 -      for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
 -              write_op(tp, cpu_scratch_base + i, 0);
 -      tw32(cpu_base + CPU_STATE, 0xffffffff);
 -      tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
 -      for (i = 0; i < (info->fw_len / sizeof(u32)); i++)
 -              write_op(tp, (cpu_scratch_base +
 -                            (info->fw_base & 0xffff) +
 -                            (i * sizeof(u32))),
 -                            be32_to_cpu(info->fw_data[i]));
 +              for (j = 0; j < pagesize; j += 4) {
 +                      ret = tg3_nvram_read_be32(tp, phy_addr + j,
 +                                                (__be32 *) (tmp + j));
 +                      if (ret)
 +                              break;
 +              }
 +              if (ret)
 +                      break;
  
 -      err = 0;
 +              page_off = offset & pagemask;
 +              size = pagesize;
 +              if (len < size)
 +                      size = len;
  
 -out:
 -      return err;
 -}
 +              len -= size;
  
 -/* tp->lock is held. */
 -static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
 -{
 -      struct fw_info info;
 -      const __be32 *fw_data;
 -      int err, i;
 +              memcpy(tmp + page_off, buf, size);
  
 -      fw_data = (void *)tp->fw->data;
 +              offset = offset + (pagesize - page_off);
  
 -      /* Firmware blob starts with version numbers, followed by
 -         start address and length. We are setting complete length.
 -         length = end_address_of_bss - start_address_of_text.
 -         Remainder is the blob to be loaded contiguously
 -         from start address. */
 +              tg3_enable_nvram_access(tp);
  
 -      info.fw_base = be32_to_cpu(fw_data[1]);
 -      info.fw_len = tp->fw->size - 12;
 -      info.fw_data = &fw_data[3];
 +              /*
 +               * Before we can erase the flash page, we need
 +               * to issue a special "write enable" command.
 +               */
 +              nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE;
  
 -      err = tg3_load_firmware_cpu(tp, RX_CPU_BASE,
 -                                  RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE,
 -                                  &info);
 -      if (err)
 -              return err;
 +              if (tg3_nvram_exec_cmd(tp, nvram_cmd))
 +                      break;
  
 -      err = tg3_load_firmware_cpu(tp, TX_CPU_BASE,
 -                                  TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE,
 -                                  &info);
 -      if (err)
 -              return err;
 +              /* Erase the target page */
 +              tw32(NVRAM_ADDR, phy_addr);
  
 -      /* Now startup only the RX cpu. */
 -      tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
 -      tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
 +              nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR |
 +                      NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_ERASE;
  
 -      for (i = 0; i < 5; i++) {
 -              if (tr32(RX_CPU_BASE + CPU_PC) == info.fw_base)
 +              if (tg3_nvram_exec_cmd(tp, nvram_cmd))
                        break;
 -              tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
 -              tw32(RX_CPU_BASE + CPU_MODE,  CPU_MODE_HALT);
 -              tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
 -              udelay(1000);
 -      }
 -      if (i >= 5) {
 -              netdev_err(tp->dev, "%s fails to set RX CPU PC, is %08x "
 -                         "should be %08x\n", __func__,
 -                         tr32(RX_CPU_BASE + CPU_PC), info.fw_base);
 -              return -ENODEV;
 -      }
 -      tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
 -      tw32_f(RX_CPU_BASE + CPU_MODE,  0x00000000);
  
 -      return 0;
 -}
 +              /* Issue another write enable to start the write. */
 +              nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE;
  
 -/* tp->lock is held. */
 -static int tg3_load_tso_firmware(struct tg3 *tp)
 -{
 -      struct fw_info info;
 -      const __be32 *fw_data;
 -      unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
 -      int err, i;
 +              if (tg3_nvram_exec_cmd(tp, nvram_cmd))
 +                      break;
  
 -      if (tg3_flag(tp, HW_TSO_1) ||
 -          tg3_flag(tp, HW_TSO_2) ||
 -          tg3_flag(tp, HW_TSO_3))
 -              return 0;
 +              for (j = 0; j < pagesize; j += 4) {
 +                      __be32 data;
  
 -      fw_data = (void *)tp->fw->data;
 +                      data = *((__be32 *) (tmp + j));
 +
 +                      tw32(NVRAM_WRDATA, be32_to_cpu(data));
 +
 +                      tw32(NVRAM_ADDR, phy_addr + j);
 +
 +                      nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE |
 +                              NVRAM_CMD_WR;
 +
 +                      if (j == 0)
 +                              nvram_cmd |= NVRAM_CMD_FIRST;
 +                      else if (j == (pagesize - 4))
 +                              nvram_cmd |= NVRAM_CMD_LAST;
 +
 +                      ret = tg3_nvram_exec_cmd(tp, nvram_cmd);
 +                      if (ret)
 +                              break;
 +              }
 +              if (ret)
 +                      break;
 +      }
 +
 +      nvram_cmd = NVRAM_CMD_WRDI | NVRAM_CMD_GO | NVRAM_CMD_DONE;
 +      tg3_nvram_exec_cmd(tp, nvram_cmd);
 +
 +      kfree(tmp);
 +
 +      return ret;
 +}
 +
 +/* offset and length are dword aligned */
 +static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
 +              u8 *buf)
 +{
 +      int i, ret = 0;
 +
 +      for (i = 0; i < len; i += 4, offset += 4) {
 +              u32 page_off, phy_addr, nvram_cmd;
 +              __be32 data;
 +
 +              memcpy(&data, buf + i, 4);
 +              tw32(NVRAM_WRDATA, be32_to_cpu(data));
 +
 +              page_off = offset % tp->nvram_pagesize;
 +
 +              phy_addr = tg3_nvram_phys_addr(tp, offset);
 +
 +              nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR;
 +
 +              if (page_off == 0 || i == 0)
 +                      nvram_cmd |= NVRAM_CMD_FIRST;
 +              if (page_off == (tp->nvram_pagesize - 4))
 +                      nvram_cmd |= NVRAM_CMD_LAST;
 +
 +              if (i == (len - 4))
 +                      nvram_cmd |= NVRAM_CMD_LAST;
 +
 +              if ((nvram_cmd & NVRAM_CMD_FIRST) ||
 +                  !tg3_flag(tp, FLASH) ||
 +                  !tg3_flag(tp, 57765_PLUS))
 +                      tw32(NVRAM_ADDR, phy_addr);
 +
 +              if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
 +                  !tg3_flag(tp, 5755_PLUS) &&
 +                  (tp->nvram_jedecnum == JEDEC_ST) &&
 +                  (nvram_cmd & NVRAM_CMD_FIRST)) {
 +                      u32 cmd;
 +
 +                      cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE;
 +                      ret = tg3_nvram_exec_cmd(tp, cmd);
 +                      if (ret)
 +                              break;
 +              }
 +              if (!tg3_flag(tp, FLASH)) {
 +                      /* We always do complete word writes to eeprom. */
 +                      nvram_cmd |= (NVRAM_CMD_FIRST | NVRAM_CMD_LAST);
 +              }
 +
 +              ret = tg3_nvram_exec_cmd(tp, nvram_cmd);
 +              if (ret)
 +                      break;
 +      }
 +      return ret;
 +}
 +
 +/* offset and length are dword aligned */
 +static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
 +{
 +      int ret;
 +
 +      if (tg3_flag(tp, EEPROM_WRITE_PROT)) {
 +              tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl &
 +                     ~GRC_LCLCTRL_GPIO_OUTPUT1);
 +              udelay(40);
 +      }
 +
 +      if (!tg3_flag(tp, NVRAM)) {
 +              ret = tg3_nvram_write_block_using_eeprom(tp, offset, len, buf);
 +      } else {
 +              u32 grc_mode;
 +
 +              ret = tg3_nvram_lock(tp);
 +              if (ret)
 +                      return ret;
 +
 +              tg3_enable_nvram_access(tp);
 +              if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM))
 +                      tw32(NVRAM_WRITE1, 0x406);
 +
 +              grc_mode = tr32(GRC_MODE);
 +              tw32(GRC_MODE, grc_mode | GRC_MODE_NVRAM_WR_ENABLE);
 +
 +              if (tg3_flag(tp, NVRAM_BUFFERED) || !tg3_flag(tp, FLASH)) {
 +                      ret = tg3_nvram_write_block_buffered(tp, offset, len,
 +                              buf);
 +              } else {
 +                      ret = tg3_nvram_write_block_unbuffered(tp, offset, len,
 +                              buf);
 +              }
 +
 +              grc_mode = tr32(GRC_MODE);
 +              tw32(GRC_MODE, grc_mode & ~GRC_MODE_NVRAM_WR_ENABLE);
 +
 +              tg3_disable_nvram_access(tp);
 +              tg3_nvram_unlock(tp);
 +      }
 +
 +      if (tg3_flag(tp, EEPROM_WRITE_PROT)) {
 +              tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
 +              udelay(40);
 +      }
 +
 +      return ret;
 +}
 +
 +#define RX_CPU_SCRATCH_BASE   0x30000
 +#define RX_CPU_SCRATCH_SIZE   0x04000
 +#define TX_CPU_SCRATCH_BASE   0x34000
 +#define TX_CPU_SCRATCH_SIZE   0x04000
 +
 +/* tp->lock is held. */
 +static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
 +{
 +      int i;
 +
 +      BUG_ON(offset == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
 +
 +      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
 +              u32 val = tr32(GRC_VCPU_EXT_CTRL);
 +
 +              tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_HALT_CPU);
 +              return 0;
 +      }
 +      if (offset == RX_CPU_BASE) {
 +              for (i = 0; i < 10000; i++) {
 +                      tw32(offset + CPU_STATE, 0xffffffff);
 +                      tw32(offset + CPU_MODE,  CPU_MODE_HALT);
 +                      if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
 +                              break;
 +              }
 +
 +              tw32(offset + CPU_STATE, 0xffffffff);
 +              tw32_f(offset + CPU_MODE,  CPU_MODE_HALT);
 +              udelay(10);
 +      } else {
 +              for (i = 0; i < 10000; i++) {
 +                      tw32(offset + CPU_STATE, 0xffffffff);
 +                      tw32(offset + CPU_MODE,  CPU_MODE_HALT);
 +                      if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
 +                              break;
 +              }
 +      }
 +
 +      if (i >= 10000) {
 +              netdev_err(tp->dev, "%s timed out, %s CPU\n",
 +                         __func__, offset == RX_CPU_BASE ? "RX" : "TX");
 +              return -ENODEV;
 +      }
 +
 +      /* Clear firmware's nvram arbitration. */
 +      if (tg3_flag(tp, NVRAM))
 +              tw32(NVRAM_SWARB, SWARB_REQ_CLR0);
 +      return 0;
 +}
 +
 +struct fw_info {
 +      unsigned int fw_base;
 +      unsigned int fw_len;
 +      const __be32 *fw_data;
 +};
 +
 +/* tp->lock is held. */
 +static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
 +                               u32 cpu_scratch_base, int cpu_scratch_size,
 +                               struct fw_info *info)
 +{
 +      int err, lock_err, i;
 +      void (*write_op)(struct tg3 *, u32, u32);
 +
 +      if (cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS)) {
 +              netdev_err(tp->dev,
 +                         "%s: Trying to load TX cpu firmware which is 5705\n",
 +                         __func__);
 +              return -EINVAL;
 +      }
 +
 +      if (tg3_flag(tp, 5705_PLUS))
 +              write_op = tg3_write_mem;
 +      else
 +              write_op = tg3_write_indirect_reg32;
 +
 +      /* It is possible that bootcode is still loading at this point.
 +       * Get the nvram lock first before halting the cpu.
 +       */
 +      lock_err = tg3_nvram_lock(tp);
 +      err = tg3_halt_cpu(tp, cpu_base);
 +      if (!lock_err)
 +              tg3_nvram_unlock(tp);
 +      if (err)
 +              goto out;
 +
 +      for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
 +              write_op(tp, cpu_scratch_base + i, 0);
 +      tw32(cpu_base + CPU_STATE, 0xffffffff);
 +      tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
 +      for (i = 0; i < (info->fw_len / sizeof(u32)); i++)
 +              write_op(tp, (cpu_scratch_base +
 +                            (info->fw_base & 0xffff) +
 +                            (i * sizeof(u32))),
 +                            be32_to_cpu(info->fw_data[i]));
 +
 +      err = 0;
 +
 +out:
 +      return err;
 +}
 +
 +/* tp->lock is held. */
 +static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
 +{
 +      struct fw_info info;
 +      const __be32 *fw_data;
 +      int err, i;
 +
 +      fw_data = (void *)tp->fw->data;
 +
 +      /* Firmware blob starts with version numbers, followed by
 +         start address and length. We are setting complete length.
 +         length = end_address_of_bss - start_address_of_text.
 +         Remainder is the blob to be loaded contiguously
 +         from start address. */
 +
 +      info.fw_base = be32_to_cpu(fw_data[1]);
 +      info.fw_len = tp->fw->size - 12;
 +      info.fw_data = &fw_data[3];
 +
 +      err = tg3_load_firmware_cpu(tp, RX_CPU_BASE,
 +                                  RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE,
 +                                  &info);
 +      if (err)
 +              return err;
 +
 +      err = tg3_load_firmware_cpu(tp, TX_CPU_BASE,
 +                                  TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE,
 +                                  &info);
 +      if (err)
 +              return err;
 +
 +      /* Now startup only the RX cpu. */
 +      tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
 +      tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
 +
 +      for (i = 0; i < 5; i++) {
 +              if (tr32(RX_CPU_BASE + CPU_PC) == info.fw_base)
 +                      break;
 +              tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
 +              tw32(RX_CPU_BASE + CPU_MODE,  CPU_MODE_HALT);
 +              tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
 +              udelay(1000);
 +      }
 +      if (i >= 5) {
 +              netdev_err(tp->dev, "%s fails to set RX CPU PC, is %08x "
 +                         "should be %08x\n", __func__,
 +                         tr32(RX_CPU_BASE + CPU_PC), info.fw_base);
 +              return -ENODEV;
 +      }
 +      tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
 +      tw32_f(RX_CPU_BASE + CPU_MODE,  0x00000000);
 +
 +      return 0;
 +}
 +
 +/* tp->lock is held. */
 +static int tg3_load_tso_firmware(struct tg3 *tp)
 +{
 +      struct fw_info info;
 +      const __be32 *fw_data;
 +      unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
 +      int err, i;
 +
 +      if (tg3_flag(tp, HW_TSO_1) ||
 +          tg3_flag(tp, HW_TSO_2) ||
 +          tg3_flag(tp, HW_TSO_3))
 +              return 0;
 +
 +      fw_data = (void *)tp->fw->data;
  
        /* Firmware blob starts with version numbers, followed by
           start address and length. We are setting complete length.
@@@ -3525,8 -3264,6 +3525,8 @@@ static int tg3_power_up(struct tg3 *tp
        return err;
  }
  
 +static int tg3_setup_phy(struct tg3 *, int);
 +
  static int tg3_power_down_prepare(struct tg3 *tp)
  {
        u32 misc_host_ctrl;
  
                        tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER;
  
 -                      tp->link_config.orig_speed = phydev->speed;
 -                      tp->link_config.orig_duplex = phydev->duplex;
 -                      tp->link_config.orig_autoneg = phydev->autoneg;
 -                      tp->link_config.orig_advertising = phydev->advertising;
 +                      tp->link_config.speed = phydev->speed;
 +                      tp->link_config.duplex = phydev->duplex;
 +                      tp->link_config.autoneg = phydev->autoneg;
 +                      tp->link_config.advertising = phydev->advertising;
  
                        advertising = ADVERTISED_TP |
                                      ADVERTISED_Pause |
        } else {
                do_low_power = true;
  
 -              if (!(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
 +              if (!(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER))
                        tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER;
 -                      tp->link_config.orig_speed = tp->link_config.speed;
 -                      tp->link_config.orig_duplex = tp->link_config.duplex;
 -                      tp->link_config.orig_autoneg = tp->link_config.autoneg;
 -              }
  
 -              if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) {
 -                      tp->link_config.speed = SPEED_10;
 -                      tp->link_config.duplex = DUPLEX_HALF;
 -                      tp->link_config.autoneg = AUTONEG_ENABLE;
 +              if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
                        tg3_setup_phy(tp, 0);
 -              }
        }
  
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
@@@ -3814,8 -3559,8 +3814,8 @@@ static void tg3_aux_stat_to_speed_duple
                                  DUPLEX_HALF;
                        break;
                }
 -              *speed = SPEED_INVALID;
 -              *duplex = DUPLEX_INVALID;
 +              *speed = SPEED_UNKNOWN;
 +              *duplex = DUPLEX_UNKNOWN;
                break;
        }
  }
@@@ -3895,33 -3640,51 +3895,33 @@@ done
  
  static void tg3_phy_copper_begin(struct tg3 *tp)
  {
 -      u32 new_adv;
 -      int i;
 +      if (tp->link_config.autoneg == AUTONEG_ENABLE ||
 +          (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
 +              u32 adv, fc;
  
 -      if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
 -              new_adv = ADVERTISED_10baseT_Half |
 -                        ADVERTISED_10baseT_Full;
 -              if (tg3_flag(tp, WOL_SPEED_100MB))
 -                      new_adv |= ADVERTISED_100baseT_Half |
 -                                 ADVERTISED_100baseT_Full;
 -
 -              tg3_phy_autoneg_cfg(tp, new_adv,
 -                                  FLOW_CTRL_TX | FLOW_CTRL_RX);
 -      } else if (tp->link_config.speed == SPEED_INVALID) {
 -              if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
 -                      tp->link_config.advertising &=
 -                              ~(ADVERTISED_1000baseT_Half |
 -                                ADVERTISED_1000baseT_Full);
 +              if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
 +                      adv = ADVERTISED_10baseT_Half |
 +                            ADVERTISED_10baseT_Full;
 +                      if (tg3_flag(tp, WOL_SPEED_100MB))
 +                              adv |= ADVERTISED_100baseT_Half |
 +                                     ADVERTISED_100baseT_Full;
  
 -              tg3_phy_autoneg_cfg(tp, tp->link_config.advertising,
 -                                  tp->link_config.flowctrl);
 -      } else {
 -              /* Asking for a specific link mode. */
 -              if (tp->link_config.speed == SPEED_1000) {
 -                      if (tp->link_config.duplex == DUPLEX_FULL)
 -                              new_adv = ADVERTISED_1000baseT_Full;
 -                      else
 -                              new_adv = ADVERTISED_1000baseT_Half;
 -              } else if (tp->link_config.speed == SPEED_100) {
 -                      if (tp->link_config.duplex == DUPLEX_FULL)
 -                              new_adv = ADVERTISED_100baseT_Full;
 -                      else
 -                              new_adv = ADVERTISED_100baseT_Half;
 +                      fc = FLOW_CTRL_TX | FLOW_CTRL_RX;
                } else {
 -                      if (tp->link_config.duplex == DUPLEX_FULL)
 -                              new_adv = ADVERTISED_10baseT_Full;
 -                      else
 -                              new_adv = ADVERTISED_10baseT_Half;
 +                      adv = tp->link_config.advertising;
 +                      if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
 +                              adv &= ~(ADVERTISED_1000baseT_Half |
 +                                       ADVERTISED_1000baseT_Full);
 +
 +                      fc = tp->link_config.flowctrl;
                }
  
 -              tg3_phy_autoneg_cfg(tp, new_adv,
 -                                  tp->link_config.flowctrl);
 -      }
 +              tg3_phy_autoneg_cfg(tp, adv, fc);
  
 -      if (tp->link_config.autoneg == AUTONEG_DISABLE &&
 -          tp->link_config.speed != SPEED_INVALID) {
 +              tg3_writephy(tp, MII_BMCR,
 +                           BMCR_ANENABLE | BMCR_ANRESTART);
 +      } else {
 +              int i;
                u32 bmcr, orig_bmcr;
  
                tp->link_config.active_speed = tp->link_config.speed;
                        tg3_writephy(tp, MII_BMCR, bmcr);
                        udelay(40);
                }
 -      } else {
 -              tg3_writephy(tp, MII_BMCR,
 -                           BMCR_ANENABLE | BMCR_ANRESTART);
        }
  }
  
@@@ -4012,16 -3778,7 +4012,16 @@@ static bool tg3_phy_copper_an_config_ok
                if (tg3_readphy(tp, MII_CTRL1000, &tg3_ctrl))
                        return false;
  
 -              tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL);
 +              if (tgtadv &&
 +                  (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
 +                   tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) {
 +                      tgtadv |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
 +                      tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL |
 +                                   CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER);
 +              } else {
 +                      tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL);
 +              }
 +
                if (tg3_ctrl != tgtadv)
                        return false;
        }
@@@ -4152,8 -3909,8 +4152,8 @@@ static int tg3_setup_copper_phy(struct 
        }
  
        current_link_up = 0;
 -      current_speed = SPEED_INVALID;
 -      current_duplex = DUPLEX_INVALID;
 +      current_speed = SPEED_UNKNOWN;
 +      current_duplex = DUPLEX_UNKNOWN;
        tp->phy_flags &= ~TG3_PHYFLG_MDIX_STATE;
        tp->link_config.rmt_adv = 0;
  
@@@ -5049,8 -4806,8 +5049,8 @@@ static int tg3_setup_fiber_phy(struct t
                                    LED_CTRL_LNKLED_OVERRIDE |
                                    LED_CTRL_1000MBPS_ON));
        } else {
 -              tp->link_config.active_speed = SPEED_INVALID;
 -              tp->link_config.active_duplex = DUPLEX_INVALID;
 +              tp->link_config.active_speed = SPEED_UNKNOWN;
 +              tp->link_config.active_duplex = DUPLEX_UNKNOWN;
                tw32(MAC_LED_CTRL, (tp->led_ctrl |
                                    LED_CTRL_LNKLED_OVERRIDE |
                                    LED_CTRL_TRAFFIC_OVERRIDE));
@@@ -5098,8 -4855,8 +5098,8 @@@ static int tg3_setup_fiber_mii_phy(stru
                tg3_phy_reset(tp);
  
        current_link_up = 0;
 -      current_speed = SPEED_INVALID;
 -      current_duplex = DUPLEX_INVALID;
 +      current_speed = SPEED_UNKNOWN;
 +      current_duplex = DUPLEX_UNKNOWN;
        tp->link_config.rmt_adv = 0;
  
        err |= tg3_readphy(tp, MII_BMSR, &bmsr);
@@@ -5595,7 -5352,7 +5595,7 @@@ static void tg3_tx(struct tg3_napi *tna
                }
        }
  
-       netdev_completed_queue(tp->dev, pkts_compl, bytes_compl);
+       netdev_tx_completed_queue(txq, pkts_compl, bytes_compl);
  
        tnapi->tx_cons = sw_idx;
  
@@@ -5928,9 -5685,6 +5928,9 @@@ next_pkt_nopost
  
        /* Refill RX ring(s). */
        if (!tg3_flag(tp, ENABLE_RSS)) {
 +              /* Sync BD data before updating mailbox */
 +              wmb();
 +
                if (work_mask & RXD_OPAQUE_RING_STD) {
                        tpr->rx_std_prod_idx = std_prod_idx &
                                               tp->rx_std_ring_mask;
@@@ -6167,7 -5921,6 +6167,7 @@@ static inline void tg3_reset_task_cance
  {
        cancel_work_sync(&tp->reset_task);
        tg3_flag_clear(tp, RESET_TASK_PENDING);
 +      tg3_flag_clear(tp, TX_RECOVERY_PENDING);
  }
  
  static int tg3_poll_msix(struct napi_struct *napi, int budget)
@@@ -6539,6 -6292,33 +6539,6 @@@ static irqreturn_t tg3_test_isr(int irq
        return IRQ_RETVAL(0);
  }
  
 -static int tg3_init_hw(struct tg3 *, int);
 -static int tg3_halt(struct tg3 *, int, int);
 -
 -/* Restart hardware after configuration changes, self-test, etc.
 - * Invoked with tp->lock held.
 - */
 -static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
 -      __releases(tp->lock)
 -      __acquires(tp->lock)
 -{
 -      int err;
 -
 -      err = tg3_init_hw(tp, reset_phy);
 -      if (err) {
 -              netdev_err(tp->dev,
 -                         "Failed to re-initialize device, aborting\n");
 -              tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
 -              tg3_full_unlock(tp);
 -              del_timer_sync(&tp->timer);
 -              tp->irq_sync = 0;
 -              tg3_napi_enable(tp);
 -              dev_close(tp->dev);
 -              tg3_full_lock(tp, 0);
 -      }
 -      return err;
 -}
 -
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void tg3_poll_controller(struct net_device *dev)
  {
  }
  #endif
  
 -static void tg3_reset_task(struct work_struct *work)
 -{
 -      struct tg3 *tp = container_of(work, struct tg3, reset_task);
 -      int err;
 -
 -      tg3_full_lock(tp, 0);
 -
 -      if (!netif_running(tp->dev)) {
 -              tg3_flag_clear(tp, RESET_TASK_PENDING);
 -              tg3_full_unlock(tp);
 -              return;
 -      }
 -
 -      tg3_full_unlock(tp);
 -
 -      tg3_phy_stop(tp);
 -
 -      tg3_netif_stop(tp);
 -
 -      tg3_full_lock(tp, 1);
 -
 -      if (tg3_flag(tp, TX_RECOVERY_PENDING)) {
 -              tp->write32_tx_mbox = tg3_write32_tx_mbox;
 -              tp->write32_rx_mbox = tg3_write_flush_reg32;
 -              tg3_flag_set(tp, MBOX_WRITE_REORDER);
 -              tg3_flag_clear(tp, TX_RECOVERY_PENDING);
 -      }
 -
 -      tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
 -      err = tg3_init_hw(tp, 1);
 -      if (err)
 -              goto out;
 -
 -      tg3_netif_start(tp);
 -
 -out:
 -      tg3_full_unlock(tp);
 -
 -      if (!err)
 -              tg3_phy_start(tp);
 -
 -      tg3_flag_clear(tp, RESET_TASK_PENDING);
 -}
 -
  static void tg3_tx_timeout(struct net_device *dev)
  {
        struct tg3 *tp = netdev_priv(dev);
@@@ -6921,6 -6745,7 +6921,6 @@@ static netdev_tx_t tg3_start_xmit(struc
                          ((skb_shinfo(skb)->nr_frags == 0) ? TXD_FLAG_END : 0),
                            mss, vlan)) {
                would_hit_hwbug = 1;
 -      /* Now loop through additional data fragments, and queue them. */
        } else if (skb_shinfo(skb)->nr_frags > 0) {
                u32 tmp_mss = mss;
  
                    !tg3_flag(tp, HW_TSO_3))
                        tmp_mss = 0;
  
 +              /* Now loop through additional data
 +               * fragments, and queue them.
 +               */
                last = skb_shinfo(skb)->nr_frags - 1;
                for (i = 0; i <= last; i++) {
                        skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
        }
  
        skb_tx_timestamp(skb);
-       netdev_sent_queue(tp->dev, skb->len);
+       netdev_tx_sent_queue(txq, skb->len);
  
 +      /* Sync BD data before updating mailbox */
 +      wmb();
 +
        /* Packets are ready, update Tx producer idx local and on card. */
        tw32_tx_mbox(tnapi->prodmbox, entry);
  
@@@ -7174,6 -6993,66 +7174,6 @@@ static int tg3_set_features(struct net_
        return 0;
  }
  
 -static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
 -                             int new_mtu)
 -{
 -      dev->mtu = new_mtu;
 -
 -      if (new_mtu > ETH_DATA_LEN) {
 -              if (tg3_flag(tp, 5780_CLASS)) {
 -                      netdev_update_features(dev);
 -                      tg3_flag_clear(tp, TSO_CAPABLE);
 -              } else {
 -                      tg3_flag_set(tp, JUMBO_RING_ENABLE);
 -              }
 -      } else {
 -              if (tg3_flag(tp, 5780_CLASS)) {
 -                      tg3_flag_set(tp, TSO_CAPABLE);
 -                      netdev_update_features(dev);
 -              }
 -              tg3_flag_clear(tp, JUMBO_RING_ENABLE);
 -      }
 -}
 -
 -static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 -{
 -      struct tg3 *tp = netdev_priv(dev);
 -      int err;
 -
 -      if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU(tp))
 -              return -EINVAL;
 -
 -      if (!netif_running(dev)) {
 -              /* We'll just catch it later when the
 -               * device is up'd.
 -               */
 -              tg3_set_mtu(dev, tp, new_mtu);
 -              return 0;
 -      }
 -
 -      tg3_phy_stop(tp);
 -
 -      tg3_netif_stop(tp);
 -
 -      tg3_full_lock(tp, 1);
 -
 -      tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
 -
 -      tg3_set_mtu(dev, tp, new_mtu);
 -
 -      err = tg3_restart_hw(tp, 0);
 -
 -      if (!err)
 -              tg3_netif_start(tp);
 -
 -      tg3_full_unlock(tp);
 -
 -      if (!err)
 -              tg3_phy_start(tp);
 -
 -      return err;
 -}
 -
  static void tg3_rx_prodring_free(struct tg3 *tp,
                                 struct tg3_rx_prodring_set *tpr)
  {
@@@ -7396,8 -7275,8 +7396,8 @@@ static void tg3_free_rings(struct tg3 *
  
                        dev_kfree_skb_any(skb);
                }
+               netdev_tx_reset_queue(netdev_get_tx_queue(tp->dev, j));
        }
-       netdev_reset_queue(tp->dev);
  }
  
  /* Initialize tx/rx rings for packet processing.
@@@ -8029,7 -7908,7 +8029,7 @@@ static int tg3_halt(struct tg3 *tp, in
  
        if (tp->hw_stats) {
                /* Save the stats across chip resets... */
 -              tg3_get_nstats(tp, &tp->net_stats_prev),
 +              tg3_get_nstats(tp, &tp->net_stats_prev);
                tg3_get_estats(tp, &tp->estats_prev);
  
                /* And make sure the next sample is new data */
@@@ -8049,7 -7928,7 +8049,7 @@@ static int tg3_set_mac_addr(struct net_
        int err = 0, skip_mac_1 = 0;
  
        if (!is_valid_ether_addr(addr->sa_data))
 -              return -EINVAL;
 +              return -EADDRNOTAVAIL;
  
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
  
@@@ -8097,6 -7976,7 +8097,6 @@@ static void tg3_set_bdinfo(struct tg3 *
                              nic_addr);
  }
  
 -static void __tg3_set_rx_mode(struct net_device *);
  static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec)
  {
        int i;
@@@ -8333,93 -8213,6 +8333,93 @@@ static void tg3_setup_rxbd_thresholds(s
                tw32(JMB_REPLENISH_LWM, bdcache_maxcnt);
  }
  
 +static inline u32 calc_crc(unsigned char *buf, int len)
 +{
 +      u32 reg;
 +      u32 tmp;
 +      int j, k;
 +
 +      reg = 0xffffffff;
 +
 +      for (j = 0; j < len; j++) {
 +              reg ^= buf[j];
 +
 +              for (k = 0; k < 8; k++) {
 +                      tmp = reg & 0x01;
 +
 +                      reg >>= 1;
 +
 +                      if (tmp)
 +                              reg ^= 0xedb88320;
 +              }
 +      }
 +
 +      return ~reg;
 +}
 +
 +static void tg3_set_multi(struct tg3 *tp, unsigned int accept_all)
 +{
 +      /* accept or reject all multicast frames */
 +      tw32(MAC_HASH_REG_0, accept_all ? 0xffffffff : 0);
 +      tw32(MAC_HASH_REG_1, accept_all ? 0xffffffff : 0);
 +      tw32(MAC_HASH_REG_2, accept_all ? 0xffffffff : 0);
 +      tw32(MAC_HASH_REG_3, accept_all ? 0xffffffff : 0);
 +}
 +
 +static void __tg3_set_rx_mode(struct net_device *dev)
 +{
 +      struct tg3 *tp = netdev_priv(dev);
 +      u32 rx_mode;
 +
 +      rx_mode = tp->rx_mode & ~(RX_MODE_PROMISC |
 +                                RX_MODE_KEEP_VLAN_TAG);
 +
 +#if !defined(CONFIG_VLAN_8021Q) && !defined(CONFIG_VLAN_8021Q_MODULE)
 +      /* When ASF is in use, we always keep the RX_MODE_KEEP_VLAN_TAG
 +       * flag clear.
 +       */
 +      if (!tg3_flag(tp, ENABLE_ASF))
 +              rx_mode |= RX_MODE_KEEP_VLAN_TAG;
 +#endif
 +
 +      if (dev->flags & IFF_PROMISC) {
 +              /* Promiscuous mode. */
 +              rx_mode |= RX_MODE_PROMISC;
 +      } else if (dev->flags & IFF_ALLMULTI) {
 +              /* Accept all multicast. */
 +              tg3_set_multi(tp, 1);
 +      } else if (netdev_mc_empty(dev)) {
 +              /* Reject all multicast. */
 +              tg3_set_multi(tp, 0);
 +      } else {
 +              /* Accept one or more multicast(s). */
 +              struct netdev_hw_addr *ha;
 +              u32 mc_filter[4] = { 0, };
 +              u32 regidx;
 +              u32 bit;
 +              u32 crc;
 +
 +              netdev_for_each_mc_addr(ha, dev) {
 +                      crc = calc_crc(ha->addr, ETH_ALEN);
 +                      bit = ~crc & 0x7f;
 +                      regidx = (bit & 0x60) >> 5;
 +                      bit &= 0x1f;
 +                      mc_filter[regidx] |= (1 << bit);
 +              }
 +
 +              tw32(MAC_HASH_REG_0, mc_filter[0]);
 +              tw32(MAC_HASH_REG_1, mc_filter[1]);
 +              tw32(MAC_HASH_REG_2, mc_filter[2]);
 +              tw32(MAC_HASH_REG_3, mc_filter[3]);
 +      }
 +
 +      if (rx_mode != tp->rx_mode) {
 +              tp->rx_mode = rx_mode;
 +              tw32_f(MAC_RX_MODE, rx_mode);
 +              udelay(10);
 +      }
 +}
 +
  static void tg3_rss_init_dflt_indir_tbl(struct tg3 *tp)
  {
        int i;
@@@ -8895,6 -8688,9 +8895,6 @@@ static int tg3_reset_hw(struct tg3 *tp
        if (tg3_flag(tp, PCI_EXPRESS))
                rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
  
 -      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
 -              rdmac_mode |= RDMAC_MODE_JMB_2K_MMRR;
 -
        if (tg3_flag(tp, HW_TSO_1) ||
            tg3_flag(tp, HW_TSO_2) ||
            tg3_flag(tp, HW_TSO_3))
        }
  
        if (!tg3_flag(tp, USE_PHYLIB)) {
 -              if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
 +              if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
                        tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER;
 -                      tp->link_config.speed = tp->link_config.orig_speed;
 -                      tp->link_config.duplex = tp->link_config.orig_duplex;
 -                      tp->link_config.autoneg = tp->link_config.orig_autoneg;
 -              }
  
                err = tg3_setup_phy(tp, 0);
                if (err)
@@@ -9503,148 -9303,46 +9503,148 @@@ static void tg3_timer(unsigned long __o
                        tg3_serdes_parallel_detect(tp);
                }
  
 -              tp->timer_counter = tp->timer_multiplier;
 +              tp->timer_counter = tp->timer_multiplier;
 +      }
 +
 +      /* Heartbeat is only sent once every 2 seconds.
 +       *
 +       * The heartbeat is to tell the ASF firmware that the host
 +       * driver is still alive.  In the event that the OS crashes,
 +       * ASF needs to reset the hardware to free up the FIFO space
 +       * that may be filled with rx packets destined for the host.
 +       * If the FIFO is full, ASF will no longer function properly.
 +       *
 +       * Unintended resets have been reported on real time kernels
 +       * where the timer doesn't run on time.  Netpoll will also have
 +       * same problem.
 +       *
 +       * The new FWCMD_NICDRV_ALIVE3 command tells the ASF firmware
 +       * to check the ring condition when the heartbeat is expiring
 +       * before doing the reset.  This will prevent most unintended
 +       * resets.
 +       */
 +      if (!--tp->asf_counter) {
 +              if (tg3_flag(tp, ENABLE_ASF) && !tg3_flag(tp, ENABLE_APE)) {
 +                      tg3_wait_for_event_ack(tp);
 +
 +                      tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
 +                                    FWCMD_NICDRV_ALIVE3);
 +                      tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
 +                      tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX,
 +                                    TG3_FW_UPDATE_TIMEOUT_SEC);
 +
 +                      tg3_generate_fw_event(tp);
 +              }
 +              tp->asf_counter = tp->asf_multiplier;
 +      }
 +
 +      spin_unlock(&tp->lock);
 +
 +restart_timer:
 +      tp->timer.expires = jiffies + tp->timer_offset;
 +      add_timer(&tp->timer);
 +}
 +
 +static void __devinit tg3_timer_init(struct tg3 *tp)
 +{
 +      if (tg3_flag(tp, TAGGED_STATUS) &&
 +          GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
 +          !tg3_flag(tp, 57765_CLASS))
 +              tp->timer_offset = HZ;
 +      else
 +              tp->timer_offset = HZ / 10;
 +
 +      BUG_ON(tp->timer_offset > HZ);
 +
 +      tp->timer_multiplier = (HZ / tp->timer_offset);
 +      tp->asf_multiplier = (HZ / tp->timer_offset) *
 +                           TG3_FW_UPDATE_FREQ_SEC;
 +
 +      init_timer(&tp->timer);
 +      tp->timer.data = (unsigned long) tp;
 +      tp->timer.function = tg3_timer;
 +}
 +
 +static void tg3_timer_start(struct tg3 *tp)
 +{
 +      tp->asf_counter   = tp->asf_multiplier;
 +      tp->timer_counter = tp->timer_multiplier;
 +
 +      tp->timer.expires = jiffies + tp->timer_offset;
 +      add_timer(&tp->timer);
 +}
 +
 +static void tg3_timer_stop(struct tg3 *tp)
 +{
 +      del_timer_sync(&tp->timer);
 +}
 +
 +/* Restart hardware after configuration changes, self-test, etc.
 + * Invoked with tp->lock held.
 + */
 +static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
 +      __releases(tp->lock)
 +      __acquires(tp->lock)
 +{
 +      int err;
 +
 +      err = tg3_init_hw(tp, reset_phy);
 +      if (err) {
 +              netdev_err(tp->dev,
 +                         "Failed to re-initialize device, aborting\n");
 +              tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
 +              tg3_full_unlock(tp);
 +              tg3_timer_stop(tp);
 +              tp->irq_sync = 0;
 +              tg3_napi_enable(tp);
 +              dev_close(tp->dev);
 +              tg3_full_lock(tp, 0);
 +      }
 +      return err;
 +}
 +
 +static void tg3_reset_task(struct work_struct *work)
 +{
 +      struct tg3 *tp = container_of(work, struct tg3, reset_task);
 +      int err;
 +
 +      tg3_full_lock(tp, 0);
 +
 +      if (!netif_running(tp->dev)) {
 +              tg3_flag_clear(tp, RESET_TASK_PENDING);
 +              tg3_full_unlock(tp);
 +              return;
 +      }
 +
 +      tg3_full_unlock(tp);
 +
 +      tg3_phy_stop(tp);
 +
 +      tg3_netif_stop(tp);
 +
 +      tg3_full_lock(tp, 1);
 +
 +      if (tg3_flag(tp, TX_RECOVERY_PENDING)) {
 +              tp->write32_tx_mbox = tg3_write32_tx_mbox;
 +              tp->write32_rx_mbox = tg3_write_flush_reg32;
 +              tg3_flag_set(tp, MBOX_WRITE_REORDER);
 +              tg3_flag_clear(tp, TX_RECOVERY_PENDING);
        }
  
 -      /* Heartbeat is only sent once every 2 seconds.
 -       *
 -       * The heartbeat is to tell the ASF firmware that the host
 -       * driver is still alive.  In the event that the OS crashes,
 -       * ASF needs to reset the hardware to free up the FIFO space
 -       * that may be filled with rx packets destined for the host.
 -       * If the FIFO is full, ASF will no longer function properly.
 -       *
 -       * Unintended resets have been reported on real time kernels
 -       * where the timer doesn't run on time.  Netpoll will also have
 -       * same problem.
 -       *
 -       * The new FWCMD_NICDRV_ALIVE3 command tells the ASF firmware
 -       * to check the ring condition when the heartbeat is expiring
 -       * before doing the reset.  This will prevent most unintended
 -       * resets.
 -       */
 -      if (!--tp->asf_counter) {
 -              if (tg3_flag(tp, ENABLE_ASF) && !tg3_flag(tp, ENABLE_APE)) {
 -                      tg3_wait_for_event_ack(tp);
 +      tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
 +      err = tg3_init_hw(tp, 1);
 +      if (err)
 +              goto out;
  
 -                      tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
 -                                    FWCMD_NICDRV_ALIVE3);
 -                      tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
 -                      tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX,
 -                                    TG3_FW_UPDATE_TIMEOUT_SEC);
 +      tg3_netif_start(tp);
  
 -                      tg3_generate_fw_event(tp);
 -              }
 -              tp->asf_counter = tp->asf_multiplier;
 -      }
 +out:
 +      tg3_full_unlock(tp);
  
 -      spin_unlock(&tp->lock);
 +      if (!err)
 +              tg3_phy_start(tp);
  
 -restart_timer:
 -      tp->timer.expires = jiffies + tp->timer_offset;
 -      add_timer(&tp->timer);
 +      tg3_flag_clear(tp, RESET_TASK_PENDING);
  }
  
  static int tg3_request_irq(struct tg3 *tp, int irq_num)
@@@ -9701,7 -9399,7 +9701,7 @@@ static int tg3_test_interrupt(struct tg
        }
  
        err = request_irq(tnapi->irq_vec, tg3_test_isr,
 -                        IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, tnapi);
 +                        IRQF_SHARED, dev->name, tnapi);
        if (err)
                return err;
  
@@@ -10012,6 -9710,24 +10012,6 @@@ static int tg3_open(struct net_device *
        if (err) {
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
                tg3_free_rings(tp);
 -      } else {
 -              if (tg3_flag(tp, TAGGED_STATUS) &&
 -                  GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
 -                  !tg3_flag(tp, 57765_CLASS))
 -                      tp->timer_offset = HZ;
 -              else
 -                      tp->timer_offset = HZ / 10;
 -
 -              BUG_ON(tp->timer_offset > HZ);
 -              tp->timer_counter = tp->timer_multiplier =
 -                      (HZ / tp->timer_offset);
 -              tp->asf_counter = tp->asf_multiplier =
 -                      ((HZ / tp->timer_offset) * 2);
 -
 -              init_timer(&tp->timer);
 -              tp->timer.expires = jiffies + tp->timer_offset;
 -              tp->timer.data = (unsigned long) tp;
 -              tp->timer.function = tg3_timer;
        }
  
        tg3_full_unlock(tp);
  
        tg3_full_lock(tp, 0);
  
 -      add_timer(&tp->timer);
 +      tg3_timer_start(tp);
        tg3_flag_set(tp, INIT_COMPLETE);
        tg3_enable_ints(tp);
  
@@@ -10088,7 -9804,7 +10088,7 @@@ static int tg3_close(struct net_device 
  
        netif_tx_stop_all_queues(dev);
  
 -      del_timer_sync(&tp->timer);
 +      tg3_timer_stop(tp);
  
        tg3_phy_stop(tp);
  
@@@ -10162,6 -9878,9 +10162,6 @@@ static void tg3_get_estats(struct tg3 *
        struct tg3_ethtool_stats *old_estats = &tp->estats_prev;
        struct tg3_hw_stats *hw_stats = tp->hw_stats;
  
 -      if (!hw_stats)
 -              return;
 -
        ESTAT_ADD(rx_octets);
        ESTAT_ADD(rx_fragments);
        ESTAT_ADD(rx_ucast_packets);
@@@ -10297,6 -10016,105 +10297,6 @@@ static void tg3_get_nstats(struct tg3 *
        stats->tx_dropped = tp->tx_dropped;
  }
  
 -static inline u32 calc_crc(unsigned char *buf, int len)
 -{
 -      u32 reg;
 -      u32 tmp;
 -      int j, k;
 -
 -      reg = 0xffffffff;
 -
 -      for (j = 0; j < len; j++) {
 -              reg ^= buf[j];
 -
 -              for (k = 0; k < 8; k++) {
 -                      tmp = reg & 0x01;
 -
 -                      reg >>= 1;
 -
 -                      if (tmp)
 -                              reg ^= 0xedb88320;
 -              }
 -      }
 -
 -      return ~reg;
 -}
 -
 -static void tg3_set_multi(struct tg3 *tp, unsigned int accept_all)
 -{
 -      /* accept or reject all multicast frames */
 -      tw32(MAC_HASH_REG_0, accept_all ? 0xffffffff : 0);
 -      tw32(MAC_HASH_REG_1, accept_all ? 0xffffffff : 0);
 -      tw32(MAC_HASH_REG_2, accept_all ? 0xffffffff : 0);
 -      tw32(MAC_HASH_REG_3, accept_all ? 0xffffffff : 0);
 -}
 -
 -static void __tg3_set_rx_mode(struct net_device *dev)
 -{
 -      struct tg3 *tp = netdev_priv(dev);
 -      u32 rx_mode;
 -
 -      rx_mode = tp->rx_mode & ~(RX_MODE_PROMISC |
 -                                RX_MODE_KEEP_VLAN_TAG);
 -
 -#if !defined(CONFIG_VLAN_8021Q) && !defined(CONFIG_VLAN_8021Q_MODULE)
 -      /* When ASF is in use, we always keep the RX_MODE_KEEP_VLAN_TAG
 -       * flag clear.
 -       */
 -      if (!tg3_flag(tp, ENABLE_ASF))
 -              rx_mode |= RX_MODE_KEEP_VLAN_TAG;
 -#endif
 -
 -      if (dev->flags & IFF_PROMISC) {
 -              /* Promiscuous mode. */
 -              rx_mode |= RX_MODE_PROMISC;
 -      } else if (dev->flags & IFF_ALLMULTI) {
 -              /* Accept all multicast. */
 -              tg3_set_multi(tp, 1);
 -      } else if (netdev_mc_empty(dev)) {
 -              /* Reject all multicast. */
 -              tg3_set_multi(tp, 0);
 -      } else {
 -              /* Accept one or more multicast(s). */
 -              struct netdev_hw_addr *ha;
 -              u32 mc_filter[4] = { 0, };
 -              u32 regidx;
 -              u32 bit;
 -              u32 crc;
 -
 -              netdev_for_each_mc_addr(ha, dev) {
 -                      crc = calc_crc(ha->addr, ETH_ALEN);
 -                      bit = ~crc & 0x7f;
 -                      regidx = (bit & 0x60) >> 5;
 -                      bit &= 0x1f;
 -                      mc_filter[regidx] |= (1 << bit);
 -              }
 -
 -              tw32(MAC_HASH_REG_0, mc_filter[0]);
 -              tw32(MAC_HASH_REG_1, mc_filter[1]);
 -              tw32(MAC_HASH_REG_2, mc_filter[2]);
 -              tw32(MAC_HASH_REG_3, mc_filter[3]);
 -      }
 -
 -      if (rx_mode != tp->rx_mode) {
 -              tp->rx_mode = rx_mode;
 -              tw32_f(MAC_RX_MODE, rx_mode);
 -              udelay(10);
 -      }
 -}
 -
 -static void tg3_set_rx_mode(struct net_device *dev)
 -{
 -      struct tg3 *tp = netdev_priv(dev);
 -
 -      if (!netif_running(dev))
 -              return;
 -
 -      tg3_full_lock(tp, 0);
 -      __tg3_set_rx_mode(dev);
 -      tg3_full_unlock(tp);
 -}
 -
  static int tg3_get_regs_len(struct net_device *dev)
  {
        return TG3_REG_BLK_SIZE;
@@@ -10391,6 -10209,8 +10391,6 @@@ static int tg3_get_eeprom(struct net_de
        return 0;
  }
  
 -static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf);
 -
  static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
  {
        struct tg3 *tp = netdev_priv(dev);
@@@ -10504,8 -10324,8 +10504,8 @@@ static int tg3_get_settings(struct net_
                                cmd->eth_tp_mdix = ETH_TP_MDI;
                }
        } else {
 -              ethtool_cmd_speed_set(cmd, SPEED_INVALID);
 -              cmd->duplex = DUPLEX_INVALID;
 +              ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
 +              cmd->duplex = DUPLEX_UNKNOWN;
                cmd->eth_tp_mdix = ETH_TP_MDI_INVALID;
        }
        cmd->phy_address = tp->phy_addr;
@@@ -10587,14 -10407,18 +10587,14 @@@ static int tg3_set_settings(struct net_
        if (cmd->autoneg == AUTONEG_ENABLE) {
                tp->link_config.advertising = (cmd->advertising |
                                              ADVERTISED_Autoneg);
 -              tp->link_config.speed = SPEED_INVALID;
 -              tp->link_config.duplex = DUPLEX_INVALID;
 +              tp->link_config.speed = SPEED_UNKNOWN;
 +              tp->link_config.duplex = DUPLEX_UNKNOWN;
        } else {
                tp->link_config.advertising = 0;
                tp->link_config.speed = speed;
                tp->link_config.duplex = cmd->duplex;
        }
  
 -      tp->link_config.orig_speed = tp->link_config.speed;
 -      tp->link_config.orig_duplex = tp->link_config.duplex;
 -      tp->link_config.orig_autoneg = tp->link_config.autoneg;
 -
        if (netif_running(dev))
                tg3_setup_phy(tp, 1);
  
@@@ -10841,10 -10665,10 +10841,10 @@@ static int tg3_set_pauseparam(struct ne
                        if (!epause->autoneg)
                                tg3_setup_flow_control(tp, 0, 0);
                } else {
 -                      tp->link_config.orig_advertising &=
 +                      tp->link_config.advertising &=
                                        ~(ADVERTISED_Pause |
                                          ADVERTISED_Asym_Pause);
 -                      tp->link_config.orig_advertising |= newadv;
 +                      tp->link_config.advertising |= newadv;
                }
        } else {
                int irq_sync = 0;
@@@ -11021,10 -10845,7 +11021,10 @@@ static void tg3_get_ethtool_stats(struc
  {
        struct tg3 *tp = netdev_priv(dev);
  
 -      tg3_get_estats(tp, (struct tg3_ethtool_stats *)tmp_stats);
 +      if (tp->hw_stats)
 +              tg3_get_estats(tp, (struct tg3_ethtool_stats *)tmp_stats);
 +      else
 +              memset(tmp_stats, 0, sizeof(struct tg3_ethtool_stats));
  }
  
  static __be32 *tg3_vpd_readblock(struct tg3 *tp, u32 *vpdlen)
@@@ -11733,10 -11554,6 +11733,10 @@@ static int tg3_run_loopback(struct tg3 
        } else {
                num_pkts = 1;
                data_off = ETH_HLEN;
 +
 +              if (tg3_flag(tp, USE_JUMBO_BDFLAG) &&
 +                  tx_len > VLAN_ETH_FRAME_LEN)
 +                      base_flags |= TXD_FLAG_JMB_PKT;
        }
  
        for (i = data_off; i < tx_len; i++)
  
        tnapi->tx_prod++;
  
 +      /* Sync BD data before updating mailbox */
 +      wmb();
 +
        tw32_tx_mbox(tnapi->prodmbox, tnapi->tx_prod);
        tr32_mailbox(tnapi->prodmbox);
  
@@@ -11870,10 -11684,6 +11870,10 @@@ static int tg3_test_loopback(struct tg
  {
        int err = -EIO;
        u32 eee_cap;
 +      u32 jmb_pkt_sz = 9000;
 +
 +      if (tp->dma_limit)
 +              jmb_pkt_sz = tp->dma_limit - ETH_HLEN;
  
        eee_cap = tp->phy_flags & TG3_PHYFLG_EEE_CAP;
        tp->phy_flags &= ~TG3_PHYFLG_EEE_CAP;
                        data[0] |= TG3_STD_LOOPBACK_FAILED;
  
                if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
 -                  tg3_run_loopback(tp, 9000 + ETH_HLEN, false))
 +                  tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false))
                        data[0] |= TG3_JMB_LOOPBACK_FAILED;
  
                tg3_mac_loopback(tp, false);
                    tg3_run_loopback(tp, ETH_FRAME_LEN, true))
                        data[1] |= TG3_TSO_LOOPBACK_FAILED;
                if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
 -                  tg3_run_loopback(tp, 9000 + ETH_HLEN, false))
 +                  tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false))
                        data[1] |= TG3_JMB_LOOPBACK_FAILED;
  
                if (do_extlpbk) {
                            tg3_run_loopback(tp, ETH_FRAME_LEN, true))
                                data[2] |= TG3_TSO_LOOPBACK_FAILED;
                        if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
 -                          tg3_run_loopback(tp, 9000 + ETH_HLEN, false))
 +                          tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false))
                                data[2] |= TG3_JMB_LOOPBACK_FAILED;
                }
  
@@@ -12216,117 -12026,6 +12216,117 @@@ static const struct ethtool_ops tg3_eth
        .set_rxfh_indir         = tg3_set_rxfh_indir,
  };
  
 +static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
 +                                              struct rtnl_link_stats64 *stats)
 +{
 +      struct tg3 *tp = netdev_priv(dev);
 +
 +      if (!tp->hw_stats)
 +              return &tp->net_stats_prev;
 +
 +      spin_lock_bh(&tp->lock);
 +      tg3_get_nstats(tp, stats);
 +      spin_unlock_bh(&tp->lock);
 +
 +      return stats;
 +}
 +
 +static void tg3_set_rx_mode(struct net_device *dev)
 +{
 +      struct tg3 *tp = netdev_priv(dev);
 +
 +      if (!netif_running(dev))
 +              return;
 +
 +      tg3_full_lock(tp, 0);
 +      __tg3_set_rx_mode(dev);
 +      tg3_full_unlock(tp);
 +}
 +
 +static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
 +                             int new_mtu)
 +{
 +      dev->mtu = new_mtu;
 +
 +      if (new_mtu > ETH_DATA_LEN) {
 +              if (tg3_flag(tp, 5780_CLASS)) {
 +                      netdev_update_features(dev);
 +                      tg3_flag_clear(tp, TSO_CAPABLE);
 +              } else {
 +                      tg3_flag_set(tp, JUMBO_RING_ENABLE);
 +              }
 +      } else {
 +              if (tg3_flag(tp, 5780_CLASS)) {
 +                      tg3_flag_set(tp, TSO_CAPABLE);
 +                      netdev_update_features(dev);
 +              }
 +              tg3_flag_clear(tp, JUMBO_RING_ENABLE);
 +      }
 +}
 +
 +static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 +{
 +      struct tg3 *tp = netdev_priv(dev);
 +      int err, reset_phy = 0;
 +
 +      if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU(tp))
 +              return -EINVAL;
 +
 +      if (!netif_running(dev)) {
 +              /* We'll just catch it later when the
 +               * device is up'd.
 +               */
 +              tg3_set_mtu(dev, tp, new_mtu);
 +              return 0;
 +      }
 +
 +      tg3_phy_stop(tp);
 +
 +      tg3_netif_stop(tp);
 +
 +      tg3_full_lock(tp, 1);
 +
 +      tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
 +
 +      tg3_set_mtu(dev, tp, new_mtu);
 +
 +      /* Reset PHY, otherwise the read DMA engine will be in a mode that
 +       * breaks all requests to 256 bytes.
 +       */
 +      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
 +              reset_phy = 1;
 +
 +      err = tg3_restart_hw(tp, reset_phy);
 +
 +      if (!err)
 +              tg3_netif_start(tp);
 +
 +      tg3_full_unlock(tp);
 +
 +      if (!err)
 +              tg3_phy_start(tp);
 +
 +      return err;
 +}
 +
 +static const struct net_device_ops tg3_netdev_ops = {
 +      .ndo_open               = tg3_open,
 +      .ndo_stop               = tg3_close,
 +      .ndo_start_xmit         = tg3_start_xmit,
 +      .ndo_get_stats64        = tg3_get_stats64,
 +      .ndo_validate_addr      = eth_validate_addr,
 +      .ndo_set_rx_mode        = tg3_set_rx_mode,
 +      .ndo_set_mac_address    = tg3_set_mac_addr,
 +      .ndo_do_ioctl           = tg3_ioctl,
 +      .ndo_tx_timeout         = tg3_tx_timeout,
 +      .ndo_change_mtu         = tg3_change_mtu,
 +      .ndo_fix_features       = tg3_fix_features,
 +      .ndo_set_features       = tg3_set_features,
 +#ifdef CONFIG_NET_POLL_CONTROLLER
 +      .ndo_poll_controller    = tg3_poll_controller,
 +#endif
 +};
 +
  static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
  {
        u32 cursize, val, magic;
@@@ -13004,18 -12703,266 +13004,18 @@@ static void __devinit tg3_nvram_init(st
                else
                        tg3_get_nvram_info(tp);
  
 -              if (tp->nvram_size == 0)
 -                      tg3_get_nvram_size(tp);
 -
 -              tg3_disable_nvram_access(tp);
 -              tg3_nvram_unlock(tp);
 -
 -      } else {
 -              tg3_flag_clear(tp, NVRAM);
 -              tg3_flag_clear(tp, NVRAM_BUFFERED);
 -
 -              tg3_get_eeprom_size(tp);
 -      }
 -}
 -
 -static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp,
 -                                  u32 offset, u32 len, u8 *buf)
 -{
 -      int i, j, rc = 0;
 -      u32 val;
 -
 -      for (i = 0; i < len; i += 4) {
 -              u32 addr;
 -              __be32 data;
 -
 -              addr = offset + i;
 -
 -              memcpy(&data, buf + i, 4);
 -
 -              /*
 -               * The SEEPROM interface expects the data to always be opposite
 -               * the native endian format.  We accomplish this by reversing
 -               * all the operations that would have been performed on the
 -               * data from a call to tg3_nvram_read_be32().
 -               */
 -              tw32(GRC_EEPROM_DATA, swab32(be32_to_cpu(data)));
 -
 -              val = tr32(GRC_EEPROM_ADDR);
 -              tw32(GRC_EEPROM_ADDR, val | EEPROM_ADDR_COMPLETE);
 -
 -              val &= ~(EEPROM_ADDR_ADDR_MASK | EEPROM_ADDR_DEVID_MASK |
 -                      EEPROM_ADDR_READ);
 -              tw32(GRC_EEPROM_ADDR, val |
 -                      (0 << EEPROM_ADDR_DEVID_SHIFT) |
 -                      (addr & EEPROM_ADDR_ADDR_MASK) |
 -                      EEPROM_ADDR_START |
 -                      EEPROM_ADDR_WRITE);
 -
 -              for (j = 0; j < 1000; j++) {
 -                      val = tr32(GRC_EEPROM_ADDR);
 -
 -                      if (val & EEPROM_ADDR_COMPLETE)
 -                              break;
 -                      msleep(1);
 -              }
 -              if (!(val & EEPROM_ADDR_COMPLETE)) {
 -                      rc = -EBUSY;
 -                      break;
 -              }
 -      }
 -
 -      return rc;
 -}
 -
 -/* offset and length are dword aligned */
 -static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
 -              u8 *buf)
 -{
 -      int ret = 0;
 -      u32 pagesize = tp->nvram_pagesize;
 -      u32 pagemask = pagesize - 1;
 -      u32 nvram_cmd;
 -      u8 *tmp;
 -
 -      tmp = kmalloc(pagesize, GFP_KERNEL);
 -      if (tmp == NULL)
 -              return -ENOMEM;
 -
 -      while (len) {
 -              int j;
 -              u32 phy_addr, page_off, size;
 -
 -              phy_addr = offset & ~pagemask;
 -
 -              for (j = 0; j < pagesize; j += 4) {
 -                      ret = tg3_nvram_read_be32(tp, phy_addr + j,
 -                                                (__be32 *) (tmp + j));
 -                      if (ret)
 -                              break;
 -              }
 -              if (ret)
 -                      break;
 -
 -              page_off = offset & pagemask;
 -              size = pagesize;
 -              if (len < size)
 -                      size = len;
 -
 -              len -= size;
 -
 -              memcpy(tmp + page_off, buf, size);
 -
 -              offset = offset + (pagesize - page_off);
 -
 -              tg3_enable_nvram_access(tp);
 -
 -              /*
 -               * Before we can erase the flash page, we need
 -               * to issue a special "write enable" command.
 -               */
 -              nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE;
 -
 -              if (tg3_nvram_exec_cmd(tp, nvram_cmd))
 -                      break;
 -
 -              /* Erase the target page */
 -              tw32(NVRAM_ADDR, phy_addr);
 -
 -              nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR |
 -                      NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_ERASE;
 -
 -              if (tg3_nvram_exec_cmd(tp, nvram_cmd))
 -                      break;
 -
 -              /* Issue another write enable to start the write. */
 -              nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE;
 -
 -              if (tg3_nvram_exec_cmd(tp, nvram_cmd))
 -                      break;
 -
 -              for (j = 0; j < pagesize; j += 4) {
 -                      __be32 data;
 -
 -                      data = *((__be32 *) (tmp + j));
 -
 -                      tw32(NVRAM_WRDATA, be32_to_cpu(data));
 -
 -                      tw32(NVRAM_ADDR, phy_addr + j);
 -
 -                      nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE |
 -                              NVRAM_CMD_WR;
 -
 -                      if (j == 0)
 -                              nvram_cmd |= NVRAM_CMD_FIRST;
 -                      else if (j == (pagesize - 4))
 -                              nvram_cmd |= NVRAM_CMD_LAST;
 -
 -                      if ((ret = tg3_nvram_exec_cmd(tp, nvram_cmd)))
 -                              break;
 -              }
 -              if (ret)
 -                      break;
 -      }
 -
 -      nvram_cmd = NVRAM_CMD_WRDI | NVRAM_CMD_GO | NVRAM_CMD_DONE;
 -      tg3_nvram_exec_cmd(tp, nvram_cmd);
 -
 -      kfree(tmp);
 -
 -      return ret;
 -}
 -
 -/* offset and length are dword aligned */
 -static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
 -              u8 *buf)
 -{
 -      int i, ret = 0;
 -
 -      for (i = 0; i < len; i += 4, offset += 4) {
 -              u32 page_off, phy_addr, nvram_cmd;
 -              __be32 data;
 -
 -              memcpy(&data, buf + i, 4);
 -              tw32(NVRAM_WRDATA, be32_to_cpu(data));
 -
 -              page_off = offset % tp->nvram_pagesize;
 -
 -              phy_addr = tg3_nvram_phys_addr(tp, offset);
 -
 -              tw32(NVRAM_ADDR, phy_addr);
 -
 -              nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR;
 -
 -              if (page_off == 0 || i == 0)
 -                      nvram_cmd |= NVRAM_CMD_FIRST;
 -              if (page_off == (tp->nvram_pagesize - 4))
 -                      nvram_cmd |= NVRAM_CMD_LAST;
 -
 -              if (i == (len - 4))
 -                      nvram_cmd |= NVRAM_CMD_LAST;
 -
 -              if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
 -                  !tg3_flag(tp, 5755_PLUS) &&
 -                  (tp->nvram_jedecnum == JEDEC_ST) &&
 -                  (nvram_cmd & NVRAM_CMD_FIRST)) {
 -
 -                      if ((ret = tg3_nvram_exec_cmd(tp,
 -                              NVRAM_CMD_WREN | NVRAM_CMD_GO |
 -                              NVRAM_CMD_DONE)))
 -
 -                              break;
 -              }
 -              if (!tg3_flag(tp, FLASH)) {
 -                      /* We always do complete word writes to eeprom. */
 -                      nvram_cmd |= (NVRAM_CMD_FIRST | NVRAM_CMD_LAST);
 -              }
 -
 -              if ((ret = tg3_nvram_exec_cmd(tp, nvram_cmd)))
 -                      break;
 -      }
 -      return ret;
 -}
 -
 -/* offset and length are dword aligned */
 -static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
 -{
 -      int ret;
 -
 -      if (tg3_flag(tp, EEPROM_WRITE_PROT)) {
 -              tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl &
 -                     ~GRC_LCLCTRL_GPIO_OUTPUT1);
 -              udelay(40);
 -      }
 -
 -      if (!tg3_flag(tp, NVRAM)) {
 -              ret = tg3_nvram_write_block_using_eeprom(tp, offset, len, buf);
 -      } else {
 -              u32 grc_mode;
 -
 -              ret = tg3_nvram_lock(tp);
 -              if (ret)
 -                      return ret;
 -
 -              tg3_enable_nvram_access(tp);
 -              if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM))
 -                      tw32(NVRAM_WRITE1, 0x406);
 -
 -              grc_mode = tr32(GRC_MODE);
 -              tw32(GRC_MODE, grc_mode | GRC_MODE_NVRAM_WR_ENABLE);
 -
 -              if (tg3_flag(tp, NVRAM_BUFFERED) || !tg3_flag(tp, FLASH)) {
 -                      ret = tg3_nvram_write_block_buffered(tp, offset, len,
 -                              buf);
 -              } else {
 -                      ret = tg3_nvram_write_block_unbuffered(tp, offset, len,
 -                              buf);
 -              }
 -
 -              grc_mode = tr32(GRC_MODE);
 -              tw32(GRC_MODE, grc_mode & ~GRC_MODE_NVRAM_WR_ENABLE);
 +              if (tp->nvram_size == 0)
 +                      tg3_get_nvram_size(tp);
  
                tg3_disable_nvram_access(tp);
                tg3_nvram_unlock(tp);
 -      }
  
 -      if (tg3_flag(tp, EEPROM_WRITE_PROT)) {
 -              tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
 -              udelay(40);
 -      }
 +      } else {
 +              tg3_flag_clear(tp, NVRAM);
 +              tg3_flag_clear(tp, NVRAM_BUFFERED);
  
 -      return ret;
 +              tg3_get_eeprom_size(tp);
 +      }
  }
  
  struct subsys_tbl_ent {
@@@ -13368,13 -13315,14 +13368,13 @@@ static void __devinit tg3_phy_init_link
                adv |= ADVERTISED_FIBRE;
  
        tp->link_config.advertising = adv;
 -      tp->link_config.speed = SPEED_INVALID;
 -      tp->link_config.duplex = DUPLEX_INVALID;
 +      tp->link_config.speed = SPEED_UNKNOWN;
 +      tp->link_config.duplex = DUPLEX_UNKNOWN;
        tp->link_config.autoneg = AUTONEG_ENABLE;
 -      tp->link_config.active_speed = SPEED_INVALID;
 -      tp->link_config.active_duplex = DUPLEX_INVALID;
 -      tp->link_config.orig_speed = SPEED_INVALID;
 -      tp->link_config.orig_duplex = DUPLEX_INVALID;
 -      tp->link_config.orig_autoneg = AUTONEG_INVALID;
 +      tp->link_config.active_speed = SPEED_UNKNOWN;
 +      tp->link_config.active_duplex = DUPLEX_UNKNOWN;
 +
 +      tp->old_link = -1;
  }
  
  static int __devinit tg3_phy_probe(struct tg3 *tp)
@@@ -13871,6 -13819,8 +13871,6 @@@ done
        tp->fw_ver[TG3_VER_SIZE - 1] = 0;
  }
  
 -static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
 -
  static inline u32 tg3_rx_ret_ring_size(struct tg3 *tp)
  {
        if (tg3_flag(tp, LRG_PROD_RING_CAP))
@@@ -13888,50 -13838,49 +13888,50 @@@ static DEFINE_PCI_DEVICE_TABLE(tg3_writ
        { },
  };
  
 -static int __devinit tg3_get_invariants(struct tg3 *tp)
 +static struct pci_dev * __devinit tg3_find_peer(struct tg3 *tp)
  {
 -      u32 misc_ctrl_reg;
 -      u32 pci_state_reg, grc_misc_cfg;
 -      u32 val;
 -      u16 pci_cmd;
 -      int err;
 +      struct pci_dev *peer;
 +      unsigned int func, devnr = tp->pdev->devfn & ~7;
  
 -      /* Force memory write invalidate off.  If we leave it on,
 -       * then on 5700_BX chips we have to enable a workaround.
 -       * The workaround is to set the TG3PCI_DMA_RW_CTRL boundary
 -       * to match the cacheline size.  The Broadcom driver have this
 -       * workaround but turns MWI off all the times so never uses
 -       * it.  This seems to suggest that the workaround is insufficient.
 +      for (func = 0; func < 8; func++) {
 +              peer = pci_get_slot(tp->pdev->bus, devnr | func);
 +              if (peer && peer != tp->pdev)
 +                      break;
 +              pci_dev_put(peer);
 +      }
 +      /* 5704 can be configured in single-port mode, set peer to
 +       * tp->pdev in that case.
         */
 -      pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
 -      pci_cmd &= ~PCI_COMMAND_INVALIDATE;
 -      pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
 +      if (!peer) {
 +              peer = tp->pdev;
 +              return peer;
 +      }
  
 -      /* Important! -- Make sure register accesses are byteswapped
 -       * correctly.  Also, for those chips that require it, make
 -       * sure that indirect register accesses are enabled before
 -       * the first operation.
 +      /*
 +       * We don't need to keep the refcount elevated; there's no way
 +       * to remove one half of this device without removing the other
         */
 -      pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
 -                            &misc_ctrl_reg);
 -      tp->misc_host_ctrl |= (misc_ctrl_reg &
 -                             MISC_HOST_CTRL_CHIPREV);
 -      pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
 -                             tp->misc_host_ctrl);
 +      pci_dev_put(peer);
 +
 +      return peer;
 +}
  
 -      tp->pci_chip_rev_id = (misc_ctrl_reg >>
 -                             MISC_HOST_CTRL_CHIPREV_SHIFT);
 +static void __devinit tg3_detect_asic_rev(struct tg3 *tp, u32 misc_ctrl_reg)
 +{
 +      tp->pci_chip_rev_id = misc_ctrl_reg >> MISC_HOST_CTRL_CHIPREV_SHIFT;
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) {
 -              u32 prod_id_asic_rev;
 +              u32 reg;
 +
 +              /* All devices that use the alternate
 +               * ASIC REV location have a CPMU.
 +               */
 +              tg3_flag_set(tp, CPMU_PRESENT);
  
                if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 ||
                    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
                    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 ||
                    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720)
 -                      pci_read_config_dword(tp->pdev,
 -                                            TG3PCI_GEN2_PRODID_ASICREV,
 -                                            &prod_id_asic_rev);
 +                      reg = TG3PCI_GEN2_PRODID_ASICREV;
                else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57781 ||
                         tp->pdev->device == TG3PCI_DEVICE_TIGON3_57785 ||
                         tp->pdev->device == TG3PCI_DEVICE_TIGON3_57761 ||
                         tp->pdev->device == TG3PCI_DEVICE_TIGON3_57766 ||
                         tp->pdev->device == TG3PCI_DEVICE_TIGON3_57782 ||
                         tp->pdev->device == TG3PCI_DEVICE_TIGON3_57786)
 -                      pci_read_config_dword(tp->pdev,
 -                                            TG3PCI_GEN15_PRODID_ASICREV,
 -                                            &prod_id_asic_rev);
 +                      reg = TG3PCI_GEN15_PRODID_ASICREV;
                else
 -                      pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV,
 -                                            &prod_id_asic_rev);
 +                      reg = TG3PCI_PRODID_ASICREV;
  
 -              tp->pci_chip_rev_id = prod_id_asic_rev;
 +              pci_read_config_dword(tp->pdev, reg, &tp->pci_chip_rev_id);
        }
  
        /* Wrong chip ID in 5752 A0. This code can be removed later
        if (tp->pci_chip_rev_id == CHIPREV_ID_5752_A0_HW)
                tp->pci_chip_rev_id = CHIPREV_ID_5752_A0;
  
 +      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
 +          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
 +          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
 +              tg3_flag_set(tp, 5717_PLUS);
 +
 +      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 ||
 +          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
 +              tg3_flag_set(tp, 57765_CLASS);
 +
 +      if (tg3_flag(tp, 57765_CLASS) || tg3_flag(tp, 5717_PLUS))
 +              tg3_flag_set(tp, 57765_PLUS);
 +
 +      /* Intentionally exclude ASIC_REV_5906 */
 +      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
 +          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
 +          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
 +          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
 +          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
 +          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
 +          tg3_flag(tp, 57765_PLUS))
 +              tg3_flag_set(tp, 5755_PLUS);
 +
 +      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 ||
 +          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)
 +              tg3_flag_set(tp, 5780_CLASS);
 +
 +      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
 +          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
 +          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
 +          tg3_flag(tp, 5755_PLUS) ||
 +          tg3_flag(tp, 5780_CLASS))
 +              tg3_flag_set(tp, 5750_PLUS);
 +
 +      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
 +          tg3_flag(tp, 5750_PLUS))
 +              tg3_flag_set(tp, 5705_PLUS);
 +}
 +
 +static int __devinit tg3_get_invariants(struct tg3 *tp)
 +{
 +      u32 misc_ctrl_reg;
 +      u32 pci_state_reg, grc_misc_cfg;
 +      u32 val;
 +      u16 pci_cmd;
 +      int err;
 +
 +      /* Force memory write invalidate off.  If we leave it on,
 +       * then on 5700_BX chips we have to enable a workaround.
 +       * The workaround is to set the TG3PCI_DMA_RW_CTRL boundary
 +       * to match the cacheline size.  The Broadcom driver have this
 +       * workaround but turns MWI off all the times so never uses
 +       * it.  This seems to suggest that the workaround is insufficient.
 +       */
 +      pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
 +      pci_cmd &= ~PCI_COMMAND_INVALIDATE;
 +      pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
 +
 +      /* Important! -- Make sure register accesses are byteswapped
 +       * correctly.  Also, for those chips that require it, make
 +       * sure that indirect register accesses are enabled before
 +       * the first operation.
 +       */
 +      pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
 +                            &misc_ctrl_reg);
 +      tp->misc_host_ctrl |= (misc_ctrl_reg &
 +                             MISC_HOST_CTRL_CHIPREV);
 +      pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
 +                             tp->misc_host_ctrl);
 +
 +      tg3_detect_asic_rev(tp, misc_ctrl_reg);
 +
        /* If we have 5702/03 A1 or A2 on certain ICH chipsets,
         * we need to disable memory and use config. cycles
         * only to access all registers. The 5702/03 chips
         * Any tg3 device found behind the bridge will also need the 40-bit
         * DMA workaround.
         */
 -      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 ||
 -          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
 -              tg3_flag_set(tp, 5780_CLASS);
 +      if (tg3_flag(tp, 5780_CLASS)) {
                tg3_flag_set(tp, 40BIT_DMA_BUG);
                tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI);
        } else {
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)
                tp->pdev_peer = tg3_find_peer(tp);
  
 -      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
 -          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
 -          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
 -              tg3_flag_set(tp, 5717_PLUS);
 -
 -      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 ||
 -          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
 -              tg3_flag_set(tp, 57765_CLASS);
 -
 -      if (tg3_flag(tp, 57765_CLASS) || tg3_flag(tp, 5717_PLUS))
 -              tg3_flag_set(tp, 57765_PLUS);
 -
 -      /* Intentionally exclude ASIC_REV_5906 */
 -      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
 -          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
 -          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
 -          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
 -          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
 -          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
 -          tg3_flag(tp, 57765_PLUS))
 -              tg3_flag_set(tp, 5755_PLUS);
 -
 -      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
 -          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
 -          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
 -          tg3_flag(tp, 5755_PLUS) ||
 -          tg3_flag(tp, 5780_CLASS))
 -              tg3_flag_set(tp, 5750_PLUS);
 -
 -      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
 -          tg3_flag(tp, 5750_PLUS))
 -              tg3_flag_set(tp, 5705_PLUS);
 -
        /* Determine TSO capabilities */
        if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0)
                ; /* Do nothing. HW bug. */
  
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
                tp->dma_limit = TG3_TX_BD_DMA_MAX_4K;
 -      else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
 -              tp->dma_limit = TG3_TX_BD_DMA_MAX_2K;
  
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
  
                tg3_flag_set(tp, PCI_EXPRESS);
  
 -              if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0) {
 -                      int readrq = pcie_get_readrq(tp->pdev);
 -                      if (readrq > 2048)
 -                              pcie_set_readrq(tp->pdev, 2048);
 -              }
 -
                pci_read_config_word(tp->pdev,
                                     pci_pcie_cap(tp->pdev) + PCI_EXP_LNKCTL,
                                     &lnkctl);
                tg3_ape_lock_init(tp);
        }
  
 -      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
 -          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
 -          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
 -          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
 -          tg3_flag(tp, 57765_PLUS))
 -              tg3_flag_set(tp, CPMU_PRESENT);
 -
        /* Set up tp->grc_local_ctrl before calling
         * tg3_pwrsrc_switch_to_vmain().  GPIO1 driven high
         * will bring 5700's external PHY out of reset.
@@@ -15405,6 -15336,34 +15405,6 @@@ static char * __devinit tg3_bus_string(
        return str;
  }
  
 -static struct pci_dev * __devinit tg3_find_peer(struct tg3 *tp)
 -{
 -      struct pci_dev *peer;
 -      unsigned int func, devnr = tp->pdev->devfn & ~7;
 -
 -      for (func = 0; func < 8; func++) {
 -              peer = pci_get_slot(tp->pdev->bus, devnr | func);
 -              if (peer && peer != tp->pdev)
 -                      break;
 -              pci_dev_put(peer);
 -      }
 -      /* 5704 can be configured in single-port mode, set peer to
 -       * tp->pdev in that case.
 -       */
 -      if (!peer) {
 -              peer = tp->pdev;
 -              return peer;
 -      }
 -
 -      /*
 -       * We don't need to keep the refcount elevated; there's no way
 -       * to remove one half of this device without removing the other
 -       */
 -      pci_dev_put(peer);
 -
 -      return peer;
 -}
 -
  static void __devinit tg3_init_coal(struct tg3 *tp)
  {
        struct ethtool_coalesce *ec = &tp->coal;
        }
  }
  
 -static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
 -                                              struct rtnl_link_stats64 *stats)
 -{
 -      struct tg3 *tp = netdev_priv(dev);
 -
 -      if (!tp->hw_stats)
 -              return &tp->net_stats_prev;
 -
 -      spin_lock_bh(&tp->lock);
 -      tg3_get_nstats(tp, stats);
 -      spin_unlock_bh(&tp->lock);
 -
 -      return stats;
 -}
 -
 -static const struct net_device_ops tg3_netdev_ops = {
 -      .ndo_open               = tg3_open,
 -      .ndo_stop               = tg3_close,
 -      .ndo_start_xmit         = tg3_start_xmit,
 -      .ndo_get_stats64        = tg3_get_stats64,
 -      .ndo_validate_addr      = eth_validate_addr,
 -      .ndo_set_rx_mode        = tg3_set_rx_mode,
 -      .ndo_set_mac_address    = tg3_set_mac_addr,
 -      .ndo_do_ioctl           = tg3_ioctl,
 -      .ndo_tx_timeout         = tg3_tx_timeout,
 -      .ndo_change_mtu         = tg3_change_mtu,
 -      .ndo_fix_features       = tg3_fix_features,
 -      .ndo_set_features       = tg3_set_features,
 -#ifdef CONFIG_NET_POLL_CONTROLLER
 -      .ndo_poll_controller    = tg3_poll_controller,
 -#endif
 -};
 -
  static int __devinit tg3_init_one(struct pci_dev *pdev,
                                  const struct pci_device_id *ent)
  {
  
        dev = alloc_etherdev_mq(sizeof(*tp), TG3_IRQ_MAX_VECS);
        if (!dev) {
 -              dev_err(&pdev->dev, "Etherdev alloc failed, aborting\n");
                err = -ENOMEM;
                goto err_out_power_down;
        }
                tg3_frob_aux_power(tp, false);
        }
  
 +      tg3_timer_init(tp);
 +
        err = register_netdev(dev);
        if (err) {
                dev_err(&pdev->dev, "Cannot register net device, aborting\n");
@@@ -15863,7 -15854,7 +15863,7 @@@ static int tg3_suspend(struct device *d
        tg3_phy_stop(tp);
        tg3_netif_stop(tp);
  
 -      del_timer_sync(&tp->timer);
 +      tg3_timer_stop(tp);
  
        tg3_full_lock(tp, 1);
        tg3_disable_ints(tp);
                if (err2)
                        goto out;
  
 -              tp->timer.expires = jiffies + tp->timer_offset;
 -              add_timer(&tp->timer);
 +              tg3_timer_start(tp);
  
                netif_device_attach(dev);
                tg3_netif_start(tp);
@@@ -15921,7 -15913,8 +15921,7 @@@ static int tg3_resume(struct device *de
        if (err)
                goto out;
  
 -      tp->timer.expires = jiffies + tp->timer_offset;
 -      add_timer(&tp->timer);
 +      tg3_timer_start(tp);
  
        tg3_netif_start(tp);
  
@@@ -15969,10 -15962,11 +15969,10 @@@ static pci_ers_result_t tg3_io_error_de
  
        tg3_netif_stop(tp);
  
 -      del_timer_sync(&tp->timer);
 +      tg3_timer_stop(tp);
  
        /* Want to make sure that the reset task doesn't run */
        tg3_reset_task_cancel(tp);
 -      tg3_flag_clear(tp, TX_RECOVERY_PENDING);
  
        netif_device_detach(netdev);
  
@@@ -16065,7 -16059,8 +16065,7 @@@ static void tg3_io_resume(struct pci_de
  
        netif_device_attach(netdev);
  
 -      tp->timer.expires = jiffies + tp->timer_offset;
 -      add_timer(&tp->timer);
 +      tg3_timer_start(tp);
  
        tg3_netif_start(tp);
  
@@@ -196,6 -196,8 +196,8 @@@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pc
        CH_DEVICE(0x4408, 4),
        CH_DEVICE(0x4409, 4),
        CH_DEVICE(0x440a, 4),
+       CH_DEVICE(0x440d, 4),
+       CH_DEVICE(0x440e, 4),
        { 0, }
  };
  
@@@ -2809,7 -2811,7 +2811,7 @@@ static int cxgb_set_mac_addr(struct net
        struct port_info *pi = netdev_priv(dev);
  
        if (!is_valid_ether_addr(addr->sa_data))
 -              return -EINVAL;
 +              return -EADDRNOTAVAIL;
  
        ret = t4_change_mac(pi->adapter, pi->adapter->fn, pi->viid,
                            pi->xact_addr_filt, addr->sa_data, true, true);
@@@ -1130,7 -1130,7 +1130,7 @@@ static int cxgb4vf_set_mac_addr(struct 
        struct port_info *pi = netdev_priv(dev);
  
        if (!is_valid_ether_addr(addr->sa_data))
 -              return -EINVAL;
 +              return -EADDRNOTAVAIL;
  
        ret = t4vf_change_mac(pi->adapter, pi->viid, pi->xact_addr_filt,
                              addr->sa_data, true);
@@@ -2596,6 -2596,8 +2596,6 @@@ static int __devinit cxgb4vf_pci_probe(
                netdev = alloc_etherdev_mq(sizeof(struct port_info),
                                           MAX_PORT_QSETS);
                if (netdev == NULL) {
 -                      dev_err(&pdev->dev, "cannot allocate netdev for"
 -                              " port %d\n", port_id);
                        t4vf_free_vi(adapter, viid);
                        err = -ENOMEM;
                        goto err_free_dev;
@@@ -2890,6 -2892,8 +2890,8 @@@ static struct pci_device_id cxgb4vf_pci
        CH_DEVICE(0x4808, 0),   /* T420-cx */
        CH_DEVICE(0x4809, 0),   /* T420-bt */
        CH_DEVICE(0x480a, 0),   /* T404-bt */
+       CH_DEVICE(0x480d, 0),   /* T480-cr */
+       CH_DEVICE(0x480e, 0),   /* T440-lp-cr */
        { 0, }
  };
  
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - *  linux/drivers/net/ehea/ehea_main.c
 + *  linux/drivers/net/ethernet/ibm/ehea/ehea_main.c
   *
   *  eHEA ethernet device driver for IBM eServer System p
   *
@@@ -336,7 -336,9 +336,9 @@@ static struct rtnl_link_stats64 *ehea_g
        stats->tx_bytes = tx_bytes;
        stats->rx_packets = rx_packets;
  
-       return &port->stats;
+       stats->multicast = port->stats.multicast;
+       stats->rx_errors = port->stats.rx_errors;
+       return stats;
  }
  
  static void ehea_update_stats(struct work_struct *work)
@@@ -2980,6 -2982,7 +2982,6 @@@ static struct ehea_port *ehea_setup_sin
        dev = alloc_etherdev_mq(sizeof(struct ehea_port), EHEA_MAX_PORT_RES);
  
        if (!dev) {
 -              pr_err("no mem for net_device\n");
                ret = -ENOMEM;
                goto out_err;
        }
@@@ -667,25 -667,12 +667,25 @@@ struct rtl8169_counters 
        __le16  tx_underun;
  };
  
 +enum rtl_flag {
 +      RTL_FLAG_TASK_ENABLED,
 +      RTL_FLAG_TASK_SLOW_PENDING,
 +      RTL_FLAG_TASK_RESET_PENDING,
 +      RTL_FLAG_TASK_PHY_PENDING,
 +      RTL_FLAG_MAX
 +};
 +
 +struct rtl8169_stats {
 +      u64                     packets;
 +      u64                     bytes;
 +      struct u64_stats_sync   syncp;
 +};
 +
  struct rtl8169_private {
        void __iomem *mmio_addr;        /* memory map physical address */
        struct pci_dev *pci_dev;
        struct net_device *dev;
        struct napi_struct napi;
 -      spinlock_t lock;
        u32 msg_enable;
        u16 txd_version;
        u16 mac_version;
        u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
        u32 dirty_rx;
        u32 dirty_tx;
 +      struct rtl8169_stats rx_stats;
 +      struct rtl8169_stats tx_stats;
        struct TxDesc *TxDescArray;     /* 256-aligned Tx descriptor ring */
        struct RxDesc *RxDescArray;     /* 256-aligned Rx descriptor ring */
        dma_addr_t TxPhyAddr;
        struct ring_info tx_skb[NUM_TX_DESC];   /* Tx data buffers */
        struct timer_list timer;
        u16 cp_cmd;
 -      u16 intr_event;
 -      u16 napi_event;
 -      u16 intr_mask;
 +
 +      u16 event_slow;
  
        struct mdio_ops {
                void (*write)(void __iomem *, int, int);
        unsigned int (*phy_reset_pending)(struct rtl8169_private *tp);
        unsigned int (*link_ok)(void __iomem *);
        int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd);
 -      struct delayed_work task;
 +
 +      struct {
 +              DECLARE_BITMAP(flags, RTL_FLAG_MAX);
 +              struct mutex mutex;
 +              struct work_struct work;
 +      } wk;
 +
        unsigned features;
  
        struct mii_if_info mii;
@@@ -783,23 -763,14 +783,23 @@@ static void rtl_hw_start(struct net_dev
  static int rtl8169_close(struct net_device *dev);
  static void rtl_set_rx_mode(struct net_device *dev);
  static void rtl8169_tx_timeout(struct net_device *dev);
 -static struct net_device_stats *rtl8169_get_stats(struct net_device *dev);
 -static int rtl8169_rx_interrupt(struct net_device *, struct rtl8169_private *,
 -                              void __iomem *, u32 budget);
 +static struct rtnl_link_stats64 *rtl8169_get_stats64(struct net_device *dev,
 +                                                  struct rtnl_link_stats64
 +                                                  *stats);
  static int rtl8169_change_mtu(struct net_device *dev, int new_mtu);
  static void rtl8169_rx_clear(struct rtl8169_private *tp);
  static int rtl8169_poll(struct napi_struct *napi, int budget);
  
 +static void rtl_lock_work(struct rtl8169_private *tp)
 +{
 +      mutex_lock(&tp->wk.mutex);
 +}
 +
 +static void rtl_unlock_work(struct rtl8169_private *tp)
 +{
 +      mutex_unlock(&tp->wk.mutex);
 +}
 +
  static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
  {
        int cap = pci_pcie_cap(pdev);
@@@ -1209,51 -1180,12 +1209,51 @@@ static u8 rtl8168d_efuse_read(void __io
        return value;
  }
  
 +static u16 rtl_get_events(struct rtl8169_private *tp)
 +{
 +      void __iomem *ioaddr = tp->mmio_addr;
 +
 +      return RTL_R16(IntrStatus);
 +}
 +
 +static void rtl_ack_events(struct rtl8169_private *tp, u16 bits)
 +{
 +      void __iomem *ioaddr = tp->mmio_addr;
 +
 +      RTL_W16(IntrStatus, bits);
 +      mmiowb();
 +}
 +
 +static void rtl_irq_disable(struct rtl8169_private *tp)
 +{
 +      void __iomem *ioaddr = tp->mmio_addr;
 +
 +      RTL_W16(IntrMask, 0);
 +      mmiowb();
 +}
 +
 +static void rtl_irq_enable(struct rtl8169_private *tp, u16 bits)
 +{
 +      void __iomem *ioaddr = tp->mmio_addr;
 +
 +      RTL_W16(IntrMask, bits);
 +}
 +
 +#define RTL_EVENT_NAPI_RX     (RxOK | RxErr)
 +#define RTL_EVENT_NAPI_TX     (TxOK | TxErr)
 +#define RTL_EVENT_NAPI                (RTL_EVENT_NAPI_RX | RTL_EVENT_NAPI_TX)
 +
 +static void rtl_irq_enable_all(struct rtl8169_private *tp)
 +{
 +      rtl_irq_enable(tp, RTL_EVENT_NAPI | tp->event_slow);
 +}
 +
  static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)
  {
        void __iomem *ioaddr = tp->mmio_addr;
  
 -      RTL_W16(IntrMask, 0x0000);
 -      RTL_W16(IntrStatus, tp->intr_event);
 +      rtl_irq_disable(tp);
 +      rtl_ack_events(tp, RTL_EVENT_NAPI | tp->event_slow);
        RTL_R8(ChipCmd);
  }
  
@@@ -1344,6 -1276,9 +1344,6 @@@ static void __rtl8169_check_link_status
                                        struct rtl8169_private *tp,
                                        void __iomem *ioaddr, bool pm)
  {
 -      unsigned long flags;
 -
 -      spin_lock_irqsave(&tp->lock, flags);
        if (tp->link_ok(ioaddr)) {
                rtl_link_chg_patch(tp);
                /* This is to cancel a scheduled suspend if there's one. */
                if (pm)
                        pm_schedule_suspend(&tp->pci_dev->dev, 5000);
        }
 -      spin_unlock_irqrestore(&tp->lock, flags);
  }
  
  static void rtl8169_check_link_status(struct net_device *dev,
@@@ -1400,12 -1336,12 +1400,12 @@@ static void rtl8169_get_wol(struct net_
  {
        struct rtl8169_private *tp = netdev_priv(dev);
  
 -      spin_lock_irq(&tp->lock);
 +      rtl_lock_work(tp);
  
        wol->supported = WAKE_ANY;
        wol->wolopts = __rtl8169_get_wol(tp);
  
 -      spin_unlock_irq(&tp->lock);
 +      rtl_unlock_work(tp);
  }
  
  static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
@@@ -1442,15 -1378,14 +1442,15 @@@ static int rtl8169_set_wol(struct net_d
  {
        struct rtl8169_private *tp = netdev_priv(dev);
  
 -      spin_lock_irq(&tp->lock);
 +      rtl_lock_work(tp);
  
        if (wol->wolopts)
                tp->features |= RTL_FEATURE_WOL;
        else
                tp->features &= ~RTL_FEATURE_WOL;
        __rtl8169_set_wol(tp, wol->wolopts);
 -      spin_unlock_irq(&tp->lock);
 +
 +      rtl_unlock_work(tp);
  
        device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
  
  static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
  {
        struct rtl8169_private *tp = netdev_priv(dev);
 -      unsigned long flags;
        int ret;
  
        del_timer_sync(&tp->timer);
  
 -      spin_lock_irqsave(&tp->lock, flags);
 +      rtl_lock_work(tp);
        ret = rtl8169_set_speed(dev, cmd->autoneg, ethtool_cmd_speed(cmd),
                                cmd->duplex, cmd->advertising);
 -      spin_unlock_irqrestore(&tp->lock, flags);
 +      rtl_unlock_work(tp);
  
        return ret;
  }
@@@ -1632,51 -1568,33 +1632,51 @@@ static netdev_features_t rtl8169_fix_fe
        return features;
  }
  
 -static int rtl8169_set_features(struct net_device *dev,
 -      netdev_features_t features)
 +static void __rtl8169_set_features(struct net_device *dev,
 +                                 netdev_features_t features)
  {
        struct rtl8169_private *tp = netdev_priv(dev);
 +      netdev_features_t changed = features ^ dev->features;
        void __iomem *ioaddr = tp->mmio_addr;
 -      unsigned long flags;
  
 -      spin_lock_irqsave(&tp->lock, flags);
 +      if (!(changed & (NETIF_F_RXALL | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)))
 +              return;
 +
 +      if (changed & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)) {
 +              if (features & NETIF_F_RXCSUM)
 +                      tp->cp_cmd |= RxChkSum;
 +              else
 +                      tp->cp_cmd &= ~RxChkSum;
  
 -      if (features & NETIF_F_RXCSUM)
 -              tp->cp_cmd |= RxChkSum;
 -      else
 -              tp->cp_cmd &= ~RxChkSum;
 +              if (dev->features & NETIF_F_HW_VLAN_RX)
 +                      tp->cp_cmd |= RxVlan;
 +              else
 +                      tp->cp_cmd &= ~RxVlan;
  
 -      if (dev->features & NETIF_F_HW_VLAN_RX)
 -              tp->cp_cmd |= RxVlan;
 -      else
 -              tp->cp_cmd &= ~RxVlan;
 +              RTL_W16(CPlusCmd, tp->cp_cmd);
 +              RTL_R16(CPlusCmd);
 +      }
 +      if (changed & NETIF_F_RXALL) {
 +              int tmp = (RTL_R32(RxConfig) & ~(AcceptErr | AcceptRunt));
 +              if (features & NETIF_F_RXALL)
 +                      tmp |= (AcceptErr | AcceptRunt);
 +              RTL_W32(RxConfig, tmp);
 +      }
 +}
  
 -      RTL_W16(CPlusCmd, tp->cp_cmd);
 -      RTL_R16(CPlusCmd);
 +static int rtl8169_set_features(struct net_device *dev,
 +                              netdev_features_t features)
 +{
 +      struct rtl8169_private *tp = netdev_priv(dev);
  
 -      spin_unlock_irqrestore(&tp->lock, flags);
 +      rtl_lock_work(tp);
 +      __rtl8169_set_features(dev, features);
 +      rtl_unlock_work(tp);
  
        return 0;
  }
  
 +
  static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
                                      struct sk_buff *skb)
  {
@@@ -1725,12 -1643,14 +1725,12 @@@ static int rtl8169_gset_xmii(struct net
  static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
  {
        struct rtl8169_private *tp = netdev_priv(dev);
 -      unsigned long flags;
        int rc;
  
 -      spin_lock_irqsave(&tp->lock, flags);
 -
 +      rtl_lock_work(tp);
        rc = tp->get_settings(dev, cmd);
 +      rtl_unlock_work(tp);
  
 -      spin_unlock_irqrestore(&tp->lock, flags);
        return rc;
  }
  
@@@ -1738,13 -1658,14 +1738,13 @@@ static void rtl8169_get_regs(struct net
                             void *p)
  {
        struct rtl8169_private *tp = netdev_priv(dev);
 -      unsigned long flags;
  
        if (regs->len > R8169_REGS_SIZE)
                regs->len = R8169_REGS_SIZE;
  
 -      spin_lock_irqsave(&tp->lock, flags);
 +      rtl_lock_work(tp);
        memcpy_fromio(p, tp->mmio_addr, regs->len);
 -      spin_unlock_irqrestore(&tp->lock, flags);
 +      rtl_unlock_work(tp);
  }
  
  static u32 rtl8169_get_msglevel(struct net_device *dev)
@@@ -3261,14 -3182,18 +3261,14 @@@ static void rtl_hw_phy_config(struct ne
        }
  }
  
 -static void rtl8169_phy_timer(unsigned long __opaque)
 +static void rtl_phy_work(struct rtl8169_private *tp)
  {
 -      struct net_device *dev = (struct net_device *)__opaque;
 -      struct rtl8169_private *tp = netdev_priv(dev);
        struct timer_list *timer = &tp->timer;
        void __iomem *ioaddr = tp->mmio_addr;
        unsigned long timeout = RTL8169_PHY_TIMEOUT;
  
        assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
  
 -      spin_lock_irq(&tp->lock);
 -
        if (tp->phy_reset_pending(tp)) {
                /*
                 * A busy loop could burn quite a few cycles on nowadays CPU.
        }
  
        if (tp->link_ok(ioaddr))
 -              goto out_unlock;
 +              return;
  
 -      netif_warn(tp, link, dev, "PHY reset until link up\n");
 +      netif_warn(tp, link, tp->dev, "PHY reset until link up\n");
  
        tp->phy_reset_enable(tp);
  
  out_mod_timer:
        mod_timer(timer, jiffies + timeout);
 -out_unlock:
 -      spin_unlock_irq(&tp->lock);
 +}
 +
 +static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag)
 +{
 +      if (!test_and_set_bit(flag, tp->wk.flags))
 +              schedule_work(&tp->wk.work);
 +}
 +
 +static void rtl8169_phy_timer(unsigned long __opaque)
 +{
 +      struct net_device *dev = (struct net_device *)__opaque;
 +      struct rtl8169_private *tp = netdev_priv(dev);
 +
 +      rtl_schedule_task(tp, RTL_FLAG_TASK_PHY_PENDING);
  }
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void rtl8169_netpoll(struct net_device *dev)
  {
        struct rtl8169_private *tp = netdev_priv(dev);
 -      struct pci_dev *pdev = tp->pci_dev;
  
 -      disable_irq(pdev->irq);
 -      rtl8169_interrupt(pdev->irq, dev);
 -      enable_irq(pdev->irq);
 +      rtl8169_interrupt(tp->pci_dev->irq, dev);
  }
  #endif
  
@@@ -3389,7 -3310,7 +3389,7 @@@ static void rtl_rar_set(struct rtl8169_
        low  = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
        high = addr[4] | (addr[5] << 8);
  
 -      spin_lock_irq(&tp->lock);
 +      rtl_lock_work(tp);
  
        RTL_W8(Cfg9346, Cfg9346_Unlock);
  
  
        RTL_W8(Cfg9346, Cfg9346_Lock);
  
 -      spin_unlock_irq(&tp->lock);
 +      rtl_unlock_work(tp);
  }
  
  static int rtl_set_mac_address(struct net_device *dev, void *p)
@@@ -3467,7 -3388,8 +3467,7 @@@ static const struct rtl_cfg_info 
        void (*hw_start)(struct net_device *);
        unsigned int region;
        unsigned int align;
 -      u16 intr_event;
 -      u16 napi_event;
 +      u16 event_slow;
        unsigned features;
        u8 default_ver;
  } rtl_cfg_infos [] = {
                .hw_start       = rtl_hw_start_8169,
                .region         = 1,
                .align          = 0,
 -              .intr_event     = SYSErr | LinkChg | RxOverflow |
 -                                RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
 -              .napi_event     = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
 +              .event_slow     = SYSErr | LinkChg | RxOverflow | RxFIFOOver,
                .features       = RTL_FEATURE_GMII,
                .default_ver    = RTL_GIGA_MAC_VER_01,
        },
                .hw_start       = rtl_hw_start_8168,
                .region         = 2,
                .align          = 8,
 -              .intr_event     = SYSErr | LinkChg | RxOverflow |
 -                                TxErr | TxOK | RxOK | RxErr,
 -              .napi_event     = TxErr | TxOK | RxOK | RxOverflow,
 +              .event_slow     = SYSErr | LinkChg | RxOverflow,
                .features       = RTL_FEATURE_GMII | RTL_FEATURE_MSI,
                .default_ver    = RTL_GIGA_MAC_VER_11,
        },
                .hw_start       = rtl_hw_start_8101,
                .region         = 2,
                .align          = 8,
 -              .intr_event     = SYSErr | LinkChg | RxOverflow | PCSTimeout |
 -                                RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
 -              .napi_event     = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
 +              .event_slow     = SYSErr | LinkChg | RxOverflow | RxFIFOOver |
 +                                PCSTimeout,
                .features       = RTL_FEATURE_MSI,
                .default_ver    = RTL_GIGA_MAC_VER_13,
        }
@@@ -3531,7 -3458,7 +3531,7 @@@ static void rtl_disable_msi(struct pci_
  static const struct net_device_ops rtl8169_netdev_ops = {
        .ndo_open               = rtl8169_open,
        .ndo_stop               = rtl8169_close,
 -      .ndo_get_stats          = rtl8169_get_stats,
 +      .ndo_get_stats64        = rtl8169_get_stats64,
        .ndo_start_xmit         = rtl8169_start_xmit,
        .ndo_tx_timeout         = rtl8169_tx_timeout,
        .ndo_validate_addr      = eth_validate_addr,
@@@ -3905,21 -3832,23 +3905,21 @@@ static void r8168dp_hw_jumbo_disable(st
  static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp)
  {
        void __iomem *ioaddr = tp->mmio_addr;
 -      struct pci_dev *pdev = tp->pci_dev;
  
        RTL_W8(MaxTxPacketSize, 0x3f);
        RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
        RTL_W8(Config4, RTL_R8(Config4) | 0x01);
 -      pci_write_config_byte(pdev, 0x79, 0x20);
 +      rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
  }
  
  static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
  {
        void __iomem *ioaddr = tp->mmio_addr;
 -      struct pci_dev *pdev = tp->pci_dev;
  
        RTL_W8(MaxTxPacketSize, 0x0c);
        RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
        RTL_W8(Config4, RTL_R8(Config4) & ~0x01);
 -      pci_write_config_byte(pdev, 0x79, 0x50);
 +      rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
  }
  
  static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp)
@@@ -4037,6 -3966,8 +4037,6 @@@ rtl8169_init_one(struct pci_dev *pdev, 
  
        dev = alloc_etherdev(sizeof (*tp));
        if (!dev) {
 -              if (netif_msg_drv(&debug))
 -                      dev_err(&pdev->dev, "unable to alloc new ethernet\n");
                rc = -ENOMEM;
                goto out;
        }
  
        rtl_init_rxcfg(tp);
  
 -      RTL_W16(IntrMask, 0x0000);
 +      rtl_irq_disable(tp);
  
        rtl_hw_reset(tp);
  
 -      RTL_W16(IntrStatus, 0xffff);
 +      rtl_ack_events(tp, 0xffff);
  
        pci_set_master(pdev);
  
                tp->do_ioctl = rtl_xmii_ioctl;
        }
  
 -      spin_lock_init(&tp->lock);
 +      mutex_init(&tp->wk.mutex);
  
        /* Get MAC address */
        for (i = 0; i < ETH_ALEN; i++)
                /* 8110SCd requires hardware Rx VLAN - disallow toggling */
                dev->hw_features &= ~NETIF_F_HW_VLAN_RX;
  
 -      tp->intr_mask = 0xffff;
 +      dev->hw_features |= NETIF_F_RXALL;
 +      dev->hw_features |= NETIF_F_RXFCS;
 +
        tp->hw_start = cfg->hw_start;
 -      tp->intr_event = cfg->intr_event;
 -      tp->napi_event = cfg->napi_event;
 +      tp->event_slow = cfg->event_slow;
  
        tp->opts1_mask = (tp->mac_version != RTL_GIGA_MAC_VER_01) ?
                ~(RxBOVF | RxFOVF) : ~0;
@@@ -4274,7 -4204,7 +4274,7 @@@ static void __devexit rtl8169_remove_on
                rtl8168_driver_stop(tp);
        }
  
 -      cancel_delayed_work_sync(&tp->task);
 +      cancel_work_sync(&tp->wk.work);
  
        unregister_netdev(dev);
  
@@@ -4335,8 -4265,6 +4335,8 @@@ static void rtl_request_firmware(struc
                rtl_request_uncached_firmware(tp);
  }
  
 +static void rtl_task(struct work_struct *);
 +
  static int rtl8169_open(struct net_device *dev)
  {
        struct rtl8169_private *tp = netdev_priv(dev);
        if (retval < 0)
                goto err_free_rx_1;
  
 -      INIT_DELAYED_WORK(&tp->task, NULL);
 +      INIT_WORK(&tp->wk.work, rtl_task);
  
        smp_mb();
  
        if (retval < 0)
                goto err_release_fw_2;
  
 +      rtl_lock_work(tp);
 +
 +      set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
 +
        napi_enable(&tp->napi);
  
        rtl8169_init_phy(dev, tp);
  
 -      rtl8169_set_features(dev, dev->features);
 +      __rtl8169_set_features(dev, dev->features);
  
        rtl_pll_power_up(tp);
  
        rtl_hw_start(dev);
  
 +      netif_start_queue(dev);
 +
 +      rtl_unlock_work(tp);
 +
        tp->saved_wolopts = 0;
        pm_runtime_put_noidle(&pdev->dev);
  
@@@ -4467,7 -4387,7 +4467,7 @@@ static void rtl_hw_start(struct net_dev
  
        tp->hw_start(dev);
  
 -      netif_start_queue(dev);
 +      rtl_irq_enable_all(tp);
  }
  
  static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
@@@ -4594,6 -4514,9 +4594,6 @@@ static void rtl_hw_start_8169(struct ne
  
        /* no early-rx interrupts */
        RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
 -
 -      /* Enable all known interrupts by setting the interrupt mask. */
 -      RTL_W16(IntrMask, tp->intr_event);
  }
  
  static void rtl_csi_access_enable(void __iomem *ioaddr, u32 bits)
@@@ -4973,8 -4896,8 +4973,8 @@@ static void rtl_hw_start_8168(struct ne
  
        /* Work around for RxFIFO overflow. */
        if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
 -              tp->intr_event |= RxFIFOOver | PCSTimeout;
 -              tp->intr_event &= ~RxOverflow;
 +              tp->event_slow |= RxFIFOOver | PCSTimeout;
 +              tp->event_slow &= ~RxOverflow;
        }
  
        rtl_set_rx_tx_desc_registers(tp, ioaddr);
        RTL_W8(Cfg9346, Cfg9346_Lock);
  
        RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
 -
 -      RTL_W16(IntrMask, tp->intr_event);
  }
  
  #define R810X_CPCMD_QUIRK_MASK (\
@@@ -5160,8 -5085,10 +5160,8 @@@ static void rtl_hw_start_8101(struct ne
        void __iomem *ioaddr = tp->mmio_addr;
        struct pci_dev *pdev = tp->pci_dev;
  
 -      if (tp->mac_version >= RTL_GIGA_MAC_VER_30) {
 -              tp->intr_event &= ~RxFIFOOver;
 -              tp->napi_event &= ~RxFIFOOver;
 -      }
 +      if (tp->mac_version >= RTL_GIGA_MAC_VER_30)
 +              tp->event_slow &= ~RxFIFOOver;
  
        if (tp->mac_version == RTL_GIGA_MAC_VER_13 ||
            tp->mac_version == RTL_GIGA_MAC_VER_16) {
        rtl_set_rx_mode(dev);
  
        RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
 -
 -      RTL_W16(IntrMask, tp->intr_event);
  }
  
  static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
@@@ -5407,37 -5336,94 +5407,37 @@@ static void rtl8169_tx_clear(struct rtl
  {
        rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC);
        tp->cur_tx = tp->dirty_tx = 0;
 +      netdev_reset_queue(tp->dev);
  }
  
 -static void rtl8169_schedule_work(struct net_device *dev, work_func_t task)
 -{
 -      struct rtl8169_private *tp = netdev_priv(dev);
 -
 -      PREPARE_DELAYED_WORK(&tp->task, task);
 -      schedule_delayed_work(&tp->task, 4);
 -}
 -
 -static void rtl8169_wait_for_quiescence(struct net_device *dev)
 -{
 -      struct rtl8169_private *tp = netdev_priv(dev);
 -      void __iomem *ioaddr = tp->mmio_addr;
 -
 -      synchronize_irq(dev->irq);
 -
 -      /* Wait for any pending NAPI task to complete */
 -      napi_disable(&tp->napi);
 -
 -      rtl8169_irq_mask_and_ack(tp);
 -
 -      tp->intr_mask = 0xffff;
 -      RTL_W16(IntrMask, tp->intr_event);
 -      napi_enable(&tp->napi);
 -}
 -
 -static void rtl8169_reinit_task(struct work_struct *work)
 -{
 -      struct rtl8169_private *tp =
 -              container_of(work, struct rtl8169_private, task.work);
 -      struct net_device *dev = tp->dev;
 -      int ret;
 -
 -      rtnl_lock();
 -
 -      if (!netif_running(dev))
 -              goto out_unlock;
 -
 -      rtl8169_wait_for_quiescence(dev);
 -      rtl8169_close(dev);
 -
 -      ret = rtl8169_open(dev);
 -      if (unlikely(ret < 0)) {
 -              if (net_ratelimit())
 -                      netif_err(tp, drv, dev,
 -                                "reinit failure (status = %d). Rescheduling\n",
 -                                ret);
 -              rtl8169_schedule_work(dev, rtl8169_reinit_task);
 -      }
 -
 -out_unlock:
 -      rtnl_unlock();
 -}
 -
 -static void rtl8169_reset_task(struct work_struct *work)
 +static void rtl_reset_work(struct rtl8169_private *tp)
  {
        struct net_device *dev = tp->dev;
        int i;
  
 -      rtnl_lock();
 -
 -      if (!netif_running(dev))
 -              goto out_unlock;
 +      napi_disable(&tp->napi);
 +      netif_stop_queue(dev);
 +      synchronize_sched();
  
        rtl8169_hw_reset(tp);
  
 -      rtl8169_wait_for_quiescence(dev);
 -
        for (i = 0; i < NUM_RX_DESC; i++)
                rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz);
  
        rtl8169_tx_clear(tp);
        rtl8169_init_ring_indexes(tp);
  
 +      napi_enable(&tp->napi);
        rtl_hw_start(dev);
        netif_wake_queue(dev);
        rtl8169_check_link_status(dev, tp, tp->mmio_addr);
 -
 -out_unlock:
 -      rtnl_unlock();
  }
  
  static void rtl8169_tx_timeout(struct net_device *dev)
  {
 -      rtl8169_schedule_work(dev, rtl8169_reset_task);
 +      struct rtl8169_private *tp = netdev_priv(dev);
 +
 +      rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
  }
  
  static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
@@@ -5562,8 -5548,6 +5562,8 @@@ static netdev_tx_t rtl8169_start_xmit(s
  
        txd->opts2 = cpu_to_le32(opts[1]);
  
 +      netdev_sent_queue(dev, skb->len);
 +
        wmb();
  
        /* Anti gcc 2.95.3 bugware (sic) */
  
        RTL_W8(TxPoll, NPQ);
  
 +      mmiowb();
 +
        if (TX_BUFFS_AVAIL(tp) < MAX_SKB_FRAGS) {
 +              /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must
 +               * not miss a ring update when it notices a stopped queue.
 +               */
 +              smp_wmb();
                netif_stop_queue(dev);
 -              smp_rmb();
 +              /* Sync with rtl_tx:
 +               * - publish queue status and cur_tx ring index (write barrier)
 +               * - refresh dirty_tx ring index (read barrier).
 +               * May the current thread have a pessimistic view of the ring
 +               * status and forget to wake up queue, a racing rtl_tx thread
 +               * can't.
 +               */
 +              smp_mb();
                if (TX_BUFFS_AVAIL(tp) >= MAX_SKB_FRAGS)
                        netif_wake_queue(dev);
        }
@@@ -5655,19 -5626,14 +5655,19 @@@ static void rtl8169_pcierr_interrupt(st
  
        rtl8169_hw_reset(tp);
  
 -      rtl8169_schedule_work(dev, rtl8169_reinit_task);
 +      rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
  }
  
 -static void rtl8169_tx_interrupt(struct net_device *dev,
 -                               struct rtl8169_private *tp,
 -                               void __iomem *ioaddr)
 +struct rtl_txc {
 +      int packets;
 +      int bytes;
 +};
 +
 +static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
  {
 +      struct rtl8169_stats *tx_stats = &tp->tx_stats;
        unsigned int dirty_tx, tx_left;
 +      struct rtl_txc txc = { 0, 0 };
  
        dirty_tx = tp->dirty_tx;
        smp_rmb();
                rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
                                     tp->TxDescArray + entry);
                if (status & LastFrag) {
 -                      dev->stats.tx_packets++;
 -                      dev->stats.tx_bytes += tx_skb->skb->len;
 -                      dev_kfree_skb(tx_skb->skb);
 +                      struct sk_buff *skb = tx_skb->skb;
 +
 +                      txc.packets++;
 +                      txc.bytes += skb->len;
 +                      dev_kfree_skb(skb);
                        tx_skb->skb = NULL;
                }
                dirty_tx++;
                tx_left--;
        }
  
 +      u64_stats_update_begin(&tx_stats->syncp);
 +      tx_stats->packets += txc.packets;
 +      tx_stats->bytes += txc.bytes;
 +      u64_stats_update_end(&tx_stats->syncp);
 +
 +      netdev_completed_queue(dev, txc.packets, txc.bytes);
 +
        if (tp->dirty_tx != dirty_tx) {
                tp->dirty_tx = dirty_tx;
 -              smp_wmb();
 +              /* Sync with rtl8169_start_xmit:
 +               * - publish dirty_tx ring index (write barrier)
 +               * - refresh cur_tx ring index and queue status (read barrier)
 +               * May the current thread miss the stopped queue condition,
 +               * a racing xmit thread can only have a right view of the
 +               * ring status.
 +               */
 +              smp_mb();
                if (netif_queue_stopped(dev) &&
                    (TX_BUFFS_AVAIL(tp) >= MAX_SKB_FRAGS)) {
                        netif_wake_queue(dev);
                 * of start_xmit activity is detected (if it is not detected,
                 * it is slow enough). -- FR
                 */
 -              smp_rmb();
 -              if (tp->cur_tx != dirty_tx)
 +              if (tp->cur_tx != dirty_tx) {
 +                      void __iomem *ioaddr = tp->mmio_addr;
 +
                        RTL_W8(TxPoll, NPQ);
 +              }
        }
  }
  
@@@ -5767,7 -5715,9 +5767,7 @@@ static struct sk_buff *rtl8169_try_rx_c
        return skb;
  }
  
 -static int rtl8169_rx_interrupt(struct net_device *dev,
 -                              struct rtl8169_private *tp,
 -                              void __iomem *ioaddr, u32 budget)
 +static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget)
  {
        unsigned int cur_rx, rx_left;
        unsigned int count;
                        if (status & RxCRC)
                                dev->stats.rx_crc_errors++;
                        if (status & RxFOVF) {
 -                              rtl8169_schedule_work(dev, rtl8169_reset_task);
 +                              rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
                                dev->stats.rx_fifo_errors++;
                        }
 +                      if ((status & (RxRUNT | RxCRC)) &&
 +                          !(status & (RxRWT | RxFOVF)) &&
 +                          (dev->features & NETIF_F_RXALL))
 +                              goto process_pkt;
 +
                        rtl8169_mark_to_asic(desc, rx_buf_sz);
                } else {
                        struct sk_buff *skb;
 -                      dma_addr_t addr = le64_to_cpu(desc->addr);
 -                      int pkt_size = (status & 0x00003fff) - 4;
 +                      dma_addr_t addr;
 +                      int pkt_size;
 +
 +process_pkt:
 +                      addr = le64_to_cpu(desc->addr);
 +                      if (likely(!(dev->features & NETIF_F_RXFCS)))
 +                              pkt_size = (status & 0x00003fff) - 4;
 +                      else
 +                              pkt_size = status & 0x00003fff;
  
                        /*
                         * The driver does not support incoming fragmented
  
                        napi_gro_receive(&tp->napi, skb);
  
 -                      dev->stats.rx_bytes += pkt_size;
 -                      dev->stats.rx_packets++;
 +                      u64_stats_update_begin(&tp->rx_stats.syncp);
 +                      tp->rx_stats.packets++;
 +                      tp->rx_stats.bytes += pkt_size;
 +                      u64_stats_update_end(&tp->rx_stats.syncp);
                }
  
                /* Work around for AMD plateform. */
@@@ -5870,120 -5806,101 +5870,120 @@@ static irqreturn_t rtl8169_interrupt(in
  {
        struct net_device *dev = dev_instance;
        struct rtl8169_private *tp = netdev_priv(dev);
 -      void __iomem *ioaddr = tp->mmio_addr;
        int handled = 0;
 -      int status;
 +      u16 status;
  
 -      /* loop handling interrupts until we have no new ones or
 -       * we hit a invalid/hotplug case.
 -       */
 -      status = RTL_R16(IntrStatus);
 -      while (status && status != 0xffff) {
 -              status &= tp->intr_event;
 -              if (!status)
 -                      break;
 +      status = rtl_get_events(tp);
 +      if (status && status != 0xffff) {
 +              status &= RTL_EVENT_NAPI | tp->event_slow;
 +              if (status) {
 +                      handled = 1;
  
 -              handled = 1;
 +                      rtl_irq_disable(tp);
 +                      napi_schedule(&tp->napi);
 +              }
 +      }
 +      return IRQ_RETVAL(handled);
 +}
  
 -              /* Handle all of the error cases first. These will reset
 -               * the chip, so just exit the loop.
 -               */
 -              if (unlikely(!netif_running(dev))) {
 -                      rtl8169_hw_reset(tp);
 +/*
 + * Workqueue context.
 + */
 +static void rtl_slow_event_work(struct rtl8169_private *tp)
 +{
 +      struct net_device *dev = tp->dev;
 +      u16 status;
 +
 +      status = rtl_get_events(tp) & tp->event_slow;
 +      rtl_ack_events(tp, status);
 +
 +      if (unlikely(status & RxFIFOOver)) {
 +              switch (tp->mac_version) {
 +              /* Work around for rx fifo overflow */
 +              case RTL_GIGA_MAC_VER_11:
 +                      netif_stop_queue(dev);
 +                      /* XXX - Hack alert. See rtl_task(). */
 +                      set_bit(RTL_FLAG_TASK_RESET_PENDING, tp->wk.flags);
 +              default:
                        break;
                }
 +      }
  
 -              if (unlikely(status & RxFIFOOver)) {
 -                      switch (tp->mac_version) {
 -                      /* Work around for rx fifo overflow */
 -                      case RTL_GIGA_MAC_VER_11:
 -                              netif_stop_queue(dev);
 -                              rtl8169_tx_timeout(dev);
 -                              goto done;
 -                      default:
 -                              break;
 -                      }
 -              }
 +      if (unlikely(status & SYSErr))
 +              rtl8169_pcierr_interrupt(dev);
  
 -              if (unlikely(status & SYSErr)) {
 -                      rtl8169_pcierr_interrupt(dev);
 -                      break;
 -              }
 +      if (status & LinkChg)
 +              __rtl8169_check_link_status(dev, tp, tp->mmio_addr, true);
  
 -              if (status & LinkChg)
 -                      __rtl8169_check_link_status(dev, tp, ioaddr, true);
 +      napi_disable(&tp->napi);
 +      rtl_irq_disable(tp);
  
 -              /* We need to see the lastest version of tp->intr_mask to
 -               * avoid ignoring an MSI interrupt and having to wait for
 -               * another event which may never come.
 -               */
 -              smp_rmb();
 -              if (status & tp->intr_mask & tp->napi_event) {
 -                      RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
 -                      tp->intr_mask = ~tp->napi_event;
 +      napi_enable(&tp->napi);
 +      napi_schedule(&tp->napi);
 +}
  
 -                      if (likely(napi_schedule_prep(&tp->napi)))
 -                              __napi_schedule(&tp->napi);
 -                      else
 -                              netif_info(tp, intr, dev,
 -                                         "interrupt %04x in poll\n", status);
 -              }
 +static void rtl_task(struct work_struct *work)
 +{
 +      static const struct {
 +              int bitnr;
 +              void (*action)(struct rtl8169_private *);
 +      } rtl_work[] = {
 +              /* XXX - keep rtl_slow_event_work() as first element. */
 +              { RTL_FLAG_TASK_SLOW_PENDING,   rtl_slow_event_work },
 +              { RTL_FLAG_TASK_RESET_PENDING,  rtl_reset_work },
 +              { RTL_FLAG_TASK_PHY_PENDING,    rtl_phy_work }
 +      };
 +      struct rtl8169_private *tp =
 +              container_of(work, struct rtl8169_private, wk.work);
 +      struct net_device *dev = tp->dev;
 +      int i;
  
 -              /* We only get a new MSI interrupt when all active irq
 -               * sources on the chip have been acknowledged. So, ack
 -               * everything we've seen and check if new sources have become
 -               * active to avoid blocking all interrupts from the chip.
 -               */
 -              RTL_W16(IntrStatus,
 -                      (status & RxFIFOOver) ? (status | RxOverflow) : status);
 -              status = RTL_R16(IntrStatus);
 +      rtl_lock_work(tp);
 +
 +      if (!netif_running(dev) ||
 +          !test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
 +              goto out_unlock;
 +
 +      for (i = 0; i < ARRAY_SIZE(rtl_work); i++) {
 +              bool pending;
 +
 +              pending = test_and_clear_bit(rtl_work[i].bitnr, tp->wk.flags);
 +              if (pending)
 +                      rtl_work[i].action(tp);
        }
 -done:
 -      return IRQ_RETVAL(handled);
 +
 +out_unlock:
 +      rtl_unlock_work(tp);
  }
  
  static int rtl8169_poll(struct napi_struct *napi, int budget)
  {
        struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
        struct net_device *dev = tp->dev;
 -      void __iomem *ioaddr = tp->mmio_addr;
 -      int work_done;
 +      u16 enable_mask = RTL_EVENT_NAPI | tp->event_slow;
 +      int work_done= 0;
 +      u16 status;
 +
 +      status = rtl_get_events(tp);
 +      rtl_ack_events(tp, status & ~tp->event_slow);
 +
 +      if (status & RTL_EVENT_NAPI_RX)
 +              work_done = rtl_rx(dev, tp, (u32) budget);
 +
 +      if (status & RTL_EVENT_NAPI_TX)
 +              rtl_tx(dev, tp);
  
 -      work_done = rtl8169_rx_interrupt(dev, tp, ioaddr, (u32) budget);
 -      rtl8169_tx_interrupt(dev, tp, ioaddr);
 +      if (status & tp->event_slow) {
 +              enable_mask &= ~tp->event_slow;
 +
 +              rtl_schedule_task(tp, RTL_FLAG_TASK_SLOW_PENDING);
 +      }
  
        if (work_done < budget) {
                napi_complete(napi);
  
 -              /* We need for force the visibility of tp->intr_mask
 -               * for other CPUs, as we can loose an MSI interrupt
 -               * and potentially wait for a retransmit timeout if we don't.
 -               * The posted write to IntrMask is safe, as it will
 -               * eventually make it to the chip and we won't loose anything
 -               * until it does.
 -               */
 -              tp->intr_mask = 0xffff;
 -              wmb();
 -              RTL_W16(IntrMask, tp->intr_event);
 +              rtl_irq_enable(tp, enable_mask);
 +              mmiowb();
        }
  
        return work_done;
@@@ -6007,19 -5924,26 +6007,19 @@@ static void rtl8169_down(struct net_dev
  
        del_timer_sync(&tp->timer);
  
 -      netif_stop_queue(dev);
 -
        napi_disable(&tp->napi);
 -
 -      spin_lock_irq(&tp->lock);
 +      netif_stop_queue(dev);
  
        rtl8169_hw_reset(tp);
        /*
         * At this point device interrupts can not be enabled in any function,
 -       * as netif_running is not true (rtl8169_interrupt, rtl8169_reset_task,
 -       * rtl8169_reinit_task) and napi is disabled (rtl8169_poll).
 +       * as netif_running is not true (rtl8169_interrupt, rtl8169_reset_task)
 +       * and napi is disabled (rtl8169_poll).
         */
        rtl8169_rx_missed(dev, ioaddr);
  
 -      spin_unlock_irq(&tp->lock);
 -
 -      synchronize_irq(dev->irq);
 -
        /* Give a racing hard_start_xmit a few cycles to complete. */
 -      synchronize_sched();  /* FIXME: should this be synchronize_irq()? */
 +      synchronize_sched();
  
        rtl8169_tx_clear(tp);
  
@@@ -6038,11 -5962,7 +6038,11 @@@ static int rtl8169_close(struct net_dev
        /* Update counters before going down */
        rtl8169_update_counters(dev);
  
 +      rtl_lock_work(tp);
 +      clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
 +
        rtl8169_down(dev);
 +      rtl_unlock_work(tp);
  
        free_irq(dev->irq, dev);
  
@@@ -6062,6 -5982,7 +6062,6 @@@ static void rtl_set_rx_mode(struct net_
  {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
 -      unsigned long flags;
        u32 mc_filter[2];       /* Multicast hash filter */
        int rx_mode;
        u32 tmp = 0;
                }
        }
  
 -      spin_lock_irqsave(&tp->lock, flags);
 +      if (dev->features & NETIF_F_RXALL)
 +              rx_mode |= (AcceptErr | AcceptRunt);
  
        tmp = (RTL_R32(RxConfig) & ~RX_CONFIG_ACCEPT_MASK) | rx_mode;
  
        RTL_W32(MAR0 + 0, mc_filter[0]);
  
        RTL_W32(RxConfig, tmp);
 -
 -      spin_unlock_irqrestore(&tp->lock, flags);
  }
  
 -/**
 - *  rtl8169_get_stats - Get rtl8169 read/write statistics
 - *  @dev: The Ethernet Device to get statistics for
 - *
 - *  Get TX/RX statistics for rtl8169
 - */
 -static struct net_device_stats *rtl8169_get_stats(struct net_device *dev)
 +static struct rtnl_link_stats64 *
 +rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
  {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
 -      unsigned long flags;
 +      unsigned int start;
  
 -      if (netif_running(dev)) {
 -              spin_lock_irqsave(&tp->lock, flags);
 +      if (netif_running(dev))
                rtl8169_rx_missed(dev, ioaddr);
 -              spin_unlock_irqrestore(&tp->lock, flags);
 -      }
  
 -      return &dev->stats;
 +      do {
 +              start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
 +              stats->rx_packets = tp->rx_stats.packets;
 +              stats->rx_bytes = tp->rx_stats.bytes;
 +      } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
 +
 +
 +      do {
 +              start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
 +              stats->tx_packets = tp->tx_stats.packets;
 +              stats->tx_bytes = tp->tx_stats.bytes;
 +      } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
 +
 +      stats->rx_dropped       = dev->stats.rx_dropped;
 +      stats->tx_dropped       = dev->stats.tx_dropped;
 +      stats->rx_length_errors = dev->stats.rx_length_errors;
 +      stats->rx_errors        = dev->stats.rx_errors;
 +      stats->rx_crc_errors    = dev->stats.rx_crc_errors;
 +      stats->rx_fifo_errors   = dev->stats.rx_fifo_errors;
 +      stats->rx_missed_errors = dev->stats.rx_missed_errors;
 +
 +      return stats;
  }
  
  static void rtl8169_net_suspend(struct net_device *dev)
        if (!netif_running(dev))
                return;
  
 -      rtl_pll_power_down(tp);
 -
        netif_device_detach(dev);
        netif_stop_queue(dev);
 +
 +      rtl_lock_work(tp);
 +      napi_disable(&tp->napi);
 +      clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
 +      rtl_unlock_work(tp);
 +
 +      rtl_pll_power_down(tp);
  }
  
  #ifdef CONFIG_PM
@@@ -6180,9 -6084,7 +6180,9 @@@ static void __rtl8169_resume(struct net
  
        rtl_pll_power_up(tp);
  
 -      rtl8169_schedule_work(dev, rtl8169_reset_task);
 +      set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
 +
 +      rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
  }
  
  static int rtl8169_resume(struct device *device)
@@@ -6208,10 -6110,10 +6208,10 @@@ static int rtl8169_runtime_suspend(stru
        if (!tp->TxDescArray)
                return 0;
  
 -      spin_lock_irq(&tp->lock);
 +      rtl_lock_work(tp);
        tp->saved_wolopts = __rtl8169_get_wol(tp);
        __rtl8169_set_wol(tp, WAKE_ANY);
 -      spin_unlock_irq(&tp->lock);
 +      rtl_unlock_work(tp);
  
        rtl8169_net_suspend(dev);
  
@@@ -6227,10 -6129,10 +6227,10 @@@ static int rtl8169_runtime_resume(struc
        if (!tp->TxDescArray)
                return 0;
  
 -      spin_lock_irq(&tp->lock);
 +      rtl_lock_work(tp);
        __rtl8169_set_wol(tp, tp->saved_wolopts);
        tp->saved_wolopts = 0;
 -      spin_unlock_irq(&tp->lock);
 +      rtl_unlock_work(tp);
  
        rtl8169_init_phy(dev, tp);
  
@@@ -6292,14 -6194,21 +6292,17 @@@ static void rtl_shutdown(struct pci_de
  {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct rtl8169_private *tp = netdev_priv(dev);
+       struct device *d = &pdev->dev;
+       pm_runtime_get_sync(d);
  
        rtl8169_net_suspend(dev);
  
        /* Restore original MAC address */
        rtl_rar_set(tp, dev->perm_addr);
  
 -      spin_lock_irq(&tp->lock);
 -
        rtl8169_hw_reset(tp);
  
 -      spin_unlock_irq(&tp->lock);
 -
        if (system_state == SYSTEM_POWER_OFF) {
                if (__rtl8169_get_wol(tp) & WAKE_ANY) {
                        rtl_wol_suspend_quirk(tp);
                pci_wake_from_d3(pdev, true);
                pci_set_power_state(pdev, PCI_D3hot);
        }
+       pm_runtime_put_noidle(d);
  }
  
  static struct pci_driver rtl8169_pci_driver = {
@@@ -267,10 -267,13 +267,10 @@@ void netvsc_linkstatus_callback(struct 
  int netvsc_recv_callback(struct hv_device *device_obj,
                                struct hv_netvsc_packet *packet)
  {
 -      struct net_device *net = dev_get_drvdata(&device_obj->device);
 +      struct net_device *net;
        struct sk_buff *skb;
 -      struct netvsc_device *net_device;
 -
 -      net_device = hv_get_drvdata(device_obj);
 -      net = net_device->ndev;
  
 +      net = ((struct netvsc_device *)hv_get_drvdata(device_obj))->ndev;
        if (!net) {
                netdev_err(net, "got receive callback but net device"
                        " not initialized yet\n");
  static void netvsc_get_drvinfo(struct net_device *net,
                               struct ethtool_drvinfo *info)
  {
-       strcpy(info->driver, "hv_netvsc");
+       strcpy(info->driver, KBUILD_MODNAME);
        strcpy(info->version, HV_DRV_VERSION);
        strcpy(info->fw_version, "N/A");
  }
@@@ -482,7 -485,7 +482,7 @@@ MODULE_DEVICE_TABLE(vmbus, id_table)
  
  /* The one and only one */
  static struct  hv_driver netvsc_drv = {
-       .name = "netvsc",
+       .name = KBUILD_MODNAME,
        .id_table = id_table,
        .probe = netvsc_probe,
        .remove = netvsc_remove,
diff --combined drivers/net/usb/usbnet.c
@@@ -589,6 -589,7 +589,7 @@@ static int unlink_urbs (struct usbnet *
                entry = (struct skb_data *) skb->cb;
                urb = entry->urb;
  
+               spin_unlock_irqrestore(&q->lock, flags);
                // during some PM-driven resume scenarios,
                // these (async) unlinks complete immediately
                retval = usb_unlink_urb (urb);
                        netdev_dbg(dev->net, "unlink urb err, %d\n", retval);
                else
                        count++;
+               spin_lock_irqsave(&q->lock, flags);
        }
        spin_unlock_irqrestore (&q->lock, flags);
        return count;
@@@ -1334,8 -1336,10 +1336,8 @@@ usbnet_probe (struct usb_interface *ude
  
        // set up our own records
        net = alloc_etherdev(sizeof(*dev));
 -      if (!net) {
 -              dbg ("can't kmalloc dev");
 +      if (!net)
                goto out;
 -      }
  
        /* netdev_printk() needs this so do it as early as possible */
        SET_NETDEV_DEV(net, &udev->dev);
@@@ -2,7 -2,7 +2,7 @@@
   *
   * GPL LICENSE SUMMARY
   *
 - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
 + * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of version 2 of the GNU General Public License as
@@@ -32,6 -32,7 +32,6 @@@
  #include <linux/init.h>
  #include <linux/sched.h>
  
 -#include "iwl-wifi.h"
  #include "iwl-dev.h"
  #include "iwl-core.h"
  #include "iwl-io.h"
@@@ -51,7 -52,7 +51,7 @@@ int iwlagn_send_tx_power(struct iwl_pri
        struct iwlagn_tx_power_dbm_cmd tx_power_cmd;
        u8 tx_ant_cfg_cmd;
  
 -      if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->shrd->status),
 +      if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status),
                      "TX Power requested while scanning!\n"))
                return -EAGAIN;
  
        tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED;
        tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO;
  
 -      if (IWL_UCODE_API(priv->ucode_ver) == 1)
 +      if (IWL_UCODE_API(priv->fw->ucode_ver) == 1)
                tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
        else
                tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
  
 -      return iwl_trans_send_cmd_pdu(trans(priv), tx_ant_cfg_cmd, CMD_SYNC,
 +      return iwl_dvm_send_cmd_pdu(priv, tx_ant_cfg_cmd, CMD_SYNC,
                        sizeof(tx_power_cmd), &tx_power_cmd);
  }
  
  void iwlagn_temperature(struct iwl_priv *priv)
  {
 +      lockdep_assert_held(&priv->statistics.lock);
 +
        /* store temperature from correct statistics (in Celsius) */
        priv->temperature = le32_to_cpu(priv->statistics.common.temperature);
        iwl_tt_handler(priv);
@@@ -234,19 -233,19 +234,19 @@@ int iwlagn_txfifo_flush(struct iwl_pri
                                IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK |
                                IWL_PAN_SCD_MULTICAST_MSK;
  
 -      if (cfg(priv)->sku & EEPROM_SKU_CAP_11N_ENABLE)
 +      if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE)
                flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK;
  
        IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n",
                       flush_cmd.fifo_control);
        flush_cmd.flush_control = cpu_to_le16(flush_control);
  
 -      return iwl_trans_send_cmd(trans(priv), &cmd);
 +      return iwl_dvm_send_cmd(priv, &cmd);
  }
  
  void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
  {
 -      mutex_lock(&priv->shrd->mutex);
 +      mutex_lock(&priv->mutex);
        ieee80211_stop_queues(priv->hw);
        if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
                IWL_ERR(priv, "flush request fail\n");
        iwl_trans_wait_tx_queue_empty(trans(priv));
  done:
        ieee80211_wake_queues(priv->hw);
 -      mutex_unlock(&priv->shrd->mutex);
 +      mutex_unlock(&priv->mutex);
  }
  
  /*
@@@ -435,12 -434,12 +435,12 @@@ void iwlagn_send_advance_bt_config(stru
        if (cfg(priv)->bt_params->bt_session_2) {
                memcpy(&bt_cmd_2000.basic, &basic,
                        sizeof(basic));
 -              ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_BT_CONFIG,
 +              ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
                        CMD_SYNC, sizeof(bt_cmd_2000), &bt_cmd_2000);
        } else {
                memcpy(&bt_cmd_6000.basic, &basic,
                        sizeof(basic));
 -              ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_BT_CONFIG,
 +              ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
                        CMD_SYNC, sizeof(bt_cmd_6000), &bt_cmd_6000);
        }
        if (ret)
@@@ -453,7 -452,7 +453,7 @@@ void iwlagn_bt_adjust_rssi_monitor(stru
        struct iwl_rxon_context *ctx, *found_ctx = NULL;
        bool found_ap = false;
  
 -      lockdep_assert_held(&priv->shrd->mutex);
 +      lockdep_assert_held(&priv->mutex);
  
        /* Check whether AP or GO mode is active. */
        if (rssi_ena) {
@@@ -566,7 -565,7 +566,7 @@@ static void iwlagn_bt_traffic_change_wo
                break;
        }
  
 -      mutex_lock(&priv->shrd->mutex);
 +      mutex_lock(&priv->mutex);
  
        /*
         * We can not send command to firmware while scanning. When the scan
         * STATUS_SCANNING to avoid race when queue_work two times from
         * different notifications, but quit and not perform any work at all.
         */
 -      if (test_bit(STATUS_SCAN_HW, &priv->shrd->status))
 +      if (test_bit(STATUS_SCAN_HW, &priv->status))
                goto out;
  
        iwl_update_chain_flags(priv);
         */
        iwlagn_bt_coex_rssi_monitor(priv);
  out:
 -      mutex_unlock(&priv->shrd->mutex);
 +      mutex_unlock(&priv->mutex);
  }
  
  /*
@@@ -701,16 -700,17 +701,16 @@@ static void iwlagn_set_kill_msk(struct 
                priv->kill_cts_mask = bt_kill_cts_msg[kill_msk];
  
                /* schedule to send runtime bt_config */
 -              queue_work(priv->shrd->workqueue, &priv->bt_runtime_config);
 +              queue_work(priv->workqueue, &priv->bt_runtime_config);
        }
  }
  
  int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
 -                                struct iwl_rx_mem_buffer *rxb,
 +                                struct iwl_rx_cmd_buffer *rxb,
                                  struct iwl_device_cmd *cmd)
  {
 -      unsigned long flags;
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
 -      struct iwl_bt_coex_profile_notif *coex = &pkt->u.bt_coex_profile_notif;
 +      struct iwl_bt_coex_profile_notif *coex = (void *)pkt->data;
        struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg;
  
        if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {
                                        IWL_BT_COEX_TRAFFIC_LOAD_NONE;
                        }
                        priv->bt_status = coex->bt_status;
 -                      queue_work(priv->shrd->workqueue,
 +                      queue_work(priv->workqueue,
                                   &priv->bt_traffic_change_work);
                }
        }
  
        /* FIXME: based on notification, adjust the prio_boost */
  
 -      spin_lock_irqsave(&priv->shrd->lock, flags);
        priv->bt_ci_compliance = coex->bt_ci_compliance;
 -      spin_unlock_irqrestore(&priv->shrd->lock, flags);
        return 0;
  }
  
@@@ -957,7 -959,7 +957,7 @@@ static void iwlagn_wowlan_program_keys(
                               struct ieee80211_key_conf *key,
                               void *_data)
  {
 -      struct iwl_priv *priv = hw->priv;
 +      struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct wowlan_key_data *data = _data;
        struct iwl_rxon_context *ctx = data->ctx;
        struct aes_sc *aes_sc, *aes_tx_sc = NULL;
        u16 p1k[IWLAGN_P1K_SIZE];
        int ret, i;
  
 -      mutex_lock(&priv->shrd->mutex);
 +      mutex_lock(&priv->mutex);
  
        if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
             key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
                break;
        }
  
 -      mutex_unlock(&priv->shrd->mutex);
 +      mutex_unlock(&priv->mutex);
  }
  
  int iwlagn_send_patterns(struct iwl_priv *priv,
        }
  
        cmd.data[0] = pattern_cmd;
 -      err = iwl_trans_send_cmd(trans(priv), &cmd);
 +      err = iwl_dvm_send_cmd(priv, &cmd);
        kfree(pattern_cmd);
        return err;
  }
  
 -int iwlagn_suspend(struct iwl_priv *priv,
 -              struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 +int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan)
  {
        struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd;
        struct iwl_rxon_cmd rxon;
  
        iwl_trans_stop_device(trans(priv));
  
 -      priv->shrd->wowlan = true;
 +      priv->wowlan = true;
  
 -      ret = iwl_load_ucode_wait_alive(trans(priv), IWL_UCODE_WOWLAN);
 +      ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
        if (ret)
                goto out;
  
                 * constraints. Since we're in the suspend path
                 * that isn't really a problem though.
                 */
 -              mutex_unlock(&priv->shrd->mutex);
 +              mutex_unlock(&priv->mutex);
                ieee80211_iter_keys(priv->hw, ctx->vif,
                                    iwlagn_wowlan_program_keys,
                                    &key_data);
 -              mutex_lock(&priv->shrd->mutex);
 +              mutex_lock(&priv->mutex);
                if (key_data.error) {
                        ret = -EIO;
                        goto out;
                                .flags = CMD_SYNC,
                                .data[0] = key_data.rsc_tsc,
                                .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
-                               .len[0] = sizeof(key_data.rsc_tsc),
+                               .len[0] = sizeof(*key_data.rsc_tsc),
                        };
  
 -                      ret = iwl_trans_send_cmd(trans(priv), &rsc_tsc_cmd);
 +                      ret = iwl_dvm_send_cmd(priv, &rsc_tsc_cmd);
                        if (ret)
                                goto out;
                }
  
                if (key_data.use_tkip) {
 -                      ret = iwl_trans_send_cmd_pdu(trans(priv),
 +                      ret = iwl_dvm_send_cmd_pdu(priv,
                                                 REPLY_WOWLAN_TKIP_PARAMS,
                                                 CMD_SYNC, sizeof(tkip_cmd),
                                                 &tkip_cmd);
                        kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
                        kek_kck_cmd.replay_ctr = priv->replay_ctr;
  
 -                      ret = iwl_trans_send_cmd_pdu(trans(priv),
 +                      ret = iwl_dvm_send_cmd_pdu(priv,
                                                 REPLY_WOWLAN_KEK_KCK_MATERIAL,
                                                 CMD_SYNC, sizeof(kek_kck_cmd),
                                                 &kek_kck_cmd);
                }
        }
  
 -      ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_D3_CONFIG, CMD_SYNC,
 +      ret = iwl_dvm_send_cmd_pdu(priv, REPLY_D3_CONFIG, CMD_SYNC,
                                     sizeof(d3_cfg_cmd), &d3_cfg_cmd);
        if (ret)
                goto out;
  
 -      ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WOWLAN_WAKEUP_FILTER,
 +      ret = iwl_dvm_send_cmd_pdu(priv, REPLY_WOWLAN_WAKEUP_FILTER,
                                 CMD_SYNC, sizeof(wakeup_filter_cmd),
                                 &wakeup_filter_cmd);
        if (ret)
        return ret;
  }
  #endif
 +
 +int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 +{
 +      if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
 +              IWL_WARN(priv, "Not sending command - %s KILL\n",
 +                       iwl_is_rfkill(priv) ? "RF" : "CT");
 +              return -EIO;
 +      }
 +
 +      /*
 +       * Synchronous commands from this op-mode must hold
 +       * the mutex, this ensures we don't try to send two
 +       * (or more) synchronous commands at a time.
 +       */
 +      if (cmd->flags & CMD_SYNC)
 +              lockdep_assert_held(&priv->mutex);
 +
 +      if (priv->ucode_owner == IWL_OWNERSHIP_TM &&
 +          !(cmd->flags & CMD_ON_DEMAND)) {
 +              IWL_DEBUG_HC(priv, "tm own the uCode, no regular hcmd send\n");
 +              return -EIO;
 +      }
 +
 +      return iwl_trans_send_cmd(trans(priv), cmd);
 +}
 +
 +int iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id,
 +                       u32 flags, u16 len, const void *data)
 +{
 +      struct iwl_host_cmd cmd = {
 +              .id = id,
 +              .len = { len, },
 +              .data = { data, },
 +              .flags = flags,
 +      };
 +
 +      return iwl_dvm_send_cmd(priv, &cmd);
 +}
diff --combined net/ipv4/route.c
@@@ -132,7 -132,6 +132,6 @@@ static int ip_rt_mtu_expires __read_mos
  static int ip_rt_min_pmtu __read_mostly               = 512 + 20 + 20;
  static int ip_rt_min_advmss __read_mostly     = 256;
  static int rt_chain_length_max __read_mostly  = 20;
- static int redirect_genid;
  
  static struct delayed_work expires_work;
  static unsigned long expires_ljiffies;
@@@ -937,7 -936,7 +936,7 @@@ static void rt_cache_invalidate(struct 
  
        get_random_bytes(&shuffle, sizeof(shuffle));
        atomic_add(shuffle + 1U, &net->ipv4.rt_genid);
-       redirect_genid++;
+       inetpeer_invalidate_tree(AF_INET);
  }
  
  /*
@@@ -1117,17 -1116,12 +1116,17 @@@ static struct neighbour *ipv4_neigh_loo
        static const __be32 inaddr_any = 0;
        struct net_device *dev = dst->dev;
        const __be32 *pkey = daddr;
 +      const struct rtable *rt;
        struct neighbour *n;
  
 +      rt = (const struct rtable *) dst;
 +
        if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
                pkey = &inaddr_any;
 +      else if (rt->rt_gateway)
 +              pkey = (const __be32 *) &rt->rt_gateway;
  
 -      n = __ipv4_neigh_lookup(&arp_tbl, dev, *(__force u32 *)pkey);
 +      n = __ipv4_neigh_lookup(dev, *(__force u32 *)pkey);
        if (n)
                return n;
        return neigh_create(&arp_tbl, pkey, dev);
@@@ -1490,10 -1484,8 +1489,8 @@@ void ip_rt_redirect(__be32 old_gw, __be
  
                                peer = rt->peer;
                                if (peer) {
-                                       if (peer->redirect_learned.a4 != new_gw ||
-                                           peer->redirect_genid != redirect_genid) {
+                                       if (peer->redirect_learned.a4 != new_gw) {
                                                peer->redirect_learned.a4 = new_gw;
-                                               peer->redirect_genid = redirect_genid;
                                                atomic_inc(&__rt_peer_genid);
                                        }
                                        check_peer_redir(&rt->dst, peer);
@@@ -1798,8 -1790,6 +1795,6 @@@ static void ipv4_validate_peer(struct r
                if (peer) {
                        check_peer_pmtu(&rt->dst, peer);
  
-                       if (peer->redirect_genid != redirect_genid)
-                               peer->redirect_learned.a4 = 0;
                        if (peer->redirect_learned.a4 &&
                            peer->redirect_learned.a4 != rt->rt_gateway)
                                check_peer_redir(&rt->dst, peer);
@@@ -1963,8 -1953,7 +1958,7 @@@ static void rt_init_metrics(struct rtab
                dst_init_metrics(&rt->dst, peer->metrics, false);
  
                check_peer_pmtu(&rt->dst, peer);
-               if (peer->redirect_genid != redirect_genid)
-                       peer->redirect_learned.a4 = 0;
                if (peer->redirect_learned.a4 &&
                    peer->redirect_learned.a4 != rt->rt_gateway) {
                        rt->rt_gateway = peer->redirect_learned.a4;
@@@ -44,7 -44,6 +44,7 @@@
  #include <net/netfilter/nf_conntrack_ecache.h>
  #include <net/netfilter/nf_conntrack_zones.h>
  #include <net/netfilter/nf_conntrack_timestamp.h>
 +#include <net/netfilter/nf_conntrack_timeout.h>
  #include <net/netfilter/nf_nat.h>
  #include <net/netfilter/nf_nat_core.h>
  
@@@ -636,8 -635,12 +636,12 @@@ static noinline int early_drop(struct n
  
        if (del_timer(&ct->timeout)) {
                death_by_timeout((unsigned long)ct);
-               dropped = 1;
-               NF_CT_STAT_INC_ATOMIC(net, early_drop);
+               /* Check if we indeed killed this entry. Reliable event
+                  delivery may have inserted it into the dying list. */
+               if (test_bit(IPS_DYING_BIT, &ct->status)) {
+                       dropped = 1;
+                       NF_CT_STAT_INC_ATOMIC(net, early_drop);
+               }
        }
        nf_ct_put(ct);
        return dropped;
@@@ -764,8 -767,7 +768,8 @@@ init_conntrack(struct net *net, struct 
               struct nf_conntrack_l3proto *l3proto,
               struct nf_conntrack_l4proto *l4proto,
               struct sk_buff *skb,
 -             unsigned int dataoff, u32 hash)
 +             unsigned int dataoff, u32 hash,
 +             unsigned int *timeouts)
  {
        struct nf_conn *ct;
        struct nf_conn_help *help;
        if (IS_ERR(ct))
                return (struct nf_conntrack_tuple_hash *)ct;
  
 -      if (!l4proto->new(ct, skb, dataoff)) {
 +      if (!l4proto->new(ct, skb, dataoff, timeouts)) {
                nf_conntrack_free(ct);
                pr_debug("init conntrack: can't track with proto module\n");
                return NULL;
@@@ -850,8 -852,7 +854,8 @@@ resolve_normal_ct(struct net *net, stru
                  struct nf_conntrack_l3proto *l3proto,
                  struct nf_conntrack_l4proto *l4proto,
                  int *set_reply,
 -                enum ip_conntrack_info *ctinfo)
 +                enum ip_conntrack_info *ctinfo,
 +                unsigned int *timeouts)
  {
        struct nf_conntrack_tuple tuple;
        struct nf_conntrack_tuple_hash *h;
        h = __nf_conntrack_find_get(net, zone, &tuple, hash);
        if (!h) {
                h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto,
 -                                 skb, dataoff, hash);
 +                                 skb, dataoff, hash, timeouts);
                if (!h)
                        return NULL;
                if (IS_ERR(h))
@@@ -912,8 -913,6 +916,8 @@@ nf_conntrack_in(struct net *net, u_int8
        enum ip_conntrack_info ctinfo;
        struct nf_conntrack_l3proto *l3proto;
        struct nf_conntrack_l4proto *l4proto;
 +      struct nf_conn_timeout *timeout_ext;
 +      unsigned int *timeouts;
        unsigned int dataoff;
        u_int8_t protonum;
        int set_reply = 0;
                        goto out;
        }
  
 +      /* Decide what timeout policy we want to apply to this flow. */
 +      if (tmpl) {
 +              timeout_ext = nf_ct_timeout_find(tmpl);
 +              if (timeout_ext)
 +                      timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext);
 +              else
 +                      timeouts = l4proto->get_timeouts(net);
 +      } else
 +              timeouts = l4proto->get_timeouts(net);
 +
        ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum,
 -                             l3proto, l4proto, &set_reply, &ctinfo);
 +                             l3proto, l4proto, &set_reply, &ctinfo,
 +                             timeouts);
        if (!ct) {
                /* Not valid part of a connection */
                NF_CT_STAT_INC_ATOMIC(net, invalid);
  
        NF_CT_ASSERT(skb->nfct);
  
 -      ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum);
 +      ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum, timeouts);
        if (ret <= 0) {
                /* Invalid: inverse of the return code tells
                 * the netfilter core what to do */
@@@ -1343,7 -1331,6 +1347,7 @@@ static void nf_conntrack_cleanup_net(st
        }
  
        nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
 +      nf_conntrack_timeout_fini(net);
        nf_conntrack_ecache_fini(net);
        nf_conntrack_tstamp_fini(net);
        nf_conntrack_acct_fini(net);
@@@ -1575,14 -1562,9 +1579,14 @@@ static int nf_conntrack_init_net(struc
        ret = nf_conntrack_ecache_init(net);
        if (ret < 0)
                goto err_ecache;
 +      ret = nf_conntrack_timeout_init(net);
 +      if (ret < 0)
 +              goto err_timeout;
  
        return 0;
  
 +err_timeout:
 +      nf_conntrack_timeout_fini(net);
  err_ecache:
        nf_conntrack_tstamp_fini(net);
  err_tstamp:
@@@ -110,16 -110,15 +110,16 @@@ ctnetlink_dump_tuples(struct sk_buff *s
        struct nf_conntrack_l3proto *l3proto;
        struct nf_conntrack_l4proto *l4proto;
  
 +      rcu_read_lock();
        l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
        ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto);
  
 -      if (unlikely(ret < 0))
 -              return ret;
 -
 -      l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
 -      ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto);
 -
 +      if (ret >= 0) {
 +              l4proto = __nf_ct_l4proto_find(tuple->src.l3num,
 +                                             tuple->dst.protonum);
 +              ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto);
 +      }
 +      rcu_read_unlock();
        return ret;
  }
  
@@@ -692,18 -691,9 +692,18 @@@ static int ctnetlink_done(struct netlin
  {
        if (cb->args[1])
                nf_ct_put((struct nf_conn *)cb->args[1]);
 +      if (cb->data)
 +              kfree(cb->data);
        return 0;
  }
  
 +struct ctnetlink_dump_filter {
 +      struct {
 +              u_int32_t val;
 +              u_int32_t mask;
 +      } mark;
 +};
 +
  static int
  ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
  {
        struct hlist_nulls_node *n;
        struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
        u_int8_t l3proto = nfmsg->nfgen_family;
 +      int res;
 +#ifdef CONFIG_NF_CONNTRACK_MARK
 +      const struct ctnetlink_dump_filter *filter = cb->data;
 +#endif
  
        spin_lock_bh(&nf_conntrack_lock);
        last = (struct nf_conn *)cb->args[1];
@@@ -737,20 -723,11 +737,20 @@@ restart
                                        continue;
                                cb->args[1] = 0;
                        }
 -                      if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
 -                                              cb->nlh->nlmsg_seq,
 -                                              NFNL_MSG_TYPE(
 -                                                      cb->nlh->nlmsg_type),
 -                                              ct) < 0) {
 +#ifdef CONFIG_NF_CONNTRACK_MARK
 +                      if (filter && !((ct->mark & filter->mark.mask) ==
 +                                      filter->mark.val)) {
 +                              continue;
 +                      }
 +#endif
 +                      rcu_read_lock();
 +                      res =
 +                      ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
 +                                          cb->nlh->nlmsg_seq,
 +                                          NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
 +                                          ct);
 +                      rcu_read_unlock();
 +                      if (res < 0) {
                                nf_conntrack_get(&ct->ct_general);
                                cb->args[1] = (unsigned long)ct;
                                goto out;
@@@ -917,7 -894,6 +917,7 @@@ static const struct nla_policy ct_nla_p
        [CTA_NAT_DST]           = { .type = NLA_NESTED },
        [CTA_TUPLE_MASTER]      = { .type = NLA_NESTED },
        [CTA_ZONE]              = { .type = NLA_U16 },
 +      [CTA_MARK_MASK]         = { .type = NLA_U32 },
  };
  
  static int
@@@ -1001,28 -977,9 +1001,28 @@@ ctnetlink_get_conntrack(struct sock *ct
        u16 zone;
        int err;
  
 -      if (nlh->nlmsg_flags & NLM_F_DUMP)
 -              return netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table,
 -                                        ctnetlink_done, 0);
 +      if (nlh->nlmsg_flags & NLM_F_DUMP) {
 +              struct netlink_dump_control c = {
 +                      .dump = ctnetlink_dump_table,
 +                      .done = ctnetlink_done,
 +              };
 +#ifdef CONFIG_NF_CONNTRACK_MARK
 +              if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) {
 +                      struct ctnetlink_dump_filter *filter;
 +
 +                      filter = kzalloc(sizeof(struct ctnetlink_dump_filter),
 +                                       GFP_ATOMIC);
 +                      if (filter == NULL)
 +                              return -ENOMEM;
 +
 +                      filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK]));
 +                      filter->mark.mask =
 +                              ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
 +                      c.data = filter;
 +              }
 +#endif
 +              return netlink_dump_start(ctnl, skb, nlh, &c);
 +      }
  
        err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
        if (err < 0)
@@@ -1084,16 -1041,13 +1084,13 @@@ ctnetlink_parse_nat_setup(struct nf_con
        if (!parse_nat_setup) {
  #ifdef CONFIG_MODULES
                rcu_read_unlock();
                nfnl_unlock();
                if (request_module("nf-nat-ipv4") < 0) {
                        nfnl_lock();
-                       spin_lock_bh(&nf_conntrack_lock);
                        rcu_read_lock();
                        return -EOPNOTSUPP;
                }
                nfnl_lock();
-               spin_lock_bh(&nf_conntrack_lock);
                rcu_read_lock();
                if (nfnetlink_parse_nat_setup_hook)
                        return -EAGAIN;
@@@ -1655,16 -1609,14 +1652,16 @@@ ctnetlink_exp_dump_mask(struct sk_buff 
        if (!nest_parms)
                goto nla_put_failure;
  
 +      rcu_read_lock();
        l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
        ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto);
 -
 -      if (unlikely(ret < 0))
 -              goto nla_put_failure;
 -
 -      l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
 +      if (ret >= 0) {
 +              l4proto = __nf_ct_l4proto_find(tuple->src.l3num,
 +                                             tuple->dst.protonum);
        ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto);
 +      }
 +      rcu_read_unlock();
 +
        if (unlikely(ret < 0))
                goto nla_put_failure;
  
@@@ -1683,11 -1635,6 +1680,11 @@@ ctnetlink_exp_dump_expect(struct sk_buf
        struct nf_conn *master = exp->master;
        long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ;
        struct nf_conn_help *help;
 +#ifdef CONFIG_NF_NAT_NEEDED
 +      struct nlattr *nest_parms;
 +      struct nf_conntrack_tuple nat_tuple = {};
 +#endif
 +      struct nf_ct_helper_expectfn *expfn;
  
        if (timeout < 0)
                timeout = 0;
                                 CTA_EXPECT_MASTER) < 0)
                goto nla_put_failure;
  
 +#ifdef CONFIG_NF_NAT_NEEDED
 +      if (exp->saved_ip || exp->saved_proto.all) {
 +              nest_parms = nla_nest_start(skb, CTA_EXPECT_NAT | NLA_F_NESTED);
 +              if (!nest_parms)
 +                      goto nla_put_failure;
 +
 +              NLA_PUT_BE32(skb, CTA_EXPECT_NAT_DIR, htonl(exp->dir));
 +
 +              nat_tuple.src.l3num = nf_ct_l3num(master);
 +              nat_tuple.src.u3.ip = exp->saved_ip;
 +              nat_tuple.dst.protonum = nf_ct_protonum(master);
 +              nat_tuple.src.u = exp->saved_proto;
 +
 +              if (ctnetlink_exp_dump_tuple(skb, &nat_tuple,
 +                                              CTA_EXPECT_NAT_TUPLE) < 0)
 +                      goto nla_put_failure;
 +              nla_nest_end(skb, nest_parms);
 +      }
 +#endif
        NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout));
        NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp));
        NLA_PUT_BE32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags));
 +      NLA_PUT_BE32(skb, CTA_EXPECT_CLASS, htonl(exp->class));
        help = nfct_help(master);
        if (help) {
                struct nf_conntrack_helper *helper;
                if (helper)
                        NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name);
        }
 +      expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn);
 +      if (expfn != NULL)
 +              NLA_PUT_STRING(skb, CTA_EXPECT_FN, expfn->name);
  
        return 0;
  
@@@ -1892,9 -1816,6 +1889,9 @@@ static const struct nla_policy exp_nla_
        [CTA_EXPECT_HELP_NAME]  = { .type = NLA_NUL_STRING },
        [CTA_EXPECT_ZONE]       = { .type = NLA_U16 },
        [CTA_EXPECT_FLAGS]      = { .type = NLA_U32 },
 +      [CTA_EXPECT_CLASS]      = { .type = NLA_U32 },
 +      [CTA_EXPECT_NAT]        = { .type = NLA_NESTED },
 +      [CTA_EXPECT_FN]         = { .type = NLA_NUL_STRING },
  };
  
  static int
@@@ -1912,11 -1833,9 +1909,11 @@@ ctnetlink_get_expect(struct sock *ctnl
        int err;
  
        if (nlh->nlmsg_flags & NLM_F_DUMP) {
 -              return netlink_dump_start(ctnl, skb, nlh,
 -                                        ctnetlink_exp_dump_table,
 -                                        ctnetlink_exp_done, 0);
 +              struct netlink_dump_control c = {
 +                      .dump = ctnetlink_exp_dump_table,
 +                      .done = ctnetlink_exp_done,
 +              };
 +              return netlink_dump_start(ctnl, skb, nlh, &c);
        }
  
        err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
@@@ -2070,41 -1989,6 +2067,41 @@@ ctnetlink_change_expect(struct nf_connt
        return -EOPNOTSUPP;
  }
  
 +static const struct nla_policy exp_nat_nla_policy[CTA_EXPECT_NAT_MAX+1] = {
 +      [CTA_EXPECT_NAT_DIR]    = { .type = NLA_U32 },
 +      [CTA_EXPECT_NAT_TUPLE]  = { .type = NLA_NESTED },
 +};
 +
 +static int
 +ctnetlink_parse_expect_nat(const struct nlattr *attr,
 +                         struct nf_conntrack_expect *exp,
 +                         u_int8_t u3)
 +{
 +#ifdef CONFIG_NF_NAT_NEEDED
 +      struct nlattr *tb[CTA_EXPECT_NAT_MAX+1];
 +      struct nf_conntrack_tuple nat_tuple = {};
 +      int err;
 +
 +      nla_parse_nested(tb, CTA_EXPECT_NAT_MAX, attr, exp_nat_nla_policy);
 +
 +      if (!tb[CTA_EXPECT_NAT_DIR] || !tb[CTA_EXPECT_NAT_TUPLE])
 +              return -EINVAL;
 +
 +      err = ctnetlink_parse_tuple((const struct nlattr * const *)tb,
 +                                      &nat_tuple, CTA_EXPECT_NAT_TUPLE, u3);
 +      if (err < 0)
 +              return err;
 +
 +      exp->saved_ip = nat_tuple.src.u3.ip;
 +      exp->saved_proto = nat_tuple.src.u;
 +      exp->dir = ntohl(nla_get_be32(tb[CTA_EXPECT_NAT_DIR]));
 +
 +      return 0;
 +#else
 +      return -EOPNOTSUPP;
 +#endif
 +}
 +
  static int
  ctnetlink_create_expect(struct net *net, u16 zone,
                        const struct nlattr * const cda[],
        struct nf_conntrack_expect *exp;
        struct nf_conn *ct;
        struct nf_conn_help *help;
 +      struct nf_conntrack_helper *helper = NULL;
 +      u_int32_t class = 0;
        int err = 0;
  
        /* caller guarantees that those three CTA_EXPECT_* exist */
        if (!h)
                return -ENOENT;
        ct = nf_ct_tuplehash_to_ctrack(h);
 +
 +      /* Look for helper of this expectation */
 +      if (cda[CTA_EXPECT_HELP_NAME]) {
 +              const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
 +
 +              helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
 +                                                  nf_ct_protonum(ct));
 +              if (helper == NULL) {
 +#ifdef CONFIG_MODULES
 +                      if (request_module("nfct-helper-%s", helpname) < 0) {
 +                              err = -EOPNOTSUPP;
 +                              goto out;
 +                      }
 +
 +                      helper = __nf_conntrack_helper_find(helpname,
 +                                                          nf_ct_l3num(ct),
 +                                                          nf_ct_protonum(ct));
 +                      if (helper) {
 +                              err = -EAGAIN;
 +                              goto out;
 +                      }
 +#endif
 +                      err = -EOPNOTSUPP;
 +                      goto out;
 +              }
 +      }
 +
 +      if (cda[CTA_EXPECT_CLASS] && helper) {
 +              class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS]));
 +              if (class > helper->expect_class_max) {
 +                      err = -EINVAL;
 +                      goto out;
 +              }
 +      }
        exp = nf_ct_expect_alloc(ct);
        if (!exp) {
                err = -ENOMEM;
                } else
                        exp->flags = 0;
        }
 +      if (cda[CTA_EXPECT_FN]) {
 +              const char *name = nla_data(cda[CTA_EXPECT_FN]);
 +              struct nf_ct_helper_expectfn *expfn;
 +
 +              expfn = nf_ct_helper_expectfn_find_by_name(name);
 +              if (expfn == NULL) {
 +                      err = -EINVAL;
 +                      goto err_out;
 +              }
 +              exp->expectfn = expfn->expectfn;
 +      } else
 +              exp->expectfn = NULL;
  
 -      exp->class = 0;
 -      exp->expectfn = NULL;
 +      exp->class = class;
        exp->master = ct;
 -      exp->helper = NULL;
 +      exp->helper = helper;
        memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple));
        memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3));
        exp->mask.src.u.all = mask.src.u.all;
  
 +      if (cda[CTA_EXPECT_NAT]) {
 +              err = ctnetlink_parse_expect_nat(cda[CTA_EXPECT_NAT],
 +                                               exp, u3);
 +              if (err < 0)
 +                      goto err_out;
 +      }
        err = nf_ct_expect_related_report(exp, pid, report);
 +err_out:
        nf_ct_expect_put(exp);
 -
  out:
        nf_ct_put(nf_ct_tuplehash_to_ctrack(h));
        return err;