]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
authorDavid S. Miller <davem@davemloft.net>
Tue, 17 Mar 2009 22:01:30 +0000 (15:01 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 17 Mar 2009 22:01:30 +0000 (15:01 -0700)
Conflicts:
drivers/net/igb/igb_main.c
drivers/net/qlge/qlge_main.c
drivers/net/wireless/ath9k/ath9k.h
drivers/net/wireless/ath9k/core.h
drivers/net/wireless/ath9k/hw.c

19 files changed:
1  2 
MAINTAINERS
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/igb/igb_main.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/mv643xx_eth.c
drivers/net/netxen/netxen_nic.h
drivers/net/netxen/netxen_nic_hw.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/qlge/qlge_main.c
drivers/net/r8169.c
drivers/net/wireless/ath9k/ath9k.h
drivers/net/wireless/ath9k/hw.c
drivers/net/wireless/ath9k/hw.h
drivers/net/wireless/ath9k/main.c
drivers/net/wireless/zd1211rw/zd_mac.c
net/core/dev.c
net/ipv6/af_inet6.c
net/mac80211/tx.c

diff --combined MAINTAINERS
index 0d9ea2a4e4975d40c1dab8532f21ae98cd0b916f,43934437511bc0c73586ff0457fcf4edf117e180..27114518eb05b4f82957b1fd126447227225bfcc
@@@ -1011,8 -1011,6 +1011,8 @@@ L:      netdev@vger.kernel.or
  S:    Supported
  
  BROADCOM TG3 GIGABIT ETHERNET DRIVER
 +P:    Matt Carlson
 +M:    mcarlson@broadcom.com
  P:    Michael Chan
  M:    mchan@broadcom.com
  L:    netdev@vger.kernel.org
@@@ -3641,12 -3639,6 +3641,12 @@@ M:    florian.fainelli@telecomint.e
  L:    netdev@vger.kernel.org
  S:    Maintained
  
 +RDS - RELIABLE DATAGRAM SOCKETS
 +P:    Andy Grover
 +M:    andy.grover@oracle.com
 +L:    rds-devel@oss.oracle.com
 +S:    Supported
 +
  READ-COPY UPDATE (RCU)
  P:    Dipankar Sarma
  M:    dipankar@in.ibm.com
@@@ -3888,6 -3880,15 +3888,15 @@@ L:    linux-ide@vger.kernel.or
  T:    git kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
  S:    Supported
  
+ SERVER ENGINES 10Gbps NIC - BladeEngine 2 DRIVER
+ P:    Sathya Perla
+ M:    sathyap@serverengines.com
+ P:      Subbu Seetharaman
+ M:      subbus@serverengines.com
+ L:      netdev@vger.kernel.org
+ W:      http://www.serverengines.com
+ S:      Supported
  SFC NETWORK DRIVER
  P:    Steve Hodgson
  P:    Ben Hutchings
diff --combined drivers/net/Kconfig
index 45403e67e351059fd5cca16ae61ef3e1199fab06,435e2e3a82c84a076c8dd3e20aa7bf1851df9ea3..6b1af549b2ff36267cbc03394096954f05607bdb
@@@ -1040,6 -1040,17 +1040,17 @@@ config NI6
          To compile this driver as a module, choose M here. The module
          will be called ni65.
  
+ config DNET
+       tristate "Dave ethernet support (DNET)"
+       depends on NET_ETHERNET
+       select PHYLIB
+       help
+         The Dave ethernet interface (DNET) is found on Qong Board FPGA.
+         Say Y to include support for the DNET chip.
+         To compile this driver as a module, choose M here: the module
+         will be called dnet.
  source "drivers/net/tulip/Kconfig"
  
  config AT1700
@@@ -1829,10 -1840,10 +1840,10 @@@ config 68360_ENE
  
  config FEC
        bool "FEC ethernet controller (of ColdFire CPUs)"
 -      depends on M523x || M527x || M5272 || M528x || M520x || M532x
 +      depends on M523x || M527x || M5272 || M528x || M520x || M532x || MACH_MX27
        help
          Say Y here if you want to use the built-in 10/100 Fast ethernet
 -        controller on some Motorola ColdFire processors.
 +        controller on some Motorola ColdFire and Freescale i.MX processors.
  
  config FEC2
        bool "Second FEC ethernet controller (on some ColdFire CPUs)"
@@@ -2019,6 -2030,15 +2030,6 @@@ config IG
           To compile this driver as a module, choose M here. The module
           will be called igb.
  
 -config IGB_LRO 
 -      bool "Use software LRO"
 -      depends on IGB && INET
 -      select INET_LRO
 -      ---help---
 -        Say Y here if you want to use large receive offload. 
 -
 -        If in doubt, say N.
 -
  config IGB_DCA
        bool "Direct Cache Access (DCA) Support"
        default y
@@@ -2264,17 -2284,9 +2275,17 @@@ config GELIC_WIRELESS_OLD_PSK_INTERFAC
  
            If unsure, say N.
  
 +config FSL_PQ_MDIO
 +      tristate "Freescale PQ MDIO"
 +      depends on FSL_SOC
 +      select PHYLIB
 +      help
 +        This driver supports the MDIO bus used by the gianfar and UCC drivers.
 +
  config GIANFAR
        tristate "Gianfar Ethernet"
        depends on FSL_SOC
 +      select FSL_PQ_MDIO
        select PHYLIB
        select CRC32
        help
  config UCC_GETH
        tristate "Freescale QE Gigabit Ethernet"
        depends on QUICC_ENGINE
 +      select FSL_PQ_MDIO
        select PHYLIB
        help
          This driver supports the Gigabit Ethernet mode of the QUICC Engine,
@@@ -2301,7 -2312,6 +2312,7 @@@ config UGETH_TX_ON_DEMAN
  config MV643XX_ETH
        tristate "Marvell Discovery (643XX) and Orion ethernet support"
        depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || PLAT_ORION
 +      select INET_LRO
        select PHYLIB
        help
          This driver supports the gigabit ethernet MACs in the
@@@ -2420,6 -2430,7 +2431,6 @@@ config CHELSIO_T
        tristate "Chelsio Communications T3 10Gb Ethernet support"
        depends on CHELSIO_T3_DEPENDS
        select FW_LOADER
 -      select INET_LRO
        help
          This driver supports Chelsio T3-based gigabit and 10Gb Ethernet
          adapters.
@@@ -2455,6 -2466,7 +2466,6 @@@ config ENI
  config IXGBE
        tristate "Intel(R) 10GbE PCI Express adapters support"
        depends on PCI && INET
 -      select INET_LRO
        ---help---
          This driver supports Intel(R) 10GbE PCI Express family of
          adapters.  For more information on how to identify your adapter, go
@@@ -2618,6 -2630,8 +2629,8 @@@ config QLG
  
  source "drivers/net/sfc/Kconfig"
  
+ source "drivers/net/benet/Kconfig"
  endif # NETDEV_10000
  
  source "drivers/net/tokenring/Kconfig"
diff --combined drivers/net/Makefile
index 3f8cb311e077668ba0ea0866667aa7d37f49c5f6,471baaff229ff4e0a9363eaa884806714d1ed634..758ecdf4c8202d492f9ec683d696a6834e09262a
@@@ -22,15 -22,15 +22,16 @@@ obj-$(CONFIG_GIANFAR) += gianfar_driver
  obj-$(CONFIG_TEHUTI) += tehuti.o
  obj-$(CONFIG_ENIC) += enic/
  obj-$(CONFIG_JME) += jme.o
+ obj-$(CONFIG_BE2NET) += benet/
  
  gianfar_driver-objs := gianfar.o \
                gianfar_ethtool.o \
 -              gianfar_mii.o \
                gianfar_sysfs.o
  
  obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
 -ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o ucc_geth_ethtool.o
 +ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o
 +
 +obj-$(CONFIG_FSL_PQ_MDIO) += fsl_pq_mdio.o
  
  #
  # link order important here
@@@ -232,6 -232,7 +233,7 @@@ obj-$(CONFIG_ENC28J60) += enc28j60.
  
  obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o
  
+ obj-$(CONFIG_DNET) += dnet.o
  obj-$(CONFIG_MACB) += macb.o
  
  obj-$(CONFIG_ARM) += arm/
index 7124f59fb99fdb59527da0be1fc0776b1c04f6ef,9dd13ad12ce48a502469c96474e8210ccb5c00a1..7c4481b994abedfb186ade8f2684ec38ea768870
@@@ -1,7 -1,7 +1,7 @@@
  /*******************************************************************************
  
    Intel(R) Gigabit Ethernet Linux driver
 -  Copyright(c) 2007 Intel Corporation.
 +  Copyright(c) 2007-2009 Intel Corporation.
  
    This program is free software; you can redistribute it and/or modify it
    under the terms and conditions of the GNU General Public License,
@@@ -34,7 -34,6 +34,7 @@@
  #include <linux/ipv6.h>
  #include <net/checksum.h>
  #include <net/ip6_checksum.h>
 +#include <linux/net_tstamp.h>
  #include <linux/mii.h>
  #include <linux/ethtool.h>
  #include <linux/if_vlan.h>
  #endif
  #include "igb.h"
  
 -#define DRV_VERSION "1.2.45-k2"
 +#define DRV_VERSION "1.3.16-k2"
  char igb_driver_name[] = "igb";
  char igb_driver_version[] = DRV_VERSION;
  static const char igb_driver_string[] =
                                "Intel(R) Gigabit Ethernet Network Driver";
 -static const char igb_copyright[] = "Copyright (c) 2008 Intel Corporation.";
 +static const char igb_copyright[] = "Copyright (c) 2007-2009 Intel Corporation.";
  
  static const struct e1000_info *igb_info_tbl[] = {
        [board_82575] = &e1000_82575_info,
  
  static struct pci_device_id igb_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576), board_82575 },
 +      { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 },
 +      { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER), board_82575 },
@@@ -108,6 -105,7 +108,6 @@@ static irqreturn_t igb_intr_msi(int irq
  static irqreturn_t igb_msix_other(int irq, void *);
  static irqreturn_t igb_msix_rx(int irq, void *);
  static irqreturn_t igb_msix_tx(int irq, void *);
 -static int igb_clean_rx_ring_msix(struct napi_struct *, int);
  #ifdef CONFIG_IGB_DCA
  static void igb_update_rx_dca(struct igb_ring *);
  static void igb_update_tx_dca(struct igb_ring *);
@@@ -117,6 -115,9 +117,6 @@@ static bool igb_clean_tx_irq(struct igb
  static int igb_poll(struct napi_struct *, int);
  static bool igb_clean_rx_irq_adv(struct igb_ring *, int *, int);
  static void igb_alloc_rx_buffers_adv(struct igb_ring *, int);
 -#ifdef CONFIG_IGB_LRO
 -static int igb_get_skb_hdr(struct sk_buff *skb, void **, void **, u64 *, void *);
 -#endif
  static int igb_ioctl(struct net_device *, struct ifreq *, int cmd);
  static void igb_tx_timeout(struct net_device *);
  static void igb_reset_task(struct work_struct *);
@@@ -124,16 -125,6 +124,16 @@@ static void igb_vlan_rx_register(struc
  static void igb_vlan_rx_add_vid(struct net_device *, u16);
  static void igb_vlan_rx_kill_vid(struct net_device *, u16);
  static void igb_restore_vlan(struct igb_adapter *);
 +static void igb_ping_all_vfs(struct igb_adapter *);
 +static void igb_msg_task(struct igb_adapter *);
 +static int igb_rcv_msg_from_vf(struct igb_adapter *, u32);
 +static inline void igb_set_rah_pool(struct e1000_hw *, int , int);
 +static void igb_set_mc_list_pools(struct igb_adapter *, int, u16);
 +static void igb_vmm_control(struct igb_adapter *);
 +static inline void igb_set_vmolr(struct e1000_hw *, int);
 +static inline int igb_set_vf_rlpml(struct igb_adapter *, int, int);
 +static int igb_set_vf_mac(struct igb_adapter *adapter, int, unsigned char *);
 +static void igb_restore_vf_multicasts(struct igb_adapter *adapter);
  
  static int igb_suspend(struct pci_dev *, pm_message_t);
  #ifdef CONFIG_PM
@@@ -148,18 -139,12 +148,18 @@@ static struct notifier_block dca_notifi
        .priority       = 0
  };
  #endif
 -
  #ifdef CONFIG_NET_POLL_CONTROLLER
  /* for netdump / net console */
  static void igb_netpoll(struct net_device *);
  #endif
  
 +#ifdef CONFIG_PCI_IOV
 +static ssize_t igb_set_num_vfs(struct device *, struct device_attribute *,
 +                               const char *, size_t);
 +static ssize_t igb_show_num_vfs(struct device *, struct device_attribute *,
 +                               char *);
 +DEVICE_ATTR(num_vfs, S_IRUGO | S_IWUSR, igb_show_num_vfs, igb_set_num_vfs);
 +#endif
  static pci_ers_result_t igb_io_error_detected(struct pci_dev *,
                     pci_channel_state_t);
  static pci_ers_result_t igb_io_slot_reset(struct pci_dev *);
@@@ -193,54 -178,6 +193,54 @@@ MODULE_DESCRIPTION("Intel(R) Gigabit Et
  MODULE_LICENSE("GPL");
  MODULE_VERSION(DRV_VERSION);
  
 +/**
 + * Scale the NIC clock cycle by a large factor so that
 + * relatively small clock corrections can be added or
 + * substracted at each clock tick. The drawbacks of a
 + * large factor are a) that the clock register overflows
 + * more quickly (not such a big deal) and b) that the
 + * increment per tick has to fit into 24 bits.
 + *
 + * Note that
 + *   TIMINCA = IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS *
 + *             IGB_TSYNC_SCALE
 + *   TIMINCA += TIMINCA * adjustment [ppm] / 1e9
 + *
 + * The base scale factor is intentionally a power of two
 + * so that the division in %struct timecounter can be done with
 + * a shift.
 + */
 +#define IGB_TSYNC_SHIFT (19)
 +#define IGB_TSYNC_SCALE (1<<IGB_TSYNC_SHIFT)
 +
 +/**
 + * The duration of one clock cycle of the NIC.
 + *
 + * @todo This hard-coded value is part of the specification and might change
 + * in future hardware revisions. Add revision check.
 + */
 +#define IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS 16
 +
 +#if (IGB_TSYNC_SCALE * IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS) >= (1<<24)
 +# error IGB_TSYNC_SCALE and/or IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS are too large to fit into TIMINCA
 +#endif
 +
 +/**
 + * igb_read_clock - read raw cycle counter (to be used by time counter)
 + */
 +static cycle_t igb_read_clock(const struct cyclecounter *tc)
 +{
 +      struct igb_adapter *adapter =
 +              container_of(tc, struct igb_adapter, cycles);
 +      struct e1000_hw *hw = &adapter->hw;
 +      u64 stamp;
 +
 +      stamp =  rd32(E1000_SYSTIML);
 +      stamp |= (u64)rd32(E1000_SYSTIMH) << 32ULL;
 +
 +      return stamp;
 +}
 +
  #ifdef DEBUG
  /**
   * igb_get_hw_dev_name - return device name string
@@@ -251,30 -188,6 +251,30 @@@ char *igb_get_hw_dev_name(struct e1000_
        struct igb_adapter *adapter = hw->back;
        return adapter->netdev->name;
  }
 +
 +/**
 + * igb_get_time_str - format current NIC and system time as string
 + */
 +static char *igb_get_time_str(struct igb_adapter *adapter,
 +                            char buffer[160])
 +{
 +      cycle_t hw = adapter->cycles.read(&adapter->cycles);
 +      struct timespec nic = ns_to_timespec(timecounter_read(&adapter->clock));
 +      struct timespec sys;
 +      struct timespec delta;
 +      getnstimeofday(&sys);
 +
 +      delta = timespec_sub(nic, sys);
 +
 +      sprintf(buffer,
 +              "HW %llu, NIC %ld.%09lus, SYS %ld.%09lus, NIC-SYS %lds + %09luns",
 +              hw,
 +              (long)nic.tv_sec, nic.tv_nsec,
 +              (long)sys.tv_sec, sys.tv_nsec,
 +              (long)delta.tv_sec, delta.tv_nsec);
 +
 +      return buffer;
 +}
  #endif
  
  /**
@@@ -330,7 -243,6 +330,7 @@@ module_exit(igb_exit_module)
  static void igb_cache_ring_register(struct igb_adapter *adapter)
  {
        int i;
 +      unsigned int rbase_offset = adapter->vfs_allocated_count;
  
        switch (adapter->hw.mac.type) {
        case e1000_82576:
                 * and continue consuming queues in the same sequence
                 */
                for (i = 0; i < adapter->num_rx_queues; i++)
 -                      adapter->rx_ring[i].reg_idx = Q_IDX_82576(i);
 +                      adapter->rx_ring[i].reg_idx = rbase_offset +
 +                                                    Q_IDX_82576(i);
                for (i = 0; i < adapter->num_tx_queues; i++)
 -                      adapter->tx_ring[i].reg_idx = Q_IDX_82576(i);
 +                      adapter->tx_ring[i].reg_idx = rbase_offset +
 +                                                    Q_IDX_82576(i);
                break;
        case e1000_82575:
        default:
@@@ -444,7 -354,7 +444,7 @@@ static void igb_assign_vector(struct ig
                   a vector number along with a "valid" bit.  Sadly, the layout
                   of the table is somewhat counterintuitive. */
                if (rx_queue > IGB_N0_QUEUE) {
 -                      index = (rx_queue >> 1);
 +                      index = (rx_queue >> 1) + adapter->vfs_allocated_count;
                        ivar = array_rd32(E1000_IVAR0, index);
                        if (rx_queue & 0x1) {
                                /* vector goes into third byte of register */
                        array_wr32(E1000_IVAR0, index, ivar);
                }
                if (tx_queue > IGB_N0_QUEUE) {
 -                      index = (tx_queue >> 1);
 +                      index = (tx_queue >> 1) + adapter->vfs_allocated_count;
                        ivar = array_rd32(E1000_IVAR0, index);
                        if (tx_queue & 0x1) {
                                /* vector goes into high byte of register */
@@@ -497,7 -407,7 +497,7 @@@ static void igb_configure_msix(struct i
                /* Turn on MSI-X capability first, or our settings
                 * won't stick.  And it will take days to debug. */
                wr32(E1000_GPIE, E1000_GPIE_MSIX_MODE |
 -                                 E1000_GPIE_PBA | E1000_GPIE_EIAME | 
 +                                 E1000_GPIE_PBA | E1000_GPIE_EIAME |
                                   E1000_GPIE_NSICR);
  
        for (i = 0; i < adapter->num_tx_queues; i++) {
@@@ -596,6 -506,9 +596,6 @@@ static int igb_request_msix(struct igb_
                        goto out;
                ring->itr_register = E1000_EITR(0) + (vector << 2);
                ring->itr_val = adapter->itr;
 -              /* overwrite the poll routine for MSIX, we've already done
 -               * netif_napi_add */
 -              ring->napi.poll = &igb_clean_rx_ring_msix;
                vector++;
        }
  
@@@ -633,11 -546,6 +633,11 @@@ static void igb_set_interrupt_capabilit
        int err;
        int numvecs, i;
  
 +      /* Number of supported queues. */
 +      /* Having more queues than CPUs doesn't make sense. */
 +      adapter->num_rx_queues = min_t(u32, IGB_MAX_RX_QUEUES, num_online_cpus());
 +      adapter->num_tx_queues = min_t(u32, IGB_MAX_TX_QUEUES, num_online_cpus());
 +
        numvecs = adapter->num_tx_queues + adapter->num_rx_queues + 1;
        adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry),
                                        GFP_KERNEL);
@@@ -779,10 -687,7 +779,10 @@@ static void igb_irq_enable(struct igb_a
                wr32(E1000_EIAC, adapter->eims_enable_mask);
                wr32(E1000_EIAM, adapter->eims_enable_mask);
                wr32(E1000_EIMS, adapter->eims_enable_mask);
 -              wr32(E1000_IMS, E1000_IMS_LSC);
 +              if (adapter->vfs_allocated_count)
 +                      wr32(E1000_MBVFIMR, 0xFF);
 +              wr32(E1000_IMS, (E1000_IMS_LSC | E1000_IMS_VMMB |
 +                               E1000_IMS_DOUTSYNC));
        } else {
                wr32(E1000_IMS, IMS_ENABLE_MASK);
                wr32(E1000_IAM, IMS_ENABLE_MASK);
@@@ -906,10 -811,6 +906,10 @@@ int igb_up(struct igb_adapter *adapter
        if (adapter->msix_entries)
                igb_configure_msix(adapter);
  
 +      igb_vmm_control(adapter);
 +      igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0);
 +      igb_set_vmolr(hw, adapter->vfs_allocated_count);
 +
        /* Clear any pending interrupts. */
        rd32(E1000_ICR);
        igb_irq_enable(adapter);
@@@ -955,10 -856,6 +955,10 @@@ void igb_down(struct igb_adapter *adapt
  
        netdev->tx_queue_len = adapter->tx_queue_len;
        netif_carrier_off(netdev);
 +
 +      /* record the stats before reset*/
 +      igb_update_stats(adapter);
 +
        adapter->link_speed = 0;
        adapter->link_duplex = 0;
  
@@@ -989,14 -886,11 +989,14 @@@ void igb_reset(struct igb_adapter *adap
        /* Repartition Pba for greater than 9k mtu
         * To take effect CTRL.RST is required.
         */
 -      if (mac->type != e1000_82576) {
 -      pba = E1000_PBA_34K;
 -      }
 -      else {
 +      switch (mac->type) {
 +      case e1000_82576:
                pba = E1000_PBA_64K;
 +              break;
 +      case e1000_82575:
 +      default:
 +              pba = E1000_PBA_34K;
 +              break;
        }
  
        if ((adapter->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) &&
                /* the tx fifo also stores 16 bytes of information about the tx
                 * but don't include ethernet FCS because hardware appends it */
                min_tx_space = (adapter->max_frame_size +
 -                              sizeof(struct e1000_tx_desc) -
 +                              sizeof(union e1000_adv_tx_desc) -
                                ETH_FCS_LEN) * 2;
                min_tx_space = ALIGN(min_tx_space, 1024);
                min_tx_space >>= 10;
        fc->send_xon = 1;
        fc->type = fc->original_type;
  
 +      /* disable receive for all VFs and wait one second */
 +      if (adapter->vfs_allocated_count) {
 +              int i;
 +              for (i = 0 ; i < adapter->vfs_allocated_count; i++)
 +                      adapter->vf_data[i].clear_to_send = false;
 +
 +              /* ping all the active vfs to let them know we are going down */
 +                      igb_ping_all_vfs(adapter);
 +
 +              /* disable transmits and receives */
 +              wr32(E1000_VFRE, 0);
 +              wr32(E1000_VFTE, 0);
 +      }
 +
        /* Allow time for pending master requests to run */
        adapter->hw.mac.ops.reset_hw(&adapter->hw);
        wr32(E1000_WUC, 0);
        igb_get_phy_info(&adapter->hw);
  }
  
 -/**
 - * igb_is_need_ioport - determine if an adapter needs ioport resources or not
 - * @pdev: PCI device information struct
 - *
 - * Returns true if an adapter needs ioport resources
 - **/
 -static int igb_is_need_ioport(struct pci_dev *pdev)
 -{
 -      switch (pdev->device) {
 -      /* Currently there are no adapters that need ioport resources */
 -      default:
 -              return false;
 -      }
 -}
 -
  static const struct net_device_ops igb_netdev_ops = {
        .ndo_open               = igb_open,
        .ndo_stop               = igb_close,
@@@ -1128,15 -1023,23 +1128,14 @@@ static int __devinit igb_probe(struct p
        struct net_device *netdev;
        struct igb_adapter *adapter;
        struct e1000_hw *hw;
-       struct pci_dev *us_dev;
        const struct e1000_info *ei = igb_info_tbl[ent->driver_data];
        unsigned long mmio_start, mmio_len;
-       int err, pci_using_dac, pos;
-       u16 eeprom_data = 0, state = 0;
 -      int i, err, pci_using_dac;
++      int err, pci_using_dac;
+       u16 eeprom_data = 0;
        u16 eeprom_apme_mask = IGB_EEPROM_APME;
        u32 part_num;
 -      int bars, need_ioport;
  
 -      /* do not allocate ioport bars when not needed */
 -      need_ioport = igb_is_need_ioport(pdev);
 -      if (need_ioport) {
 -              bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO);
 -              err = pci_enable_device(pdev);
 -      } else {
 -              bars = pci_select_bars(pdev, IORESOURCE_MEM);
 -              err = pci_enable_device_mem(pdev);
 -      }
 +      err = pci_enable_device_mem(pdev);
        if (err)
                return err;
  
                }
        }
  
-       /* 82575 requires that the pci-e link partner disable the L0s state */
-       switch (pdev->device) {
-       case E1000_DEV_ID_82575EB_COPPER:
-       case E1000_DEV_ID_82575EB_FIBER_SERDES:
-       case E1000_DEV_ID_82575GB_QUAD_COPPER:
-               us_dev = pdev->bus->self;
-               pos = pci_find_capability(us_dev, PCI_CAP_ID_EXP);
-               if (pos) {
-                       pci_read_config_word(us_dev, pos + PCI_EXP_LNKCTL,
-                                            &state);
-                       state &= ~PCIE_LINK_STATE_L0S;
-                       pci_write_config_word(us_dev, pos + PCI_EXP_LNKCTL,
-                                             state);
-                       dev_info(&pdev->dev,
-                                "Disabling ASPM L0s upstream switch port %s\n",
-                                pci_name(us_dev));
-               }
-       default:
-               break;
-       }
 -      err = pci_request_selected_regions(pdev, bars, igb_driver_name);
 +      err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
 +                                         IORESOURCE_MEM),
 +                                         igb_driver_name);
        if (err)
                goto err_pci_reg;
  
        pci_save_state(pdev);
  
        err = -ENOMEM;
 -      netdev = alloc_etherdev_mq(sizeof(struct igb_adapter), IGB_MAX_TX_QUEUES);
 +      netdev = alloc_etherdev_mq(sizeof(struct igb_adapter),
 +                                 IGB_ABS_MAX_TX_QUEUES);
        if (!netdev)
                goto err_alloc_etherdev;
  
        hw = &adapter->hw;
        hw->back = adapter;
        adapter->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE;
 -      adapter->bars = bars;
 -      adapter->need_ioport = need_ioport;
  
        mmio_start = pci_resource_start(pdev, 0);
        mmio_len = pci_resource_len(pdev, 0);
  
        err = -EIO;
 -      adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
 -      if (!adapter->hw.hw_addr)
 +      hw->hw_addr = ioremap(mmio_start, mmio_len);
 +      if (!hw->hw_addr)
                goto err_ioremap;
  
        netdev->netdev_ops = &igb_netdev_ops;
        /* Initialize skew-specific constants */
        err = ei->get_invariants(hw);
        if (err)
 -              goto err_hw_init;
 +              goto err_sw_init;
  
 +      /* setup the private structure */
        err = igb_sw_init(adapter);
        if (err)
                goto err_sw_init;
                        "PHY reset is blocked due to SOL/IDER session.\n");
  
        netdev->features = NETIF_F_SG |
 -                         NETIF_F_HW_CSUM |
 +                         NETIF_F_IP_CSUM |
                           NETIF_F_HW_VLAN_TX |
                           NETIF_F_HW_VLAN_RX |
                           NETIF_F_HW_VLAN_FILTER;
  
 +      netdev->features |= NETIF_F_IPV6_CSUM;
        netdev->features |= NETIF_F_TSO;
        netdev->features |= NETIF_F_TSO6;
  
 -#ifdef CONFIG_IGB_LRO
 -      netdev->features |= NETIF_F_LRO;
 -#endif
 +      netdev->features |= NETIF_F_GRO;
  
        netdev->vlan_features |= NETIF_F_TSO;
        netdev->vlan_features |= NETIF_F_TSO6;
 -      netdev->vlan_features |= NETIF_F_HW_CSUM;
 +      netdev->vlan_features |= NETIF_F_IP_CSUM;
        netdev->vlan_features |= NETIF_F_SG;
  
        if (pci_using_dac)
                netdev->features |= NETIF_F_HIGHDMA;
  
 -      netdev->features |= NETIF_F_LLTX;
        adapter->en_mng_pt = igb_enable_mng_pass_thru(&adapter->hw);
  
        /* before reading the NVM, reset the controller to put the device in a
        INIT_WORK(&adapter->reset_task, igb_reset_task);
        INIT_WORK(&adapter->watchdog_task, igb_watchdog_task);
  
 -      /* Initialize link & ring properties that are user-changeable */
 -      adapter->tx_ring->count = 256;
 -      for (i = 0; i < adapter->num_tx_queues; i++)
 -              adapter->tx_ring[i].count = adapter->tx_ring->count;
 -      adapter->rx_ring->count = 256;
 -      for (i = 0; i < adapter->num_rx_queues; i++)
 -              adapter->rx_ring[i].count = adapter->rx_ring->count;
 -
 +      /* Initialize link properties that are user-changeable */
        adapter->fc_autoneg = true;
        hw->mac.autoneg = true;
        hw->phy.autoneg_advertised = 0x2f;
        hw->fc.original_type = e1000_fc_default;
        hw->fc.type = e1000_fc_default;
  
 -      adapter->itr_setting = 3;
 +      adapter->itr_setting = IGB_DEFAULT_ITR;
        adapter->itr = IGB_START_ITR;
  
        igb_validate_mdi_setting(hw);
         * enable the ACPI Magic Packet filter
         */
  
 -      if (hw->bus.func == 0 ||
 -          hw->device_id == E1000_DEV_ID_82575EB_COPPER)
 -              hw->nvm.ops.read_nvm(hw, NVM_INIT_CONTROL3_PORT_A, 1,
 -                                   &eeprom_data);
 +      if (hw->bus.func == 0)
 +              hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
 +      else if (hw->bus.func == 1)
 +              hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
  
        if (eeprom_data & eeprom_apme_mask)
                adapter->eeprom_wol |= E1000_WUFC_MAG;
                if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1)
                        adapter->eeprom_wol = 0;
                break;
 +      case E1000_DEV_ID_82576_QUAD_COPPER:
 +              /* if quad port adapter, disable WoL on all but port A */
 +              if (global_quad_port_a != 0)
 +                      adapter->eeprom_wol = 0;
 +              else
 +                      adapter->flags |= IGB_FLAG_QUAD_PORT_A;
 +              /* Reset for multiple quad port adapters */
 +              if (++global_quad_port_a == 4)
 +                      global_quad_port_a = 0;
 +              break;
        }
  
        /* initialize the wol settings based on the eeprom settings */
        if (err)
                goto err_register;
  
 +#ifdef CONFIG_PCI_IOV
 +      /* since iov functionality isn't critical to base device function we
 +       * can accept failure.  If it fails we don't allow iov to be enabled */
 +      if (hw->mac.type == e1000_82576) {
 +              err = pci_enable_sriov(pdev, 0);
 +              if (!err)
 +                      err = device_create_file(&netdev->dev,
 +                                               &dev_attr_num_vfs);
 +              if (err)
 +                      dev_err(&pdev->dev, "Failed to initialize IOV\n");
 +      }
 +
 +#endif
  #ifdef CONFIG_IGB_DCA
        if (dca_add_requester(&pdev->dev) == 0) {
                adapter->flags |= IGB_FLAG_DCA_ENABLED;
                dev_info(&pdev->dev, "DCA enabled\n");
                /* Always use CB2 mode, difference is masked
                 * in the CB driver. */
 -              wr32(E1000_DCA_CTRL, 2);
 +              wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_CB2);
                igb_setup_dca(adapter);
        }
  #endif
  
 +      /*
 +       * Initialize hardware timer: we keep it running just in case
 +       * that some program needs it later on.
 +       */
 +      memset(&adapter->cycles, 0, sizeof(adapter->cycles));
 +      adapter->cycles.read = igb_read_clock;
 +      adapter->cycles.mask = CLOCKSOURCE_MASK(64);
 +      adapter->cycles.mult = 1;
 +      adapter->cycles.shift = IGB_TSYNC_SHIFT;
 +      wr32(E1000_TIMINCA,
 +           (1<<24) |
 +           IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS * IGB_TSYNC_SCALE);
 +#if 0
 +      /*
 +       * Avoid rollover while we initialize by resetting the time counter.
 +       */
 +      wr32(E1000_SYSTIML, 0x00000000);
 +      wr32(E1000_SYSTIMH, 0x00000000);
 +#else
 +      /*
 +       * Set registers so that rollover occurs soon to test this.
 +       */
 +      wr32(E1000_SYSTIML, 0x00000000);
 +      wr32(E1000_SYSTIMH, 0xFF800000);
 +#endif
 +      wrfl();
 +      timecounter_init(&adapter->clock,
 +                       &adapter->cycles,
 +                       ktime_to_ns(ktime_get_real()));
 +
 +      /*
 +       * Synchronize our NIC clock against system wall clock. NIC
 +       * time stamp reading requires ~3us per sample, each sample
 +       * was pretty stable even under load => only require 10
 +       * samples for each offset comparison.
 +       */
 +      memset(&adapter->compare, 0, sizeof(adapter->compare));
 +      adapter->compare.source = &adapter->clock;
 +      adapter->compare.target = ktime_get_real;
 +      adapter->compare.num_samples = 10;
 +      timecompare_update(&adapter->compare, 0);
 +
 +#ifdef DEBUG
 +      {
 +              char buffer[160];
 +              printk(KERN_DEBUG
 +                      "igb: %s: hw %p initialized timer\n",
 +                      igb_get_time_str(adapter, buffer),
 +                      &adapter->hw);
 +      }
 +#endif
 +
        dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n");
        /* print bus type/speed/width info */
        dev_info(&pdev->dev, "%s: (PCIe:%s:%s) %pM\n",
@@@ -1516,14 -1330,15 +1494,14 @@@ err_eeprom
        if (hw->flash_address)
                iounmap(hw->flash_address);
  
 -      igb_remove_device(hw);
        igb_free_queues(adapter);
  err_sw_init:
 -err_hw_init:
        iounmap(hw->hw_addr);
  err_ioremap:
        free_netdev(netdev);
  err_alloc_etherdev:
 -      pci_release_selected_regions(pdev, bars);
 +      pci_release_selected_regions(pdev, pci_select_bars(pdev,
 +                                   IORESOURCE_MEM));
  err_pci_reg:
  err_dma:
        pci_disable_device(pdev);
@@@ -1543,7 -1358,9 +1521,7 @@@ static void __devexit igb_remove(struc
  {
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct igb_adapter *adapter = netdev_priv(netdev);
 -#ifdef CONFIG_IGB_DCA
        struct e1000_hw *hw = &adapter->hw;
 -#endif
        int err;
  
        /* flush_scheduled work may reschedule our watchdog task, so
                dev_info(&pdev->dev, "DCA disabled\n");
                dca_remove_requester(&pdev->dev);
                adapter->flags &= ~IGB_FLAG_DCA_ENABLED;
 -              wr32(E1000_DCA_CTRL, 1);
 +              wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_DISABLE);
        }
  #endif
  
        if (!igb_check_reset_block(&adapter->hw))
                igb_reset_phy(&adapter->hw);
  
 -      igb_remove_device(&adapter->hw);
        igb_reset_interrupt_capability(adapter);
  
        igb_free_queues(adapter);
  
 -      iounmap(adapter->hw.hw_addr);
 -      if (adapter->hw.flash_address)
 -              iounmap(adapter->hw.flash_address);
 -      pci_release_selected_regions(pdev, adapter->bars);
 +#ifdef CONFIG_PCI_IOV
 +      /* reclaim resources allocated to VFs */
 +      if (adapter->vf_data) {
 +              /* disable iov and allow time for transactions to clear */
 +              pci_disable_sriov(pdev);
 +              msleep(500);
 +
 +              kfree(adapter->vf_data);
 +              adapter->vf_data = NULL;
 +              wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
 +              msleep(100);
 +              dev_info(&pdev->dev, "IOV Disabled\n");
 +      }
 +#endif
 +      iounmap(hw->hw_addr);
 +      if (hw->flash_address)
 +              iounmap(hw->flash_address);
 +      pci_release_selected_regions(pdev, pci_select_bars(pdev,
 +                                   IORESOURCE_MEM));
  
        free_netdev(netdev);
  
@@@ -1629,6 -1432,11 +1607,6 @@@ static int __devinit igb_sw_init(struc
        adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
        adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
  
 -      /* Number of supported queues. */
 -      /* Having more queues than CPUs doesn't make sense. */
 -      adapter->num_rx_queues = min_t(u32, IGB_MAX_RX_QUEUES, num_online_cpus());
 -      adapter->num_tx_queues = min_t(u32, IGB_MAX_TX_QUEUES, num_online_cpus());
 -
        /* This call may decrease the number of queues depending on
         * interrupt mode. */
        igb_set_interrupt_capability(adapter);
@@@ -1691,10 -1499,6 +1669,10 @@@ static int igb_open(struct net_device *
         * clean_rx handler before we do so.  */
        igb_configure(adapter);
  
 +      igb_vmm_control(adapter);
 +      igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0);
 +      igb_set_vmolr(hw, adapter->vfs_allocated_count);
 +
        err = igb_request_irq(adapter);
        if (err)
                goto err_req_irq;
@@@ -1770,6 -1574,7 +1748,6 @@@ static int igb_close(struct net_device 
   *
   * Return 0 on success, negative on failure
   **/
 -
  int igb_setup_tx_resources(struct igb_adapter *adapter,
                           struct igb_ring *tx_ring)
  {
        memset(tx_ring->buffer_info, 0, size);
  
        /* round up to nearest 4K */
 -      tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
 +      tx_ring->size = tx_ring->count * sizeof(union e1000_adv_tx_desc);
        tx_ring->size = ALIGN(tx_ring->size, 4096);
  
        tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
@@@ -1830,7 -1635,7 +1808,7 @@@ static int igb_setup_all_tx_resources(s
        for (i = 0; i < IGB_MAX_TX_QUEUES; i++) {
                r_idx = i % adapter->num_tx_queues;
                adapter->multi_tx_table[i] = &adapter->tx_ring[r_idx];
 -      }       
 +      }
        return err;
  }
  
@@@ -1849,13 -1654,13 +1827,13 @@@ static void igb_configure_tx(struct igb
        int i, j;
  
        for (i = 0; i < adapter->num_tx_queues; i++) {
 -              struct igb_ring *ring = &(adapter->tx_ring[i]);
 +              struct igb_ring *ring = &adapter->tx_ring[i];
                j = ring->reg_idx;
                wr32(E1000_TDLEN(j),
 -                              ring->count * sizeof(struct e1000_tx_desc));
 +                   ring->count * sizeof(union e1000_adv_tx_desc));
                tdba = ring->dma;
                wr32(E1000_TDBAL(j),
 -                              tdba & 0x00000000ffffffffULL);
 +                   tdba & 0x00000000ffffffffULL);
                wr32(E1000_TDBAH(j), tdba >> 32);
  
                ring->head = E1000_TDH(j);
                wr32(E1000_DCA_TXCTRL(j), txctrl);
        }
  
 -
 -
 -      /* Use the default values for the Tx Inter Packet Gap (IPG) timer */
 +      /* disable queue 0 to prevent tail bump w/o re-configuration */
 +      if (adapter->vfs_allocated_count)
 +              wr32(E1000_TXDCTL(0), 0);
  
        /* Program the Transmit Control Register */
 -
        tctl = rd32(E1000_TCTL);
        tctl &= ~E1000_TCTL_CT;
        tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
   *
   * Returns 0 on success, negative on failure
   **/
 -
  int igb_setup_rx_resources(struct igb_adapter *adapter,
                           struct igb_ring *rx_ring)
  {
        struct pci_dev *pdev = adapter->pdev;
        int size, desc_len;
  
 -#ifdef CONFIG_IGB_LRO
 -      size = sizeof(struct net_lro_desc) * MAX_LRO_DESCRIPTORS;
 -      rx_ring->lro_mgr.lro_arr = vmalloc(size);
 -      if (!rx_ring->lro_mgr.lro_arr)
 -              goto err;
 -      memset(rx_ring->lro_mgr.lro_arr, 0, size);
 -#endif
 -
        size = sizeof(struct igb_buffer) * rx_ring->count;
        rx_ring->buffer_info = vmalloc(size);
        if (!rx_ring->buffer_info)
        return 0;
  
  err:
 -#ifdef CONFIG_IGB_LRO
 -      vfree(rx_ring->lro_mgr.lro_arr);
 -      rx_ring->lro_mgr.lro_arr = NULL;
 -#endif
        vfree(rx_ring->buffer_info);
        dev_err(&adapter->pdev->dev, "Unable to allocate memory for "
                "the receive descriptor ring\n");
@@@ -1983,13 -1802,13 +1961,13 @@@ static void igb_setup_rctl(struct igb_a
        rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
  
        rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_RDMTS_HALF |
 -              (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
 +              (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
  
        /*
         * enable stripping of CRC. It's unlikely this will break BMC
         * redirection as it did with e1000. Newer features require
         * that the HW strips the CRC.
 -      */
 +       */
        rctl |= E1000_RCTL_SECRC;
  
        /*
                srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
        }
  
 +      /* Attention!!!  For SR-IOV PF driver operations you must enable
 +       * queue drop for all VF and PF queues to prevent head of line blocking
 +       * if an un-trusted VF does not provide descriptors to hardware.
 +       */
 +      if (adapter->vfs_allocated_count) {
 +              u32 vmolr;
 +
 +              j = adapter->rx_ring[0].reg_idx;
 +
 +              /* set all queue drop enable bits */
 +              wr32(E1000_QDE, ALL_QUEUES);
 +              srrctl |= E1000_SRRCTL_DROP_EN;
 +
 +              /* disable queue 0 to prevent tail write w/o re-config */
 +              wr32(E1000_RXDCTL(0), 0);
 +
 +              vmolr = rd32(E1000_VMOLR(j));
 +              if (rctl & E1000_RCTL_LPE)
 +                      vmolr |= E1000_VMOLR_LPE;
 +              if (adapter->num_rx_queues > 0)
 +                      vmolr |= E1000_VMOLR_RSSE;
 +              wr32(E1000_VMOLR(j), vmolr);
 +      }
 +
        for (i = 0; i < adapter->num_rx_queues; i++) {
                j = adapter->rx_ring[i].reg_idx;
                wr32(E1000_SRRCTL(j), srrctl);
        wr32(E1000_RCTL, rctl);
  }
  
 +/**
 + * igb_rlpml_set - set maximum receive packet size
 + * @adapter: board private structure
 + *
 + * Configure maximum receivable packet size.
 + **/
 +static void igb_rlpml_set(struct igb_adapter *adapter)
 +{
 +      u32 max_frame_size = adapter->max_frame_size;
 +      struct e1000_hw *hw = &adapter->hw;
 +      u16 pf_id = adapter->vfs_allocated_count;
 +
 +      if (adapter->vlgrp)
 +              max_frame_size += VLAN_TAG_SIZE;
 +
 +      /* if vfs are enabled we set RLPML to the largest possible request
 +       * size and set the VMOLR RLPML to the size we need */
 +      if (pf_id) {
 +              igb_set_vf_rlpml(adapter, max_frame_size, pf_id);
 +              max_frame_size = MAX_STD_JUMBO_FRAME_SIZE + VLAN_TAG_SIZE;
 +      }
 +
 +      wr32(E1000_RLPML, max_frame_size);
 +}
 +
 +/**
 + * igb_configure_vt_default_pool - Configure VT default pool
 + * @adapter: board private structure
 + *
 + * Configure the default pool
 + **/
 +static void igb_configure_vt_default_pool(struct igb_adapter *adapter)
 +{
 +      struct e1000_hw *hw = &adapter->hw;
 +      u16 pf_id = adapter->vfs_allocated_count;
 +      u32 vtctl;
 +
 +      /* not in sr-iov mode - do nothing */
 +      if (!pf_id)
 +              return;
 +
 +      vtctl = rd32(E1000_VT_CTL);
 +      vtctl &= ~(E1000_VT_CTL_DEFAULT_POOL_MASK |
 +                 E1000_VT_CTL_DISABLE_DEF_POOL);
 +      vtctl |= pf_id << E1000_VT_CTL_DEFAULT_POOL_SHIFT;
 +      wr32(E1000_VT_CTL, vtctl);
 +}
 +
  /**
   * igb_configure_rx - Configure receive Unit after Reset
   * @adapter: board private structure
@@@ -2125,7 -1872,7 +2103,7 @@@ static void igb_configure_rx(struct igb
        struct e1000_hw *hw = &adapter->hw;
        u32 rctl, rxcsum;
        u32 rxdctl;
 -      int i, j;
 +      int i;
  
        /* disable receives while setting up the descriptors */
        rctl = rd32(E1000_RCTL);
        /* Setup the HW Rx Head and Tail Descriptor Pointers and
         * the Base and Length of the Rx Descriptor Ring */
        for (i = 0; i < adapter->num_rx_queues; i++) {
 -              struct igb_ring *ring = &(adapter->rx_ring[i]);
 -              j = ring->reg_idx;
 +              struct igb_ring *ring = &adapter->rx_ring[i];
 +              int j = ring->reg_idx;
                rdba = ring->dma;
                wr32(E1000_RDBAL(j),
 -                              rdba & 0x00000000ffffffffULL);
 +                   rdba & 0x00000000ffffffffULL);
                wr32(E1000_RDBAH(j), rdba >> 32);
                wr32(E1000_RDLEN(j),
 -                             ring->count * sizeof(union e1000_adv_rx_desc));
 +                   ring->count * sizeof(union e1000_adv_rx_desc));
  
                ring->head = E1000_RDH(j);
                ring->tail = E1000_RDT(j);
                rxdctl |= IGB_RX_HTHRESH << 8;
                rxdctl |= IGB_RX_WTHRESH << 16;
                wr32(E1000_RXDCTL(j), rxdctl);
 -#ifdef CONFIG_IGB_LRO
 -              /* Intitial LRO Settings */
 -              ring->lro_mgr.max_aggr = MAX_LRO_AGGR;
 -              ring->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS;
 -              ring->lro_mgr.get_skb_header = igb_get_skb_hdr;
 -              ring->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
 -              ring->lro_mgr.dev = adapter->netdev;
 -              ring->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
 -              ring->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
 -#endif
        }
  
        if (adapter->num_rx_queues > 1) {
                                writel(reta.dword,
                                       hw->hw_addr + E1000_RETA(0) + (j & ~3));
                }
 -              mrqc = E1000_MRQC_ENABLE_RSS_4Q;
 +              if (adapter->vfs_allocated_count)
 +                      mrqc = E1000_MRQC_ENABLE_VMDQ_RSS_2Q;
 +              else
 +                      mrqc = E1000_MRQC_ENABLE_RSS_4Q;
  
                /* Fill out hash function seeds */
                for (j = 0; j < 10; j++)
                rxcsum |= E1000_RXCSUM_PCSD;
                wr32(E1000_RXCSUM, rxcsum);
        } else {
 +              /* Enable multi-queue for sr-iov */
 +              if (adapter->vfs_allocated_count)
 +                      wr32(E1000_MRQC, E1000_MRQC_ENABLE_VMDQ);
                /* Enable Receive Checksum Offload for TCP and UDP */
                rxcsum = rd32(E1000_RXCSUM);
 -              if (adapter->rx_csum) {
 -                      rxcsum |= E1000_RXCSUM_TUOFL;
 +              if (adapter->rx_csum)
 +                      rxcsum |= E1000_RXCSUM_TUOFL | E1000_RXCSUM_IPPCSE;
 +              else
 +                      rxcsum &= ~(E1000_RXCSUM_TUOFL | E1000_RXCSUM_IPPCSE);
  
 -                      /* Enable IPv4 payload checksum for UDP fragments
 -                       * Must be used in conjunction with packet-split. */
 -                      if (adapter->rx_ps_hdr_size)
 -                              rxcsum |= E1000_RXCSUM_IPPCSE;
 -              } else {
 -                      rxcsum &= ~E1000_RXCSUM_TUOFL;
 -                      /* don't need to clear IPPCSE as it defaults to 0 */
 -              }
                wr32(E1000_RXCSUM, rxcsum);
        }
  
 -      if (adapter->vlgrp)
 -              wr32(E1000_RLPML,
 -                              adapter->max_frame_size + VLAN_TAG_SIZE);
 -      else
 -              wr32(E1000_RLPML, adapter->max_frame_size);
 +      /* Set the default pool for the PF's first queue */
 +      igb_configure_vt_default_pool(adapter);
 +
 +      igb_rlpml_set(adapter);
  
        /* Enable Receives */
        wr32(E1000_RCTL, rctl);
@@@ -2283,7 -2041,6 +2261,7 @@@ static void igb_unmap_and_free_tx_resou
                buffer_info->skb = NULL;
        }
        buffer_info->time_stamp = 0;
 +      buffer_info->next_to_watch = 0;
        /* buffer_info must be completely set up in the transmit path */
  }
  
@@@ -2348,6 -2105,11 +2326,6 @@@ void igb_free_rx_resources(struct igb_r
        vfree(rx_ring->buffer_info);
        rx_ring->buffer_info = NULL;
  
 -#ifdef CONFIG_IGB_LRO
 -      vfree(rx_ring->lro_mgr.lro_arr);
 -      rx_ring->lro_mgr.lro_arr = NULL;
 -#endif 
 -
        pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
  
        rx_ring->desc = NULL;
@@@ -2447,18 -2209,15 +2425,18 @@@ static void igb_clean_all_rx_rings(stru
  static int igb_set_mac(struct net_device *netdev, void *p)
  {
        struct igb_adapter *adapter = netdev_priv(netdev);
 +      struct e1000_hw *hw = &adapter->hw;
        struct sockaddr *addr = p;
  
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
  
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 -      memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len);
 +      memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len);
 +
 +      hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
  
 -      adapter->hw.mac.ops.rar_set(&adapter->hw, adapter->hw.mac.addr, 0);
 +      igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0);
  
        return 0;
  }
@@@ -2501,8 -2260,8 +2479,8 @@@ static void igb_set_multi(struct net_de
  
        if (!netdev->mc_count) {
                /* nothing to program, so clear mc list */
 -              igb_update_mc_addr_list_82575(hw, NULL, 0, 1,
 -                                        mac->rar_entry_count);
 +              igb_update_mc_addr_list(hw, NULL, 0, 1,
 +                                      mac->rar_entry_count);
                return;
        }
  
                memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN);
                mc_ptr = mc_ptr->next;
        }
 -      igb_update_mc_addr_list_82575(hw, mta_list, i, 1,
 -                                    mac->rar_entry_count);
 +      igb_update_mc_addr_list(hw, mta_list, i,
 +                              adapter->vfs_allocated_count + 1,
 +                              mac->rar_entry_count);
 +
 +      igb_set_mc_list_pools(adapter, i, mac->rar_entry_count);
 +      igb_restore_vf_multicasts(adapter);
 +
        kfree(mta_list);
  }
  
@@@ -2537,46 -2291,6 +2515,46 @@@ static void igb_update_phy_info(unsigne
        igb_get_phy_info(&adapter->hw);
  }
  
 +/**
 + * igb_has_link - check shared code for link and determine up/down
 + * @adapter: pointer to driver private info
 + **/
 +static bool igb_has_link(struct igb_adapter *adapter)
 +{
 +      struct e1000_hw *hw = &adapter->hw;
 +      bool link_active = false;
 +      s32 ret_val = 0;
 +
 +      /* get_link_status is set on LSC (link status) interrupt or
 +       * rx sequence error interrupt.  get_link_status will stay
 +       * false until the e1000_check_for_link establishes link
 +       * for copper adapters ONLY
 +       */
 +      switch (hw->phy.media_type) {
 +      case e1000_media_type_copper:
 +              if (hw->mac.get_link_status) {
 +                      ret_val = hw->mac.ops.check_for_link(hw);
 +                      link_active = !hw->mac.get_link_status;
 +              } else {
 +                      link_active = true;
 +              }
 +              break;
 +      case e1000_media_type_fiber:
 +              ret_val = hw->mac.ops.check_for_link(hw);
 +              link_active = !!(rd32(E1000_STATUS) & E1000_STATUS_LU);
 +              break;
 +      case e1000_media_type_internal_serdes:
 +              ret_val = hw->mac.ops.check_for_link(hw);
 +              link_active = hw->mac.serdes_has_link;
 +              break;
 +      default:
 +      case e1000_media_type_unknown:
 +              break;
 +      }
 +
 +      return link_active;
 +}
 +
  /**
   * igb_watchdog - Timer Call-back
   * @data: pointer to adapter cast into an unsigned long
@@@ -2593,16 -2307,34 +2571,16 @@@ static void igb_watchdog_task(struct wo
        struct igb_adapter *adapter = container_of(work,
                                        struct igb_adapter, watchdog_task);
        struct e1000_hw *hw = &adapter->hw;
 -
        struct net_device *netdev = adapter->netdev;
        struct igb_ring *tx_ring = adapter->tx_ring;
 -      struct e1000_mac_info *mac = &adapter->hw.mac;
        u32 link;
        u32 eics = 0;
 -      s32 ret_val;
        int i;
  
 -      if ((netif_carrier_ok(netdev)) &&
 -          (rd32(E1000_STATUS) & E1000_STATUS_LU))
 +      link = igb_has_link(adapter);
 +      if ((netif_carrier_ok(netdev)) && link)
                goto link_up;
  
 -      ret_val = hw->mac.ops.check_for_link(&adapter->hw);
 -      if ((ret_val == E1000_ERR_PHY) &&
 -          (hw->phy.type == e1000_phy_igp_3) &&
 -          (rd32(E1000_CTRL) &
 -           E1000_PHY_CTRL_GBE_DISABLE))
 -              dev_info(&adapter->pdev->dev,
 -                       "Gigabit has been disabled, downgrading speed\n");
 -
 -      if ((hw->phy.media_type == e1000_media_type_internal_serdes) &&
 -          !(rd32(E1000_TXCW) & E1000_TXCW_ANE))
 -              link = mac->serdes_has_link;
 -      else
 -              link = rd32(E1000_STATUS) &
 -                                    E1000_STATUS_LU;
 -
        if (link) {
                if (!netif_carrier_ok(netdev)) {
                        u32 ctrl;
                        netif_carrier_on(netdev);
                        netif_tx_wake_all_queues(netdev);
  
 +                      igb_ping_all_vfs(adapter);
 +
 +                      /* link state has changed, schedule phy info update */
                        if (!test_bit(__IGB_DOWN, &adapter->state))
                                mod_timer(&adapter->phy_info_timer,
                                          round_jiffies(jiffies + 2 * HZ));
                               netdev->name);
                        netif_carrier_off(netdev);
                        netif_tx_stop_all_queues(netdev);
 +
 +                      igb_ping_all_vfs(adapter);
 +
 +                      /* link state has changed, schedule phy info update */
                        if (!test_bit(__IGB_DOWN, &adapter->state))
                                mod_timer(&adapter->phy_info_timer,
                                          round_jiffies(jiffies + 2 * HZ));
  link_up:
        igb_update_stats(adapter);
  
 -      mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old;
 +      hw->mac.tx_packet_delta = adapter->stats.tpt - adapter->tpt_old;
        adapter->tpt_old = adapter->stats.tpt;
 -      mac->collision_delta = adapter->stats.colc - adapter->colc_old;
 +      hw->mac.collision_delta = adapter->stats.colc - adapter->colc_old;
        adapter->colc_old = adapter->stats.colc;
  
        adapter->gorc = adapter->stats.gorc - adapter->gorc_old;
@@@ -2829,7 -2554,7 +2807,7 @@@ static unsigned int igb_update_itr(stru
                if (bytes > 25000) {
                        if (packets > 35)
                                retval = low_latency;
 -              } else if (bytes < 6000) {
 +              } else if (bytes < 1500) {
                        retval = low_latency;
                }
                break;
@@@ -2861,13 -2586,15 +2839,13 @@@ static void igb_set_itr(struct igb_adap
                                            adapter->tx_itr,
                                            adapter->tx_ring->total_packets,
                                            adapter->tx_ring->total_bytes);
 -
                current_itr = max(adapter->rx_itr, adapter->tx_itr);
        } else {
                current_itr = adapter->rx_itr;
        }
  
        /* conservative mode (itr 3) eliminates the lowest_latency setting */
 -      if (adapter->itr_setting == 3 &&
 -          current_itr == lowest_latency)
 +      if (adapter->itr_setting == 3 && current_itr == lowest_latency)
                current_itr = low_latency;
  
        switch (current_itr) {
@@@ -2919,7 -2646,6 +2897,7 @@@ set_itr_now
  #define IGB_TX_FLAGS_VLAN             0x00000002
  #define IGB_TX_FLAGS_TSO              0x00000004
  #define IGB_TX_FLAGS_IPV4             0x00000008
 +#define IGB_TX_FLAGS_TSTAMP             0x00000010
  #define IGB_TX_FLAGS_VLAN_MASK        0xffff0000
  #define IGB_TX_FLAGS_VLAN_SHIFT       16
  
@@@ -2985,7 -2711,7 +2963,7 @@@ static inline int igb_tso_adv(struct ig
        mss_l4len_idx = (skb_shinfo(skb)->gso_size << E1000_ADVTXD_MSS_SHIFT);
        mss_l4len_idx |= (l4len << E1000_ADVTXD_L4LEN_SHIFT);
  
 -      /* Context index must be unique per ring. */
 +      /* For 82575, context index must be unique per ring. */
        if (adapter->flags & IGB_FLAG_NEED_CTX_IDX)
                mss_l4len_idx |= tx_ring->queue_index << 4;
  
@@@ -3031,12 -2757,12 +3009,12 @@@ static inline bool igb_tx_csum_adv(stru
  
                if (skb->ip_summed == CHECKSUM_PARTIAL) {
                        switch (skb->protocol) {
 -                      case __constant_htons(ETH_P_IP):
 +                      case cpu_to_be16(ETH_P_IP):
                                tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
                                if (ip_hdr(skb)->protocol == IPPROTO_TCP)
                                        tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
                                break;
 -                      case __constant_htons(ETH_P_IPV6):
 +                      case cpu_to_be16(ETH_P_IPV6):
                                /* XXX what about other V6 headers?? */
                                if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
                                        tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
                if (adapter->flags & IGB_FLAG_NEED_CTX_IDX)
                        context_desc->mss_l4len_idx =
                                cpu_to_le32(tx_ring->queue_index << 4);
 +              else
 +                      context_desc->mss_l4len_idx = 0;
  
                buffer_info->time_stamp = jiffies;
                buffer_info->next_to_watch = i;
  
                return true;
        }
 -
 -
        return false;
  }
  
@@@ -3145,9 -2871,6 +3123,9 @@@ static inline void igb_tx_queue_adv(str
        if (tx_flags & IGB_TX_FLAGS_VLAN)
                cmd_type_len |= E1000_ADVTXD_DCMD_VLE;
  
 +      if (tx_flags & IGB_TX_FLAGS_TSTAMP)
 +              cmd_type_len |= E1000_ADVTXD_MAC_TSTAMP;
 +
        if (tx_flags & IGB_TX_FLAGS_TSO) {
                cmd_type_len |= E1000_ADVTXD_DCMD_TSE;
  
@@@ -3227,6 -2950,8 +3205,6 @@@ static int igb_maybe_stop_tx(struct net
        return __igb_maybe_stop_tx(netdev, tx_ring, size);
  }
  
 -#define TXD_USE_COUNT(S) (((S) >> (IGB_MAX_TXD_PWR)) + 1)
 -
  static int igb_xmit_frame_ring_adv(struct sk_buff *skb,
                                   struct net_device *netdev,
                                   struct igb_ring *tx_ring)
        struct igb_adapter *adapter = netdev_priv(netdev);
        unsigned int first;
        unsigned int tx_flags = 0;
 -      unsigned int len;
        u8 hdr_len = 0;
        int tso = 0;
 -
 -      len = skb_headlen(skb);
 +      union skb_shared_tx *shtx;
  
        if (test_bit(__IGB_DOWN, &adapter->state)) {
                dev_kfree_skb_any(skb);
                /* this is a hard error */
                return NETDEV_TX_BUSY;
        }
 -      skb_orphan(skb);
 +
 +      /*
 +       * TODO: check that there currently is no other packet with
 +       * time stamping in the queue
 +       *
 +       * When doing time stamping, keep the connection to the socket
 +       * a while longer: it is still needed by skb_hwtstamp_tx(),
 +       * called either in igb_tx_hwtstamp() or by our caller when
 +       * doing software time stamping.
 +       */
 +      shtx = skb_tx(skb);
 +      if (unlikely(shtx->hardware)) {
 +              shtx->in_progress = 1;
 +              tx_flags |= IGB_TX_FLAGS_TSTAMP;
 +      }
  
        if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
                tx_flags |= IGB_TX_FLAGS_VLAN;
                tx_flags |= IGB_TX_FLAGS_IPV4;
  
        first = tx_ring->next_to_use;
 -
        tso = skb_is_gso(skb) ? igb_tso_adv(adapter, tx_ring, skb, tx_flags,
                                              &hdr_len) : 0;
  
  
        if (tso)
                tx_flags |= IGB_TX_FLAGS_TSO;
 -      else if (igb_tx_csum_adv(adapter, tx_ring, skb, tx_flags))
 -                      if (skb->ip_summed == CHECKSUM_PARTIAL)
 -                              tx_flags |= IGB_TX_FLAGS_CSUM;
 +      else if (igb_tx_csum_adv(adapter, tx_ring, skb, tx_flags) &&
 +               (skb->ip_summed == CHECKSUM_PARTIAL))
 +              tx_flags |= IGB_TX_FLAGS_CSUM;
  
        igb_tx_queue_adv(adapter, tx_ring, tx_flags,
                         igb_tx_map_adv(adapter, tx_ring, skb, first),
@@@ -3314,7 -3028,7 +3292,7 @@@ static int igb_xmit_frame_adv(struct sk
        struct igb_ring *tx_ring;
  
        int r_idx = 0;
 -      r_idx = skb->queue_mapping & (IGB_MAX_TX_QUEUES - 1);
 +      r_idx = skb->queue_mapping & (IGB_ABS_MAX_TX_QUEUES - 1);
        tx_ring = adapter->multi_tx_table[r_idx];
  
        /* This goes back to the question of how to logically map a tx queue
@@@ -3336,8 -3050,8 +3314,8 @@@ static void igb_tx_timeout(struct net_d
        /* Do the reset outside of interrupt context */
        adapter->tx_timeout_count++;
        schedule_work(&adapter->reset_task);
 -      wr32(E1000_EICS, adapter->eims_enable_mask &
 -              ~(E1000_EIMS_TCP_TIMER | E1000_EIMS_OTHER));
 +      wr32(E1000_EICS,
 +           (adapter->eims_enable_mask & ~adapter->eims_other));
  }
  
  static void igb_reset_task(struct work_struct *work)
   * Returns the address of the device statistics structure.
   * The statistics are actually updated from the timer callback.
   **/
 -static struct net_device_stats *
 -igb_get_stats(struct net_device *netdev)
 +static struct net_device_stats *igb_get_stats(struct net_device *netdev)
  {
        struct igb_adapter *adapter = netdev_priv(netdev);
  
@@@ -3381,6 -3096,7 +3359,6 @@@ static int igb_change_mtu(struct net_de
                return -EINVAL;
        }
  
 -#define MAX_STD_JUMBO_FRAME_SIZE 9234
        if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) {
                dev_err(&adapter->pdev->dev, "MTU > 9216 not supported.\n");
                return -EINVAL;
  
        while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
                msleep(1);
 +
        /* igb_down has a dependency on max_frame_size */
        adapter->max_frame_size = max_frame;
        if (netif_running(netdev))
  #else
                adapter->rx_buffer_len = PAGE_SIZE / 2;
  #endif
 +
 +      /* if sr-iov is enabled we need to force buffer size to 1K or larger */
 +      if (adapter->vfs_allocated_count &&
 +          (adapter->rx_buffer_len < IGB_RXBUFFER_1024))
 +              adapter->rx_buffer_len = IGB_RXBUFFER_1024;
 +
        /* adjust allocation if LPE protects us, and we aren't using SBP */
        if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) ||
             (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE))
@@@ -3564,7 -3273,8 +3542,7 @@@ void igb_update_stats(struct igb_adapte
        /* Phy Stats */
        if (hw->phy.media_type == e1000_media_type_copper) {
                if ((adapter->link_speed == SPEED_1000) &&
 -                 (!igb_read_phy_reg(hw, PHY_1000T_STATUS,
 -                                            &phy_tmp))) {
 +                 (!igb_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) {
                        phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
                        adapter->phy_stats.idle_errors += phy_tmp;
                }
        adapter->stats.mgpdc += rd32(E1000_MGTPDC);
  }
  
 -
  static irqreturn_t igb_msix_other(int irq, void *data)
  {
        struct net_device *netdev = data;
        u32 icr = rd32(E1000_ICR);
  
        /* reading ICR causes bit 31 of EICR to be cleared */
 -      if (!(icr & E1000_ICR_LSC))
 -              goto no_link_interrupt;
 -      hw->mac.get_link_status = 1;
 -      /* guard against interrupt when we're going down */
 -      if (!test_bit(__IGB_DOWN, &adapter->state))
 -              mod_timer(&adapter->watchdog_timer, jiffies + 1);
 -      
 -no_link_interrupt:
 -      wr32(E1000_IMS, E1000_IMS_LSC);
 +
 +      if(icr & E1000_ICR_DOUTSYNC) {
 +              /* HW is reporting DMA is out of sync */
 +              adapter->stats.doosync++;
 +      }
 +
 +      /* Check for a mailbox event */
 +      if (icr & E1000_ICR_VMMB)
 +              igb_msg_task(adapter);
 +
 +      if (icr & E1000_ICR_LSC) {
 +              hw->mac.get_link_status = 1;
 +              /* guard against interrupt when we're going down */
 +              if (!test_bit(__IGB_DOWN, &adapter->state))
 +                      mod_timer(&adapter->watchdog_timer, jiffies + 1);
 +      }
 +
 +      wr32(E1000_IMS, E1000_IMS_LSC | E1000_IMS_DOUTSYNC | E1000_IMS_VMMB);
        wr32(E1000_EIMS, adapter->eims_other);
  
        return IRQ_HANDLED;
@@@ -3617,7 -3319,6 +3595,7 @@@ static irqreturn_t igb_msix_tx(int irq
        if (adapter->flags & IGB_FLAG_DCA_ENABLED)
                igb_update_tx_dca(tx_ring);
  #endif
 +
        tx_ring->total_bytes = 0;
        tx_ring->total_packets = 0;
  
@@@ -3638,11 -3339,13 +3616,11 @@@ static void igb_write_itr(struct igb_ri
        if ((ring->adapter->itr_setting & 3) && ring->set_itr) {
                switch (hw->mac.type) {
                case e1000_82576:
 -                      wr32(ring->itr_register,
 -                           ring->itr_val |
 +                      wr32(ring->itr_register, ring->itr_val |
                             0x80000000);
                        break;
                default:
 -                      wr32(ring->itr_register,
 -                           ring->itr_val |
 +                      wr32(ring->itr_register, ring->itr_val |
                             (ring->itr_val << 16));
                        break;
                }
@@@ -3660,8 -3363,8 +3638,8 @@@ static irqreturn_t igb_msix_rx(int irq
  
        igb_write_itr(rx_ring);
  
 -      if (netif_rx_schedule_prep(&rx_ring->napi))
 -              __netif_rx_schedule(&rx_ring->napi);
 +      if (napi_schedule_prep(&rx_ring->napi))
 +              __napi_schedule(&rx_ring->napi);
  
  #ifdef CONFIG_IGB_DCA
        if (rx_ring->adapter->flags & IGB_FLAG_DCA_ENABLED)
@@@ -3683,11 -3386,11 +3661,11 @@@ static void igb_update_rx_dca(struct ig
                dca_rxctrl = rd32(E1000_DCA_RXCTRL(q));
                if (hw->mac.type == e1000_82576) {
                        dca_rxctrl &= ~E1000_DCA_RXCTRL_CPUID_MASK_82576;
 -                      dca_rxctrl |= dca_get_tag(cpu) <<
 +                      dca_rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu) <<
                                      E1000_DCA_RXCTRL_CPUID_SHIFT;
                } else {
                        dca_rxctrl &= ~E1000_DCA_RXCTRL_CPUID_MASK;
 -                      dca_rxctrl |= dca_get_tag(cpu);
 +                      dca_rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
                }
                dca_rxctrl |= E1000_DCA_RXCTRL_DESC_DCA_EN;
                dca_rxctrl |= E1000_DCA_RXCTRL_HEAD_DCA_EN;
@@@ -3710,11 -3413,11 +3688,11 @@@ static void igb_update_tx_dca(struct ig
                dca_txctrl = rd32(E1000_DCA_TXCTRL(q));
                if (hw->mac.type == e1000_82576) {
                        dca_txctrl &= ~E1000_DCA_TXCTRL_CPUID_MASK_82576;
 -                      dca_txctrl |= dca_get_tag(cpu) <<
 +                      dca_txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu) <<
                                      E1000_DCA_TXCTRL_CPUID_SHIFT;
                } else {
                        dca_txctrl &= ~E1000_DCA_TXCTRL_CPUID_MASK;
 -                      dca_txctrl |= dca_get_tag(cpu);
 +                      dca_txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
                }
                dca_txctrl |= E1000_DCA_TXCTRL_DESC_DCA_EN;
                wr32(E1000_DCA_TXCTRL(q), dca_txctrl);
@@@ -3754,7 -3457,7 +3732,7 @@@ static int __igb_notify_dca(struct devi
                        break;
                /* Always use CB2 mode, difference is masked
                 * in the CB driver. */
 -              wr32(E1000_DCA_CTRL, 2);
 +              wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_CB2);
                if (dca_add_requester(dev) == 0) {
                        adapter->flags |= IGB_FLAG_DCA_ENABLED;
                        dev_info(&adapter->pdev->dev, "DCA enabled\n");
                        dca_remove_requester(dev);
                        dev_info(&adapter->pdev->dev, "DCA disabled\n");
                        adapter->flags &= ~IGB_FLAG_DCA_ENABLED;
 -                      wr32(E1000_DCA_CTRL, 1);
 +                      wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_DISABLE);
                }
                break;
        }
@@@ -3789,368 -3492,48 +3767,368 @@@ static int igb_notify_dca(struct notifi
  }
  #endif /* CONFIG_IGB_DCA */
  
 -/**
 - * igb_intr_msi - Interrupt Handler
 - * @irq: interrupt number
 - * @data: pointer to a network interface device structure
 - **/
 -static irqreturn_t igb_intr_msi(int irq, void *data)
 +static void igb_ping_all_vfs(struct igb_adapter *adapter)
  {
 -      struct net_device *netdev = data;
 -      struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 -      /* read ICR disables interrupts using IAM */
 -      u32 icr = rd32(E1000_ICR);
 -
 -      igb_write_itr(adapter->rx_ring);
 +      u32 ping;
 +      int i;
  
 -      if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
 -              hw->mac.get_link_status = 1;
 -              if (!test_bit(__IGB_DOWN, &adapter->state))
 -                      mod_timer(&adapter->watchdog_timer, jiffies + 1);
 +      for (i = 0 ; i < adapter->vfs_allocated_count; i++) {
 +              ping = E1000_PF_CONTROL_MSG;
 +              if (adapter->vf_data[i].clear_to_send)
 +                      ping |= E1000_VT_MSGTYPE_CTS;
 +              igb_write_mbx(hw, &ping, 1, i);
        }
 +}
 +
 +static int igb_set_vf_multicasts(struct igb_adapter *adapter,
 +                                u32 *msgbuf, u32 vf)
 +{
 +      int n = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
 +      u16 *hash_list = (u16 *)&msgbuf[1];
 +      struct vf_data_storage *vf_data = &adapter->vf_data[vf];
 +      int i;
  
 -      netif_rx_schedule(&adapter->rx_ring[0].napi);
 +      /* only up to 30 hash values supported */
 +      if (n > 30)
 +              n = 30;
  
 -      return IRQ_HANDLED;
 +      /* salt away the number of multi cast addresses assigned
 +       * to this VF for later use to restore when the PF multi cast
 +       * list changes
 +       */
 +      vf_data->num_vf_mc_hashes = n;
 +
 +      /* VFs are limited to using the MTA hash table for their multicast
 +       * addresses */
 +      for (i = 0; i < n; i++)
 +              vf_data->vf_mc_hashes[i] = hash_list[i];;
 +
 +      /* Flush and reset the mta with the new values */
 +      igb_set_multi(adapter->netdev);
 +
 +      return 0;
  }
  
 -/**
 - * igb_intr - Interrupt Handler
 - * @irq: interrupt number
 - * @data: pointer to a network interface device structure
 - **/
 -static irqreturn_t igb_intr(int irq, void *data)
 +static void igb_restore_vf_multicasts(struct igb_adapter *adapter)
  {
 -      struct net_device *netdev = data;
 -      struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 -      /* Interrupt Auto-Mask...upon reading ICR, interrupts are masked.  No
 -       * need for the IMC write */
 -      u32 icr = rd32(E1000_ICR);
 -      u32 eicr = 0;
 -      if (!icr)
 -              return IRQ_NONE;  /* Not our interrupt */
 +      struct vf_data_storage *vf_data;
 +      int i, j;
 +
 +      for (i = 0; i < adapter->vfs_allocated_count; i++) {
 +              vf_data = &adapter->vf_data[i];
 +              for (j = 0; j < vf_data->num_vf_mc_hashes; j++)
 +                      igb_mta_set(hw, vf_data->vf_mc_hashes[j]);
 +      }
 +}
 +
 +static void igb_clear_vf_vfta(struct igb_adapter *adapter, u32 vf)
 +{
 +      struct e1000_hw *hw = &adapter->hw;
 +      u32 pool_mask, reg, vid;
 +      int i;
 +
 +      pool_mask = 1 << (E1000_VLVF_POOLSEL_SHIFT + vf);
 +
 +      /* Find the vlan filter for this id */
 +      for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
 +              reg = rd32(E1000_VLVF(i));
 +
 +              /* remove the vf from the pool */
 +              reg &= ~pool_mask;
 +
 +              /* if pool is empty then remove entry from vfta */
 +              if (!(reg & E1000_VLVF_POOLSEL_MASK) &&
 +                  (reg & E1000_VLVF_VLANID_ENABLE)) {
 +                      reg = 0;
 +                      vid = reg & E1000_VLVF_VLANID_MASK;
 +                      igb_vfta_set(hw, vid, false);
 +              }
 +
 +              wr32(E1000_VLVF(i), reg);
 +      }
 +}
 +
 +static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf)
 +{
 +      struct e1000_hw *hw = &adapter->hw;
 +      u32 reg, i;
 +
 +      /* It is an error to call this function when VFs are not enabled */
 +      if (!adapter->vfs_allocated_count)
 +              return -1;
 +
 +      /* Find the vlan filter for this id */
 +      for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
 +              reg = rd32(E1000_VLVF(i));
 +              if ((reg & E1000_VLVF_VLANID_ENABLE) &&
 +                  vid == (reg & E1000_VLVF_VLANID_MASK))
 +                      break;
 +      }
 +
 +      if (add) {
 +              if (i == E1000_VLVF_ARRAY_SIZE) {
 +                      /* Did not find a matching VLAN ID entry that was
 +                       * enabled.  Search for a free filter entry, i.e.
 +                       * one without the enable bit set
 +                       */
 +                      for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
 +                              reg = rd32(E1000_VLVF(i));
 +                              if (!(reg & E1000_VLVF_VLANID_ENABLE))
 +                                      break;
 +                      }
 +              }
 +              if (i < E1000_VLVF_ARRAY_SIZE) {
 +                      /* Found an enabled/available entry */
 +                      reg |= 1 << (E1000_VLVF_POOLSEL_SHIFT + vf);
 +
 +                      /* if !enabled we need to set this up in vfta */
 +                      if (!(reg & E1000_VLVF_VLANID_ENABLE)) {
 +                              /* add VID to filter table, if bit already set
 +                               * PF must have added it outside of table */
 +                              if (igb_vfta_set(hw, vid, true))
 +                                      reg |= 1 << (E1000_VLVF_POOLSEL_SHIFT +
 +                                              adapter->vfs_allocated_count);
 +                              reg |= E1000_VLVF_VLANID_ENABLE;
 +                      }
 +                      reg &= ~E1000_VLVF_VLANID_MASK;
 +                      reg |= vid;
 +
 +                      wr32(E1000_VLVF(i), reg);
 +                      return 0;
 +              }
 +      } else {
 +              if (i < E1000_VLVF_ARRAY_SIZE) {
 +                      /* remove vf from the pool */
 +                      reg &= ~(1 << (E1000_VLVF_POOLSEL_SHIFT + vf));
 +                      /* if pool is empty then remove entry from vfta */
 +                      if (!(reg & E1000_VLVF_POOLSEL_MASK)) {
 +                              reg = 0;
 +                              igb_vfta_set(hw, vid, false);
 +                      }
 +                      wr32(E1000_VLVF(i), reg);
 +                      return 0;
 +              }
 +      }
 +      return -1;
 +}
 +
 +static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
 +{
 +      int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
 +      int vid = (msgbuf[1] & E1000_VLVF_VLANID_MASK);
 +
 +      return igb_vlvf_set(adapter, vid, add, vf);
 +}
 +
 +static inline void igb_vf_reset_event(struct igb_adapter *adapter, u32 vf)
 +{
 +      struct e1000_hw *hw = &adapter->hw;
 +
 +      /* disable mailbox functionality for vf */
 +      adapter->vf_data[vf].clear_to_send = false;
 +
 +      /* reset offloads to defaults */
 +      igb_set_vmolr(hw, vf);
 +
 +      /* reset vlans for device */
 +      igb_clear_vf_vfta(adapter, vf);
 +
 +      /* reset multicast table array for vf */
 +      adapter->vf_data[vf].num_vf_mc_hashes = 0;
 +
 +      /* Flush and reset the mta with the new values */
 +      igb_set_multi(adapter->netdev);
 +}
 +
 +static inline void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf)
 +{
 +      struct e1000_hw *hw = &adapter->hw;
 +      unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses;
 +      u32 reg, msgbuf[3];
 +      u8 *addr = (u8 *)(&msgbuf[1]);
 +
 +      /* process all the same items cleared in a function level reset */
 +      igb_vf_reset_event(adapter, vf);
 +
 +      /* set vf mac address */
 +      igb_rar_set(hw, vf_mac, vf + 1);
 +      igb_set_rah_pool(hw, vf, vf + 1);
 +
 +      /* enable transmit and receive for vf */
 +      reg = rd32(E1000_VFTE);
 +      wr32(E1000_VFTE, reg | (1 << vf));
 +      reg = rd32(E1000_VFRE);
 +      wr32(E1000_VFRE, reg | (1 << vf));
 +
 +      /* enable mailbox functionality for vf */
 +      adapter->vf_data[vf].clear_to_send = true;
 +
 +      /* reply to reset with ack and vf mac address */
 +      msgbuf[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_ACK;
 +      memcpy(addr, vf_mac, 6);
 +      igb_write_mbx(hw, msgbuf, 3, vf);
 +}
 +
 +static int igb_set_vf_mac_addr(struct igb_adapter *adapter, u32 *msg, int vf)
 +{
 +              unsigned char *addr = (char *)&msg[1];
 +              int err = -1;
 +
 +              if (is_valid_ether_addr(addr))
 +                      err = igb_set_vf_mac(adapter, vf, addr);
 +
 +              return err;
 +
 +}
 +
 +static void igb_rcv_ack_from_vf(struct igb_adapter *adapter, u32 vf)
 +{
 +      struct e1000_hw *hw = &adapter->hw;
 +      u32 msg = E1000_VT_MSGTYPE_NACK;
 +
 +      /* if device isn't clear to send it shouldn't be reading either */
 +      if (!adapter->vf_data[vf].clear_to_send)
 +              igb_write_mbx(hw, &msg, 1, vf);
 +}
 +
 +
 +static void igb_msg_task(struct igb_adapter *adapter)
 +{
 +      struct e1000_hw *hw = &adapter->hw;
 +      u32 vf;
 +
 +      for (vf = 0; vf < adapter->vfs_allocated_count; vf++) {
 +              /* process any reset requests */
 +              if (!igb_check_for_rst(hw, vf)) {
 +                      adapter->vf_data[vf].clear_to_send = false;
 +                      igb_vf_reset_event(adapter, vf);
 +              }
 +
 +              /* process any messages pending */
 +              if (!igb_check_for_msg(hw, vf))
 +                      igb_rcv_msg_from_vf(adapter, vf);
 +
 +              /* process any acks */
 +              if (!igb_check_for_ack(hw, vf))
 +                      igb_rcv_ack_from_vf(adapter, vf);
 +
 +      }
 +}
 +
 +static int igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
 +{
 +      u32 mbx_size = E1000_VFMAILBOX_SIZE;
 +      u32 msgbuf[mbx_size];
 +      struct e1000_hw *hw = &adapter->hw;
 +      s32 retval;
 +
 +      retval = igb_read_mbx(hw, msgbuf, mbx_size, vf);
 +
 +      if (retval)
 +              dev_err(&adapter->pdev->dev,
 +                      "Error receiving message from VF\n");
 +
 +      /* this is a message we already processed, do nothing */
 +      if (msgbuf[0] & (E1000_VT_MSGTYPE_ACK | E1000_VT_MSGTYPE_NACK))
 +              return retval;
 +
 +      /*
 +       * until the vf completes a reset it should not be
 +       * allowed to start any configuration.
 +       */
 +
 +      if (msgbuf[0] == E1000_VF_RESET) {
 +              igb_vf_reset_msg(adapter, vf);
 +
 +              return retval;
 +      }
 +
 +      if (!adapter->vf_data[vf].clear_to_send) {
 +              msgbuf[0] |= E1000_VT_MSGTYPE_NACK;
 +              igb_write_mbx(hw, msgbuf, 1, vf);
 +              return retval;
 +      }
 +
 +      switch ((msgbuf[0] & 0xFFFF)) {
 +      case E1000_VF_SET_MAC_ADDR:
 +              retval = igb_set_vf_mac_addr(adapter, msgbuf, vf);
 +              break;
 +      case E1000_VF_SET_MULTICAST:
 +              retval = igb_set_vf_multicasts(adapter, msgbuf, vf);
 +              break;
 +      case E1000_VF_SET_LPE:
 +              retval = igb_set_vf_rlpml(adapter, msgbuf[1], vf);
 +              break;
 +      case E1000_VF_SET_VLAN:
 +              retval = igb_set_vf_vlan(adapter, msgbuf, vf);
 +              break;
 +      default:
 +              dev_err(&adapter->pdev->dev, "Unhandled Msg %08x\n", msgbuf[0]);
 +              retval = -1;
 +              break;
 +      }
 +
 +      /* notify the VF of the results of what it sent us */
 +      if (retval)
 +              msgbuf[0] |= E1000_VT_MSGTYPE_NACK;
 +      else
 +              msgbuf[0] |= E1000_VT_MSGTYPE_ACK;
 +
 +      msgbuf[0] |= E1000_VT_MSGTYPE_CTS;
 +
 +      igb_write_mbx(hw, msgbuf, 1, vf);
 +
 +      return retval;
 +}
 +
 +/**
 + * igb_intr_msi - Interrupt Handler
 + * @irq: interrupt number
 + * @data: pointer to a network interface device structure
 + **/
 +static irqreturn_t igb_intr_msi(int irq, void *data)
 +{
 +      struct net_device *netdev = data;
 +      struct igb_adapter *adapter = netdev_priv(netdev);
 +      struct e1000_hw *hw = &adapter->hw;
 +      /* read ICR disables interrupts using IAM */
 +      u32 icr = rd32(E1000_ICR);
 +
 +      igb_write_itr(adapter->rx_ring);
 +
 +      if(icr & E1000_ICR_DOUTSYNC) {
 +              /* HW is reporting DMA is out of sync */
 +              adapter->stats.doosync++;
 +      }
 +
 +      if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
 +              hw->mac.get_link_status = 1;
 +              if (!test_bit(__IGB_DOWN, &adapter->state))
 +                      mod_timer(&adapter->watchdog_timer, jiffies + 1);
 +      }
 +
 +      napi_schedule(&adapter->rx_ring[0].napi);
 +
 +      return IRQ_HANDLED;
 +}
 +
 +/**
 + * igb_intr - Legacy Interrupt Handler
 + * @irq: interrupt number
 + * @data: pointer to a network interface device structure
 + **/
 +static irqreturn_t igb_intr(int irq, void *data)
 +{
 +      struct net_device *netdev = data;
 +      struct igb_adapter *adapter = netdev_priv(netdev);
 +      struct e1000_hw *hw = &adapter->hw;
 +      /* Interrupt Auto-Mask...upon reading ICR, interrupts are masked.  No
 +       * need for the IMC write */
 +      u32 icr = rd32(E1000_ICR);
 +      if (!icr)
 +              return IRQ_NONE;  /* Not our interrupt */
  
        igb_write_itr(adapter->rx_ring);
  
        if (!(icr & E1000_ICR_INT_ASSERTED))
                return IRQ_NONE;
  
 -      eicr = rd32(E1000_EICR);
 +      if(icr & E1000_ICR_DOUTSYNC) {
 +              /* HW is reporting DMA is out of sync */
 +              adapter->stats.doosync++;
 +      }
  
        if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
                hw->mac.get_link_status = 1;
                        mod_timer(&adapter->watchdog_timer, jiffies + 1);
        }
  
 -      netif_rx_schedule(&adapter->rx_ring[0].napi);
 +      napi_schedule(&adapter->rx_ring[0].napi);
  
        return IRQ_HANDLED;
  }
  
 +static inline void igb_rx_irq_enable(struct igb_ring *rx_ring)
 +{
 +      struct igb_adapter *adapter = rx_ring->adapter;
 +      struct e1000_hw *hw = &adapter->hw;
 +
 +      if (adapter->itr_setting & 3) {
 +              if (adapter->num_rx_queues == 1)
 +                      igb_set_itr(adapter);
 +              else
 +                      igb_update_ring_itr(rx_ring);
 +      }
 +
 +      if (!test_bit(__IGB_DOWN, &adapter->state)) {
 +              if (adapter->msix_entries)
 +                      wr32(E1000_EIMS, rx_ring->eims_value);
 +              else
 +                      igb_irq_enable(adapter);
 +      }
 +}
 +
  /**
   * igb_poll - NAPI Rx polling callback
   * @napi: napi polling structure
  static int igb_poll(struct napi_struct *napi, int budget)
  {
        struct igb_ring *rx_ring = container_of(napi, struct igb_ring, napi);
 -      struct igb_adapter *adapter = rx_ring->adapter;
 -      struct net_device *netdev = adapter->netdev;
 -      int tx_clean_complete, work_done = 0;
 +      int work_done = 0;
  
 -      /* this poll routine only supports one tx and one rx queue */
  #ifdef CONFIG_IGB_DCA
 -      if (adapter->flags & IGB_FLAG_DCA_ENABLED)
 -              igb_update_tx_dca(&adapter->tx_ring[0]);
 +      if (rx_ring->adapter->flags & IGB_FLAG_DCA_ENABLED)
 +              igb_update_rx_dca(rx_ring);
  #endif
 -      tx_clean_complete = igb_clean_tx_irq(&adapter->tx_ring[0]);
 +      igb_clean_rx_irq_adv(rx_ring, &work_done, budget);
  
 +      if (rx_ring->buddy) {
  #ifdef CONFIG_IGB_DCA
 -      if (adapter->flags & IGB_FLAG_DCA_ENABLED)
 -              igb_update_rx_dca(&adapter->rx_ring[0]);
 +              if (rx_ring->adapter->flags & IGB_FLAG_DCA_ENABLED)
 +                      igb_update_tx_dca(rx_ring->buddy);
  #endif
 -      igb_clean_rx_irq_adv(&adapter->rx_ring[0], &work_done, budget);
 +              if (!igb_clean_tx_irq(rx_ring->buddy))
 +                      work_done = budget;
 +      }
  
 -      /* If no Tx and not enough Rx work done, exit the polling mode */
 -      if ((tx_clean_complete && (work_done < budget)) ||
 -          !netif_running(netdev)) {
 -              if (adapter->itr_setting & 3)
 -                      igb_set_itr(adapter);
 -              netif_rx_complete(napi);
 -              if (!test_bit(__IGB_DOWN, &adapter->state))
 -                      igb_irq_enable(adapter);
 -              return 0;
 +      /* If not enough Rx work done, exit the polling mode */
 +      if (work_done < budget) {
 +              napi_complete(napi);
 +              igb_rx_irq_enable(rx_ring);
        }
  
 -      return 1;
 +      return work_done;
  }
  
 -static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget)
 +/**
 + * igb_hwtstamp - utility function which checks for TX time stamp
 + * @adapter: board private structure
 + * @skb: packet that was just sent
 + *
 + * If we were asked to do hardware stamping and such a time stamp is
 + * available, then it must have been for this skb here because we only
 + * allow only one such packet into the queue.
 + */
 +static void igb_tx_hwtstamp(struct igb_adapter *adapter, struct sk_buff *skb)
  {
 -      struct igb_ring *rx_ring = container_of(napi, struct igb_ring, napi);
 -      struct igb_adapter *adapter = rx_ring->adapter;
 +      union skb_shared_tx *shtx = skb_tx(skb);
        struct e1000_hw *hw = &adapter->hw;
 -      struct net_device *netdev = adapter->netdev;
 -      int work_done = 0;
  
 -#ifdef CONFIG_IGB_DCA
 -      if (adapter->flags & IGB_FLAG_DCA_ENABLED)
 -              igb_update_rx_dca(rx_ring);
 -#endif
 -      igb_clean_rx_irq_adv(rx_ring, &work_done, budget);
 -
 -
 -      /* If not enough Rx work done, exit the polling mode */
 -      if ((work_done == 0) || !netif_running(netdev)) {
 -              netif_rx_complete(napi);
 -
 -              if (adapter->itr_setting & 3) {
 -                      if (adapter->num_rx_queues == 1)
 -                              igb_set_itr(adapter);
 -                      else
 -                              igb_update_ring_itr(rx_ring);
 +      if (unlikely(shtx->hardware)) {
 +              u32 valid = rd32(E1000_TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID;
 +              if (valid) {
 +                      u64 regval = rd32(E1000_TXSTMPL);
 +                      u64 ns;
 +                      struct skb_shared_hwtstamps shhwtstamps;
 +
 +                      memset(&shhwtstamps, 0, sizeof(shhwtstamps));
 +                      regval |= (u64)rd32(E1000_TXSTMPH) << 32;
 +                      ns = timecounter_cyc2time(&adapter->clock,
 +                                                regval);
 +                      timecompare_update(&adapter->compare, ns);
 +                      shhwtstamps.hwtstamp = ns_to_ktime(ns);
 +                      shhwtstamps.syststamp =
 +                              timecompare_transform(&adapter->compare, ns);
 +                      skb_tstamp_tx(skb, &shhwtstamps);
                }
 -
 -              if (!test_bit(__IGB_DOWN, &adapter->state))
 -                      wr32(E1000_EIMS, rx_ring->eims_value);
 -
 -              return 0;
        }
 -
 -      return 1;
  }
  
  /**
@@@ -4302,8 -3668,6 +4280,8 @@@ static bool igb_clean_tx_irq(struct igb
                                            skb->len;
                                total_packets += segs;
                                total_bytes += bytecount;
 +
 +                              igb_tx_hwtstamp(adapter, skb);
                        }
  
                        igb_unmap_and_free_tx_resource(adapter, buffer_info);
                        if (i == tx_ring->count)
                                i = 0;
                }
 -
                eop = tx_ring->buffer_info[i].next_to_watch;
                eop_desc = E1000_TX_DESC_ADV(*tx_ring, eop);
        }
        return (count < tx_ring->count);
  }
  
 -#ifdef CONFIG_IGB_LRO
 - /**
 - * igb_get_skb_hdr - helper function for LRO header processing
 - * @skb: pointer to sk_buff to be added to LRO packet
 - * @iphdr: pointer to ip header structure
 - * @tcph: pointer to tcp header structure
 - * @hdr_flags: pointer to header flags
 - * @priv: pointer to the receive descriptor for the current sk_buff
 - **/
 -static int igb_get_skb_hdr(struct sk_buff *skb, void **iphdr, void **tcph,
 -                           u64 *hdr_flags, void *priv)
 -{
 -      union e1000_adv_rx_desc *rx_desc = priv;
 -      u16 pkt_type = rx_desc->wb.lower.lo_dword.pkt_info &
 -                     (E1000_RXDADV_PKTTYPE_IPV4 | E1000_RXDADV_PKTTYPE_TCP);
 -
 -      /* Verify that this is a valid IPv4 TCP packet */
 -      if (pkt_type != (E1000_RXDADV_PKTTYPE_IPV4 |
 -                        E1000_RXDADV_PKTTYPE_TCP))
 -              return -1;
 -
 -      /* Set network headers */
 -      skb_reset_network_header(skb);
 -      skb_set_transport_header(skb, ip_hdrlen(skb));
 -      *iphdr = ip_hdr(skb);
 -      *tcph = tcp_hdr(skb);
 -      *hdr_flags = LRO_IPV4 | LRO_TCP;
 -
 -      return 0;
 -
 -}
 -#endif /* CONFIG_IGB_LRO */
 -
  /**
   * igb_receive_skb - helper function to handle rx indications
 - * @ring: pointer to receive ring receving this packet 
 + * @ring: pointer to receive ring receving this packet
   * @status: descriptor status field as written by hardware
 - * @vlan: descriptor vlan field as written by hardware (no le/be conversion)
 + * @rx_desc: receive descriptor containing vlan and type information.
   * @skb: pointer to sk_buff to be indicated to stack
   **/
  static void igb_receive_skb(struct igb_ring *ring, u8 status,
        struct igb_adapter * adapter = ring->adapter;
        bool vlan_extracted = (adapter->vlgrp && (status & E1000_RXD_STAT_VP));
  
 -#ifdef CONFIG_IGB_LRO
 -      if (adapter->netdev->features & NETIF_F_LRO &&
 -          skb->ip_summed == CHECKSUM_UNNECESSARY) {
 +      skb_record_rx_queue(skb, ring->queue_index);
 +      if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
                if (vlan_extracted)
 -                      lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb,
 -                                         adapter->vlgrp,
 -                                         le16_to_cpu(rx_desc->wb.upper.vlan),
 -                                         rx_desc);
 +                      vlan_gro_receive(&ring->napi, adapter->vlgrp,
 +                                       le16_to_cpu(rx_desc->wb.upper.vlan),
 +                                       skb);
                else
 -                      lro_receive_skb(&ring->lro_mgr,skb, rx_desc);
 -              ring->lro_used = 1;
 +                      napi_gro_receive(&ring->napi, skb);
        } else {
 -#endif
                if (vlan_extracted)
                        vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
                                          le16_to_cpu(rx_desc->wb.upper.vlan));
                else
 -
                        netif_receive_skb(skb);
 -#ifdef CONFIG_IGB_LRO
        }
 -#endif
  }
  
 -
  static inline void igb_rx_checksum_adv(struct igb_adapter *adapter,
                                       u32 status_err, struct sk_buff *skb)
  {
@@@ -4435,19 -3841,17 +4413,19 @@@ static bool igb_clean_rx_irq_adv(struc
  {
        struct igb_adapter *adapter = rx_ring->adapter;
        struct net_device *netdev = adapter->netdev;
 +      struct e1000_hw *hw = &adapter->hw;
        struct pci_dev *pdev = adapter->pdev;
        union e1000_adv_rx_desc *rx_desc , *next_rxd;
        struct igb_buffer *buffer_info , *next_buffer;
        struct sk_buff *skb;
 -      unsigned int i;
 -      u32 length, hlen, staterr;
        bool cleaned = false;
        int cleaned_count = 0;
        unsigned int total_bytes = 0, total_packets = 0;
 +      unsigned int i;
 +      u32 length, hlen, staterr;
  
        i = rx_ring->next_to_clean;
 +      buffer_info = &rx_ring->buffer_info[i];
        rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
        staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
  
                if (*work_done >= budget)
                        break;
                (*work_done)++;
 -              buffer_info = &rx_ring->buffer_info[i];
  
 -              /* HW will not DMA in data larger than the given buffer, even
 -               * if it parses the (NFS, of course) header to be larger.  In
 -               * that case, it fills the header buffer and spills the rest
 -               * into the page.
 -               */
 -              hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) &
 -                E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT;
 -              if (hlen > adapter->rx_ps_hdr_size)
 -                      hlen = adapter->rx_ps_hdr_size;
 +              skb = buffer_info->skb;
 +              prefetch(skb->data - NET_IP_ALIGN);
 +              buffer_info->skb = NULL;
 +
 +              i++;
 +              if (i == rx_ring->count)
 +                      i = 0;
 +              next_rxd = E1000_RX_DESC_ADV(*rx_ring, i);
 +              prefetch(next_rxd);
 +              next_buffer = &rx_ring->buffer_info[i];
  
                length = le16_to_cpu(rx_desc->wb.upper.length);
                cleaned = true;
                cleaned_count++;
  
 -              skb = buffer_info->skb;
 -              prefetch(skb->data - NET_IP_ALIGN);
 -              buffer_info->skb = NULL;
                if (!adapter->rx_ps_hdr_size) {
                        pci_unmap_single(pdev, buffer_info->dma,
                                         adapter->rx_buffer_len +
                        goto send_up;
                }
  
 +              /* HW will not DMA in data larger than the given buffer, even
 +               * if it parses the (NFS, of course) header to be larger.  In
 +               * that case, it fills the header buffer and spills the rest
 +               * into the page.
 +               */
 +              hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) &
 +                E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT;
 +              if (hlen > adapter->rx_ps_hdr_size)
 +                      hlen = adapter->rx_ps_hdr_size;
 +
                if (!skb_shinfo(skb)->nr_frags) {
                        pci_unmap_single(pdev, buffer_info->dma,
 -                                       adapter->rx_ps_hdr_size +
 -                                         NET_IP_ALIGN,
 +                                       adapter->rx_ps_hdr_size + NET_IP_ALIGN,
                                         PCI_DMA_FROMDEVICE);
                        skb_put(skb, hlen);
                }
  
                        skb->truesize += length;
                }
 -send_up:
 -              i++;
 -              if (i == rx_ring->count)
 -                      i = 0;
 -              next_rxd = E1000_RX_DESC_ADV(*rx_ring, i);
 -              prefetch(next_rxd);
 -              next_buffer = &rx_ring->buffer_info[i];
  
                if (!(staterr & E1000_RXD_STAT_EOP)) {
                        buffer_info->skb = next_buffer->skb;
                        next_buffer->dma = 0;
                        goto next_desc;
                }
 +send_up:
 +              /*
 +               * If this bit is set, then the RX registers contain
 +               * the time stamp. No other packet will be time
 +               * stamped until we read these registers, so read the
 +               * registers to make them available again. Because
 +               * only one packet can be time stamped at a time, we
 +               * know that the register values must belong to this
 +               * one here and therefore we don't need to compare
 +               * any of the additional attributes stored for it.
 +               *
 +               * If nothing went wrong, then it should have a
 +               * skb_shared_tx that we can turn into a
 +               * skb_shared_hwtstamps.
 +               *
 +               * TODO: can time stamping be triggered (thus locking
 +               * the registers) without the packet reaching this point
 +               * here? In that case RX time stamping would get stuck.
 +               *
 +               * TODO: in "time stamp all packets" mode this bit is
 +               * not set. Need a global flag for this mode and then
 +               * always read the registers. Cannot be done without
 +               * a race condition.
 +               */
 +              if (unlikely(staterr & E1000_RXD_STAT_TS)) {
 +                      u64 regval;
 +                      u64 ns;
 +                      struct skb_shared_hwtstamps *shhwtstamps =
 +                              skb_hwtstamps(skb);
 +
 +                      WARN(!(rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID),
 +                           "igb: no RX time stamp available for time stamped packet");
 +                      regval = rd32(E1000_RXSTMPL);
 +                      regval |= (u64)rd32(E1000_RXSTMPH) << 32;
 +                      ns = timecounter_cyc2time(&adapter->clock, regval);
 +                      timecompare_update(&adapter->compare, ns);
 +                      memset(shhwtstamps, 0, sizeof(*shhwtstamps));
 +                      shhwtstamps->hwtstamp = ns_to_ktime(ns);
 +                      shhwtstamps->syststamp =
 +                              timecompare_transform(&adapter->compare, ns);
 +              }
  
                if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) {
                        dev_kfree_skb_irq(skb);
@@@ -4594,12 -3958,20 +4572,12 @@@ next_desc
                /* use prefetched values */
                rx_desc = next_rxd;
                buffer_info = next_buffer;
 -
                staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
        }
  
        rx_ring->next_to_clean = i;
        cleaned_count = IGB_DESC_UNUSED(rx_ring);
  
 -#ifdef CONFIG_IGB_LRO
 -      if (rx_ring->lro_used) {
 -              lro_flush_all(&rx_ring->lro_mgr);
 -              rx_ring->lro_used = 0;
 -      }
 -#endif
 -
        if (cleaned_count)
                igb_alloc_rx_buffers_adv(rx_ring, cleaned_count);
  
        return cleaned;
  }
  
 -
  /**
   * igb_alloc_rx_buffers_adv - Replace used receive buffers; packet split
   * @adapter: address of board private structure
@@@ -4626,17 -3999,10 +4604,17 @@@ static void igb_alloc_rx_buffers_adv(st
        struct igb_buffer *buffer_info;
        struct sk_buff *skb;
        unsigned int i;
 +      int bufsz;
  
        i = rx_ring->next_to_use;
        buffer_info = &rx_ring->buffer_info[i];
  
 +      if (adapter->rx_ps_hdr_size)
 +              bufsz = adapter->rx_ps_hdr_size;
 +      else
 +              bufsz = adapter->rx_buffer_len;
 +      bufsz += NET_IP_ALIGN;
 +
        while (cleaned_count--) {
                rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
  
                                buffer_info->page_offset ^= PAGE_SIZE / 2;
                        }
                        buffer_info->page_dma =
 -                              pci_map_page(pdev,
 -                                           buffer_info->page,
 +                              pci_map_page(pdev, buffer_info->page,
                                             buffer_info->page_offset,
                                             PAGE_SIZE / 2,
                                             PCI_DMA_FROMDEVICE);
                }
  
                if (!buffer_info->skb) {
 -                      int bufsz;
 -
 -                      if (adapter->rx_ps_hdr_size)
 -                              bufsz = adapter->rx_ps_hdr_size;
 -                      else
 -                              bufsz = adapter->rx_buffer_len;
 -                      bufsz += NET_IP_ALIGN;
                        skb = netdev_alloc_skb(netdev, bufsz);
 -
                        if (!skb) {
                                adapter->alloc_rx_buff_failed++;
                                goto no_buffers;
                        buffer_info->dma = pci_map_single(pdev, skb->data,
                                                          bufsz,
                                                          PCI_DMA_FROMDEVICE);
 -
                }
                /* Refresh the desc even if buffer_addrs didn't change because
                 * each write-back erases this info. */
@@@ -4743,163 -4119,6 +4721,163 @@@ static int igb_mii_ioctl(struct net_dev
        return 0;
  }
  
 +/**
 + * igb_hwtstamp_ioctl - control hardware time stamping
 + * @netdev:
 + * @ifreq:
 + * @cmd:
 + *
 + * Outgoing time stamping can be enabled and disabled. Play nice and
 + * disable it when requested, although it shouldn't case any overhead
 + * when no packet needs it. At most one packet in the queue may be
 + * marked for time stamping, otherwise it would be impossible to tell
 + * for sure to which packet the hardware time stamp belongs.
 + *
 + * Incoming time stamping has to be configured via the hardware
 + * filters. Not all combinations are supported, in particular event
 + * type has to be specified. Matching the kind of event packet is
 + * not supported, with the exception of "all V2 events regardless of
 + * level 2 or 4".
 + *
 + **/
 +static int igb_hwtstamp_ioctl(struct net_device *netdev,
 +                            struct ifreq *ifr, int cmd)
 +{
 +      struct igb_adapter *adapter = netdev_priv(netdev);
 +      struct e1000_hw *hw = &adapter->hw;
 +      struct hwtstamp_config config;
 +      u32 tsync_tx_ctl_bit = E1000_TSYNCTXCTL_ENABLED;
 +      u32 tsync_rx_ctl_bit = E1000_TSYNCRXCTL_ENABLED;
 +      u32 tsync_rx_ctl_type = 0;
 +      u32 tsync_rx_cfg = 0;
 +      int is_l4 = 0;
 +      int is_l2 = 0;
 +      short port = 319; /* PTP */
 +      u32 regval;
 +
 +      if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
 +              return -EFAULT;
 +
 +      /* reserved for future extensions */
 +      if (config.flags)
 +              return -EINVAL;
 +
 +      switch (config.tx_type) {
 +      case HWTSTAMP_TX_OFF:
 +              tsync_tx_ctl_bit = 0;
 +              break;
 +      case HWTSTAMP_TX_ON:
 +              tsync_tx_ctl_bit = E1000_TSYNCTXCTL_ENABLED;
 +              break;
 +      default:
 +              return -ERANGE;
 +      }
 +
 +      switch (config.rx_filter) {
 +      case HWTSTAMP_FILTER_NONE:
 +              tsync_rx_ctl_bit = 0;
 +              break;
 +      case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
 +      case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
 +      case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
 +      case HWTSTAMP_FILTER_ALL:
 +              /*
 +               * register TSYNCRXCFG must be set, therefore it is not
 +               * possible to time stamp both Sync and Delay_Req messages
 +               * => fall back to time stamping all packets
 +               */
 +              tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_ALL;
 +              config.rx_filter = HWTSTAMP_FILTER_ALL;
 +              break;
 +      case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
 +              tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L4_V1;
 +              tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE;
 +              is_l4 = 1;
 +              break;
 +      case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
 +              tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L4_V1;
 +              tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE;
 +              is_l4 = 1;
 +              break;
 +      case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
 +      case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
 +              tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
 +              tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE;
 +              is_l2 = 1;
 +              is_l4 = 1;
 +              config.rx_filter = HWTSTAMP_FILTER_SOME;
 +              break;
 +      case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
 +      case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
 +              tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
 +              tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE;
 +              is_l2 = 1;
 +              is_l4 = 1;
 +              config.rx_filter = HWTSTAMP_FILTER_SOME;
 +              break;
 +      case HWTSTAMP_FILTER_PTP_V2_EVENT:
 +      case HWTSTAMP_FILTER_PTP_V2_SYNC:
 +      case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
 +              tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_EVENT_V2;
 +              config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
 +              is_l2 = 1;
 +              break;
 +      default:
 +              return -ERANGE;
 +      }
 +
 +      /* enable/disable TX */
 +      regval = rd32(E1000_TSYNCTXCTL);
 +      regval = (regval & ~E1000_TSYNCTXCTL_ENABLED) | tsync_tx_ctl_bit;
 +      wr32(E1000_TSYNCTXCTL, regval);
 +
 +      /* enable/disable RX, define which PTP packets are time stamped */
 +      regval = rd32(E1000_TSYNCRXCTL);
 +      regval = (regval & ~E1000_TSYNCRXCTL_ENABLED) | tsync_rx_ctl_bit;
 +      regval = (regval & ~0xE) | tsync_rx_ctl_type;
 +      wr32(E1000_TSYNCRXCTL, regval);
 +      wr32(E1000_TSYNCRXCFG, tsync_rx_cfg);
 +
 +      /*
 +       * Ethertype Filter Queue Filter[0][15:0] = 0x88F7
 +       *                                          (Ethertype to filter on)
 +       * Ethertype Filter Queue Filter[0][26] = 0x1 (Enable filter)
 +       * Ethertype Filter Queue Filter[0][30] = 0x1 (Enable Timestamping)
 +       */
 +      wr32(E1000_ETQF0, is_l2 ? 0x440088f7 : 0);
 +
 +      /* L4 Queue Filter[0]: only filter by source and destination port */
 +      wr32(E1000_SPQF0, htons(port));
 +      wr32(E1000_IMIREXT(0), is_l4 ?
 +           ((1<<12) | (1<<19) /* bypass size and control flags */) : 0);
 +      wr32(E1000_IMIR(0), is_l4 ?
 +           (htons(port)
 +            | (0<<16) /* immediate interrupt disabled */
 +            | 0 /* (1<<17) bit cleared: do not bypass
 +                   destination port check */)
 +              : 0);
 +      wr32(E1000_FTQF0, is_l4 ?
 +           (0x11 /* UDP */
 +            | (1<<15) /* VF not compared */
 +            | (1<<27) /* Enable Timestamping */
 +            | (7<<28) /* only source port filter enabled,
 +                         source/target address and protocol
 +                         masked */)
 +           : ((1<<15) | (15<<28) /* all mask bits set = filter not
 +                                    enabled */));
 +
 +      wrfl();
 +
 +      adapter->hwtstamp_config = config;
 +
 +      /* clear TX/RX time stamp registers, just to be sure */
 +      regval = rd32(E1000_TXSTMPH);
 +      regval = rd32(E1000_RXSTMPH);
 +
 +      return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
 +              -EFAULT : 0;
 +}
 +
  /**
   * igb_ioctl -
   * @netdev:
@@@ -4913,8 -4132,6 +4891,8 @@@ static int igb_ioctl(struct net_device 
        case SIOCGMIIREG:
        case SIOCSMIIREG:
                return igb_mii_ioctl(netdev, ifr, cmd);
 +      case SIOCSHWTSTAMP:
 +              return igb_hwtstamp_ioctl(netdev, ifr, cmd);
        default:
                return -EOPNOTSUPP;
        }
@@@ -4941,6 -4158,8 +4919,6 @@@ static void igb_vlan_rx_register(struc
                rctl &= ~E1000_RCTL_CFIEN;
                wr32(E1000_RCTL, rctl);
                igb_update_mng_vlan(adapter);
 -              wr32(E1000_RLPML,
 -                              adapter->max_frame_size + VLAN_TAG_SIZE);
        } else {
                /* disable VLAN tag insert/strip */
                ctrl = rd32(E1000_CTRL);
                        igb_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
                        adapter->mng_vlan_id = IGB_MNG_VLAN_NONE;
                }
 -              wr32(E1000_RLPML,
 -                              adapter->max_frame_size);
        }
  
 +      igb_rlpml_set(adapter);
 +
        if (!test_bit(__IGB_DOWN, &adapter->state))
                igb_irq_enable(adapter);
  }
@@@ -4963,25 -4182,24 +4941,25 @@@ static void igb_vlan_rx_add_vid(struct 
  {
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 -      u32 vfta, index;
 +      int pf_id = adapter->vfs_allocated_count;
  
 -      if ((adapter->hw.mng_cookie.status &
 +      if ((hw->mng_cookie.status &
             E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
            (vid == adapter->mng_vlan_id))
                return;
 -      /* add VID to filter table */
 -      index = (vid >> 5) & 0x7F;
 -      vfta = array_rd32(E1000_VFTA, index);
 -      vfta |= (1 << (vid & 0x1F));
 -      igb_write_vfta(&adapter->hw, index, vfta);
 +
 +      /* add vid to vlvf if sr-iov is enabled,
 +       * if that fails add directly to filter table */
 +      if (igb_vlvf_set(adapter, vid, true, pf_id))
 +              igb_vfta_set(hw, vid, true);
 +
  }
  
  static void igb_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
  {
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 -      u32 vfta, index;
 +      int pf_id = adapter->vfs_allocated_count;
  
        igb_irq_disable(adapter);
        vlan_group_set_device(adapter->vlgrp, vid, NULL);
                return;
        }
  
 -      /* remove VID from filter table */
 -      index = (vid >> 5) & 0x7F;
 -      vfta = array_rd32(E1000_VFTA, index);
 -      vfta &= ~(1 << (vid & 0x1F));
 -      igb_write_vfta(&adapter->hw, index, vfta);
 +      /* remove vid from vlvf if sr-iov is enabled,
 +       * if not in vlvf remove from vfta */
 +      if (igb_vlvf_set(adapter, vid, false, pf_id))
 +              igb_vfta_set(hw, vid, false);
  }
  
  static void igb_restore_vlan(struct igb_adapter *adapter)
@@@ -5057,6 -4276,7 +5035,6 @@@ int igb_set_spd_dplx(struct igb_adapte
        return 0;
  }
  
 -
  static int igb_suspend(struct pci_dev *pdev, pm_message_t state)
  {
        struct net_device *netdev = pci_get_drvdata(pdev);
@@@ -5148,7 -4368,10 +5126,7 @@@ static int igb_resume(struct pci_dev *p
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
  
 -      if (adapter->need_ioport)
 -              err = pci_enable_device(pdev);
 -      else
 -              err = pci_enable_device_mem(pdev);
 +      err = pci_enable_device_mem(pdev);
        if (err) {
                dev_err(&pdev->dev,
                        "igb: Cannot enable PCI device from suspend\n");
        /* e1000_power_up_phy(adapter); */
  
        igb_reset(adapter);
 +
 +      /* let the f/w know that the h/w is now under the control of the
 +       * driver. */
 +      igb_get_hw_control(adapter);
 +
        wr32(E1000_WUS, ~0);
  
        if (netif_running(netdev)) {
  
        netif_device_attach(netdev);
  
 -      /* let the f/w know that the h/w is now under the control of the
 -       * driver. */
 -      igb_get_hw_control(adapter);
 -
        return 0;
  }
  #endif
@@@ -5202,27 -4424,22 +5180,27 @@@ static void igb_shutdown(struct pci_de
  static void igb_netpoll(struct net_device *netdev)
  {
        struct igb_adapter *adapter = netdev_priv(netdev);
 +      struct e1000_hw *hw = &adapter->hw;
        int i;
 -      int work_done = 0;
  
 -      igb_irq_disable(adapter);
 -      adapter->flags |= IGB_FLAG_IN_NETPOLL;
 -
 -      for (i = 0; i < adapter->num_tx_queues; i++)
 -              igb_clean_tx_irq(&adapter->tx_ring[i]);
 +      if (!adapter->msix_entries) {
 +              igb_irq_disable(adapter);
 +              napi_schedule(&adapter->rx_ring[0].napi);
 +              return;
 +      }
  
 -      for (i = 0; i < adapter->num_rx_queues; i++)
 -              igb_clean_rx_irq_adv(&adapter->rx_ring[i],
 -                                   &work_done,
 -                                   adapter->rx_ring[i].napi.weight);
 +      for (i = 0; i < adapter->num_tx_queues; i++) {
 +              struct igb_ring *tx_ring = &adapter->tx_ring[i];
 +              wr32(E1000_EIMC, tx_ring->eims_value);
 +              igb_clean_tx_irq(tx_ring);
 +              wr32(E1000_EIMS, tx_ring->eims_value);
 +      }
  
 -      adapter->flags &= ~IGB_FLAG_IN_NETPOLL;
 -      igb_irq_enable(adapter);
 +      for (i = 0; i < adapter->num_rx_queues; i++) {
 +              struct igb_ring *rx_ring = &adapter->rx_ring[i];
 +              wr32(E1000_EIMC, rx_ring->eims_value);
 +              napi_schedule(&rx_ring->napi);
 +      }
  }
  #endif /* CONFIG_NET_POLL_CONTROLLER */
  
@@@ -5265,7 -4482,12 +5243,7 @@@ static pci_ers_result_t igb_io_slot_res
        pci_ers_result_t result;
        int err;
  
 -      if (adapter->need_ioport)
 -              err = pci_enable_device(pdev);
 -      else
 -              err = pci_enable_device_mem(pdev);
 -
 -      if (err) {
 +      if (pci_enable_device_mem(pdev)) {
                dev_err(&pdev->dev,
                        "Cannot re-enable PCI device after reset.\n");
                result = PCI_ERS_RESULT_DISCONNECT;
@@@ -5318,172 -4540,4 +5296,172 @@@ static void igb_io_resume(struct pci_de
        igb_get_hw_control(adapter);
  }
  
 +static inline void igb_set_vmolr(struct e1000_hw *hw, int vfn)
 +{
 +      u32 reg_data;
 +
 +      reg_data = rd32(E1000_VMOLR(vfn));
 +      reg_data |= E1000_VMOLR_BAM |    /* Accept broadcast */
 +                  E1000_VMOLR_ROPE |   /* Accept packets matched in UTA */
 +                  E1000_VMOLR_ROMPE |  /* Accept packets matched in MTA */
 +                  E1000_VMOLR_AUPE |   /* Accept untagged packets */
 +                  E1000_VMOLR_STRVLAN; /* Strip vlan tags */
 +      wr32(E1000_VMOLR(vfn), reg_data);
 +}
 +
 +static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
 +                                 int vfn)
 +{
 +      struct e1000_hw *hw = &adapter->hw;
 +      u32 vmolr;
 +
 +      vmolr = rd32(E1000_VMOLR(vfn));
 +      vmolr &= ~E1000_VMOLR_RLPML_MASK;
 +      vmolr |= size | E1000_VMOLR_LPE;
 +      wr32(E1000_VMOLR(vfn), vmolr);
 +
 +      return 0;
 +}
 +
 +static inline void igb_set_rah_pool(struct e1000_hw *hw, int pool, int entry)
 +{
 +      u32 reg_data;
 +
 +      reg_data = rd32(E1000_RAH(entry));
 +      reg_data &= ~E1000_RAH_POOL_MASK;
 +      reg_data |= E1000_RAH_POOL_1 << pool;;
 +      wr32(E1000_RAH(entry), reg_data);
 +}
 +
 +static void igb_set_mc_list_pools(struct igb_adapter *adapter,
 +                                int entry_count, u16 total_rar_filters)
 +{
 +      struct e1000_hw *hw = &adapter->hw;
 +      int i = adapter->vfs_allocated_count + 1;
 +
 +      if ((i + entry_count) < total_rar_filters)
 +              total_rar_filters = i + entry_count;
 +
 +      for (; i < total_rar_filters; i++)
 +              igb_set_rah_pool(hw, adapter->vfs_allocated_count, i);
 +}
 +
 +static int igb_set_vf_mac(struct igb_adapter *adapter,
 +                          int vf, unsigned char *mac_addr)
 +{
 +      struct e1000_hw *hw = &adapter->hw;
 +      int rar_entry = vf + 1; /* VF MAC addresses start at entry 1 */
 +
 +      igb_rar_set(hw, mac_addr, rar_entry);
 +
 +      memcpy(adapter->vf_data[vf].vf_mac_addresses, mac_addr, ETH_ALEN);
 +
 +      igb_set_rah_pool(hw, vf, rar_entry);
 +
 +      return 0;
 +}
 +
 +static void igb_vmm_control(struct igb_adapter *adapter)
 +{
 +      struct e1000_hw *hw = &adapter->hw;
 +      u32 reg_data;
 +
 +      if (!adapter->vfs_allocated_count)
 +              return;
 +
 +      /* VF's need PF reset indication before they
 +       * can send/receive mail */
 +      reg_data = rd32(E1000_CTRL_EXT);
 +      reg_data |= E1000_CTRL_EXT_PFRSTD;
 +      wr32(E1000_CTRL_EXT, reg_data);
 +
 +      igb_vmdq_set_loopback_pf(hw, true);
 +      igb_vmdq_set_replication_pf(hw, true);
 +}
 +
 +#ifdef CONFIG_PCI_IOV
 +static ssize_t igb_show_num_vfs(struct device *dev,
 +                                struct device_attribute *attr, char *buf)
 +{
 +      struct igb_adapter *adapter = netdev_priv(to_net_dev(dev));
 +
 +      return sprintf(buf, "%d\n", adapter->vfs_allocated_count);
 +}
 +
 +static ssize_t igb_set_num_vfs(struct device *dev,
 +                               struct device_attribute *attr,
 +                               const char *buf, size_t count)
 +{
 +      struct net_device *netdev = to_net_dev(dev);
 +      struct igb_adapter *adapter = netdev_priv(netdev);
 +      struct e1000_hw *hw = &adapter->hw;
 +      struct pci_dev *pdev = adapter->pdev;
 +      unsigned int num_vfs, i;
 +      unsigned char mac_addr[ETH_ALEN];
 +      int err;
 +
 +      sscanf(buf, "%u", &num_vfs);
 +
 +      if (num_vfs > 7)
 +              num_vfs = 7;
 +
 +      /* value unchanged do nothing */
 +      if (num_vfs == adapter->vfs_allocated_count)
 +              return count;
 +
 +      if (netdev->flags & IFF_UP)
 +              igb_close(netdev);
 +
 +      igb_reset_interrupt_capability(adapter);
 +      igb_free_queues(adapter);
 +      adapter->tx_ring = NULL;
 +      adapter->rx_ring = NULL;
 +      adapter->vfs_allocated_count = 0;
 +
 +      /* reclaim resources allocated to VFs since we are changing count */
 +      if (adapter->vf_data) {
 +              /* disable iov and allow time for transactions to clear */
 +              pci_disable_sriov(pdev);
 +              msleep(500);
 +
 +              kfree(adapter->vf_data);
 +              adapter->vf_data = NULL;
 +              wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
 +              msleep(100);
 +              dev_info(&pdev->dev, "IOV Disabled\n");
 +      }
 +
 +      if (num_vfs) {
 +              adapter->vf_data = kcalloc(num_vfs,
 +                                         sizeof(struct vf_data_storage),
 +                                         GFP_KERNEL);
 +              if (!adapter->vf_data) {
 +                      dev_err(&pdev->dev, "Could not allocate VF private "
 +                              "data - IOV enable failed\n");
 +              } else {
 +                      err = pci_enable_sriov(pdev, num_vfs);
 +                      if (!err) {
 +                              adapter->vfs_allocated_count = num_vfs;
 +                              dev_info(&pdev->dev, "%d vfs allocated\n", num_vfs);
 +                              for (i = 0; i < adapter->vfs_allocated_count; i++) {
 +                                      random_ether_addr(mac_addr);
 +                                      igb_set_vf_mac(adapter, i, mac_addr);
 +                              }
 +                      } else {
 +                              kfree(adapter->vf_data);
 +                              adapter->vf_data = NULL;
 +                      }
 +              }
 +      }
 +
 +      igb_set_interrupt_capability(adapter);
 +      igb_alloc_queues(adapter);
 +      igb_reset(adapter);
 +
 +      if (netdev->flags & IFF_UP)
 +              igb_open(netdev);
 +
 +      return count;
 +}
 +#endif /* CONFIG_PCI_IOV */
  /* igb_main.c */
index 0b2b609fad851f63635d3efd624b84194879e0a5,5d364a96e35de2454bb93527946ae5c0f515505e..335119a5687abf1788ee836e80fb73b9e6fb3519
@@@ -1,7 -1,7 +1,7 @@@
  /*******************************************************************************
  
    Intel 10 Gigabit PCI Express Linux driver
 -  Copyright(c) 1999 - 2008 Intel Corporation.
 +  Copyright(c) 1999 - 2009 Intel Corporation.
  
    This program is free software; you can redistribute it and/or modify it
    under the terms and conditions of the GNU General Public License,
@@@ -47,13 -47,12 +47,13 @@@ char ixgbe_driver_name[] = "ixgbe"
  static const char ixgbe_driver_string[] =
                                "Intel(R) 10 Gigabit PCI Express Network Driver";
  
 -#define DRV_VERSION "1.3.30-k2"
 +#define DRV_VERSION "2.0.8-k2"
  const char ixgbe_driver_version[] = DRV_VERSION;
 -static char ixgbe_copyright[] = "Copyright (c) 1999-2007 Intel Corporation.";
 +static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation.";
  
  static const struct ixgbe_info *ixgbe_info_tbl[] = {
        [board_82598] = &ixgbe_82598_info,
 +      [board_82599] = &ixgbe_82599_info,
  };
  
  /* ixgbe_pci_tbl - PCI Device ID Table
@@@ -65,8 -64,6 +65,8 @@@
   *   Class, Class Mask, private data (not used) }
   */
  static struct pci_device_id ixgbe_pci_tbl[] = {
 +      {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598),
 +       board_82598 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT),
         board_82598 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT),
         board_82598 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_SFP_LOM),
         board_82598 },
 +      {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_BX),
 +       board_82598 },
 +      {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4),
 +       board_82599 },
 +      {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP),
 +       board_82599 },
  
        /* required last entry */
        {0, }
@@@ -134,53 -125,17 +134,53 @@@ static void ixgbe_get_hw_control(struc
                        ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
  }
  
 -static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, u16 int_alloc_entry,
 -                           u8 msix_vector)
 +/*
 + * ixgbe_set_ivar - set the IVAR registers, mapping interrupt causes to vectors
 + * @adapter: pointer to adapter struct
 + * @direction: 0 for Rx, 1 for Tx, -1 for other causes
 + * @queue: queue to map the corresponding interrupt to
 + * @msix_vector: the vector to map to the corresponding queue
 + *
 + */
 +static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction,
 +                         u8 queue, u8 msix_vector)
  {
        u32 ivar, index;
 -
 -      msix_vector |= IXGBE_IVAR_ALLOC_VAL;
 -      index = (int_alloc_entry >> 2) & 0x1F;
 -      ivar = IXGBE_READ_REG(&adapter->hw, IXGBE_IVAR(index));
 -      ivar &= ~(0xFF << (8 * (int_alloc_entry & 0x3)));
 -      ivar |= (msix_vector << (8 * (int_alloc_entry & 0x3)));
 -      IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar);
 +      struct ixgbe_hw *hw = &adapter->hw;
 +      switch (hw->mac.type) {
 +      case ixgbe_mac_82598EB:
 +              msix_vector |= IXGBE_IVAR_ALLOC_VAL;
 +              if (direction == -1)
 +                      direction = 0;
 +              index = (((direction * 64) + queue) >> 2) & 0x1F;
 +              ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
 +              ivar &= ~(0xFF << (8 * (queue & 0x3)));
 +              ivar |= (msix_vector << (8 * (queue & 0x3)));
 +              IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
 +              break;
 +      case ixgbe_mac_82599EB:
 +              if (direction == -1) {
 +                      /* other causes */
 +                      msix_vector |= IXGBE_IVAR_ALLOC_VAL;
 +                      index = ((queue & 1) * 8);
 +                      ivar = IXGBE_READ_REG(&adapter->hw, IXGBE_IVAR_MISC);
 +                      ivar &= ~(0xFF << index);
 +                      ivar |= (msix_vector << index);
 +                      IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR_MISC, ivar);
 +                      break;
 +              } else {
 +                      /* tx or rx causes */
 +                      msix_vector |= IXGBE_IVAR_ALLOC_VAL;
 +                      index = ((16 * (queue & 1)) + (8 * direction));
 +                      ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(queue >> 1));
 +                      ivar &= ~(0xFF << index);
 +                      ivar |= (msix_vector << index);
 +                      IXGBE_WRITE_REG(hw, IXGBE_IVAR(queue >> 1), ivar);
 +                      break;
 +              }
 +      default:
 +              break;
 +      }
  }
  
  static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
@@@ -245,39 -200,39 +245,39 @@@ static inline bool ixgbe_check_tx_hang(
  #define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
        MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */
  
 -#define GET_TX_HEAD_FROM_RING(ring) (\
 -      *(volatile u32 *) \
 -      ((union ixgbe_adv_tx_desc *)(ring)->desc + (ring)->count))
  static void ixgbe_tx_timeout(struct net_device *netdev);
  
  /**
   * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
   * @adapter: board private structure
   * @tx_ring: tx ring to clean
 + *
 + * returns true if transmit work is done
   **/
  static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
                                 struct ixgbe_ring *tx_ring)
  {
 -      union ixgbe_adv_tx_desc *tx_desc;
 -      struct ixgbe_tx_buffer *tx_buffer_info;
        struct net_device *netdev = adapter->netdev;
 -      struct sk_buff *skb;
 -      unsigned int i;
 -      u32 head, oldhead;
 -      unsigned int count = 0;
 +      union ixgbe_adv_tx_desc *tx_desc, *eop_desc;
 +      struct ixgbe_tx_buffer *tx_buffer_info;
 +      unsigned int i, eop, count = 0;
        unsigned int total_bytes = 0, total_packets = 0;
  
 -      rmb();
 -      head = GET_TX_HEAD_FROM_RING(tx_ring);
 -      head = le32_to_cpu(head);
        i = tx_ring->next_to_clean;
 -      while (1) {
 -              while (i != head) {
 +      eop = tx_ring->tx_buffer_info[i].next_to_watch;
 +      eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
 +
 +      while ((eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) &&
 +             (count < tx_ring->work_limit)) {
 +              bool cleaned = false;
 +              for ( ; !cleaned; count++) {
 +                      struct sk_buff *skb;
                        tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
                        tx_buffer_info = &tx_ring->tx_buffer_info[i];
 +                      cleaned = (i == eop);
                        skb = tx_buffer_info->skb;
  
 -                      if (skb) {
 +                      if (cleaned && skb) {
                                unsigned int segs, bytecount;
  
                                /* gso_segs is currently only valid for tcp */
                        ixgbe_unmap_and_free_tx_resource(adapter,
                                                         tx_buffer_info);
  
 +                      tx_desc->wb.status = 0;
 +
                        i++;
                        if (i == tx_ring->count)
                                i = 0;
 -
 -                      count++;
 -                      if (count == tx_ring->count)
 -                              goto done_cleaning;
                }
 -              oldhead = head;
 -              rmb();
 -              head = GET_TX_HEAD_FROM_RING(tx_ring);
 -              head = le32_to_cpu(head);
 -              if (head == oldhead)
 -                      goto done_cleaning;
 -      } /* while (1) */
 -
 -done_cleaning:
 +
 +              eop = tx_ring->tx_buffer_info[i].next_to_watch;
 +              eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
 +      }
 +
        tx_ring->next_to_clean = i;
  
  #define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
        }
  
        /* re-arm the interrupt */
 -      if ((total_packets >= tx_ring->work_limit) ||
 -          (count == tx_ring->count))
 +      if (count >= tx_ring->work_limit)
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->v_idx);
  
        tx_ring->total_bytes += total_bytes;
        tx_ring->total_packets += total_packets;
 -      tx_ring->stats.bytes += total_bytes;
        tx_ring->stats.packets += total_packets;
 +      tx_ring->stats.bytes += total_bytes;
        adapter->net_stats.tx_bytes += total_bytes;
        adapter->net_stats.tx_packets += total_packets;
 -      return (total_packets ? true : false);
 +      return (count < tx_ring->work_limit);
  }
  
  #ifdef CONFIG_IXGBE_DCA
@@@ -352,19 -314,13 +352,19 @@@ static void ixgbe_update_rx_dca(struct 
  
        if (rx_ring->cpu != cpu) {
                rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q));
 -              rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK;
 -              rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
 +              if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
 +                      rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK;
 +                      rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
 +              } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
 +                      rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK_82599;
 +                      rxctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
 +                                 IXGBE_DCA_RXCTRL_CPUID_SHIFT_82599);
 +              }
                rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN;
                rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN;
                rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_RRO_EN);
                rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN |
 -                          IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
 +                          IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q), rxctrl);
                rx_ring->cpu = cpu;
        }
@@@ -380,14 -336,8 +380,14 @@@ static void ixgbe_update_tx_dca(struct 
  
        if (tx_ring->cpu != cpu) {
                txctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_TXCTRL(q));
 -              txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK;
 -              txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
 +              if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
 +                      txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK;
 +                      txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
 +              } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
 +                      txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK_82599;
 +                      txctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
 +                                 IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599);
 +              }
                txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_TXCTRL(q), txctrl);
                tx_ring->cpu = cpu;
@@@ -453,21 -403,23 +453,21 @@@ static int __ixgbe_notify_dca(struct de
   * @rx_ring: rx descriptor ring (for a specific queue) to setup
   * @rx_desc: rx descriptor
   **/
 -static void ixgbe_receive_skb(struct ixgbe_adapter *adapter,
 +static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector,
                                struct sk_buff *skb, u8 status,
 -                              struct ixgbe_ring *ring,
                                union ixgbe_adv_rx_desc *rx_desc)
  {
 +      struct ixgbe_adapter *adapter = q_vector->adapter;
 +      struct napi_struct *napi = &q_vector->napi;
        bool is_vlan = (status & IXGBE_RXD_STAT_VP);
        u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan);
  
 -      if (adapter->netdev->features & NETIF_F_LRO &&
 -          skb->ip_summed == CHECKSUM_UNNECESSARY) {
 +      skb_record_rx_queue(skb, q_vector - &adapter->q_vector[0]);
 +      if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
                if (adapter->vlgrp && is_vlan && (tag != 0))
 -                      lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb,
 -                                                   adapter->vlgrp, tag,
 -                                                   rx_desc);
 +                      vlan_gro_receive(napi, adapter->vlgrp, tag, skb);
                else
 -                      lro_receive_skb(&ring->lro_mgr, skb, rx_desc);
 -              ring->lro_used = true;
 +                      napi_gro_receive(napi, skb);
        } else {
                if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) {
                        if (adapter->vlgrp && is_vlan && (tag != 0))
@@@ -518,19 -470,6 +518,19 @@@ static inline void ixgbe_rx_checksum(st
        adapter->hw_csum_rx_good++;
  }
  
 +static inline void ixgbe_release_rx_desc(struct ixgbe_hw *hw,
 +                                         struct ixgbe_ring *rx_ring, u32 val)
 +{
 +      /*
 +       * Force memory writes to complete before letting h/w
 +       * know there are new descriptors to fetch.  (Only
 +       * applicable for weak-ordered memory model archs,
 +       * such as IA-64).
 +       */
 +      wmb();
 +      IXGBE_WRITE_REG(hw, IXGBE_RDT(rx_ring->reg_idx), val);
 +}
 +
  /**
   * ixgbe_alloc_rx_buffers - Replace used receive buffers; packet split
   * @adapter: address of board private structure
@@@ -543,7 -482,6 +543,7 @@@ static void ixgbe_alloc_rx_buffers(stru
        union ixgbe_adv_rx_desc *rx_desc;
        struct ixgbe_rx_buffer *bi;
        unsigned int i;
 +      unsigned int bufsz = rx_ring->rx_buf_len + NET_IP_ALIGN;
  
        i = rx_ring->next_to_use;
        bi = &rx_ring->rx_buffer_info[i];
  
                if (!bi->skb) {
                        struct sk_buff *skb;
 -                      skb = netdev_alloc_skb(adapter->netdev,
 -                                             (rx_ring->rx_buf_len +
 -                                              NET_IP_ALIGN));
 +                      skb = netdev_alloc_skb(adapter->netdev, bufsz);
  
                        if (!skb) {
                                adapter->alloc_rx_buff_failed++;
                        skb_reserve(skb, NET_IP_ALIGN);
  
                        bi->skb = skb;
 -                      bi->dma = pci_map_single(pdev, skb->data,
 -                                               rx_ring->rx_buf_len,
 +                      bi->dma = pci_map_single(pdev, skb->data, bufsz,
                                                 PCI_DMA_FROMDEVICE);
                }
                /* Refresh the desc even if buffer_addrs didn't change because
@@@ -612,7 -553,14 +612,7 @@@ no_buffers
                if (i-- == 0)
                        i = (rx_ring->count - 1);
  
 -              /*
 -               * Force memory writes to complete before letting h/w
 -               * know there are new descriptors to fetch.  (Only
 -               * applicable for weak-ordered memory model archs,
 -               * such as IA-64).
 -               */
 -              wmb();
 -              writel(i, adapter->hw.hw_addr + rx_ring->tail);
 +              ixgbe_release_rx_desc(&adapter->hw, rx_ring, i);
        }
  }
  
@@@ -626,11 -574,10 +626,11 @@@ static inline u16 ixgbe_get_pkt_info(un
        return rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
  }
  
 -static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
 +static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                                 struct ixgbe_ring *rx_ring,
                                 int *work_done, int work_to_do)
  {
 +      struct ixgbe_adapter *adapter = q_vector->adapter;
        struct pci_dev *pdev = adapter->pdev;
        union ixgbe_adv_rx_desc *rx_desc, *next_rxd;
        struct ixgbe_rx_buffer *rx_buffer_info, *next_buffer;
                total_rx_packets++;
  
                skb->protocol = eth_type_trans(skb, adapter->netdev);
 -              ixgbe_receive_skb(adapter, skb, staterr, rx_ring, rx_desc);
 +              ixgbe_receive_skb(q_vector, skb, staterr, rx_desc);
  
  next_desc:
                rx_desc->wb.upper.status_error = 0;
                staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
        }
  
 -      if (rx_ring->lro_used) {
 -              lro_flush_all(&rx_ring->lro_mgr);
 -              rx_ring->lro_used = false;
 -      }
 -
        rx_ring->next_to_clean = i;
        cleaned_count = IXGBE_DESC_UNUSED(rx_ring);
  
@@@ -779,8 -731,7 +779,8 @@@ static void ixgbe_configure_msix(struc
  
        q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
  
 -      /* Populate the IVAR table and set the ITR values to the
 +      /*
 +       * Populate the IVAR table and set the ITR values to the
         * corresponding register.
         */
        for (v_idx = 0; v_idx < q_vectors; v_idx++) {
  
                for (i = 0; i < q_vector->rxr_count; i++) {
                        j = adapter->rx_ring[r_idx].reg_idx;
 -                      ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(j), v_idx);
 +                      ixgbe_set_ivar(adapter, 0, j, v_idx);
                        r_idx = find_next_bit(q_vector->rxr_idx,
                                              adapter->num_rx_queues,
                                              r_idx + 1);
  
                for (i = 0; i < q_vector->txr_count; i++) {
                        j = adapter->tx_ring[r_idx].reg_idx;
 -                      ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(j), v_idx);
 +                      ixgbe_set_ivar(adapter, 1, j, v_idx);
                        r_idx = find_next_bit(q_vector->txr_idx,
                                              adapter->num_tx_queues,
                                              r_idx + 1);
                /* if this is a tx only vector halve the interrupt rate */
                if (q_vector->txr_count && !q_vector->rxr_count)
                        q_vector->eitr = (adapter->eitr_param >> 1);
 -              else
 +              else if (q_vector->rxr_count)
                        /* rx only */
                        q_vector->eitr = adapter->eitr_param;
  
 +              /*
 +               * since this is initial set up don't need to call
 +               * ixgbe_write_eitr helper
 +               */
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx),
                                EITR_INTS_PER_SEC_TO_REG(q_vector->eitr));
        }
  
 -      ixgbe_set_ivar(adapter, IXGBE_IVAR_OTHER_CAUSES_INDEX, v_idx);
 +      if (adapter->hw.mac.type == ixgbe_mac_82598EB)
 +              ixgbe_set_ivar(adapter, -1, IXGBE_IVAR_OTHER_CAUSES_INDEX,
 +                             v_idx);
 +      else if (adapter->hw.mac.type == ixgbe_mac_82599EB)
 +              ixgbe_set_ivar(adapter, -1, 1, v_idx);
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx), 1950);
  
        /* set up to autoclear timer, and the vectors */
@@@ -902,35 -845,10 +902,35 @@@ update_itr_done
        return retval;
  }
  
 +/**
 + * ixgbe_write_eitr - write EITR register in hardware specific way
 + * @adapter: pointer to adapter struct
 + * @v_idx: vector index into q_vector array
 + * @itr_reg: new value to be written in *register* format, not ints/s
 + *
 + * This function is made to be called by ethtool and by the driver
 + * when it needs to update EITR registers at runtime.  Hardware
 + * specific quirks/differences are taken care of here.
 + */
 +void ixgbe_write_eitr(struct ixgbe_adapter *adapter, int v_idx, u32 itr_reg)
 +{
 +      struct ixgbe_hw *hw = &adapter->hw;
 +      if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
 +              /* must write high and low 16 bits to reset counter */
 +              itr_reg |= (itr_reg << 16);
 +      } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
 +              /*
 +               * set the WDIS bit to not clear the timer bits and cause an
 +               * immediate assertion of the interrupt
 +               */
 +              itr_reg |= IXGBE_EITR_CNT_WDIS;
 +      }
 +      IXGBE_WRITE_REG(hw, IXGBE_EITR(v_idx), itr_reg);
 +}
 +
  static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
  {
        struct ixgbe_adapter *adapter = q_vector->adapter;
 -      struct ixgbe_hw *hw = &adapter->hw;
        u32 new_itr;
        u8 current_itr, ret_itr;
        int i, r_idx, v_idx = ((void *)q_vector - (void *)(adapter->q_vector)) /
  
        if (new_itr != q_vector->eitr) {
                u32 itr_reg;
 +
 +              /* save the algorithm value here, not the smoothed one */
 +              q_vector->eitr = new_itr;
                /* do an exponential smoothing */
                new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100);
 -              q_vector->eitr = new_itr;
                itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr);
 -              /* must write high and low 16 bits to reset counter */
 -              DPRINTK(TX_ERR, DEBUG, "writing eitr(%d): %08X\n", v_idx,
 -                      itr_reg);
 -              IXGBE_WRITE_REG(hw, IXGBE_EITR(v_idx), itr_reg | (itr_reg)<<16);
 +              ixgbe_write_eitr(adapter, v_idx, itr_reg);
        }
  
        return;
@@@ -1009,24 -928,6 +1009,24 @@@ static void ixgbe_check_fan_failure(str
        }
  }
  
 +static void ixgbe_check_sfp_event(struct ixgbe_adapter *adapter, u32 eicr)
 +{
 +      struct ixgbe_hw *hw = &adapter->hw;
 +
 +      if (eicr & IXGBE_EICR_GPI_SDP1) {
 +              /* Clear the interrupt */
 +              IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
 +              schedule_work(&adapter->multispeed_fiber_task);
 +      } else if (eicr & IXGBE_EICR_GPI_SDP2) {
 +              /* Clear the interrupt */
 +              IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
 +              schedule_work(&adapter->sfp_config_module_task);
 +      } else {
 +              /* Interrupt isn't for us... */
 +              return;
 +      }
 +}
 +
  static void ixgbe_check_lsc(struct ixgbe_adapter *adapter)
  {
        struct ixgbe_hw *hw = &adapter->hw;
@@@ -1045,25 -946,13 +1045,25 @@@ static irqreturn_t ixgbe_msix_lsc(int i
        struct net_device *netdev = data;
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
 -      u32 eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
 +      u32 eicr;
 +
 +      /*
 +       * Workaround for Silicon errata.  Use clear-by-write instead
 +       * of clear-by-read.  Reading with EICS will return the
 +       * interrupt causes without clearing, which later be done
 +       * with the write to EICR.
 +       */
 +      eicr = IXGBE_READ_REG(hw, IXGBE_EICS);
 +      IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr);
  
        if (eicr & IXGBE_EICR_LSC)
                ixgbe_check_lsc(adapter);
  
 -      ixgbe_check_fan_failure(adapter, eicr);
 +      if (hw->mac.type == ixgbe_mac_82598EB)
 +              ixgbe_check_fan_failure(adapter, eicr);
  
 +      if (hw->mac.type == ixgbe_mac_82599EB)
 +              ixgbe_check_sfp_event(adapter, eicr);
        if (!test_bit(__IXGBE_DOWN, &adapter->state))
                IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
  
@@@ -1126,7 -1015,7 +1126,7 @@@ static irqreturn_t ixgbe_msix_clean_rx(
        rx_ring = &(adapter->rx_ring[r_idx]);
        /* disable interrupts on this vector only */
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rx_ring->v_idx);
 -      netif_rx_schedule(&q_vector->napi);
 +      napi_schedule(&q_vector->napi);
  
        return IRQ_HANDLED;
  }
@@@ -1163,12 -1052,12 +1163,12 @@@ static int ixgbe_clean_rxonly(struct na
                ixgbe_update_rx_dca(adapter, rx_ring);
  #endif
  
 -      ixgbe_clean_rx_irq(adapter, rx_ring, &work_done, budget);
 +      ixgbe_clean_rx_irq(q_vector, rx_ring, &work_done, budget);
  
        /* If all Rx work done, exit the polling mode */
        if (work_done < budget) {
 -              netif_rx_complete(napi);
 -              if (adapter->itr_setting & 3)
 +              napi_complete(napi);
 +              if (adapter->itr_setting & 1)
                        ixgbe_set_itr_msix(q_vector);
                if (!test_bit(__IXGBE_DOWN, &adapter->state))
                        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, rx_ring->v_idx);
@@@ -1206,7 -1095,7 +1206,7 @@@ static int ixgbe_clean_rxonly_many(stru
                if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
                        ixgbe_update_rx_dca(adapter, rx_ring);
  #endif
 -              ixgbe_clean_rx_irq(adapter, rx_ring, &work_done, budget);
 +              ixgbe_clean_rx_irq(q_vector, rx_ring, &work_done, budget);
                enable_mask |= rx_ring->v_idx;
                r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
                                      r_idx + 1);
        rx_ring = &(adapter->rx_ring[r_idx]);
        /* If all Rx work done, exit the polling mode */
        if (work_done < budget) {
 -              netif_rx_complete(napi);
 -              if (adapter->itr_setting & 3)
 +              napi_complete(napi);
 +              if (adapter->itr_setting & 1)
                        ixgbe_set_itr_msix(q_vector);
                if (!test_bit(__IXGBE_DOWN, &adapter->state))
                        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, enable_mask);
@@@ -1387,6 -1276,7 +1387,6 @@@ out
  
  static void ixgbe_set_itr(struct ixgbe_adapter *adapter)
  {
 -      struct ixgbe_hw *hw = &adapter->hw;
        struct ixgbe_q_vector *q_vector = adapter->q_vector;
        u8 current_itr;
        u32 new_itr = q_vector->eitr;
  
        if (new_itr != q_vector->eitr) {
                u32 itr_reg;
 +
 +              /* save the algorithm value here, not the smoothed one */
 +              q_vector->eitr = new_itr;
                /* do an exponential smoothing */
                new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100);
 -              q_vector->eitr = new_itr;
                itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr);
 -              /* must write high and low 16 bits to reset counter */
 -              IXGBE_WRITE_REG(hw, IXGBE_EITR(0), itr_reg | (itr_reg)<<16);
 +              ixgbe_write_eitr(adapter, 0, itr_reg);
        }
  
        return;
  static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
  {
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
 +      if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
 +              IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0);
 +              IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(2), ~0);
 +      }
        IXGBE_WRITE_FLUSH(&adapter->hw);
        if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
                int i;
@@@ -1464,21 -1349,7 +1464,21 @@@ static inline void ixgbe_irq_enable(str
        mask = IXGBE_EIMS_ENABLE_MASK;
        if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
                mask |= IXGBE_EIMS_GPI_SDP1;
 +      if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
 +              mask |= IXGBE_EIMS_ECC;
 +              mask |= IXGBE_EIMS_GPI_SDP1;
 +              mask |= IXGBE_EIMS_GPI_SDP2;
 +      }
 +
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
 +      if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
 +              /* enable the rest of the queue vectors */
 +              IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1),
 +                              (IXGBE_EIMS_RTX_QUEUE << 16));
 +              IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(2),
 +                              ((IXGBE_EIMS_RTX_QUEUE << 16) |
 +                                IXGBE_EIMS_RTX_QUEUE));
 +      }
        IXGBE_WRITE_FLUSH(&adapter->hw);
  }
  
@@@ -1494,12 -1365,6 +1494,12 @@@ static irqreturn_t ixgbe_intr(int irq, 
        struct ixgbe_hw *hw = &adapter->hw;
        u32 eicr;
  
 +      /*
 +       * Workaround for silicon errata.  Mask the interrupts
 +       * before the read of EICR.
 +       */
 +      IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK);
 +
        /* for NAPI, using EIAM to auto-mask tx/rx interrupt bits on read
         * therefore no explict interrupt disable is necessary */
        eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
        if (eicr & IXGBE_EICR_LSC)
                ixgbe_check_lsc(adapter);
  
 +      if (hw->mac.type == ixgbe_mac_82599EB)
 +              ixgbe_check_sfp_event(adapter, eicr);
 +
        ixgbe_check_fan_failure(adapter, eicr);
  
 -      if (netif_rx_schedule_prep(&adapter->q_vector[0].napi)) {
 +      if (napi_schedule_prep(&adapter->q_vector[0].napi)) {
                adapter->tx_ring[0].total_packets = 0;
                adapter->tx_ring[0].total_bytes = 0;
                adapter->rx_ring[0].total_packets = 0;
                adapter->rx_ring[0].total_bytes = 0;
                /* would disable interrupts here but EIAM disabled it */
 -              __netif_rx_schedule(&adapter->q_vector[0].napi);
 +              __napi_schedule(&adapter->q_vector[0].napi);
        }
  
        return IRQ_HANDLED;
@@@ -1607,8 -1469,8 +1607,8 @@@ static void ixgbe_configure_msi_and_leg
        IXGBE_WRITE_REG(hw, IXGBE_EITR(0),
                        EITR_INTS_PER_SEC_TO_REG(adapter->eitr_param));
  
 -      ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(0), 0);
 -      ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(0), 0);
 +      ixgbe_set_ivar(adapter, 0, 0, 0);
 +      ixgbe_set_ivar(adapter, 1, 0, 0);
  
        map_vector_to_rxq(adapter, 0, 0);
        map_vector_to_txq(adapter, 0, 0);
   **/
  static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
  {
 -      u64 tdba, tdwba;
 +      u64 tdba;
        struct ixgbe_hw *hw = &adapter->hw;
        u32 i, j, tdlen, txctrl;
  
                IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j),
                                (tdba & DMA_32BIT_MASK));
                IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32));
 -              tdwba = ring->dma +
 -                      (ring->count * sizeof(union ixgbe_adv_tx_desc));
 -              tdwba |= IXGBE_TDWBAL_HEAD_WB_ENABLE;
 -              IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(j), tdwba & DMA_32BIT_MASK);
 -              IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(j), (tdwba >> 32));
                IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), tdlen);
                IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0);
                IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0);
                txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
                IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl);
        }
 +      if (hw->mac.type == ixgbe_mac_82599EB) {
 +              /* We enable 8 traffic classes, DCB only */
 +              if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
 +                      IXGBE_WRITE_REG(hw, IXGBE_MTQC, (IXGBE_MTQC_RT_ENA |
 +                                      IXGBE_MTQC_8TC_8TQ));
 +      }
  }
  
 -#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT       2
 +#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2
  
  static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index)
  {
        struct ixgbe_ring *rx_ring;
        u32 srrctl;
 -      int queue0;
 +      int queue0 = 0;
        unsigned long mask;
  
 -      /* program one srrctl register per VMDq index */
 -      if (adapter->flags & IXGBE_FLAG_VMDQ_ENABLED) {
 -              long shift, len;
 -              mask = (unsigned long) adapter->ring_feature[RING_F_RSS].mask;
 -              len = sizeof(adapter->ring_feature[RING_F_VMDQ].mask) * 8;
 -              shift = find_first_bit(&mask, len);
 -              queue0 = index & mask;
 -              index = (index & mask) >> shift;
 -      /* program one srrctl per RSS queue since RDRXCTL.MVMEN is enabled */
 +      if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
 +              queue0 = index;
        } else {
                mask = (unsigned long) adapter->ring_feature[RING_F_RSS].mask;
                queue0 = index & mask;
        srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
  
        if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
 -              srrctl |= IXGBE_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
 +              u16 bufsz = IXGBE_RXBUFFER_2048;
 +              /* grow the amount we can receive on large page machines */
 +              if (bufsz < (PAGE_SIZE / 2))
 +                      bufsz = (PAGE_SIZE / 2);
 +              /* cap the bufsz at our largest descriptor size */
 +              bufsz = min((u16)IXGBE_MAX_RXBUFFER, bufsz);
 +
 +              srrctl |= bufsz >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
                srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
                srrctl |= ((IXGBE_RX_HDR_SIZE <<
                            IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
                        srrctl |= rx_ring->rx_buf_len >>
                                  IXGBE_SRRCTL_BSIZEPKT_SHIFT;
        }
 -      IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(index), srrctl);
 -}
  
 -/**
 - * ixgbe_get_skb_hdr - helper function for LRO header processing
 - * @skb: pointer to sk_buff to be added to LRO packet
 - * @iphdr: pointer to ip header structure
 - * @tcph: pointer to tcp header structure
 - * @hdr_flags: pointer to header flags
 - * @priv: private data
 - **/
 -static int ixgbe_get_skb_hdr(struct sk_buff *skb, void **iphdr, void **tcph,
 -                             u64 *hdr_flags, void *priv)
 -{
 -      union ixgbe_adv_rx_desc *rx_desc = priv;
 -
 -      /* Verify that this is a valid IPv4 TCP packet */
 -      if (!((ixgbe_get_pkt_info(rx_desc) & IXGBE_RXDADV_PKTTYPE_IPV4) &&
 -           (ixgbe_get_pkt_info(rx_desc) & IXGBE_RXDADV_PKTTYPE_TCP)))
 -              return -1;
 -
 -      /* Set network headers */
 -      skb_reset_network_header(skb);
 -      skb_set_transport_header(skb, ip_hdrlen(skb));
 -      *iphdr = ip_hdr(skb);
 -      *tcph = tcp_hdr(skb);
 -      *hdr_flags = LRO_IPV4 | LRO_TCP;
 -      return 0;
 +      IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(index), srrctl);
  }
  
 -#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \
 -                           (((S) & (PAGE_SIZE - 1)) ? 1 : 0))
 -
  /**
   * ixgbe_configure_rx - Configure 8259x Receive Unit after Reset
   * @adapter: board private structure
@@@ -1726,7 -1616,8 +1726,7 @@@ static void ixgbe_configure_rx(struct i
                          0xA54F2BEC, 0xEA49AF7C, 0xE214AD3D, 0xB855AABE,
                          0x6A3E67EA, 0x14364D17, 0x3BED200D};
        u32 fctrl, hlreg0;
 -      u32 pages;
 -      u32 reta = 0, mrqc;
 +      u32 reta = 0, mrqc = 0;
        u32 rdrxctl;
        int rx_buf_len;
  
        /* Set the RX buffer length according to the mode */
        if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
                rx_buf_len = IXGBE_RX_HDR_SIZE;
 +              if (hw->mac.type == ixgbe_mac_82599EB) {
 +                      /* PSRTYPE must be initialized in 82599 */
 +                      u32 psrtype = IXGBE_PSRTYPE_TCPHDR |
 +                                    IXGBE_PSRTYPE_UDPHDR |
 +                                    IXGBE_PSRTYPE_IPV4HDR |
 +                                    IXGBE_PSRTYPE_IPV6HDR;
 +                      IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype);
 +              }
        } else {
                if (netdev->mtu <= ETH_DATA_LEN)
                        rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
        fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
        fctrl |= IXGBE_FCTRL_BAM;
        fctrl |= IXGBE_FCTRL_DPF; /* discard pause frames when FC enabled */
 +      fctrl |= IXGBE_FCTRL_PMCF;
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl);
  
        hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
                hlreg0 |= IXGBE_HLREG0_JUMBOEN;
        IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
  
 -      pages = PAGE_USE_COUNT(adapter->netdev->mtu);
 -
        rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc);
        /* disable receives while setting up the descriptors */
        rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
                adapter->rx_ring[i].head = IXGBE_RDH(j);
                adapter->rx_ring[i].tail = IXGBE_RDT(j);
                adapter->rx_ring[i].rx_buf_len = rx_buf_len;
 -              /* Intitial LRO Settings */
 -              adapter->rx_ring[i].lro_mgr.max_aggr = IXGBE_MAX_LRO_AGGREGATE;
 -              adapter->rx_ring[i].lro_mgr.max_desc = IXGBE_MAX_LRO_DESCRIPTORS;
 -              adapter->rx_ring[i].lro_mgr.get_skb_header = ixgbe_get_skb_hdr;
 -              adapter->rx_ring[i].lro_mgr.features = LRO_F_EXTRACT_VLAN_ID;
 -              if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL))
 -                      adapter->rx_ring[i].lro_mgr.features |= LRO_F_NAPI;
 -              adapter->rx_ring[i].lro_mgr.dev = adapter->netdev;
 -              adapter->rx_ring[i].lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
 -              adapter->rx_ring[i].lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
  
                ixgbe_configure_srrctl(adapter, j);
        }
  
 -      /*
 -       * For VMDq support of different descriptor types or
 -       * buffer sizes through the use of multiple SRRCTL
 -       * registers, RDRXCTL.MVMEN must be set to 1
 -       *
 -       * also, the manual doesn't mention it clearly but DCA hints
 -       * will only use queue 0's tags unless this bit is set.  Side
 -       * effects of setting this bit are only that SRRCTL must be
 -       * fully programmed [0..15]
 -       */
 -      if (adapter->flags &
 -          (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_VMDQ_ENABLED)) {
 +      if (hw->mac.type == ixgbe_mac_82598EB) {
 +              /*
 +               * For VMDq support of different descriptor types or
 +               * buffer sizes through the use of multiple SRRCTL
 +               * registers, RDRXCTL.MVMEN must be set to 1
 +               *
 +               * also, the manual doesn't mention it clearly but DCA hints
 +               * will only use queue 0's tags unless this bit is set.  Side
 +               * effects of setting this bit are only that SRRCTL must be
 +               * fully programmed [0..15]
 +               */
                rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
                rdrxctl |= IXGBE_RDRXCTL_MVMEN;
                IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
        }
  
 +      /* Program MRQC for the distribution of queues */
 +      if (hw->mac.type == ixgbe_mac_82599EB) {
 +              int mask = adapter->flags & (
 +                              IXGBE_FLAG_RSS_ENABLED
 +                              | IXGBE_FLAG_DCB_ENABLED
 +                              );
 +
 +              switch (mask) {
 +              case (IXGBE_FLAG_RSS_ENABLED):
 +                      mrqc = IXGBE_MRQC_RSSEN;
 +                      break;
 +              case (IXGBE_FLAG_DCB_ENABLED):
 +                      mrqc = IXGBE_MRQC_RT8TCEN;
 +                      break;
 +              default:
 +                      break;
 +              }
 +      }
        if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
                /* Fill out redirection table */
                for (i = 0, j = 0; i < 128; i++, j++) {
                for (i = 0; i < 10; i++)
                        IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), seed[i]);
  
 -              mrqc = IXGBE_MRQC_RSSEN
 +              if (hw->mac.type == ixgbe_mac_82598EB)
 +                      mrqc |= IXGBE_MRQC_RSSEN;
                    /* Perform hash on these packet types */
 -                     | IXGBE_MRQC_RSS_FIELD_IPV4
 -                     | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
 -                     | IXGBE_MRQC_RSS_FIELD_IPV4_UDP
 -                     | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP
 -                     | IXGBE_MRQC_RSS_FIELD_IPV6_EX
 -                     | IXGBE_MRQC_RSS_FIELD_IPV6
 -                     | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
 -                     | IXGBE_MRQC_RSS_FIELD_IPV6_UDP
 -                     | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
 -              IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
 +              mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4
 +                    | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
 +                    | IXGBE_MRQC_RSS_FIELD_IPV4_UDP
 +                    | IXGBE_MRQC_RSS_FIELD_IPV6
 +                    | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
 +                    | IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
        }
 +      IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
  
        rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
  
        }
  
        IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
 +
 +      if (hw->mac.type == ixgbe_mac_82599EB) {
 +              rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
 +              rdrxctl |= IXGBE_RDRXCTL_CRCSTRIP;
 +              IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
 +      }
  }
  
  static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
@@@ -1902,7 -1775,6 +1902,7 @@@ static void ixgbe_vlan_rx_register(stru
  {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        u32 ctrl;
 +      int i, j;
  
        if (!test_bit(__IXGBE_DOWN, &adapter->state))
                ixgbe_irq_disable(adapter);
         * not in DCB mode.
         */
        ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL);
 -      ctrl |= IXGBE_VLNCTRL_VME;
 -      ctrl &= ~IXGBE_VLNCTRL_CFIEN;
 -      IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
 -      ixgbe_vlan_rx_add_vid(netdev, 0);
 -
 -      if (grp) {
 +      if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
 +              ctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE;
 +              ctrl &= ~IXGBE_VLNCTRL_CFIEN;
 +              IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
 +      } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
 +              ctrl |= IXGBE_VLNCTRL_VFE;
                /* enable VLAN tag insert/strip */
                ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL);
 -              ctrl |= IXGBE_VLNCTRL_VME;
                ctrl &= ~IXGBE_VLNCTRL_CFIEN;
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
 +              for (i = 0; i < adapter->num_rx_queues; i++) {
 +                      j = adapter->rx_ring[i].reg_idx;
 +                      ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(j));
 +                      ctrl |= IXGBE_RXDCTL_VME;
 +                      IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(j), ctrl);
 +              }
        }
 +      ixgbe_vlan_rx_add_vid(netdev, 0);
  
        if (!test_bit(__IXGBE_DOWN, &adapter->state))
                ixgbe_irq_enable(adapter);
@@@ -2094,21 -1960,9 +2094,21 @@@ static void ixgbe_configure_dcb(struct 
        }
        /* Enable VLAN tag insert/strip */
        vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
 -      vlnctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE;
 -      vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
 -      IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
 +      if (hw->mac.type == ixgbe_mac_82598EB) {
 +              vlnctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE;
 +              vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
 +              IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
 +      } else if (hw->mac.type == ixgbe_mac_82599EB) {
 +              vlnctrl |= IXGBE_VLNCTRL_VFE;
 +              vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
 +              IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
 +              for (i = 0; i < adapter->num_rx_queues; i++) {
 +                      j = adapter->rx_ring[i].reg_idx;
 +                      vlnctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
 +                      vlnctrl |= IXGBE_RXDCTL_VME;
 +                      IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(j), vlnctrl);
 +              }
 +      }
        hw->mac.ops.set_vfta(&adapter->hw, 0, 0, true);
  }
  
@@@ -2139,115 -1993,13 +2139,115 @@@ static void ixgbe_configure(struct ixgb
                                       (adapter->rx_ring[i].count - 1));
  }
  
 +static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw)
 +{
 +      switch (hw->phy.type) {
 +      case ixgbe_phy_sfp_avago:
 +      case ixgbe_phy_sfp_ftl:
 +      case ixgbe_phy_sfp_intel:
 +      case ixgbe_phy_sfp_unknown:
 +      case ixgbe_phy_tw_tyco:
 +      case ixgbe_phy_tw_unknown:
 +              return true;
 +      default:
 +              return false;
 +      }
 +}
 +
 +/**
 + * ixgbe_sfp_link_config - set up SFP+ link
 + * @adapter: pointer to private adapter struct
 + **/
 +static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter)
 +{
 +      struct ixgbe_hw *hw = &adapter->hw;
 +
 +              if (hw->phy.multispeed_fiber) {
 +                      /*
 +                       * In multispeed fiber setups, the device may not have
 +                       * had a physical connection when the driver loaded.
 +                       * If that's the case, the initial link configuration
 +                       * couldn't get the MAC into 10G or 1G mode, so we'll
 +                       * never have a link status change interrupt fire.
 +                       * We need to try and force an autonegotiation
 +                       * session, then bring up link.
 +                       */
 +                      hw->mac.ops.setup_sfp(hw);
 +                      if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK))
 +                              schedule_work(&adapter->multispeed_fiber_task);
 +              } else {
 +                      /*
 +                       * Direct Attach Cu and non-multispeed fiber modules
 +                       * still need to be configured properly prior to
 +                       * attempting link.
 +                       */
 +                      if (!(adapter->flags & IXGBE_FLAG_IN_SFP_MOD_TASK))
 +                              schedule_work(&adapter->sfp_config_module_task);
 +              }
 +}
 +
 +/**
 + * ixgbe_non_sfp_link_config - set up non-SFP+ link
 + * @hw: pointer to private hardware struct
 + *
 + * Returns 0 on success, negative on failure
 + **/
 +static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw)
 +{
 +      u32 autoneg;
 +      bool link_up = false;
 +      u32 ret = IXGBE_ERR_LINK_SETUP;
 +
 +      if (hw->mac.ops.check_link)
 +              ret = hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
 +
 +      if (ret)
 +              goto link_cfg_out;
 +
 +      if (hw->mac.ops.get_link_capabilities)
 +              ret = hw->mac.ops.get_link_capabilities(hw, &autoneg,
 +                                                      &hw->mac.autoneg);
 +      if (ret)
 +              goto link_cfg_out;
 +
 +      if (hw->mac.ops.setup_link_speed)
 +              ret = hw->mac.ops.setup_link_speed(hw, autoneg, true, link_up);
 +link_cfg_out:
 +      return ret;
 +}
 +
 +#define IXGBE_MAX_RX_DESC_POLL 10
 +static inline void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
 +                                            int rxr)
 +{
 +      int j = adapter->rx_ring[rxr].reg_idx;
 +      int k;
 +
 +      for (k = 0; k < IXGBE_MAX_RX_DESC_POLL; k++) {
 +              if (IXGBE_READ_REG(&adapter->hw,
 +                                 IXGBE_RXDCTL(j)) & IXGBE_RXDCTL_ENABLE)
 +                      break;
 +              else
 +                      msleep(1);
 +      }
 +      if (k >= IXGBE_MAX_RX_DESC_POLL) {
 +              DPRINTK(DRV, ERR, "RXDCTL.ENABLE on Rx queue %d "
 +                      "not set within the polling period\n", rxr);
 +      }
 +      ixgbe_release_rx_desc(&adapter->hw, &adapter->rx_ring[rxr],
 +                            (adapter->rx_ring[rxr].count - 1));
 +}
 +
  static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
  {
        struct net_device *netdev = adapter->netdev;
        struct ixgbe_hw *hw = &adapter->hw;
        int i, j = 0;
 +      int num_rx_rings = adapter->num_rx_queues;
 +      int err;
        int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
        u32 txdctl, rxdctl, mhadd;
 +      u32 dmatxctl;
        u32 gpie;
  
        ixgbe_get_hw_control(adapter);
                IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
        }
  
 +      if (hw->mac.type == ixgbe_mac_82599EB) {
 +              gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
 +              gpie |= IXGBE_SDP1_GPIEN;
 +              gpie |= IXGBE_SDP2_GPIEN;
 +              IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
 +      }
 +
        mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
        if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) {
                mhadd &= ~IXGBE_MHADD_MFS_MASK;
                txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
                /* enable WTHRESH=8 descriptors, to encourage burst writeback */
                txdctl |= (8 << 16);
 +              IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
 +      }
 +
 +      if (hw->mac.type == ixgbe_mac_82599EB) {
 +              /* DMATXCTL.EN must be set after all Tx queue config is done */
 +              dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
 +              dmatxctl |= IXGBE_DMATXCTL_TE;
 +              IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl);
 +      }
 +      for (i = 0; i < adapter->num_tx_queues; i++) {
 +              j = adapter->tx_ring[i].reg_idx;
 +              txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
                txdctl |= IXGBE_TXDCTL_ENABLE;
                IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
        }
  
 -      for (i = 0; i < adapter->num_rx_queues; i++) {
 +      for (i = 0; i < num_rx_rings; i++) {
                j = adapter->rx_ring[i].reg_idx;
                rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
                /* enable PTHRESH=32 descriptors (half the internal cache)
                rxdctl |= 0x0020;
                rxdctl |= IXGBE_RXDCTL_ENABLE;
                IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(j), rxdctl);
 +              if (hw->mac.type == ixgbe_mac_82599EB)
 +                      ixgbe_rx_desc_queue_enable(adapter, i);
        }
        /* enable all receives */
        rxdctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
 -      rxdctl |= (IXGBE_RXCTRL_DMBYPS | IXGBE_RXCTRL_RXEN);
 -      IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxdctl);
 +      if (hw->mac.type == ixgbe_mac_82598EB)
 +              rxdctl |= (IXGBE_RXCTRL_DMBYPS | IXGBE_RXCTRL_RXEN);
 +      else
 +              rxdctl |= IXGBE_RXCTRL_RXEN;
 +      hw->mac.ops.enable_rx_dma(hw, rxdctl);
  
        if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
                ixgbe_configure_msix(adapter);
        else
                ixgbe_configure_msi_and_legacy(adapter);
  
 -      ixgbe_napi_add_all(adapter);
 -
        clear_bit(__IXGBE_DOWN, &adapter->state);
        ixgbe_napi_enable_all(adapter);
  
  
        ixgbe_irq_enable(adapter);
  
 +      /*
 +       * For hot-pluggable SFP+ devices, a new SFP+ module may have
 +       * arrived before interrupts were enabled.  We need to kick off
 +       * the SFP+ module setup first, then try to bring up link.
 +       * If we're not hot-pluggable SFP+, we just need to configure link
 +       * and bring it up.
 +       */
 +      err = hw->phy.ops.identify(hw);
 +      if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
 +              DPRINTK(PROBE, ERR, "PHY not supported on this NIC %d\n", err);
 +              ixgbe_down(adapter);
 +              return err;
 +      }
 +
 +      if (ixgbe_is_sfp(hw)) {
 +              ixgbe_sfp_link_config(adapter);
 +      } else {
 +              err = ixgbe_non_sfp_link_config(hw);
 +              if (err)
 +                      DPRINTK(PROBE, ERR, "link_config FAILED %d\n", err);
 +      }
 +
        /* enable transmits */
        netif_tx_start_all_queues(netdev);
  
@@@ -2396,8 -2104,6 +2396,8 @@@ int ixgbe_up(struct ixgbe_adapter *adap
        /* hardware has been reset, we need to reload some things */
        ixgbe_configure(adapter);
  
 +      ixgbe_napi_add_all(adapter);
 +
        return ixgbe_up_complete(adapter);
  }
  
@@@ -2459,10 -2165,8 +2459,10 @@@ static void ixgbe_clean_rx_ring(struct 
        rx_ring->next_to_clean = 0;
        rx_ring->next_to_use = 0;
  
 -      writel(0, adapter->hw.hw_addr + rx_ring->head);
 -      writel(0, adapter->hw.hw_addr + rx_ring->tail);
 +      if (rx_ring->head)
 +              writel(0, adapter->hw.hw_addr + rx_ring->head);
 +      if (rx_ring->tail)
 +              writel(0, adapter->hw.hw_addr + rx_ring->tail);
  }
  
  /**
@@@ -2493,10 -2197,8 +2493,10 @@@ static void ixgbe_clean_tx_ring(struct 
        tx_ring->next_to_use = 0;
        tx_ring->next_to_clean = 0;
  
 -      writel(0, adapter->hw.hw_addr + tx_ring->head);
 -      writel(0, adapter->hw.hw_addr + tx_ring->tail);
 +      if (tx_ring->head)
 +              writel(0, adapter->hw.hw_addr + tx_ring->head);
 +      if (tx_ring->tail)
 +              writel(0, adapter->hw.hw_addr + tx_ring->tail);
  }
  
  /**
@@@ -2559,11 -2261,6 +2559,11 @@@ void ixgbe_down(struct ixgbe_adapter *a
                IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j),
                                (txdctl & ~IXGBE_TXDCTL_ENABLE));
        }
 +      /* Disable the Tx DMA engine on 82599 */
 +      if (hw->mac.type == ixgbe_mac_82599EB)
 +              IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL,
 +                              (IXGBE_READ_REG(hw, IXGBE_DMATXCTL) &
 +                               ~IXGBE_DMATXCTL_TE));
  
        netif_carrier_off(netdev);
  
   **/
  static int ixgbe_poll(struct napi_struct *napi, int budget)
  {
 -      struct ixgbe_q_vector *q_vector = container_of(napi,
 -                                                struct ixgbe_q_vector, napi);
 +      struct ixgbe_q_vector *q_vector =
 +                              container_of(napi, struct ixgbe_q_vector, napi);
        struct ixgbe_adapter *adapter = q_vector->adapter;
 -      int tx_cleaned, work_done = 0;
 +      int tx_clean_complete, work_done = 0;
  
  #ifdef CONFIG_IXGBE_DCA
        if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
        }
  #endif
  
 -      tx_cleaned = ixgbe_clean_tx_irq(adapter, adapter->tx_ring);
 -      ixgbe_clean_rx_irq(adapter, adapter->rx_ring, &work_done, budget);
 +      tx_clean_complete = ixgbe_clean_tx_irq(adapter, adapter->tx_ring);
 +      ixgbe_clean_rx_irq(q_vector, adapter->rx_ring, &work_done, budget);
  
 -      if (tx_cleaned)
 +      if (!tx_clean_complete)
                work_done = budget;
  
        /* If budget not fully consumed, exit the polling mode */
        if (work_done < budget) {
 -              netif_rx_complete(napi);
 -              if (adapter->itr_setting & 3)
 +              napi_complete(napi);
 +              if (adapter->itr_setting & 1)
                        ixgbe_set_itr(adapter);
                if (!test_bit(__IXGBE_DOWN, &adapter->state))
                        ixgbe_irq_enable(adapter);
@@@ -2656,76 -2353,68 +2656,76 @@@ static void ixgbe_reset_task(struct wor
        ixgbe_reinit_locked(adapter);
  }
  
 -static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
 +#ifdef CONFIG_IXGBE_DCB
 +static inline bool ixgbe_set_dcb_queues(struct ixgbe_adapter *adapter)
  {
 -      int nrq = 1, ntq = 1;
 -      int feature_mask = 0, rss_i, rss_m;
 -      int dcb_i, dcb_m;
 +      bool ret = false;
  
 -      /* Number of supported queues */
 -      switch (adapter->hw.mac.type) {
 -      case ixgbe_mac_82598EB:
 -              dcb_i = adapter->ring_feature[RING_F_DCB].indices;
 -              dcb_m = 0;
 -              rss_i = adapter->ring_feature[RING_F_RSS].indices;
 -              rss_m = 0;
 -              feature_mask |= IXGBE_FLAG_RSS_ENABLED;
 -              feature_mask |= IXGBE_FLAG_DCB_ENABLED;
 -
 -              switch (adapter->flags & feature_mask) {
 -              case (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_DCB_ENABLED):
 -                      dcb_m = 0x7 << 3;
 -                      rss_i = min(8, rss_i);
 -                      rss_m = 0x7;
 -                      nrq = dcb_i * rss_i;
 -                      ntq = min(MAX_TX_QUEUES, dcb_i * rss_i);
 -                      break;
 -              case (IXGBE_FLAG_DCB_ENABLED):
 -                      dcb_m = 0x7 << 3;
 -                      nrq = dcb_i;
 -                      ntq = dcb_i;
 -                      break;
 -              case (IXGBE_FLAG_RSS_ENABLED):
 -                      rss_m = 0xF;
 -                      nrq = rss_i;
 -                      ntq = rss_i;
 -                      break;
 -              case 0:
 -              default:
 -                      dcb_i = 0;
 -                      dcb_m = 0;
 -                      rss_i = 0;
 -                      rss_m = 0;
 -                      nrq = 1;
 -                      ntq = 1;
 -                      break;
 -              }
 +      if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
 +              adapter->ring_feature[RING_F_DCB].mask = 0x7 << 3;
 +              adapter->num_rx_queues =
 +                                    adapter->ring_feature[RING_F_DCB].indices;
 +              adapter->num_tx_queues =
 +                                    adapter->ring_feature[RING_F_DCB].indices;
 +              ret = true;
 +      } else {
 +              ret = false;
 +      }
  
 -              /* Sanity check, we should never have zero queues */
 -              nrq = (nrq ?:1);
 -              ntq = (ntq ?:1);
 +      return ret;
 +}
 +#endif
  
 -              adapter->ring_feature[RING_F_DCB].indices = dcb_i;
 -              adapter->ring_feature[RING_F_DCB].mask = dcb_m;
 -              adapter->ring_feature[RING_F_RSS].indices = rss_i;
 -              adapter->ring_feature[RING_F_RSS].mask = rss_m;
 -              break;
 -      default:
 -              nrq = 1;
 -              ntq = 1;
 -              break;
 +/**
 + * ixgbe_set_rss_queues: Allocate queues for RSS
 + * @adapter: board private structure to initialize
 + *
 + * This is our "base" multiqueue mode.  RSS (Receive Side Scaling) will try
 + * to allocate one Rx queue per CPU, and if available, one Tx queue per CPU.
 + *
 + **/
 +static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter)
 +{
 +      bool ret = false;
 +
 +      if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
 +              adapter->ring_feature[RING_F_RSS].mask = 0xF;
 +              adapter->num_rx_queues =
 +                                    adapter->ring_feature[RING_F_RSS].indices;
 +              adapter->num_tx_queues =
 +                                    adapter->ring_feature[RING_F_RSS].indices;
 +              ret = true;
 +      } else {
 +              ret = false;
        }
  
 -      adapter->num_rx_queues = nrq;
 -      adapter->num_tx_queues = ntq;
 +      return ret;
 +}
 +
 +/*
 + * ixgbe_set_num_queues: Allocate queues for device, feature dependant
 + * @adapter: board private structure to initialize
 + *
 + * This is the top level queue allocation routine.  The order here is very
 + * important, starting with the "most" number of features turned on at once,
 + * and ending with the smallest set of features.  This way large combinations
 + * can be allocated if they're turned on, and smaller combinations are the
 + * fallthrough conditions.
 + *
 + **/
 +static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
 +{
 +      /* Start with base case */
 +      adapter->num_rx_queues = 1;
 +      adapter->num_tx_queues = 1;
 +
 +#ifdef CONFIG_IXGBE_DCB
 +      if (ixgbe_set_dcb_queues(adapter))
 +              return;
 +
 +#endif
 +      if (ixgbe_set_rss_queues(adapter))
 +              return;
  }
  
  static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
                ixgbe_set_num_queues(adapter);
        } else {
                adapter->flags |= IXGBE_FLAG_MSIX_ENABLED; /* Woot! */
 -              adapter->num_msix_vectors = vectors;
 +              /*
 +               * Adjust for only the vectors we'll use, which is minimum
 +               * of max_msix_q_vectors + NON_Q_VECTORS, or the number of
 +               * vectors we were allocated.
 +               */
 +              adapter->num_msix_vectors = min(vectors,
 +                                 adapter->max_msix_q_vectors + NON_Q_VECTORS);
        }
  }
  
  /**
 - * ixgbe_cache_ring_register - Descriptor ring to register mapping
 + * ixgbe_cache_ring_rss - Descriptor ring to register mapping for RSS
   * @adapter: board private structure to initialize
   *
 - * Once we know the feature-set enabled for the device, we'll cache
 - * the register offset the descriptor ring is assigned to.
 + * Cache the descriptor ring offsets for RSS to the assigned rings.
 + *
   **/
 -static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter)
 +static inline bool ixgbe_cache_ring_rss(struct ixgbe_adapter *adapter)
  {
 -      int feature_mask = 0, rss_i;
 -      int i, txr_idx, rxr_idx;
 -      int dcb_i;
 +      int i;
 +      bool ret = false;
  
 -      /* Number of supported queues */
 -      switch (adapter->hw.mac.type) {
 -      case ixgbe_mac_82598EB:
 -              dcb_i = adapter->ring_feature[RING_F_DCB].indices;
 -              rss_i = adapter->ring_feature[RING_F_RSS].indices;
 -              txr_idx = 0;
 -              rxr_idx = 0;
 -              feature_mask |= IXGBE_FLAG_DCB_ENABLED;
 -              feature_mask |= IXGBE_FLAG_RSS_ENABLED;
 -              switch (adapter->flags & feature_mask) {
 -              case (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_DCB_ENABLED):
 -                      for (i = 0; i < dcb_i; i++) {
 -                              int j;
 -                              /* Rx first */
 -                              for (j = 0; j < adapter->num_rx_queues; j++) {
 -                                      adapter->rx_ring[rxr_idx].reg_idx =
 -                                              i << 3 | j;
 -                                      rxr_idx++;
 -                              }
 -                              /* Tx now */
 -                              for (j = 0; j < adapter->num_tx_queues; j++) {
 -                                      adapter->tx_ring[txr_idx].reg_idx =
 -                                              i << 2 | (j >> 1);
 -                                      if (j & 1)
 -                                              txr_idx++;
 -                              }
 -                      }
 -              case (IXGBE_FLAG_DCB_ENABLED):
 +      if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
 +              for (i = 0; i < adapter->num_rx_queues; i++)
 +                      adapter->rx_ring[i].reg_idx = i;
 +              for (i = 0; i < adapter->num_tx_queues; i++)
 +                      adapter->tx_ring[i].reg_idx = i;
 +              ret = true;
 +      } else {
 +              ret = false;
 +      }
 +
 +      return ret;
 +}
 +
 +#ifdef CONFIG_IXGBE_DCB
 +/**
 + * ixgbe_cache_ring_dcb - Descriptor ring to register mapping for DCB
 + * @adapter: board private structure to initialize
 + *
 + * Cache the descriptor ring offsets for DCB to the assigned rings.
 + *
 + **/
 +static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter)
 +{
 +      int i;
 +      bool ret = false;
 +      int dcb_i = adapter->ring_feature[RING_F_DCB].indices;
 +
 +      if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
 +              if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
                        /* the number of queues is assumed to be symmetric */
                        for (i = 0; i < dcb_i; i++) {
                                adapter->rx_ring[i].reg_idx = i << 3;
                                adapter->tx_ring[i].reg_idx = i << 2;
                        }
 -                      break;
 -              case (IXGBE_FLAG_RSS_ENABLED):
 -                      for (i = 0; i < adapter->num_rx_queues; i++)
 -                              adapter->rx_ring[i].reg_idx = i;
 -                      for (i = 0; i < adapter->num_tx_queues; i++)
 -                              adapter->tx_ring[i].reg_idx = i;
 -                      break;
 -              case 0:
 -              default:
 -                      break;
 +                      ret = true;
 +              } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
 +                      for (i = 0; i < dcb_i; i++) {
 +                              adapter->rx_ring[i].reg_idx = i << 4;
 +                              adapter->tx_ring[i].reg_idx = i << 4;
 +                      }
 +                      ret = true;
 +              } else {
 +                      ret = false;
                }
 -              break;
 -      default:
 -              break;
 +      } else {
 +              ret = false;
        }
 +
 +      return ret;
 +}
 +#endif
 +
 +/**
 + * ixgbe_cache_ring_register - Descriptor ring to register mapping
 + * @adapter: board private structure to initialize
 + *
 + * Once we know the feature-set enabled for the device, we'll cache
 + * the register offset the descriptor ring is assigned to.
 + *
 + * Note, the order the various feature calls is important.  It must start with
 + * the "most" features enabled at the same time, then trickle down to the
 + * least amount of features turned on at once.
 + **/
 +static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter)
 +{
 +      /* start with default case */
 +      adapter->rx_ring[0].reg_idx = 0;
 +      adapter->tx_ring[0].reg_idx = 0;
 +
 +#ifdef CONFIG_IXGBE_DCB
 +      if (ixgbe_cache_ring_dcb(adapter))
 +              return;
 +
 +#endif
 +      if (ixgbe_cache_ring_rss(adapter))
 +              return;
  }
  
  /**
   * @adapter: board private structure to initialize
   *
   * We allocate one ring per queue at run-time since we don't know the
 - * number of queues at compile-time.
 + * number of queues at compile-time.  The polling_netdev array is
 + * intended for Multiqueue, but should work fine with a single queue.
   **/
  static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter)
  {
@@@ -3056,8 -2711,7 +3056,8 @@@ static void ixgbe_sfp_timer(unsigned lo
  {
        struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
  
 -      /* Do the sfp_timer outside of interrupt context due to the
 +      /*
 +       * Do the sfp_timer outside of interrupt context due to the
         * delays that sfp+ detection requires
         */
        schedule_work(&adapter->sfp_task);
@@@ -3131,10 -2785,6 +3131,10 @@@ static int __devinit ixgbe_sw_init(stru
        adapter->ring_feature[RING_F_RSS].indices = rss;
        adapter->flags |= IXGBE_FLAG_RSS_ENABLED;
        adapter->ring_feature[RING_F_DCB].indices = IXGBE_MAX_DCB_INDICES;
 +      if (hw->mac.type == ixgbe_mac_82598EB)
 +              adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82598;
 +      else if (hw->mac.type == ixgbe_mac_82599EB)
 +              adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599;
  
  #ifdef CONFIG_IXGBE_DCB
        /* Configure DCB traffic classes */
                           adapter->ring_feature[RING_F_DCB].indices);
  
  #endif
 -      if (hw->mac.ops.get_media_type &&
 -          (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper))
 -              adapter->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE;
  
        /* default flow control settings */
 -      hw->fc.original_type = ixgbe_fc_none;
 -      hw->fc.type = ixgbe_fc_none;
 +      hw->fc.requested_mode = ixgbe_fc_none;
        hw->fc.high_water = IXGBE_DEFAULT_FCRTH;
        hw->fc.low_water = IXGBE_DEFAULT_FCRTL;
        hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE;
        hw->fc.send_xon = true;
  
 -      /* select 10G link by default */
 -      hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN;
 -
        /* enable itr by default in dynamic mode */
        adapter->itr_setting = 1;
        adapter->eitr_param = 20000;
@@@ -3209,7 -2866,8 +3209,7 @@@ int ixgbe_setup_tx_resources(struct ixg
        memset(tx_ring->tx_buffer_info, 0, size);
  
        /* round up to nearest 4K */
 -      tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc) +
 -                      sizeof(u32);
 +      tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc);
        tx_ring->size = ALIGN(tx_ring->size, 4096);
  
        tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
@@@ -3268,6 -2926,12 +3268,6 @@@ int ixgbe_setup_rx_resources(struct ixg
        struct pci_dev *pdev = adapter->pdev;
        int size;
  
 -      size = sizeof(struct net_lro_desc) * IXGBE_MAX_LRO_DESCRIPTORS;
 -      rx_ring->lro_mgr.lro_arr = vmalloc(size);
 -      if (!rx_ring->lro_mgr.lro_arr)
 -              return -ENOMEM;
 -      memset(rx_ring->lro_mgr.lro_arr, 0, size);
 -
        size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count;
        rx_ring->rx_buffer_info = vmalloc(size);
        if (!rx_ring->rx_buffer_info) {
        return 0;
  
  alloc_failed:
 -      vfree(rx_ring->lro_mgr.lro_arr);
 -      rx_ring->lro_mgr.lro_arr = NULL;
        return -ENOMEM;
  }
  
@@@ -3358,8 -3024,7 +3358,8 @@@ static void ixgbe_free_all_tx_resources
        int i;
  
        for (i = 0; i < adapter->num_tx_queues; i++)
 -              ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]);
 +              if (adapter->tx_ring[i].desc)
 +                      ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]);
  }
  
  /**
@@@ -3374,6 -3039,9 +3374,6 @@@ void ixgbe_free_rx_resources(struct ixg
  {
        struct pci_dev *pdev = adapter->pdev;
  
 -      vfree(rx_ring->lro_mgr.lro_arr);
 -      rx_ring->lro_mgr.lro_arr = NULL;
 -
        ixgbe_clean_rx_ring(adapter, rx_ring);
  
        vfree(rx_ring->rx_buffer_info);
@@@ -3395,8 -3063,7 +3395,8 @@@ static void ixgbe_free_all_rx_resources
        int i;
  
        for (i = 0; i < adapter->num_rx_queues; i++)
 -              ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]);
 +              if (adapter->rx_ring[i].desc)
 +                      ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]);
  }
  
  /**
@@@ -3459,8 -3126,6 +3459,8 @@@ static int ixgbe_open(struct net_devic
  
        ixgbe_configure(adapter);
  
 +      ixgbe_napi_add_all(adapter);
 +
        err = ixgbe_request_irq(adapter);
        if (err)
                goto err_req_irq;
@@@ -3515,7 -3180,6 +3515,7 @@@ static int ixgbe_close(struct net_devic
  /**
   * ixgbe_napi_add_all - prep napi structs for use
   * @adapter: private struct
 + *
   * helper function to napi_add each possible q_vector->napi
   */
  void ixgbe_napi_add_all(struct ixgbe_adapter *adapter)
@@@ -3588,6 -3252,7 +3588,6 @@@ static int ixgbe_resume(struct pci_dev 
                return err;
        }
  
 -      ixgbe_napi_add_all(adapter);
        ixgbe_reset(adapter);
  
        if (netif_running(netdev)) {
@@@ -3606,9 -3271,6 +3606,9 @@@ static int ixgbe_suspend(struct pci_de
  {
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
 +      struct ixgbe_hw *hw = &adapter->hw;
 +      u32 ctrl, fctrl;
 +      u32 wufc = adapter->wol;
  #ifdef CONFIG_PM
        int retval = 0;
  #endif
        retval = pci_save_state(pdev);
        if (retval)
                return retval;
 +
  #endif
 +      if (wufc) {
 +              ixgbe_set_rx_mode(netdev);
  
 -      pci_enable_wake(pdev, PCI_D3hot, 0);
 -      pci_enable_wake(pdev, PCI_D3cold, 0);
 +              /* turn on all-multi mode if wake on multicast is enabled */
 +              if (wufc & IXGBE_WUFC_MC) {
 +                      fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
 +                      fctrl |= IXGBE_FCTRL_MPE;
 +                      IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
 +              }
 +
 +              ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
 +              ctrl |= IXGBE_CTRL_GIO_DIS;
 +              IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
 +
 +              IXGBE_WRITE_REG(hw, IXGBE_WUFC, wufc);
 +      } else {
 +              IXGBE_WRITE_REG(hw, IXGBE_WUC, 0);
 +              IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0);
 +      }
 +
 +      if (wufc && hw->mac.type == ixgbe_mac_82599EB) {
 +              pci_enable_wake(pdev, PCI_D3hot, 1);
 +              pci_enable_wake(pdev, PCI_D3cold, 1);
 +      } else {
 +              pci_enable_wake(pdev, PCI_D3hot, 0);
 +              pci_enable_wake(pdev, PCI_D3cold, 0);
 +      }
  
        ixgbe_release_hw_control(adapter);
  
@@@ -3685,12 -3322,6 +3685,12 @@@ void ixgbe_update_stats(struct ixgbe_ad
        u64 total_mpc = 0;
        u32 i, missed_rx = 0, mpc, bprc, lxon, lxoff, xon_off_tot;
  
 +      if (hw->mac.type == ixgbe_mac_82599EB) {
 +              for (i = 0; i < 16; i++)
 +                      adapter->hw_rx_no_dma_resources +=
 +                                           IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
 +      }
 +
        adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
        for (i = 0; i < 8; i++) {
                /* for packet buffers not used, the register should read 0 */
                missed_rx += mpc;
                adapter->stats.mpc[i] += mpc;
                total_mpc += adapter->stats.mpc[i];
 -              adapter->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i));
 +              if (hw->mac.type == ixgbe_mac_82598EB)
 +                      adapter->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i));
                adapter->stats.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
                adapter->stats.qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC(i));
                adapter->stats.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
                adapter->stats.qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC(i));
 -              adapter->stats.pxonrxc[i] += IXGBE_READ_REG(hw,
 -                                                          IXGBE_PXONRXC(i));
 +              if (hw->mac.type == ixgbe_mac_82599EB) {
 +                      adapter->stats.pxonrxc[i] += IXGBE_READ_REG(hw,
 +                                                          IXGBE_PXONRXCNT(i));
 +                      adapter->stats.pxoffrxc[i] += IXGBE_READ_REG(hw,
 +                                                         IXGBE_PXOFFRXCNT(i));
 +                      adapter->stats.qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
 +              } else {
 +                      adapter->stats.pxonrxc[i] += IXGBE_READ_REG(hw,
 +                                                            IXGBE_PXONRXC(i));
 +                      adapter->stats.pxoffrxc[i] += IXGBE_READ_REG(hw,
 +                                                           IXGBE_PXOFFRXC(i));
 +              }
                adapter->stats.pxontxc[i] += IXGBE_READ_REG(hw,
                                                            IXGBE_PXONTXC(i));
 -              adapter->stats.pxoffrxc[i] += IXGBE_READ_REG(hw,
 -                                                          IXGBE_PXOFFRXC(i));
                adapter->stats.pxofftxc[i] += IXGBE_READ_REG(hw,
 -                                                          IXGBE_PXOFFTXC(i));
 +                                                           IXGBE_PXOFFTXC(i));
        }
        adapter->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
        /* work around hardware counting issue */
        adapter->stats.gprc -= missed_rx;
  
        /* 82598 hardware only has a 32 bit counter in the high register */
 -      adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
 -      adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
 -      adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
 +      if (hw->mac.type == ixgbe_mac_82599EB) {
 +              adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL);
 +              IXGBE_READ_REG(hw, IXGBE_GORCH); /* to clear */
 +              adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL);
 +              IXGBE_READ_REG(hw, IXGBE_GOTCH); /* to clear */
 +              adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORL);
 +              IXGBE_READ_REG(hw, IXGBE_TORH); /* to clear */
 +              adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT);
 +              adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT);
 +      } else {
 +              adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
 +              adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
 +              adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
 +              adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
 +              adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
 +      }
        bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
        adapter->stats.bprc += bprc;
        adapter->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
 -      adapter->stats.mprc -= bprc;
 +      if (hw->mac.type == ixgbe_mac_82598EB)
 +              adapter->stats.mprc -= bprc;
        adapter->stats.roc += IXGBE_READ_REG(hw, IXGBE_ROC);
        adapter->stats.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64);
        adapter->stats.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127);
        adapter->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
        adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
        adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
 -      adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
 -      adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
        lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC);
        adapter->stats.lxontxc += lxon;
        lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
@@@ -3826,55 -3436,6 +3826,55 @@@ static void ixgbe_watchdog(unsigned lon
        schedule_work(&adapter->watchdog_task);
  }
  
 +/**
 + * ixgbe_multispeed_fiber_task - worker thread to configure multispeed fiber
 + * @work: pointer to work_struct containing our data
 + **/
 +static void ixgbe_multispeed_fiber_task(struct work_struct *work)
 +{
 +      struct ixgbe_adapter *adapter = container_of(work,
 +                                                   struct ixgbe_adapter,
 +                                                   multispeed_fiber_task);
 +      struct ixgbe_hw *hw = &adapter->hw;
 +      u32 autoneg;
 +
 +      adapter->flags |= IXGBE_FLAG_IN_SFP_LINK_TASK;
 +      if (hw->mac.ops.get_link_capabilities)
 +              hw->mac.ops.get_link_capabilities(hw, &autoneg,
 +                                                &hw->mac.autoneg);
 +      if (hw->mac.ops.setup_link_speed)
 +              hw->mac.ops.setup_link_speed(hw, autoneg, true, true);
 +      adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
 +      adapter->flags &= ~IXGBE_FLAG_IN_SFP_LINK_TASK;
 +}
 +
 +/**
 + * ixgbe_sfp_config_module_task - worker thread to configure a new SFP+ module
 + * @work: pointer to work_struct containing our data
 + **/
 +static void ixgbe_sfp_config_module_task(struct work_struct *work)
 +{
 +      struct ixgbe_adapter *adapter = container_of(work,
 +                                                   struct ixgbe_adapter,
 +                                                   sfp_config_module_task);
 +      struct ixgbe_hw *hw = &adapter->hw;
 +      u32 err;
 +
 +      adapter->flags |= IXGBE_FLAG_IN_SFP_MOD_TASK;
 +      err = hw->phy.ops.identify_sfp(hw);
 +      if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
 +              DPRINTK(PROBE, ERR, "PHY not supported on this NIC %d\n", err);
 +              ixgbe_down(adapter);
 +              return;
 +      }
 +      hw->mac.ops.setup_sfp(hw);
 +
 +      if (!adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK)
 +              /* This will also work for DA Twinax connections */
 +              schedule_work(&adapter->multispeed_fiber_task);
 +      adapter->flags &= ~IXGBE_FLAG_IN_SFP_MOD_TASK;
 +}
 +
  /**
   * ixgbe_watchdog_task - worker thread to bring link up
   * @work: pointer to work_struct containing our data
@@@ -3905,20 -3466,10 +3905,20 @@@ static void ixgbe_watchdog_task(struct 
  
        if (link_up) {
                if (!netif_carrier_ok(netdev)) {
 -                      u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
 -                      u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
 -#define FLOW_RX (frctl & IXGBE_FCTRL_RFCE)
 -#define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X)
 +                      bool flow_rx, flow_tx;
 +
 +                      if (hw->mac.type == ixgbe_mac_82599EB) {
 +                              u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
 +                              u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
 +                              flow_rx = (mflcn & IXGBE_MFLCN_RFCE);
 +                              flow_tx = (fccfg & IXGBE_FCCFG_TFCE_802_3X);
 +                      } else {
 +                              u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
 +                              u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
 +                              flow_rx = (frctl & IXGBE_FCTRL_RFCE);
 +                              flow_tx = (rmcs & IXGBE_RMCS_TFCE_802_3X);
 +                      }
 +
                        printk(KERN_INFO "ixgbe: %s NIC Link is Up %s, "
                               "Flow Control: %s\n",
                               netdev->name,
                                "10 Gbps" :
                                (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
                                 "1 Gbps" : "unknown speed")),
 -                             ((FLOW_RX && FLOW_TX) ? "RX/TX" :
 -                              (FLOW_RX ? "RX" :
 -                              (FLOW_TX ? "TX" : "None"))));
 +                             ((flow_rx && flow_tx) ? "RX/TX" :
 +                              (flow_rx ? "RX" :
 +                              (flow_tx ? "TX" : "None"))));
  
                        netif_carrier_on(netdev);
                } else {
@@@ -4068,13 -3619,13 +4068,13 @@@ static bool ixgbe_tx_csum(struct ixgbe_
  
                if (skb->ip_summed == CHECKSUM_PARTIAL) {
                        switch (skb->protocol) {
 -                      case __constant_htons(ETH_P_IP):
 +                      case cpu_to_be16(ETH_P_IP):
                                type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
                                if (ip_hdr(skb)->protocol == IPPROTO_TCP)
                                        type_tucmd_mlhl |=
                                                IXGBE_ADVTXD_TUCMD_L4T_TCP;
                                break;
 -                      case __constant_htons(ETH_P_IPV6):
 +                      case cpu_to_be16(ETH_P_IPV6):
                                /* XXX what about other V6 headers?? */
                                if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
                                        type_tucmd_mlhl |=
@@@ -4397,11 -3948,32 +4397,12 @@@ static void ixgbe_netpoll(struct net_de
  }
  #endif
  
 -/**
 - * ixgbe_link_config - set up initial link with default speed and duplex
 - * @hw: pointer to private hardware struct
 - *
 - * Returns 0 on success, negative on failure
 - **/
 -static int ixgbe_link_config(struct ixgbe_hw *hw)
 -{
 -      u32 autoneg = IXGBE_LINK_SPEED_10GB_FULL;
 -
 -      /* must always autoneg for both 1G and 10G link */
 -      hw->mac.autoneg = true;
 -
 -      if ((hw->mac.type == ixgbe_mac_82598EB) &&
 -          (hw->phy.media_type == ixgbe_media_type_copper))
 -              autoneg = IXGBE_LINK_SPEED_82598_AUTONEG;
 -
 -      return hw->mac.ops.setup_link_speed(hw, autoneg, true, true);
 -}
 -
  static const struct net_device_ops ixgbe_netdev_ops = {
        .ndo_open               = ixgbe_open,
        .ndo_stop               = ixgbe_close,
        .ndo_start_xmit         = ixgbe_xmit_frame,
        .ndo_get_stats          = ixgbe_get_stats,
+       .ndo_set_rx_mode        = ixgbe_set_rx_mode,
        .ndo_set_multicast_list = ixgbe_set_rx_mode,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = ixgbe_set_mac,
@@@ -4435,7 -4007,7 +4436,7 @@@ static int __devinit ixgbe_probe(struc
        const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
        static int cards_found;
        int i, err, pci_using_dac;
 -      u16 link_status, link_speed, link_width;
 +      u16 pm_value = 0;
        u32 part_num, eec;
  
        err = pci_enable_device(pdev);
  
        INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task);
  
 +      /* multispeed fiber has its own tasklet, called from GPI SDP1 context */
 +      INIT_WORK(&adapter->multispeed_fiber_task, ixgbe_multispeed_fiber_task);
 +
 +      /* a new SFP+ module arrival, called from GPI SDP2 context */
 +      INIT_WORK(&adapter->sfp_config_module_task,
 +                ixgbe_sfp_config_module_task);
 +
        err = ii->get_invariants(hw);
        if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
                /* start a kernel thread to watch for a module to arrive */
        netdev->features |= NETIF_F_IPV6_CSUM;
        netdev->features |= NETIF_F_TSO;
        netdev->features |= NETIF_F_TSO6;
 -      netdev->features |= NETIF_F_LRO;
 +      netdev->features |= NETIF_F_GRO;
  
        netdev->vlan_features |= NETIF_F_TSO;
        netdev->vlan_features |= NETIF_F_TSO6;
        if (err)
                goto err_sw_init;
  
 +      switch (pdev->device) {
 +      case IXGBE_DEV_ID_82599_KX4:
 +#define IXGBE_PCIE_PMCSR 0x44
 +              adapter->wol = IXGBE_WUFC_MAG;
 +              pci_read_config_word(pdev, IXGBE_PCIE_PMCSR, &pm_value);
 +              pci_write_config_word(pdev, IXGBE_PCIE_PMCSR,
 +                                    (pm_value | (1 << 8)));
 +              break;
 +      default:
 +              adapter->wol = 0;
 +              break;
 +      }
 +      device_init_wakeup(&adapter->pdev->dev, true);
 +      device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
 +
        /* print bus type/speed/width info */
 -      pci_read_config_word(pdev, IXGBE_PCI_LINK_STATUS, &link_status);
 -      link_speed = link_status & IXGBE_PCI_LINK_SPEED;
 -      link_width = link_status & IXGBE_PCI_LINK_WIDTH;
        dev_info(&pdev->dev, "(PCI Express:%s:%s) %pM\n",
 -              ((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" :
 -               (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" :
 -               "Unknown"),
 -              ((link_width == IXGBE_PCI_LINK_WIDTH_8) ? "Width x8" :
 -               (link_width == IXGBE_PCI_LINK_WIDTH_4) ? "Width x4" :
 -               (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" :
 -               (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" :
 +              ((hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0Gb/s":
 +               (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5Gb/s":"Unknown"),
 +              ((hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" :
 +               (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" :
 +               (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" :
                 "Unknown"),
                netdev->dev_addr);
        ixgbe_read_pba_num_generic(hw, &part_num);
 -      dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
 -               hw->mac.type, hw->phy.type,
 -               (part_num >> 8), (part_num & 0xff));
 +      if (ixgbe_is_sfp(hw) && hw->phy.sfp_type != ixgbe_sfp_type_not_present)
 +              dev_info(&pdev->dev, "MAC: %d, PHY: %d, SFP+: %d, PBA No: %06x-%03x\n",
 +                       hw->mac.type, hw->phy.type, hw->phy.sfp_type,
 +                       (part_num >> 8), (part_num & 0xff));
 +      else
 +              dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
 +                       hw->mac.type, hw->phy.type,
 +                       (part_num >> 8), (part_num & 0xff));
  
 -      if (link_width <= IXGBE_PCI_LINK_WIDTH_4) {
 +      if (hw->bus.width <= ixgbe_bus_width_pcie_x4) {
                dev_warn(&pdev->dev, "PCI-Express bandwidth available for "
                         "this card is not sufficient for optimal "
                         "performance.\n");
                         "PCI-Express slot is required.\n");
        }
  
 +      /* save off EEPROM version number */
 +      hw->eeprom.ops.read(hw, 0x29, &adapter->eeprom_version);
 +
        /* reset the hardware with the new settings */
        hw->mac.ops.start_hw(hw);
  
 -      /* link_config depends on start_hw being called at least once */
 -      err = ixgbe_link_config(hw);
 -      if (err) {
 -              dev_err(&pdev->dev, "setup_link_speed FAILED %d\n", err);
 -              goto err_register;
 -      }
 -
        netif_carrier_off(netdev);
  
        strcpy(netdev->name, "eth%d");
@@@ -4699,8 -4253,6 +4700,8 @@@ err_eeprom
        clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
        del_timer_sync(&adapter->sfp_timer);
        cancel_work_sync(&adapter->sfp_task);
 +      cancel_work_sync(&adapter->multispeed_fiber_task);
 +      cancel_work_sync(&adapter->sfp_config_module_task);
        iounmap(hw->hw_addr);
  err_ioremap:
        free_netdev(netdev);
@@@ -4737,8 -4289,6 +4738,8 @@@ static void __devexit ixgbe_remove(stru
        del_timer_sync(&adapter->sfp_timer);
        cancel_work_sync(&adapter->watchdog_task);
        cancel_work_sync(&adapter->sfp_task);
 +      cancel_work_sync(&adapter->multispeed_fiber_task);
 +      cancel_work_sync(&adapter->sfp_config_module_task);
        flush_scheduled_work();
  
  #ifdef CONFIG_IXGBE_DCA
@@@ -4822,7 -4372,7 +4823,7 @@@ static pci_ers_result_t ixgbe_io_slot_r
                pci_enable_wake(pdev, PCI_D3cold, 0);
  
                ixgbe_reset(adapter);
 -
 +              IXGBE_WRITE_REG(&adapter->hw, IXGBE_WUS, ~0);
                result = PCI_ERS_RESULT_RECOVERED;
        }
  
index e1f7706c15cde6163716c371f2a97f1023ea6791,b0bc3bc18e9cdffc808a9957e964f4c81e530954..a56d9d2df73f3b108427a8ee828cb1afb0cb782d
@@@ -53,7 -53,6 +53,7 @@@
  #include <linux/mv643xx_eth.h>
  #include <linux/io.h>
  #include <linux/types.h>
 +#include <linux/inet_lro.h>
  #include <asm/system.h>
  
  static char mv643xx_eth_driver_name[] = "mv643xx_eth";
@@@ -228,12 -227,6 +228,12 @@@ struct tx_desc 
  #define RX_ENABLE_INTERRUPT           0x20000000
  #define RX_FIRST_DESC                 0x08000000
  #define RX_LAST_DESC                  0x04000000
 +#define RX_IP_HDR_OK                  0x02000000
 +#define RX_PKT_IS_IPV4                        0x01000000
 +#define RX_PKT_IS_ETHERNETV2          0x00800000
 +#define RX_PKT_LAYER4_TYPE_MASK               0x00600000
 +#define RX_PKT_LAYER4_TYPE_TCP_IPV4   0x00000000
 +#define RX_PKT_IS_VLAN_TAGGED         0x00080000
  
  /* TX descriptor command */
  #define TX_ENABLE_INTERRUPT           0x00800000
@@@ -293,9 -286,6 +293,9 @@@ struct mv643xx_eth_shared_private 
  #define TX_BW_CONTROL_OLD_LAYOUT      1
  #define TX_BW_CONTROL_NEW_LAYOUT      2
  
 +static int mv643xx_eth_open(struct net_device *dev);
 +static int mv643xx_eth_stop(struct net_device *dev);
 +
  
  /* per-port *****************************************************************/
  struct mib_counters {
        u32 late_collision;
  };
  
 +struct lro_counters {
 +      u32 lro_aggregated;
 +      u32 lro_flushed;
 +      u32 lro_no_desc;
 +};
 +
  struct rx_queue {
        int index;
  
        dma_addr_t rx_desc_dma;
        int rx_desc_area_size;
        struct sk_buff **rx_skb;
 +
 +      struct net_lro_mgr lro_mgr;
 +      struct net_lro_desc lro_arr[8];
  };
  
  struct tx_queue {
@@@ -388,8 -369,6 +388,8 @@@ struct mv643xx_eth_private 
        spinlock_t mib_counters_lock;
        struct mib_counters mib_counters;
  
 +      struct lro_counters lro_counters;
 +
        struct work_struct tx_timeout_task;
  
        struct napi_struct napi;
        /*
         * RX state.
         */
 -      int default_rx_ring_size;
 +      int rx_ring_size;
        unsigned long rx_desc_sram_addr;
        int rx_desc_sram_size;
        int rxq_count;
        /*
         * TX state.
         */
 -      int default_tx_ring_size;
 +      int tx_ring_size;
        unsigned long tx_desc_sram_addr;
        int tx_desc_sram_size;
        int txq_count;
@@@ -514,40 -493,12 +514,40 @@@ static void txq_maybe_wake(struct tx_qu
  
  
  /* rx napi ******************************************************************/
 +static int
 +mv643xx_get_skb_header(struct sk_buff *skb, void **iphdr, void **tcph,
 +                     u64 *hdr_flags, void *priv)
 +{
 +      unsigned long cmd_sts = (unsigned long)priv;
 +
 +      /*
 +       * Make sure that this packet is Ethernet II, is not VLAN
 +       * tagged, is IPv4, has a valid IP header, and is TCP.
 +       */
 +      if ((cmd_sts & (RX_IP_HDR_OK | RX_PKT_IS_IPV4 |
 +                     RX_PKT_IS_ETHERNETV2 | RX_PKT_LAYER4_TYPE_MASK |
 +                     RX_PKT_IS_VLAN_TAGGED)) !=
 +          (RX_IP_HDR_OK | RX_PKT_IS_IPV4 |
 +           RX_PKT_IS_ETHERNETV2 | RX_PKT_LAYER4_TYPE_TCP_IPV4))
 +              return -1;
 +
 +      skb_reset_network_header(skb);
 +      skb_set_transport_header(skb, ip_hdrlen(skb));
 +      *iphdr = ip_hdr(skb);
 +      *tcph = tcp_hdr(skb);
 +      *hdr_flags = LRO_IPV4 | LRO_TCP;
 +
 +      return 0;
 +}
 +
  static int rxq_process(struct rx_queue *rxq, int budget)
  {
        struct mv643xx_eth_private *mp = rxq_to_mp(rxq);
        struct net_device_stats *stats = &mp->dev->stats;
 +      int lro_flush_needed;
        int rx;
  
 +      lro_flush_needed = 0;
        rx = 0;
        while (rx < budget && rxq->rx_desc_count) {
                struct rx_desc *rx_desc;
                if (cmd_sts & LAYER_4_CHECKSUM_OK)
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                skb->protocol = eth_type_trans(skb, mp->dev);
 -              netif_receive_skb(skb);
 +
 +              if (skb->dev->features & NETIF_F_LRO &&
 +                  skb->ip_summed == CHECKSUM_UNNECESSARY) {
 +                      lro_receive_skb(&rxq->lro_mgr, skb, (void *)cmd_sts);
 +                      lro_flush_needed = 1;
 +              } else
 +                      netif_receive_skb(skb);
  
                continue;
  
@@@ -634,9 -579,6 +634,9 @@@ err
                dev_kfree_skb(skb);
        }
  
 +      if (lro_flush_needed)
 +              lro_flush_all(&rxq->lro_mgr);
 +
        if (rx < budget)
                mp->work_rx &= ~(1 << rxq->index);
  
@@@ -965,7 -907,7 +965,7 @@@ static int txq_reclaim(struct tx_queue 
  
                if (skb != NULL) {
                        if (skb_queue_len(&mp->rx_recycle) <
 -                                      mp->default_rx_ring_size &&
 +                                      mp->rx_ring_size &&
                            skb_recycle_check(skb, mp->skb_size +
                                        dma_get_cache_alignment() - 1))
                                __skb_queue_head(&mp->rx_recycle, skb);
@@@ -1216,26 -1158,6 +1216,26 @@@ static struct net_device_stats *mv643xx
        return stats;
  }
  
 +static void mv643xx_eth_grab_lro_stats(struct mv643xx_eth_private *mp)
 +{
 +      u32 lro_aggregated = 0;
 +      u32 lro_flushed = 0;
 +      u32 lro_no_desc = 0;
 +      int i;
 +
 +      for (i = 0; i < mp->rxq_count; i++) {
 +              struct rx_queue *rxq = mp->rxq + i;
 +
 +              lro_aggregated += rxq->lro_mgr.stats.aggregated;
 +              lro_flushed += rxq->lro_mgr.stats.flushed;
 +              lro_no_desc += rxq->lro_mgr.stats.no_desc;
 +      }
 +
 +      mp->lro_counters.lro_aggregated = lro_aggregated;
 +      mp->lro_counters.lro_flushed = lro_flushed;
 +      mp->lro_counters.lro_no_desc = lro_no_desc;
 +}
 +
  static inline u32 mib_read(struct mv643xx_eth_private *mp, int offset)
  {
        return rdl(mp, MIB_COUNTERS(mp->port_num) + offset);
@@@ -1299,85 -1221,6 +1299,85 @@@ static void mib_counters_timer_wrapper(
  }
  
  
 +/* interrupt coalescing *****************************************************/
 +/*
 + * Hardware coalescing parameters are set in units of 64 t_clk
 + * cycles.  I.e.:
 + *
 + *    coal_delay_in_usec = 64000000 * register_value / t_clk_rate
 + *
 + *    register_value = coal_delay_in_usec * t_clk_rate / 64000000
 + *
 + * In the ->set*() methods, we round the computed register value
 + * to the nearest integer.
 + */
 +static unsigned int get_rx_coal(struct mv643xx_eth_private *mp)
 +{
 +      u32 val = rdlp(mp, SDMA_CONFIG);
 +      u64 temp;
 +
 +      if (mp->shared->extended_rx_coal_limit)
 +              temp = ((val & 0x02000000) >> 10) | ((val & 0x003fff80) >> 7);
 +      else
 +              temp = (val & 0x003fff00) >> 8;
 +
 +      temp *= 64000000;
 +      do_div(temp, mp->shared->t_clk);
 +
 +      return (unsigned int)temp;
 +}
 +
 +static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int usec)
 +{
 +      u64 temp;
 +      u32 val;
 +
 +      temp = (u64)usec * mp->shared->t_clk;
 +      temp += 31999999;
 +      do_div(temp, 64000000);
 +
 +      val = rdlp(mp, SDMA_CONFIG);
 +      if (mp->shared->extended_rx_coal_limit) {
 +              if (temp > 0xffff)
 +                      temp = 0xffff;
 +              val &= ~0x023fff80;
 +              val |= (temp & 0x8000) << 10;
 +              val |= (temp & 0x7fff) << 7;
 +      } else {
 +              if (temp > 0x3fff)
 +                      temp = 0x3fff;
 +              val &= ~0x003fff00;
 +              val |= (temp & 0x3fff) << 8;
 +      }
 +      wrlp(mp, SDMA_CONFIG, val);
 +}
 +
 +static unsigned int get_tx_coal(struct mv643xx_eth_private *mp)
 +{
 +      u64 temp;
 +
 +      temp = (rdlp(mp, TX_FIFO_URGENT_THRESHOLD) & 0x3fff0) >> 4;
 +      temp *= 64000000;
 +      do_div(temp, mp->shared->t_clk);
 +
 +      return (unsigned int)temp;
 +}
 +
 +static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int usec)
 +{
 +      u64 temp;
 +
 +      temp = (u64)usec * mp->shared->t_clk;
 +      temp += 31999999;
 +      do_div(temp, 64000000);
 +
 +      if (temp > 0x3fff)
 +              temp = 0x3fff;
 +
 +      wrlp(mp, TX_FIFO_URGENT_THRESHOLD, temp << 4);
 +}
 +
 +
  /* ethtool ******************************************************************/
  struct mv643xx_eth_stats {
        char stat_string[ETH_GSTRING_LEN];
        { #m, FIELD_SIZEOF(struct mib_counters, m),             \
          -1, offsetof(struct mv643xx_eth_private, mib_counters.m) }
  
 +#define LROSTAT(m)                                            \
 +      { #m, FIELD_SIZEOF(struct lro_counters, m),             \
 +        -1, offsetof(struct mv643xx_eth_private, lro_counters.m) }
 +
  static const struct mv643xx_eth_stats mv643xx_eth_stats[] = {
        SSTAT(rx_packets),
        SSTAT(tx_packets),
        MIBSTAT(bad_crc_event),
        MIBSTAT(collision),
        MIBSTAT(late_collision),
 +      LROSTAT(lro_aggregated),
 +      LROSTAT(lro_flushed),
 +      LROSTAT(lro_no_desc),
  };
  
  static int
 -mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 +mv643xx_eth_get_settings_phy(struct mv643xx_eth_private *mp,
 +                           struct ethtool_cmd *cmd)
  {
 -      struct mv643xx_eth_private *mp = netdev_priv(dev);
        int err;
  
        err = phy_read_status(mp->phy);
  }
  
  static int
 -mv643xx_eth_get_settings_phyless(struct net_device *dev,
 +mv643xx_eth_get_settings_phyless(struct mv643xx_eth_private *mp,
                                 struct ethtool_cmd *cmd)
  {
 -      struct mv643xx_eth_private *mp = netdev_priv(dev);
        u32 port_status;
  
        port_status = rdlp(mp, PORT_STATUS);
        return 0;
  }
  
 +static int
 +mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 +{
 +      struct mv643xx_eth_private *mp = netdev_priv(dev);
 +
 +      if (mp->phy != NULL)
 +              return mv643xx_eth_get_settings_phy(mp, cmd);
 +      else
 +              return mv643xx_eth_get_settings_phyless(mp, cmd);
 +}
 +
  static int
  mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
  {
        struct mv643xx_eth_private *mp = netdev_priv(dev);
  
 +      if (mp->phy == NULL)
 +              return -EINVAL;
 +
        /*
         * The MAC does not support 1000baseT_Half.
         */
        return phy_ethtool_sset(mp->phy, cmd);
  }
  
 -static int
 -mv643xx_eth_set_settings_phyless(struct net_device *dev,
 -                               struct ethtool_cmd *cmd)
 -{
 -      return -EINVAL;
 -}
 -
  static void mv643xx_eth_get_drvinfo(struct net_device *dev,
                                    struct ethtool_drvinfo *drvinfo)
  {
@@@ -1537,95 -1367,17 +1537,95 @@@ static int mv643xx_eth_nway_reset(struc
  {
        struct mv643xx_eth_private *mp = netdev_priv(dev);
  
 +      if (mp->phy == NULL)
 +              return -EINVAL;
 +
        return genphy_restart_aneg(mp->phy);
  }
  
 -static int mv643xx_eth_nway_reset_phyless(struct net_device *dev)
 +static u32 mv643xx_eth_get_link(struct net_device *dev)
  {
 -      return -EINVAL;
 +      return !!netif_carrier_ok(dev);
  }
  
 -static u32 mv643xx_eth_get_link(struct net_device *dev)
 +static int
 +mv643xx_eth_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
  {
 -      return !!netif_carrier_ok(dev);
 +      struct mv643xx_eth_private *mp = netdev_priv(dev);
 +
 +      ec->rx_coalesce_usecs = get_rx_coal(mp);
 +      ec->tx_coalesce_usecs = get_tx_coal(mp);
 +
 +      return 0;
 +}
 +
 +static int
 +mv643xx_eth_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
 +{
 +      struct mv643xx_eth_private *mp = netdev_priv(dev);
 +
 +      set_rx_coal(mp, ec->rx_coalesce_usecs);
 +      set_tx_coal(mp, ec->tx_coalesce_usecs);
 +
 +      return 0;
 +}
 +
 +static void
 +mv643xx_eth_get_ringparam(struct net_device *dev, struct ethtool_ringparam *er)
 +{
 +      struct mv643xx_eth_private *mp = netdev_priv(dev);
 +
 +      er->rx_max_pending = 4096;
 +      er->tx_max_pending = 4096;
 +      er->rx_mini_max_pending = 0;
 +      er->rx_jumbo_max_pending = 0;
 +
 +      er->rx_pending = mp->rx_ring_size;
 +      er->tx_pending = mp->tx_ring_size;
 +      er->rx_mini_pending = 0;
 +      er->rx_jumbo_pending = 0;
 +}
 +
 +static int
 +mv643xx_eth_set_ringparam(struct net_device *dev, struct ethtool_ringparam *er)
 +{
 +      struct mv643xx_eth_private *mp = netdev_priv(dev);
 +
 +      if (er->rx_mini_pending || er->rx_jumbo_pending)
 +              return -EINVAL;
 +
 +      mp->rx_ring_size = er->rx_pending < 4096 ? er->rx_pending : 4096;
 +      mp->tx_ring_size = er->tx_pending < 4096 ? er->tx_pending : 4096;
 +
 +      if (netif_running(dev)) {
 +              mv643xx_eth_stop(dev);
 +              if (mv643xx_eth_open(dev)) {
 +                      dev_printk(KERN_ERR, &dev->dev,
 +                                 "fatal error on re-opening device after "
 +                                 "ring param change\n");
 +                      return -ENOMEM;
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +static u32
 +mv643xx_eth_get_rx_csum(struct net_device *dev)
 +{
 +      struct mv643xx_eth_private *mp = netdev_priv(dev);
 +
 +      return !!(rdlp(mp, PORT_CONFIG) & 0x02000000);
 +}
 +
 +static int
 +mv643xx_eth_set_rx_csum(struct net_device *dev, u32 rx_csum)
 +{
 +      struct mv643xx_eth_private *mp = netdev_priv(dev);
 +
 +      wrlp(mp, PORT_CONFIG, rx_csum ? 0x02000000 : 0x00000000);
 +
 +      return 0;
  }
  
  static void mv643xx_eth_get_strings(struct net_device *dev,
@@@ -1651,7 -1403,6 +1651,7 @@@ static void mv643xx_eth_get_ethtool_sta
  
        mv643xx_eth_get_stats(dev);
        mib_counters_update(mp);
 +      mv643xx_eth_grab_lro_stats(mp);
  
        for (i = 0; i < ARRAY_SIZE(mv643xx_eth_stats); i++) {
                const struct mv643xx_eth_stats *stat;
@@@ -1683,18 -1434,21 +1683,18 @@@ static const struct ethtool_ops mv643xx
        .get_drvinfo            = mv643xx_eth_get_drvinfo,
        .nway_reset             = mv643xx_eth_nway_reset,
        .get_link               = mv643xx_eth_get_link,
 +      .get_coalesce           = mv643xx_eth_get_coalesce,
 +      .set_coalesce           = mv643xx_eth_set_coalesce,
 +      .get_ringparam          = mv643xx_eth_get_ringparam,
 +      .set_ringparam          = mv643xx_eth_set_ringparam,
 +      .get_rx_csum            = mv643xx_eth_get_rx_csum,
 +      .set_rx_csum            = mv643xx_eth_set_rx_csum,
 +      .set_tx_csum            = ethtool_op_set_tx_csum,
        .set_sg                 = ethtool_op_set_sg,
        .get_strings            = mv643xx_eth_get_strings,
        .get_ethtool_stats      = mv643xx_eth_get_ethtool_stats,
 -      .get_sset_count         = mv643xx_eth_get_sset_count,
 -};
 -
 -static const struct ethtool_ops mv643xx_eth_ethtool_ops_phyless = {
 -      .get_settings           = mv643xx_eth_get_settings_phyless,
 -      .set_settings           = mv643xx_eth_set_settings_phyless,
 -      .get_drvinfo            = mv643xx_eth_get_drvinfo,
 -      .nway_reset             = mv643xx_eth_nway_reset_phyless,
 -      .get_link               = mv643xx_eth_get_link,
 -      .set_sg                 = ethtool_op_set_sg,
 -      .get_strings            = mv643xx_eth_get_strings,
 -      .get_ethtool_stats      = mv643xx_eth_get_ethtool_stats,
 +      .get_flags              = ethtool_op_get_flags,
 +      .set_flags              = ethtool_op_set_flags,
        .get_sset_count         = mv643xx_eth_get_sset_count,
  };
  
@@@ -1883,7 -1637,7 +1883,7 @@@ static int rxq_init(struct mv643xx_eth_
  
        rxq->index = index;
  
 -      rxq->rx_ring_size = mp->default_rx_ring_size;
 +      rxq->rx_ring_size = mp->rx_ring_size;
  
        rxq->rx_desc_count = 0;
        rxq->rx_curr_desc = 0;
                                        nexti * sizeof(struct rx_desc);
        }
  
 +      rxq->lro_mgr.dev = mp->dev;
 +      memset(&rxq->lro_mgr.stats, 0, sizeof(rxq->lro_mgr.stats));
 +      rxq->lro_mgr.features = LRO_F_NAPI;
 +      rxq->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
 +      rxq->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
 +      rxq->lro_mgr.max_desc = ARRAY_SIZE(rxq->lro_arr);
 +      rxq->lro_mgr.max_aggr = 32;
 +      rxq->lro_mgr.frag_align_pad = 0;
 +      rxq->lro_mgr.lro_arr = rxq->lro_arr;
 +      rxq->lro_mgr.get_skb_header = mv643xx_get_skb_header;
 +
 +      memset(&rxq->lro_arr, 0, sizeof(rxq->lro_arr));
 +
        return 0;
  
  
@@@ -1996,7 -1737,7 +1996,7 @@@ static int txq_init(struct mv643xx_eth_
  
        txq->index = index;
  
 -      txq->tx_ring_size = mp->default_tx_ring_size;
 +      txq->tx_ring_size = mp->tx_ring_size;
  
        txq->tx_desc_count = 0;
        txq->tx_curr_desc = 0;
@@@ -2288,11 -2029,6 +2288,6 @@@ static void port_start(struct mv643xx_e
                txq_set_fixed_prio_mode(txq);
        }
  
-       /*
-        * Add configured unicast address to address filter table.
-        */
-       mv643xx_eth_program_unicast_filter(mp->dev);
        /*
         * Receive all unmatched unicast, TCP, UDP, BPDU and broadcast
         * frames to RX queue #0, and include the pseudo-header when
         */
        wrlp(mp, PORT_CONFIG_EXT, 0x00000000);
  
+       /*
+        * Add configured unicast addresses to address filter table.
+        */
+       mv643xx_eth_program_unicast_filter(mp->dev);
        /*
         * Enable the receive queues.
         */
        }
  }
  
 -static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int delay)
 -{
 -      unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64;
 -      u32 val;
 -
 -      val = rdlp(mp, SDMA_CONFIG);
 -      if (mp->shared->extended_rx_coal_limit) {
 -              if (coal > 0xffff)
 -                      coal = 0xffff;
 -              val &= ~0x023fff80;
 -              val |= (coal & 0x8000) << 10;
 -              val |= (coal & 0x7fff) << 7;
 -      } else {
 -              if (coal > 0x3fff)
 -                      coal = 0x3fff;
 -              val &= ~0x003fff00;
 -              val |= (coal & 0x3fff) << 8;
 -      }
 -      wrlp(mp, SDMA_CONFIG, val);
 -}
 -
 -static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int delay)
 -{
 -      unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64;
 -
 -      if (coal > 0x3fff)
 -              coal = 0x3fff;
 -      wrlp(mp, TX_FIFO_URGENT_THRESHOLD, (coal & 0x3fff) << 4);
 -}
 -
  static void mv643xx_eth_recalc_skb_size(struct mv643xx_eth_private *mp)
  {
        int skb_size;
@@@ -2388,8 -2159,13 +2388,8 @@@ static int mv643xx_eth_open(struct net_
                }
        }
  
 -      netif_carrier_off(dev);
 -
        port_start(mp);
  
 -      set_rx_coal(mp, 0);
 -      set_tx_coal(mp, 0);
 -
        wrlp(mp, INT_MASK_EXT, INT_EXT_LINK_PHY | INT_EXT_TX);
        wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT);
  
@@@ -2755,17 -2531,17 +2755,17 @@@ static void set_params(struct mv643xx_e
        else
                uc_addr_get(mp, dev->dev_addr);
  
 -      mp->default_rx_ring_size = DEFAULT_RX_QUEUE_SIZE;
 +      mp->rx_ring_size = DEFAULT_RX_QUEUE_SIZE;
        if (pd->rx_queue_size)
 -              mp->default_rx_ring_size = pd->rx_queue_size;
 +              mp->rx_ring_size = pd->rx_queue_size;
        mp->rx_desc_sram_addr = pd->rx_sram_addr;
        mp->rx_desc_sram_size = pd->rx_sram_size;
  
        mp->rxq_count = pd->rx_queue_count ? : 1;
  
 -      mp->default_tx_ring_size = DEFAULT_TX_QUEUE_SIZE;
 +      mp->tx_ring_size = DEFAULT_TX_QUEUE_SIZE;
        if (pd->tx_queue_size)
 -              mp->default_tx_ring_size = pd->tx_queue_size;
 +              mp->tx_ring_size = pd->tx_queue_size;
        mp->tx_desc_sram_addr = pd->tx_sram_addr;
        mp->tx_desc_sram_size = pd->tx_sram_size;
  
@@@ -2812,7 -2588,7 +2812,7 @@@ static void phy_init(struct mv643xx_eth
  
        phy_reset(mp);
  
 -      phy_attach(mp->dev, phy->dev.bus_id, 0, PHY_INTERFACE_MODE_GMII);
 +      phy_attach(mp->dev, dev_name(&phy->dev), 0, PHY_INTERFACE_MODE_GMII);
  
        if (speed == 0) {
                phy->autoneg = AUTONEG_ENABLE;
@@@ -2856,21 -2632,6 +2856,21 @@@ static void init_pscr(struct mv643xx_et
        wrlp(mp, PORT_SERIAL_CONTROL, pscr);
  }
  
 +static const struct net_device_ops mv643xx_eth_netdev_ops = {
 +      .ndo_open               = mv643xx_eth_open,
 +      .ndo_stop               = mv643xx_eth_stop,
 +      .ndo_start_xmit         = mv643xx_eth_xmit,
 +      .ndo_set_rx_mode        = mv643xx_eth_set_rx_mode,
 +      .ndo_set_mac_address    = mv643xx_eth_set_mac_address,
 +      .ndo_do_ioctl           = mv643xx_eth_ioctl,
 +      .ndo_change_mtu         = mv643xx_eth_change_mtu,
 +      .ndo_tx_timeout         = mv643xx_eth_tx_timeout,
 +      .ndo_get_stats          = mv643xx_eth_get_stats,
 +#ifdef CONFIG_NET_POLL_CONTROLLER
 +      .ndo_poll_controller    = mv643xx_eth_netpoll,
 +#endif
 +};
 +
  static int mv643xx_eth_probe(struct platform_device *pdev)
  {
        struct mv643xx_eth_platform_data *pd;
        if (pd->phy_addr != MV643XX_ETH_PHY_NONE)
                mp->phy = phy_scan(mp, pd->phy_addr);
  
 -      if (mp->phy != NULL) {
 +      if (mp->phy != NULL)
                phy_init(mp, pd->speed, pd->duplex);
 -              SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops);
 -      } else {
 -              SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops_phyless);
 -      }
 +
 +      SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops);
  
        init_pscr(mp, pd->speed, pd->duplex);
  
        BUG_ON(!res);
        dev->irq = res->start;
  
 -      dev->get_stats = mv643xx_eth_get_stats;
 -      dev->hard_start_xmit = mv643xx_eth_xmit;
 -      dev->open = mv643xx_eth_open;
 -      dev->stop = mv643xx_eth_stop;
 -      dev->set_rx_mode = mv643xx_eth_set_rx_mode;
 -      dev->set_mac_address = mv643xx_eth_set_mac_address;
 -      dev->do_ioctl = mv643xx_eth_ioctl;
 -      dev->change_mtu = mv643xx_eth_change_mtu;
 -      dev->tx_timeout = mv643xx_eth_tx_timeout;
 -#ifdef CONFIG_NET_POLL_CONTROLLER
 -      dev->poll_controller = mv643xx_eth_netpoll;
 -#endif
 +      dev->netdev_ops = &mv643xx_eth_netdev_ops;
 +
        dev->watchdog_timeo = 2 * HZ;
        dev->base_addr = 0;
  
        if (mp->shared->win_protect)
                wrl(mp, WINDOW_PROTECT(mp->port_num), mp->shared->win_protect);
  
 +      netif_carrier_off(dev);
 +
 +      set_rx_coal(mp, 250);
 +      set_tx_coal(mp, 0);
 +
        err = register_netdev(dev);
        if (err)
                goto out;
index 78e6228937fe578f80c9f4a5c2428b95bb2f34ff,1ff066b2281a029ebd1e3ef5a7d84b985df7e080..c40815169f35bee6b0b3ac188e74d001984ab425
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (C) 2003 - 2006 NetXen, Inc.
 + * Copyright (C) 2003 - 2009 NetXen, Inc.
   * All rights reserved.
   *
   * This program is free software; you can redistribute it and/or
   *
   * Contact Information:
   *    info@netxen.com
 - * NetXen,
 - * 3965 Freedom Circle, Fourth floor,
 - * Santa Clara, CA 95054
 + * NetXen Inc,
 + * 18922 Forge Drive
 + * Cupertino, CA 95014-0701
 + *
   */
  
  #ifndef _NETXEN_NIC_H_
@@@ -66,8 -65,8 +66,8 @@@
  
  #define _NETXEN_NIC_LINUX_MAJOR 4
  #define _NETXEN_NIC_LINUX_MINOR 0
 -#define _NETXEN_NIC_LINUX_SUBVERSION 11
 -#define NETXEN_NIC_LINUX_VERSIONID  "4.0.11"
 +#define _NETXEN_NIC_LINUX_SUBVERSION 30
 +#define NETXEN_NIC_LINUX_VERSIONID  "4.0.30"
  
  #define NETXEN_VERSION_CODE(a, b, c)  (((a) << 16) + ((b) << 8) + (c))
  
  
  #define PHAN_VENDOR_ID 0x4040
  
 -#define RCV_DESC_RINGSIZE     \
 -      (sizeof(struct rcv_desc) * adapter->max_rx_desc_count)
 -#define STATUS_DESC_RINGSIZE  \
 -      (sizeof(struct status_desc)* adapter->max_rx_desc_count)
 -#define LRO_DESC_RINGSIZE     \
 -      (sizeof(rcvDesc_t) * adapter->max_lro_rx_desc_count)
 -#define TX_RINGSIZE   \
 -      (sizeof(struct netxen_cmd_buffer) * adapter->max_tx_desc_count)
 -#define RCV_BUFFSIZE  \
 -      (sizeof(struct netxen_rx_buffer) * rds_ring->max_rx_desc_count)
 +#define RCV_DESC_RINGSIZE(rds_ring)   \
 +      (sizeof(struct rcv_desc) * (rds_ring)->num_desc)
 +#define RCV_BUFF_RINGSIZE(rds_ring)   \
 +      (sizeof(struct netxen_rx_buffer) * rds_ring->num_desc)
 +#define STATUS_DESC_RINGSIZE(sds_ring)        \
 +      (sizeof(struct status_desc) * (sds_ring)->num_desc)
 +#define TX_BUFF_RINGSIZE(adapter)     \
 +      (sizeof(struct netxen_cmd_buffer) * adapter->num_txd)
 +#define TX_DESC_RINGSIZE(adapter)     \
 +      (sizeof(struct cmd_desc_type0) * adapter->num_txd)
 +
  #define find_diff_among(a,b,range) ((a)<(b)?((b)-(a)):((b)+(range)-(a)))
  
 -#define NETXEN_NETDEV_STATUS          0x1
  #define NETXEN_RCV_PRODUCER_OFFSET    0
  #define NETXEN_RCV_PEG_DB_ID          2
  #define NETXEN_HOST_DUMMY_DMA_SIZE 1024
  /* Host writes the following to notify that it has done the init-handshake */
  #define PHAN_INITIALIZE_ACK   0xf00f
  
 -#define NUM_RCV_DESC_RINGS    3       /* No of Rcv Descriptor contexts */
 -
 -/* descriptor types */
 -#define RCV_DESC_NORMAL               0x01
 -#define RCV_DESC_JUMBO                0x02
 -#define RCV_DESC_LRO          0x04
 -#define RCV_DESC_NORMAL_CTXID 0
 -#define RCV_DESC_JUMBO_CTXID  1
 -#define RCV_DESC_LRO_CTXID    2
 +#define NUM_RCV_DESC_RINGS    3
 +#define NUM_STS_DESC_RINGS    4
  
 -#define RCV_DESC_TYPE(ID) \
 -      ((ID == RCV_DESC_JUMBO_CTXID)   \
 -              ? RCV_DESC_JUMBO        \
 -              : ((ID == RCV_DESC_LRO_CTXID)   \
 -                      ? RCV_DESC_LRO :        \
 -                      (RCV_DESC_NORMAL)))
 +#define RCV_RING_NORMAL       0
 +#define RCV_RING_JUMBO        1
 +#define RCV_RING_LRO  2
  
  #define MAX_CMD_DESCRIPTORS           4096
  #define MAX_RCV_DESCRIPTORS           16384
@@@ -348,7 -357,10 +348,7 @@@ struct cmd_desc_type0 
                __le64 addr_buffer1;
        };
  
 -      __le16 buffer1_length;
 -      __le16 buffer2_length;
 -      __le16 buffer3_length;
 -      __le16 buffer4_length;
 +      __le16 buffer_length[4];
  
        union {
                struct {
@@@ -379,8 -391,11 +379,8 @@@ struct rcv_desc 
  #define STATUS_CKSUM_OK               (2)
  
  /* owner bits of status_desc */
 -#define STATUS_OWNER_HOST     (0x1)
 -#define STATUS_OWNER_PHANTOM  (0x2)
 -
 -#define NETXEN_PROT_IP                (1)
 -#define NETXEN_PROT_UNKNOWN   (0)
 +#define STATUS_OWNER_HOST     (0x1ULL << 56)
 +#define STATUS_OWNER_PHANTOM  (0x2ULL << 56)
  
  /* Note: sizeof(status_desc) should always be a mutliple of 2 */
  
  #define netxen_get_sts_opcode(sts_data)       \
        (((sts_data) >> 58) & 0x03F)
  
 -#define netxen_get_sts_owner(status_desc)     \
 -      ((le64_to_cpu((status_desc)->status_desc_data) >> 56) & 0x03)
 -#define netxen_set_sts_owner(status_desc, val)        { \
 -      (status_desc)->status_desc_data = \
 -              ((status_desc)->status_desc_data & \
 -              ~cpu_to_le64(0x3ULL << 56)) | \
 -              cpu_to_le64((u64)((val) & 0x3) << 56); \
 -}
 -
  struct status_desc {
        /* Bit pattern: 0-3 port, 4-7 status, 8-11 type, 12-27 total_length
           28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset
@@@ -688,15 -712,6 +688,15 @@@ typedef enum 
        NETXEN_FIXED_START = 0x3F0000   /* backup of crbinit */
  } netxen_flash_map_t;
  
 +#define NX_FW_VERSION_OFFSET  (NETXEN_USER_START+0x408)
 +#define NX_FW_SIZE_OFFSET     (NETXEN_USER_START+0x40c)
 +#define NX_BIOS_VERSION_OFFSET        (NETXEN_USER_START+0x83c)
 +#define NX_FW_MAGIC_OFFSET    (NETXEN_BRDCFG_START+0x128)
 +#define NX_FW_MIN_SIZE                (0x3fffff)
 +#define NX_P2_MN_ROMIMAGE     0
 +#define NX_P3_CT_ROMIMAGE     1
 +#define NX_P3_MN_ROMIMAGE     2
 +
  #define NETXEN_USER_START_OLD NETXEN_PXE_START        /* for backward compatibility */
  
  #define NETXEN_FLASH_START            (NETXEN_CRBINIT_START)
@@@ -724,7 -739,7 +724,7 @@@ extern char netxen_nic_driver_name[]
  #endif
  
  /* Number of status descriptors to handle per interrupt */
 -#define MAX_STATUS_HANDLE     (128)
 +#define MAX_STATUS_HANDLE     (64)
  
  /*
   * netxen_skb_frag{} is to contain mapping info for each SG list. This
@@@ -768,6 -783,9 +768,6 @@@ struct netxen_rx_buffer 
        u64 dma;
        u16 ref_handle;
        u16 state;
 -      u32 lro_expected_frags;
 -      u32 lro_current_frags;
 -      u32 lro_length;
  };
  
  /* Board types */
@@@ -782,19 -800,21 +782,19 @@@ struct netxen_hardware_context 
        void __iomem *pci_base0;
        void __iomem *pci_base1;
        void __iomem *pci_base2;
 -      unsigned long first_page_group_end;
 -      unsigned long first_page_group_start;
        void __iomem *db_base;
        unsigned long db_len;
        unsigned long pci_len0;
  
 -      u8 cut_through;
        int qdr_sn_window;
        int ddr_mn_window;
        unsigned long mn_win_crb;
        unsigned long ms_win_crb;
  
 +      u8 cut_through;
        u8 revision_id;
 -      u16 board_type;
 -      struct netxen_board_info boardcfg;
 +      u16 port_type;
 +      int board_type;
        u32 linkup;
        /* Address of cmd ring in Phantom */
        struct cmd_desc_type0 *cmd_desc_head;
        int pci_func;
  };
  
 -#define RCV_RING_LRO  RCV_DESC_LRO
 -
  #define MINIMUM_ETHERNET_FRAME_SIZE   64      /* With FCS */
  #define ETHERNET_FCS_SIZE             4
  
@@@ -828,36 -850,16 +828,36 @@@ struct netxen_adapter_stats 
   * be one Rcv Descriptor for normal packets, one for jumbo and may be others.
   */
  struct nx_host_rds_ring {
 -      u32 flags;
        u32 producer;
 -      dma_addr_t phys_addr;
 -      u32 crb_rcv_producer;   /* reg offset */
 -      struct rcv_desc *desc_head;     /* address of rx ring in Phantom */
 -      u32 max_rx_desc_count;
 +      u32 crb_rcv_producer;
 +      u32 num_desc;
        u32 dma_size;
        u32 skb_size;
 -      struct netxen_rx_buffer *rx_buf_arr;    /* rx buffers for receive   */
 +      u32 flags;
 +      struct rcv_desc *desc_head;
 +      struct netxen_rx_buffer *rx_buf_arr;
        struct list_head free_list;
 +      spinlock_t lock;
 +      dma_addr_t phys_addr;
 +};
 +
 +struct nx_host_sds_ring {
 +      u32 consumer;
 +      u32 crb_sts_consumer;
 +      u32 crb_intr_mask;
 +      u32 num_desc;
 +
 +      struct status_desc *desc_head;
 +      struct netxen_adapter *adapter;
 +      struct napi_struct napi;
 +      struct list_head free_list[NUM_RCV_DESC_RINGS];
 +
 +      u16 clean_tx;
 +      u16 post_rxd;
 +      int irq;
 +
 +      dma_addr_t phys_addr;
 +      char name[IFNAMSIZ+4];
  };
  
  /*
@@@ -872,7 -874,10 +872,7 @@@ struct netxen_recv_context 
        u16 virt_port;
  
        struct nx_host_rds_ring rds_rings[NUM_RCV_DESC_RINGS];
 -      u32 status_rx_consumer;
 -      u32 crb_sts_consumer;   /* reg offset */
 -      dma_addr_t rcv_status_desc_phys_addr;
 -      struct status_desc *rcv_status_desc_head;
 +      struct nx_host_sds_ring sds_rings[NUM_STS_DESC_RINGS];
  };
  
  /* New HW context creation */
@@@ -1198,13 -1203,13 +1198,13 @@@ typedef struct 
  #define NETXEN_IS_MSI_FAMILY(adapter) \
        ((adapter)->flags & (NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED))
  
 -#define MSIX_ENTRIES_PER_ADAPTER      1
 +#define MSIX_ENTRIES_PER_ADAPTER      NUM_STS_DESC_RINGS
  #define NETXEN_MSIX_TBL_SPACE         8192
  #define NETXEN_PCI_REG_MSIX_TBL               0x44
  
  #define NETXEN_DB_MAPSIZE_BYTES       0x1000
  
 -#define NETXEN_NETDEV_WEIGHT 120
 +#define NETXEN_NETDEV_WEIGHT 128
  #define NETXEN_ADAPTER_UP_MAGIC 777
  #define NETXEN_NIC_PEG_TUNE 0
  
@@@ -1219,6 -1224,7 +1219,6 @@@ struct netxen_adapter 
        struct net_device *netdev;
        struct pci_dev *pdev;
        int pci_using_dac;
 -      struct napi_struct napi;
        struct net_device_stats net_stats;
        int mtu;
        int portnum;
        nx_mac_list_t   *mac_list;
  
        struct netxen_legacy_intr_set legacy_intr;
 -      u32     crb_intr_mask;
  
        struct work_struct watchdog_task;
        struct timer_list watchdog_timer;
        u32 crb_win;
        rwlock_t adapter_lock;
  
 -      uint64_t dma_mask;
 -
        u32 cmd_producer;
        __le32 *cmd_consumer;
        u32 last_cmd_consumer;
        u32 crb_addr_cmd_producer;
        u32 crb_addr_cmd_consumer;
 +      spinlock_t tx_clean_lock;
  
 -      u32 max_tx_desc_count;
 -      u32 max_rx_desc_count;
 -      u32 max_jumbo_rx_desc_count;
 -      u32 max_lro_rx_desc_count;
 +      u32 num_txd;
 +      u32 num_rxd;
 +      u32 num_jumbo_rxd;
 +      u32 num_lro_rxd;
  
        int max_rds_rings;
 +      int max_sds_rings;
  
        u32 flags;
        u32 irq;
        u32 temp;
  
        u32 fw_major;
 +      u32 fw_version;
  
 -      u8 msix_supported;
 -      u8 max_possible_rss_rings;
 +      int msix_supported;
        struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER];
  
        struct netxen_adapter_stats stats;
        u16 state;
        u16 link_autoneg;
        int rx_csum;
 -      int status;
  
        struct netxen_cmd_buffer *cmd_buf_arr;  /* Command buffers for xmit */
  
         * Receive instances. These can be either one per port,
         * or one per peg, etc.
         */
 -      struct netxen_recv_context recv_ctx[MAX_RCV_CTX];
 +      struct netxen_recv_context recv_ctx;
  
        int is_up;
        struct netxen_dummy_dma dummy_dma;
@@@ -1390,8 -1398,6 +1390,8 @@@ void netxen_nic_write_w1(struct netxen_
  void netxen_nic_read_w1(struct netxen_adapter *adapter, u32 index, u32 *value);
  
  int netxen_nic_get_board_info(struct netxen_adapter *adapter);
 +void netxen_nic_get_firmware_info(struct netxen_adapter *adapter);
 +int netxen_nic_wol_supported(struct netxen_adapter *adapter);
  
  int netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter,
                ulong off, void *data, int len);
@@@ -1465,16 -1471,15 +1465,16 @@@ void netxen_initialize_adapter_ops(stru
  int netxen_init_firmware(struct netxen_adapter *adapter);
  void netxen_nic_clear_stats(struct netxen_adapter *adapter);
  void netxen_watchdog_task(struct work_struct *work);
 -void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx,
 -                          u32 ringid);
 +void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid,
 +              struct nx_host_rds_ring *rds_ring);
  int netxen_process_cmd_ring(struct netxen_adapter *adapter);
 -u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctx, int max);
 +int netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max);
  void netxen_p2_nic_set_multi(struct net_device *netdev);
  void netxen_p3_nic_set_multi(struct net_device *netdev);
  void netxen_p3_free_mac_list(struct netxen_adapter *adapter);
  int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32);
  int netxen_config_intr_coalesce(struct netxen_adapter *adapter);
 +int netxen_config_rss(struct netxen_adapter *adapter, int enable);
  
  int nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu);
  int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu);
@@@ -1590,7 -1595,6 +1590,6 @@@ dma_watchdog_wakeup(struct netxen_adapt
  }
  
  
- int netxen_is_flash_supported(struct netxen_adapter *adapter);
  int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac);
  int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac);
  extern void netxen_change_ringparam(struct netxen_adapter *adapter);
index b24cfddd6193225ec22baac380234851d4561b78,7fea77088108ddb217ba17bfc086085f8a3d750d..5026811c04ced0a1d1d4effe7dc033c47d083dba
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (C) 2003 - 2006 NetXen, Inc.
 + * Copyright (C) 2003 - 2009 NetXen, Inc.
   * All rights reserved.
   *
   * This program is free software; you can redistribute it and/or
   *
   * Contact Information:
   *    info@netxen.com
 - * NetXen,
 - * 3965 Freedom Circle, Fourth floor,
 - * Santa Clara, CA 95054
 - *
 - *
 - * Source file for NIC routines to access the Phantom hardware
 + * NetXen Inc,
 + * 18922 Forge Drive
 + * Cupertino, CA 95014-0701
   *
   */
  
@@@ -32,7 -35,7 +32,7 @@@
  #include "netxen_nic_hw.h"
  #include "netxen_nic_phan_reg.h"
  
 -
 +#include <linux/firmware.h>
  #include <net/ip.h>
  
  #define MASK(n) ((1ULL<<(n))-1)
@@@ -515,7 -518,7 +515,7 @@@ netxen_send_cmd_descs(struct netxen_ada
                        &cmd_desc_arr[i], sizeof(struct cmd_desc_type0));
  
                producer = get_next_index(producer,
 -                              adapter->max_tx_desc_count);
 +                              adapter->num_txd);
                i++;
  
        } while (i != nr_elements);
@@@ -670,53 -673,6 +670,53 @@@ int netxen_config_intr_coalesce(struct 
        return rv;
  }
  
 +#define RSS_HASHTYPE_IP_TCP   0x3
 +
 +int netxen_config_rss(struct netxen_adapter *adapter, int enable)
 +{
 +      nx_nic_req_t req;
 +      u64 word;
 +      int i, rv;
 +
 +      u64 key[] = { 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
 +                      0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
 +                      0x255b0ec26d5a56daULL };
 +
 +
 +      memset(&req, 0, sizeof(nx_nic_req_t));
 +      req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23);
 +
 +      word = NX_NIC_H2C_OPCODE_CONFIG_RSS | ((u64)adapter->portnum << 16);
 +      req.req_hdr = cpu_to_le64(word);
 +
 +      /*
 +       * RSS request:
 +       * bits 3-0: hash_method
 +       *      5-4: hash_type_ipv4
 +       *      7-6: hash_type_ipv6
 +       *        8: enable
 +       *        9: use indirection table
 +       *    47-10: reserved
 +       *    63-48: indirection table mask
 +       */
 +      word =  ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
 +              ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
 +              ((u64)(enable & 0x1) << 8) |
 +              ((0x7ULL) << 48);
 +      req.words[0] = cpu_to_le64(word);
 +      for (i = 0; i < 5; i++)
 +              req.words[i+1] = cpu_to_le64(key[i]);
 +
 +
 +      rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
 +      if (rv != 0) {
 +              printk(KERN_ERR "%s: could not configure RSS\n",
 +                              adapter->netdev->name);
 +      }
 +
 +      return rv;
 +}
 +
  /*
   * netxen_nic_change_mtu - Change the Maximum Transfer Unit
   * @returns 0 on success, negative on failure
@@@ -750,33 -706,12 +750,11 @@@ int netxen_nic_change_mtu(struct net_de
        return rc;
  }
  
- int netxen_is_flash_supported(struct netxen_adapter *adapter)
- {
-       const int locs[] = { 0, 0x4, 0x100, 0x4000, 0x4128 };
-       int addr, val01, val02, i, j;
-       /* if the flash size less than 4Mb, make huge war cry and die */
-       for (j = 1; j < 4; j++) {
-               addr = j * NETXEN_NIC_WINDOW_MARGIN;
-               for (i = 0; i < ARRAY_SIZE(locs); i++) {
-                       if (netxen_rom_fast_read(adapter, locs[i], &val01) == 0
-                           && netxen_rom_fast_read(adapter, (addr + locs[i]),
-                                                   &val02) == 0) {
-                               if (val01 == val02)
-                                       return -1;
-                       } else
-                               return -1;
-               }
-       }
-       return 0;
- }
  static int netxen_get_flash_block(struct netxen_adapter *adapter, int base,
                                  int size, __le32 * buf)
  {
 -      int i, addr;
 +      int i, v, addr;
        __le32 *ptr32;
 -      u32 v;
  
        addr = base;
        ptr32 = buf;
@@@ -979,12 -914,13 +957,12 @@@ netxen_nic_pci_set_crbwindow_2M(struct 
        u32 win_read;
  
        adapter->crb_win = CRB_HI(*off);
 -      writel(adapter->crb_win, (void *)(CRB_WINDOW_2M +
 -              adapter->ahw.pci_base0));
 +      writel(adapter->crb_win, (adapter->ahw.pci_base0 + CRB_WINDOW_2M));
        /*
         * Read back value to make sure write has gone through before trying
         * to use it.
         */
 -      win_read = readl((void *)(CRB_WINDOW_2M + adapter->ahw.pci_base0));
 +      win_read = readl(adapter->ahw.pci_base0 + CRB_WINDOW_2M);
        if (win_read != adapter->crb_win) {
                printk(KERN_ERR "%s: Written crbwin (0x%x) != "
                                "Read crbwin (0x%x), off=0x%lx\n",
                (ulong)adapter->ahw.pci_base0;
  }
  
 -int netxen_load_firmware(struct netxen_adapter *adapter)
 +static int
 +netxen_do_load_firmware(struct netxen_adapter *adapter, const char *fwname,
 +              const struct firmware *fw)
  {
 -      int i;
 -      u32 data, size = 0;
 -      u32 flashaddr = NETXEN_BOOTLD_START;
 +      u64 *ptr64;
 +      u32 i, flashaddr, size;
 +      struct pci_dev *pdev = adapter->pdev;
  
 -      size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START)/4;
 +      if (fw)
 +              dev_info(&pdev->dev, "loading firmware from file %s\n", fwname);
 +      else
 +              dev_info(&pdev->dev, "loading firmware from flash\n");
  
        if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
                adapter->pci_write_normalize(adapter,
                                NETXEN_ROMUSB_GLB_CAS_RST, 1);
  
 -      for (i = 0; i < size; i++) {
 -              if (netxen_rom_fast_read(adapter, flashaddr, (int *)&data) != 0)
 -                      return -EIO;
 +      if (fw) {
 +              __le64 data;
  
 -              adapter->pci_mem_write(adapter, flashaddr, &data, 4);
 -              flashaddr += 4;
 +              size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 8;
 +
 +              ptr64 = (u64 *)&fw->data[NETXEN_BOOTLD_START];
 +              flashaddr = NETXEN_BOOTLD_START;
 +
 +              for (i = 0; i < size; i++) {
 +                      data = cpu_to_le64(ptr64[i]);
 +                      adapter->pci_mem_write(adapter, flashaddr, &data, 8);
 +                      flashaddr += 8;
 +              }
 +
 +              size = *(u32 *)&fw->data[NX_FW_SIZE_OFFSET];
 +              size = (__force u32)cpu_to_le32(size) / 8;
 +
 +              ptr64 = (u64 *)&fw->data[NETXEN_IMAGE_START];
 +              flashaddr = NETXEN_IMAGE_START;
 +
 +              for (i = 0; i < size; i++) {
 +                      data = cpu_to_le64(ptr64[i]);
 +
 +                      if (adapter->pci_mem_write(adapter,
 +                                              flashaddr, &data, 8))
 +                              return -EIO;
 +
 +                      flashaddr += 8;
 +              }
 +      } else {
 +              u32 data;
 +
 +              size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 4;
 +              flashaddr = NETXEN_BOOTLD_START;
 +
 +              for (i = 0; i < size; i++) {
 +                      if (netxen_rom_fast_read(adapter,
 +                                      flashaddr, (int *)&data) != 0)
 +                              return -EIO;
 +
 +                      if (adapter->pci_mem_write(adapter,
 +                                              flashaddr, &data, 4))
 +                              return -EIO;
 +
 +                      flashaddr += 4;
 +              }
        }
        msleep(1);
  
        return 0;
  }
  
 +static int
 +netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname,
 +              const struct firmware *fw)
 +{
 +      __le32 val;
 +      u32 major, minor, build, ver, min_ver, bios;
 +      struct pci_dev *pdev = adapter->pdev;
 +
 +      if (fw->size < NX_FW_MIN_SIZE)
 +              return -EINVAL;
 +
 +      val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]);
 +      if ((__force u32)val != NETXEN_BDINFO_MAGIC)
 +              return -EINVAL;
 +
 +      val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]);
 +      major = (__force u32)val & 0xff;
 +      minor = ((__force u32)val >> 8) & 0xff;
 +      build = (__force u32)val >> 16;
 +
 +      if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
 +              min_ver = NETXEN_VERSION_CODE(4, 0, 216);
 +      else
 +              min_ver = NETXEN_VERSION_CODE(3, 4, 216);
 +
 +      ver = NETXEN_VERSION_CODE(major, minor, build);
 +
 +      if ((major > _NETXEN_NIC_LINUX_MAJOR) || (ver < min_ver)) {
 +              dev_err(&pdev->dev,
 +                              "%s: firmware version %d.%d.%d unsupported\n",
 +                              fwname, major, minor, build);
 +              return -EINVAL;
 +      }
 +
 +      val = cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]);
 +      netxen_rom_fast_read(adapter, NX_BIOS_VERSION_OFFSET, (int *)&bios);
 +      if ((__force u32)val != bios) {
 +              dev_err(&pdev->dev, "%s: firmware bios is incompatible\n",
 +                              fwname);
 +              return -EINVAL;
 +      }
 +
 +      /* check if flashed firmware is newer */
 +      if (netxen_rom_fast_read(adapter,
 +                      NX_FW_VERSION_OFFSET, (int *)&val))
 +              return -EIO;
 +      major = (__force u32)val & 0xff;
 +      minor = ((__force u32)val >> 8) & 0xff;
 +      build = (__force u32)val >> 16;
 +      if (NETXEN_VERSION_CODE(major, minor, build) > ver)
 +              return -EINVAL;
 +
 +      netxen_nic_reg_write(adapter, NETXEN_CAM_RAM(0x1fc),
 +                      NETXEN_BDINFO_MAGIC);
 +      return 0;
 +}
 +
 +static char *fw_name[] = { "nxromimg.bin", "nx3fwct.bin", "nx3fwmn.bin" };
 +
 +int netxen_load_firmware(struct netxen_adapter *adapter)
 +{
 +      u32 capability, flashed_ver;
 +      const struct firmware *fw;
 +      int fw_type;
 +      struct pci_dev *pdev = adapter->pdev;
 +      int rc = 0;
 +
 +      if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
 +              fw_type = NX_P2_MN_ROMIMAGE;
 +              goto request_fw;
 +      } else {
 +              fw_type = NX_P3_CT_ROMIMAGE;
 +              goto request_fw;
 +      }
 +
 +request_mn:
 +      capability = 0;
 +
 +      netxen_rom_fast_read(adapter,
 +                      NX_FW_VERSION_OFFSET, (int *)&flashed_ver);
 +      if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) {
 +              adapter->hw_read_wx(adapter,
 +                              NX_PEG_TUNE_CAPABILITY, &capability, 4);
 +              if (capability & NX_PEG_TUNE_MN_PRESENT) {
 +                      fw_type = NX_P3_MN_ROMIMAGE;
 +                      goto request_fw;
 +              }
 +      }
 +
 +request_fw:
 +      rc = request_firmware(&fw, fw_name[fw_type], &pdev->dev);
 +      if (rc != 0) {
 +              if (fw_type == NX_P3_CT_ROMIMAGE) {
 +                      msleep(1);
 +                      goto request_mn;
 +              }
 +
 +              fw = NULL;
 +              goto load_fw;
 +      }
 +
 +      rc = netxen_validate_firmware(adapter, fw_name[fw_type], fw);
 +      if (rc != 0) {
 +              release_firmware(fw);
 +
 +              if (fw_type == NX_P3_CT_ROMIMAGE) {
 +                      msleep(1);
 +                      goto request_mn;
 +              }
 +
 +              fw = NULL;
 +      }
 +
 +load_fw:
 +      rc = netxen_do_load_firmware(adapter, fw_name[fw_type], fw);
 +
 +      if (fw)
 +              release_firmware(fw);
 +      return rc;
 +}
 +
  int
  netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter,
                ulong off, void *data, int len)
  {
        void __iomem *addr;
  
 +      BUG_ON(len != 4);
 +
        if (ADDR_IN_WINDOW1(off)) {
                addr = NETXEN_CRB_NORMALIZE(adapter, off);
        } else {                /* Window 0 */
                netxen_nic_pci_change_crbwindow_128M(adapter, 0);
        }
  
 -      DPRINTK(INFO, "writing to base %lx offset %llx addr %p"
 -              " data %llx len %d\n",
 -              pci_base(adapter, off), off, addr,
 -              *(unsigned long long *)data, len);
        if (!addr) {
                netxen_nic_pci_change_crbwindow_128M(adapter, 1);
                return 1;
        }
  
 -      switch (len) {
 -      case 1:
 -              writeb(*(u8 *) data, addr);
 -              break;
 -      case 2:
 -              writew(*(u16 *) data, addr);
 -              break;
 -      case 4:
 -              writel(*(u32 *) data, addr);
 -              break;
 -      case 8:
 -              writeq(*(u64 *) data, addr);
 -              break;
 -      default:
 -              DPRINTK(INFO,
 -                      "writing data %lx to offset %llx, num words=%d\n",
 -                      *(unsigned long *)data, off, (len >> 3));
 +      writel(*(u32 *) data, addr);
  
 -              netxen_nic_hw_block_write64((u64 __iomem *) data, addr,
 -                                          (len >> 3));
 -              break;
 -      }
        if (!ADDR_IN_WINDOW1(off))
                netxen_nic_pci_change_crbwindow_128M(adapter, 1);
  
@@@ -1228,8 -1020,6 +1206,8 @@@ netxen_nic_hw_read_wx_128M(struct netxe
  {
        void __iomem *addr;
  
 +      BUG_ON(len != 4);
 +
        if (ADDR_IN_WINDOW1(off)) {     /* Window 1 */
                addr = NETXEN_CRB_NORMALIZE(adapter, off);
        } else {                /* Window 0 */
                netxen_nic_pci_change_crbwindow_128M(adapter, 0);
        }
  
 -      DPRINTK(INFO, "reading from base %lx offset %llx addr %p\n",
 -              pci_base(adapter, off), off, addr);
        if (!addr) {
                netxen_nic_pci_change_crbwindow_128M(adapter, 1);
                return 1;
        }
 -      switch (len) {
 -      case 1:
 -              *(u8 *) data = readb(addr);
 -              break;
 -      case 2:
 -              *(u16 *) data = readw(addr);
 -              break;
 -      case 4:
 -              *(u32 *) data = readl(addr);
 -              break;
 -      case 8:
 -              *(u64 *) data = readq(addr);
 -              break;
 -      default:
 -              netxen_nic_hw_block_read64((u64 __iomem *) data, addr,
 -                                         (len >> 3));
 -              break;
 -      }
 -      DPRINTK(INFO, "read %lx\n", *(unsigned long *)data);
 +
 +      *(u32 *)data = readl(addr);
  
        if (!ADDR_IN_WINDOW1(off))
                netxen_nic_pci_change_crbwindow_128M(adapter, 1);
@@@ -1257,8 -1066,6 +1235,8 @@@ netxen_nic_hw_write_wx_2M(struct netxen
        unsigned long flags = 0;
        int rv;
  
 +      BUG_ON(len != 4);
 +
        rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off, len);
  
        if (rv == -1) {
                write_lock_irqsave(&adapter->adapter_lock, flags);
                crb_win_lock(adapter);
                netxen_nic_pci_set_crbwindow_2M(adapter, &off);
 -      }
 -
 -      DPRINTK(1, INFO, "write data %lx to offset %llx, len=%d\n",
 -                      *(unsigned long *)data, off, len);
 -
 -      switch (len) {
 -      case 1:
 -              writeb(*(uint8_t *)data, (void *)off);
 -              break;
 -      case 2:
 -              writew(*(uint16_t *)data, (void *)off);
 -              break;
 -      case 4:
 -              writel(*(uint32_t *)data, (void *)off);
 -              break;
 -      case 8:
 -              writeq(*(uint64_t *)data, (void *)off);
 -              break;
 -      default:
 -              DPRINTK(1, INFO,
 -                      "writing data %lx to offset %llx, num words=%d\n",
 -                      *(unsigned long *)data, off, (len>>3));
 -              break;
 -      }
 -      if (rv == 1) {
 +              writel(*(uint32_t *)data, (void __iomem *)off);
                crb_win_unlock(adapter);
                write_unlock_irqrestore(&adapter->adapter_lock, flags);
 -      }
 +      } else
 +              writel(*(uint32_t *)data, (void __iomem *)off);
 +
  
        return 0;
  }
@@@ -1289,8 -1118,6 +1267,8 @@@ netxen_nic_hw_read_wx_2M(struct netxen_
        unsigned long flags = 0;
        int rv;
  
 +      BUG_ON(len != 4);
 +
        rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off, len);
  
        if (rv == -1) {
                write_lock_irqsave(&adapter->adapter_lock, flags);
                crb_win_lock(adapter);
                netxen_nic_pci_set_crbwindow_2M(adapter, &off);
 -      }
 -
 -      DPRINTK(1, INFO, "read from offset %lx, len=%d\n", off, len);
 -
 -      switch (len) {
 -      case 1:
 -              *(uint8_t *)data = readb((void *)off);
 -              break;
 -      case 2:
 -              *(uint16_t *)data = readw((void *)off);
 -              break;
 -      case 4:
 -              *(uint32_t *)data = readl((void *)off);
 -              break;
 -      case 8:
 -              *(uint64_t *)data = readq((void *)off);
 -              break;
 -      default:
 -              break;
 -      }
 -
 -      DPRINTK(1, INFO, "read %lx\n", *(unsigned long *)data);
 -
 -      if (rv == 1) {
 +              *(uint32_t *)data = readl((void __iomem *)off);
                crb_win_unlock(adapter);
                write_unlock_irqrestore(&adapter->adapter_lock, flags);
 -      }
 +      } else
 +              *(uint32_t *)data = readl((void __iomem *)off);
  
        return 0;
  }
@@@ -1570,9 -1419,10 +1548,9 @@@ static int netxen_nic_pci_mem_read_dire
                        u64 off, void *data, int size)
  {
        unsigned long flags;
 -      void *addr;
 +      void __iomem *addr, *mem_ptr = NULL;
        int ret = 0;
        u64 start;
 -      uint8_t *mem_ptr = NULL;
        unsigned long mem_base;
        unsigned long mem_page;
  
                return -1;
        }
  
 -      addr = (void *)(pci_base_offset(adapter, start));
 +      addr = pci_base_offset(adapter, start);
        if (!addr) {
                write_unlock_irqrestore(&adapter->adapter_lock, flags);
                mem_base = pci_resource_start(adapter->pdev, 0);
                break;
        }
        write_unlock_irqrestore(&adapter->adapter_lock, flags);
 -      DPRINTK(1, INFO, "read %llx\n", *(unsigned long long *)data);
  
        if (mem_ptr)
                iounmap(mem_ptr);
@@@ -1642,9 -1493,10 +1620,9 @@@ netxen_nic_pci_mem_write_direct(struct 
                void *data, int size)
  {
        unsigned long flags;
 -      void *addr;
 +      void __iomem *addr, *mem_ptr = NULL;
        int ret = 0;
        u64 start;
 -      uint8_t *mem_ptr = NULL;
        unsigned long mem_base;
        unsigned long mem_page;
  
                return -1;
        }
  
 -      addr = (void *)(pci_base_offset(adapter, start));
 +      addr = pci_base_offset(adapter, start);
        if (!addr) {
                write_unlock_irqrestore(&adapter->adapter_lock, flags);
                mem_base = pci_resource_start(adapter->pdev, 0);
                break;
        }
        write_unlock_irqrestore(&adapter->adapter_lock, flags);
 -      DPRINTK(1, INFO, "writing data %llx to offset %llx\n",
 -                      *(unsigned long long *)data, start);
        if (mem_ptr)
                iounmap(mem_ptr);
        return ret;
  netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter,
                u64 off, void *data, int size)
  {
 -      unsigned long   flags, mem_crb;
 +      unsigned long   flags;
        int          i, j, ret = 0, loop, sz[2], off0;
        uint32_t      temp;
        uint64_t      off8, tmpw, word[2] = {0, 0};
 +      void __iomem *mem_crb;
  
        /*
         * If not MN, go check for MS or invalid.
        sz[0] = (size < (8 - off0)) ? size : (8 - off0);
        sz[1] = size - sz[0];
        loop = ((off0 + size - 1) >> 3) + 1;
 -      mem_crb = (unsigned long)pci_base_offset(adapter, NETXEN_CRB_DDR_NET);
 +      mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET);
  
        if ((size != 8) || (off0 != 0))  {
                for (i = 0; i < loop; i++) {
  
        for (i = 0; i < loop; i++) {
                writel((uint32_t)(off8 + (i << 3)),
 -                      (void *)(mem_crb+MIU_TEST_AGT_ADDR_LO));
 +                      (mem_crb+MIU_TEST_AGT_ADDR_LO));
                writel(0,
 -                      (void *)(mem_crb+MIU_TEST_AGT_ADDR_HI));
 +                      (mem_crb+MIU_TEST_AGT_ADDR_HI));
                writel(word[i] & 0xffffffff,
 -                      (void *)(mem_crb+MIU_TEST_AGT_WRDATA_LO));
 +                      (mem_crb+MIU_TEST_AGT_WRDATA_LO));
                writel((word[i] >> 32) & 0xffffffff,
 -                      (void *)(mem_crb+MIU_TEST_AGT_WRDATA_HI));
 +                      (mem_crb+MIU_TEST_AGT_WRDATA_HI));
                writel(MIU_TA_CTL_ENABLE|MIU_TA_CTL_WRITE,
 -                      (void *)(mem_crb+MIU_TEST_AGT_CTRL));
 +                      (mem_crb+MIU_TEST_AGT_CTRL));
                writel(MIU_TA_CTL_START|MIU_TA_CTL_ENABLE|MIU_TA_CTL_WRITE,
 -                      (void *)(mem_crb+MIU_TEST_AGT_CTRL));
 +                      (mem_crb+MIU_TEST_AGT_CTRL));
  
                for (j = 0; j < MAX_CTL_CHECK; j++) {
                        temp = readl(
 -                           (void *)(mem_crb+MIU_TEST_AGT_CTRL));
 +                           (mem_crb+MIU_TEST_AGT_CTRL));
                        if ((temp & MIU_TA_CTL_BUSY) == 0)
                                break;
                }
  
                if (j >= MAX_CTL_CHECK) {
 -                      printk("%s: %s Fail to write through agent\n",
 -                                      __func__, netxen_nic_driver_name);
 +                      if (printk_ratelimit())
 +                              dev_err(&adapter->pdev->dev,
 +                                      "failed to write through agent\n");
                        ret = -1;
                        break;
                }
  netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter,
                u64 off, void *data, int size)
  {
 -      unsigned long   flags, mem_crb;
 +      unsigned long   flags;
        int          i, j = 0, k, start, end, loop, sz[2], off0[2];
        uint32_t      temp;
        uint64_t      off8, val, word[2] = {0, 0};
 +      void __iomem *mem_crb;
  
  
        /*
        sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]);
        sz[1] = size - sz[0];
        loop = ((off0[0] + size - 1) >> 3) + 1;
 -      mem_crb = (unsigned long)pci_base_offset(adapter, NETXEN_CRB_DDR_NET);
 +      mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET);
  
        write_lock_irqsave(&adapter->adapter_lock, flags);
        netxen_nic_pci_change_crbwindow_128M(adapter, 0);
  
        for (i = 0; i < loop; i++) {
                writel((uint32_t)(off8 + (i << 3)),
 -                      (void *)(mem_crb+MIU_TEST_AGT_ADDR_LO));
 +                      (mem_crb+MIU_TEST_AGT_ADDR_LO));
                writel(0,
 -                      (void *)(mem_crb+MIU_TEST_AGT_ADDR_HI));
 +                      (mem_crb+MIU_TEST_AGT_ADDR_HI));
                writel(MIU_TA_CTL_ENABLE,
 -                      (void *)(mem_crb+MIU_TEST_AGT_CTRL));
 +                      (mem_crb+MIU_TEST_AGT_CTRL));
                writel(MIU_TA_CTL_START|MIU_TA_CTL_ENABLE,
 -                      (void *)(mem_crb+MIU_TEST_AGT_CTRL));
 +                      (mem_crb+MIU_TEST_AGT_CTRL));
  
                for (j = 0; j < MAX_CTL_CHECK; j++) {
                        temp = readl(
 -                            (void *)(mem_crb+MIU_TEST_AGT_CTRL));
 +                            (mem_crb+MIU_TEST_AGT_CTRL));
                        if ((temp & MIU_TA_CTL_BUSY) == 0)
                                break;
                }
  
                if (j >= MAX_CTL_CHECK) {
 -                      printk(KERN_ERR "%s: %s Fail to read through agent\n",
 -                                      __func__, netxen_nic_driver_name);
 +                      if (printk_ratelimit())
 +                              dev_err(&adapter->pdev->dev,
 +                                      "failed to read through agent\n");
                        break;
                }
  
                end   = (off0[i] + sz[i] - 1) >> 2;
                for (k = start; k <= end; k++) {
                        word[i] |= ((uint64_t) readl(
 -                                  (void *)(mem_crb +
 +                                  (mem_crb +
                                    MIU_TEST_AGT_RDDATA(k))) << (32*k));
                }
        }
                *(uint64_t *)data = val;
                break;
        }
 -      DPRINTK(1, INFO, "read %llx\n", *(unsigned long long *)data);
        return 0;
  }
  
@@@ -1984,9 -1835,8 +1962,9 @@@ netxen_nic_pci_mem_write_2M(struct netx
                }
  
                if (j >= MAX_CTL_CHECK) {
 -                      printk(KERN_ERR "%s: Fail to write through agent\n",
 -                                      netxen_nic_driver_name);
 +                      if (printk_ratelimit())
 +                              dev_err(&adapter->pdev->dev,
 +                                      "failed to write through agent\n");
                        ret = -1;
                        break;
                }
@@@ -2055,9 -1905,8 +2033,9 @@@ netxen_nic_pci_mem_read_2M(struct netxe
                }
  
                if (j >= MAX_CTL_CHECK) {
 -                      printk(KERN_ERR "%s: Fail to read through agent\n",
 -                                      netxen_nic_driver_name);
 +                      if (printk_ratelimit())
 +                              dev_err(&adapter->pdev->dev,
 +                                      "failed to read through agent\n");
                        break;
                }
  
                *(uint64_t *)data = val;
                break;
        }
 -      DPRINTK(1, INFO, "read %llx\n", *(unsigned long long *)data);
        return 0;
  }
  
@@@ -2133,46 -1983,62 +2111,46 @@@ u32 netxen_nic_pci_read_normalize_2M(st
        return temp;
  }
  
 -#if 0
 -int
 -netxen_nic_erase_pxe(struct netxen_adapter *adapter)
 -{
 -      if (netxen_rom_fast_write(adapter, NETXEN_PXE_START, 0) == -1) {
 -              printk(KERN_ERR "%s: erase pxe failed\n",
 -                      netxen_nic_driver_name);
 -              return -1;
 -      }
 -      return 0;
 -}
 -#endif  /*  0  */
 -
  int netxen_nic_get_board_info(struct netxen_adapter *adapter)
  {
 -      int rv = 0;
 -      int addr = NETXEN_BRDCFG_START;
 -      struct netxen_board_info *boardinfo;
 -      int index;
 -      u32 *ptr32;
 -
 -      boardinfo = &adapter->ahw.boardcfg;
 -      ptr32 = (u32 *) boardinfo;
 -
 -      for (index = 0; index < sizeof(struct netxen_board_info) / sizeof(u32);
 -           index++) {
 -              if (netxen_rom_fast_read(adapter, addr, ptr32) == -1) {
 -                      return -EIO;
 -              }
 -              ptr32++;
 -              addr += sizeof(u32);
 -      }
 -      if (boardinfo->magic != NETXEN_BDINFO_MAGIC) {
 -              printk("%s: ERROR reading %s board config."
 -                     " Read %x, expected %x\n", netxen_nic_driver_name,
 -                     netxen_nic_driver_name,
 -                     boardinfo->magic, NETXEN_BDINFO_MAGIC);
 -              rv = -1;
 -      }
 -      if (boardinfo->header_version != NETXEN_BDINFO_VERSION) {
 -              printk("%s: Unknown board config version."
 -                     " Read %x, expected %x\n", netxen_nic_driver_name,
 -                     boardinfo->header_version, NETXEN_BDINFO_VERSION);
 -              rv = -1;
 +      int offset, board_type, magic, header_version;
 +      struct pci_dev *pdev = adapter->pdev;
 +
 +      offset = NETXEN_BRDCFG_START +
 +              offsetof(struct netxen_board_info, magic);
 +      if (netxen_rom_fast_read(adapter, offset, &magic))
 +              return -EIO;
 +
 +      offset = NETXEN_BRDCFG_START +
 +              offsetof(struct netxen_board_info, header_version);
 +      if (netxen_rom_fast_read(adapter, offset, &header_version))
 +              return -EIO;
 +
 +      if (magic != NETXEN_BDINFO_MAGIC ||
 +                      header_version != NETXEN_BDINFO_VERSION) {
 +              dev_err(&pdev->dev,
 +                      "invalid board config, magic=%08x, version=%08x\n",
 +                      magic, header_version);
 +              return -EIO;
        }
  
 -      if (boardinfo->board_type == NETXEN_BRDTYPE_P3_4_GB_MM) {
 +      offset = NETXEN_BRDCFG_START +
 +              offsetof(struct netxen_board_info, board_type);
 +      if (netxen_rom_fast_read(adapter, offset, &board_type))
 +              return -EIO;
 +
 +      adapter->ahw.board_type = board_type;
 +
 +      if (board_type == NETXEN_BRDTYPE_P3_4_GB_MM) {
                u32 gpio = netxen_nic_reg_read(adapter,
                                NETXEN_ROMUSB_GLB_PAD_GPIO_I);
                if ((gpio & 0x8000) == 0)
 -                      boardinfo->board_type = NETXEN_BRDTYPE_P3_10G_TP;
 +                      board_type = NETXEN_BRDTYPE_P3_10G_TP;
        }
  
 -      switch ((netxen_brdtype_t) boardinfo->board_type) {
 +      switch ((netxen_brdtype_t)board_type) {
        case NETXEN_BRDTYPE_P2_SB35_4G:
 -              adapter->ahw.board_type = NETXEN_NIC_GBE;
 +              adapter->ahw.port_type = NETXEN_NIC_GBE;
                break;
        case NETXEN_BRDTYPE_P2_SB31_10G:
        case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ:
        case NETXEN_BRDTYPE_P3_10G_SFP_QT:
        case NETXEN_BRDTYPE_P3_10G_XFP:
        case NETXEN_BRDTYPE_P3_10000_BASE_T:
 -              adapter->ahw.board_type = NETXEN_NIC_XGBE;
 +              adapter->ahw.port_type = NETXEN_NIC_XGBE;
                break;
        case NETXEN_BRDTYPE_P1_BD:
        case NETXEN_BRDTYPE_P1_SB:
        case NETXEN_BRDTYPE_P3_REF_QG:
        case NETXEN_BRDTYPE_P3_4_GB:
        case NETXEN_BRDTYPE_P3_4_GB_MM:
 -              adapter->ahw.board_type = NETXEN_NIC_GBE;
 +              adapter->ahw.port_type = NETXEN_NIC_GBE;
                break;
        case NETXEN_BRDTYPE_P3_10G_TP:
 -              adapter->ahw.board_type = (adapter->portnum < 2) ?
 +              adapter->ahw.port_type = (adapter->portnum < 2) ?
                        NETXEN_NIC_XGBE : NETXEN_NIC_GBE;
                break;
        default:
 -              printk("%s: Unknown(%x)\n", netxen_nic_driver_name,
 -                     boardinfo->board_type);
 -              rv = -ENODEV;
 +              dev_err(&pdev->dev, "unknown board type %x\n", board_type);
 +              adapter->ahw.port_type = NETXEN_NIC_XGBE;
                break;
        }
  
 -      return rv;
 +      return 0;
  }
  
  /* NIU access sections */
@@@ -2255,7 -2122,7 +2233,7 @@@ void netxen_nic_set_link_parameters(str
                return;
        }
  
 -      if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
 +      if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
                adapter->hw_read_wx(adapter,
                                NETXEN_PORT_MODE_ADDR, &port_mode, 4);
                if (port_mode == NETXEN_PORT_MODE_802_3_AP) {
        }
  }
  
 -void netxen_nic_flash_print(struct netxen_adapter *adapter)
 +void netxen_nic_get_firmware_info(struct netxen_adapter *adapter)
  {
 -      u32 fw_major = 0;
 -      u32 fw_minor = 0;
 -      u32 fw_build = 0;
 +      u32 fw_major, fw_minor, fw_build;
        char brd_name[NETXEN_MAX_SHORT_NAME];
        char serial_num[32];
 -      int i, addr;
 -      __le32 *ptr32;
 -
 -      struct netxen_board_info *board_info = &(adapter->ahw.boardcfg);
 +      int i, addr, val;
 +      int *ptr32;
 +      struct pci_dev *pdev = adapter->pdev;
  
        adapter->driver_mismatch = 0;
  
 -      ptr32 = (u32 *)&serial_num;
 +      ptr32 = (int *)&serial_num;
        addr = NETXEN_USER_START +
               offsetof(struct netxen_new_user_info, serial_num);
        for (i = 0; i < 8; i++) {
 -              if (netxen_rom_fast_read(adapter, addr, ptr32) == -1) {
 -                      printk("%s: ERROR reading %s board userarea.\n",
 -                             netxen_nic_driver_name,
 -                             netxen_nic_driver_name);
 +              if (netxen_rom_fast_read(adapter, addr, &val) == -1) {
 +                      dev_err(&pdev->dev, "error reading board info\n");
                        adapter->driver_mismatch = 1;
                        return;
                }
 -              ptr32++;
 +              ptr32[i] = cpu_to_le32(val);
                addr += sizeof(u32);
        }
  
        adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_SUB, &fw_build, 4);
  
        adapter->fw_major = fw_major;
 +      adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build);
  
        if (adapter->portnum == 0) {
 -              get_brd_name_by_type(board_info->board_type, brd_name);
 +              get_brd_name_by_type(adapter->ahw.board_type, brd_name);
  
                printk(KERN_INFO "NetXen %s Board S/N %s  Chip rev 0x%x\n",
                                brd_name, serial_num, adapter->ahw.revision_id);
 -              printk(KERN_INFO "NetXen Firmware version %d.%d.%d\n",
 -                              fw_major, fw_minor, fw_build);
        }
  
 -      if (NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build) <
 -                      NETXEN_VERSION_CODE(3, 4, 216)) {
 +      if (adapter->fw_version < NETXEN_VERSION_CODE(3, 4, 216)) {
                adapter->driver_mismatch = 1;
 -              printk(KERN_ERR "%s: firmware version %d.%d.%d unsupported\n",
 -                              netxen_nic_driver_name,
 +              dev_warn(&pdev->dev, "firmware version %d.%d.%d unsupported\n",
                                fw_major, fw_minor, fw_build);
                return;
        }
 +
 +      dev_info(&pdev->dev, "firmware version %d.%d.%d\n",
 +                      fw_major, fw_minor, fw_build);
 +
 +      if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
 +              adapter->hw_read_wx(adapter,
 +                              NETXEN_MIU_MN_CONTROL, &i, 4);
 +              adapter->ahw.cut_through = (i & 0x4) ? 1 : 0;
 +              dev_info(&pdev->dev, "firmware running in %s mode\n",
 +              adapter->ahw.cut_through ? "cut-through" : "legacy");
 +      }
  }
  
 +int
 +netxen_nic_wol_supported(struct netxen_adapter *adapter)
 +{
 +      u32 wol_cfg;
 +
 +      if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
 +              return 0;
 +
 +      wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG_NV);
 +      if (wol_cfg & (1UL << adapter->portnum)) {
 +              wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG);
 +              if (wol_cfg & (1 << adapter->portnum))
 +                      return 1;
 +      }
 +
 +      return 0;
 +}
index 1fb9bcf504e7f7738d73e3340fc14190fb3567c9,c172b6e24a9644f35047f3c6c0ba7f742a335dad..1af47257ba821d9a06c7e37d1a2b77425d01327e
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (C) 2003 - 2006 NetXen, Inc.
 + * Copyright (C) 2003 - 2009 NetXen, Inc.
   * All rights reserved.
   *
   * This program is free software; you can redistribute it and/or
   *
   * Contact Information:
   *    info@netxen.com
 - * NetXen,
 - * 3965 Freedom Circle, Fourth floor,
 - * Santa Clara, CA 95054
 - *
 - *
 - *  Main source file for NetXen NIC Driver on Linux
 + * NetXen Inc,
 + * 18922 Forge Drive
 + * Cupertino, CA 95014-0701
   *
   */
  
@@@ -94,6 -97,20 +94,6 @@@ static struct pci_device_id netxen_pci_
  
  MODULE_DEVICE_TABLE(pci, netxen_pci_tbl);
  
 -/*
 - * In netxen_nic_down(), we must wait for any pending callback requests into
 - * netxen_watchdog_task() to complete; eg otherwise the watchdog_timer could be
 - * reenabled right after it is deleted in netxen_nic_down().
 - * FLUSH_SCHEDULED_WORK()  does this synchronization.
 - *
 - * Normally, schedule_work()/flush_scheduled_work() could have worked, but
 - * netxen_nic_close() is invoked with kernel rtnl lock held. netif_carrier_off()
 - * call in netxen_nic_close() triggers a schedule_work(&linkwatch_work), and a
 - * subsequent call to flush_scheduled_work() in netxen_nic_down() would cause
 - * linkwatch_event() to be executed which also attempts to acquire the rtnl
 - * lock thus causing a deadlock.
 - */
 -
  static struct workqueue_struct *netxen_workq;
  #define SCHEDULE_WORK(tp)     queue_work(netxen_workq, tp)
  #define FLUSH_SCHEDULED_WORK()        flush_workqueue(netxen_workq)
@@@ -135,148 -152,130 +135,148 @@@ static uint32_t msi_tgt_status[8] = 
  
  static struct netxen_legacy_intr_set legacy_intr[] = NX_LEGACY_INTR_CONFIG;
  
 -static inline void netxen_nic_disable_int(struct netxen_adapter *adapter)
 +static inline void netxen_nic_disable_int(struct nx_host_sds_ring *sds_ring)
  {
 -      adapter->pci_write_normalize(adapter, adapter->crb_intr_mask, 0);
 +      struct netxen_adapter *adapter = sds_ring->adapter;
 +
 +      adapter->pci_write_normalize(adapter, sds_ring->crb_intr_mask, 0);
  }
  
 -static inline void netxen_nic_enable_int(struct netxen_adapter *adapter)
 +static inline void netxen_nic_enable_int(struct nx_host_sds_ring *sds_ring)
  {
 -      adapter->pci_write_normalize(adapter, adapter->crb_intr_mask, 0x1);
 +      struct netxen_adapter *adapter = sds_ring->adapter;
 +
 +      adapter->pci_write_normalize(adapter, sds_ring->crb_intr_mask, 0x1);
  
        if (!NETXEN_IS_MSI_FAMILY(adapter))
                adapter->pci_write_immediate(adapter,
                                adapter->legacy_intr.tgt_mask_reg, 0xfbff);
  }
  
 +static void
 +netxen_napi_add(struct netxen_adapter *adapter, struct net_device *netdev)
 +{
 +      int ring;
 +      struct nx_host_sds_ring *sds_ring;
 +      struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
 +
 +      if (adapter->flags & NETXEN_NIC_MSIX_ENABLED)
 +              adapter->max_sds_rings = (num_online_cpus() >= 4) ? 4 : 2;
 +      else
 +              adapter->max_sds_rings = 1;
 +
 +      for (ring = 0; ring < adapter->max_sds_rings; ring++) {
 +              sds_ring = &recv_ctx->sds_rings[ring];
 +              netif_napi_add(netdev, &sds_ring->napi,
 +                              netxen_nic_poll, NETXEN_NETDEV_WEIGHT);
 +      }
 +}
 +
 +static void
 +netxen_napi_enable(struct netxen_adapter *adapter)
 +{
 +      int ring;
 +      struct nx_host_sds_ring *sds_ring;
 +      struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
 +
 +      for (ring = 0; ring < adapter->max_sds_rings; ring++) {
 +              sds_ring = &recv_ctx->sds_rings[ring];
 +              napi_enable(&sds_ring->napi);
 +              netxen_nic_enable_int(sds_ring);
 +      }
 +}
 +
 +static void
 +netxen_napi_disable(struct netxen_adapter *adapter)
 +{
 +      int ring;
 +      struct nx_host_sds_ring *sds_ring;
 +      struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
 +
 +      for (ring = 0; ring < adapter->max_sds_rings; ring++) {
 +              sds_ring = &recv_ctx->sds_rings[ring];
 +              netxen_nic_disable_int(sds_ring);
 +              napi_disable(&sds_ring->napi);
 +      }
 +}
 +
  static int nx_set_dma_mask(struct netxen_adapter *adapter, uint8_t revision_id)
  {
        struct pci_dev *pdev = adapter->pdev;
 -      int err;
 -      uint64_t mask;
 -
 -#ifdef CONFIG_IA64
 -      adapter->dma_mask = DMA_32BIT_MASK;
 -#else
 -      if (revision_id >= NX_P3_B0) {
 -              /* should go to DMA_64BIT_MASK */
 -              adapter->dma_mask = DMA_39BIT_MASK;
 -              mask = DMA_39BIT_MASK;
 -      } else if (revision_id == NX_P3_A2) {
 -              adapter->dma_mask = DMA_39BIT_MASK;
 -              mask = DMA_39BIT_MASK;
 -      } else if (revision_id == NX_P2_C1) {
 -              adapter->dma_mask = DMA_35BIT_MASK;
 -              mask = DMA_35BIT_MASK;
 -      } else {
 -              adapter->dma_mask = DMA_32BIT_MASK;
 -              mask = DMA_32BIT_MASK;
 -              goto set_32_bit_mask;
 -      }
 +      uint64_t mask, cmask;
 +
 +      adapter->pci_using_dac = 0;
  
 +      mask = DMA_32BIT_MASK;
        /*
         * Consistent DMA mask is set to 32 bit because it cannot be set to
         * 35 bits. For P3 also leave it at 32 bits for now. Only the rings
         * come off this pool.
         */
 +      cmask = DMA_32BIT_MASK;
 +
 +#ifndef CONFIG_IA64
 +      if (revision_id >= NX_P3_B0)
 +              mask = DMA_39BIT_MASK;
 +      else if (revision_id == NX_P2_C1)
 +              mask = DMA_35BIT_MASK;
 +#endif
        if (pci_set_dma_mask(pdev, mask) == 0 &&
 -              pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK) == 0) {
 +              pci_set_consistent_dma_mask(pdev, cmask) == 0) {
                adapter->pci_using_dac = 1;
                return 0;
        }
 -set_32_bit_mask:
 -#endif /* CONFIG_IA64 */
  
 -      err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 -      if (!err)
 -              err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
 -      if (err) {
 -              DPRINTK(ERR, "No usable DMA configuration, aborting:%d\n", err);
 -              return err;
 +      return -EIO;
 +}
 +
 +/* Update addressable range if firmware supports it */
 +static int
 +nx_update_dma_mask(struct netxen_adapter *adapter)
 +{
 +      int change, shift, err;
 +      uint64_t mask, old_mask;
 +      struct pci_dev *pdev = adapter->pdev;
 +
 +      change = 0;
 +
 +      shift = netxen_nic_reg_read(adapter, CRB_DMA_SHIFT);
 +      if (shift >= 32)
 +              return 0;
 +
 +      if (NX_IS_REVISION_P3(adapter->ahw.revision_id) && (shift > 9))
 +              change = 1;
 +      else if ((adapter->ahw.revision_id == NX_P2_C1) && (shift <= 4))
 +              change = 1;
 +
 +      if (change) {
 +              old_mask = pdev->dma_mask;
 +              mask = (1ULL<<(32+shift)) - 1;
 +
 +              err = pci_set_dma_mask(pdev, mask);
 +              if (err)
 +                      return pci_set_dma_mask(pdev, old_mask);
        }
  
 -      adapter->pci_using_dac = 0;
        return 0;
  }
  
  static void netxen_check_options(struct netxen_adapter *adapter)
  {
 -      switch (adapter->ahw.boardcfg.board_type) {
 -      case NETXEN_BRDTYPE_P3_HMEZ:
 -      case NETXEN_BRDTYPE_P3_XG_LOM:
 -      case NETXEN_BRDTYPE_P3_10G_CX4:
 -      case NETXEN_BRDTYPE_P3_10G_CX4_LP:
 -      case NETXEN_BRDTYPE_P3_IMEZ:
 -      case NETXEN_BRDTYPE_P3_10G_SFP_PLUS:
 -      case NETXEN_BRDTYPE_P3_10G_SFP_QT:
 -      case NETXEN_BRDTYPE_P3_10G_SFP_CT:
 -      case NETXEN_BRDTYPE_P3_10G_XFP:
 -      case NETXEN_BRDTYPE_P3_10000_BASE_T:
 -              adapter->msix_supported = !!use_msi_x;
 -              adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_10G;
 -              break;
 -
 -      case NETXEN_BRDTYPE_P2_SB31_10G:
 -      case NETXEN_BRDTYPE_P2_SB31_10G_CX4:
 -      case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ:
 -      case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ:
 -              adapter->msix_supported = 0;
 -              adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_10G;
 -              break;
 +      if (adapter->ahw.port_type == NETXEN_NIC_XGBE)
 +              adapter->num_rxd = MAX_RCV_DESCRIPTORS_10G;
 +      else if (adapter->ahw.port_type == NETXEN_NIC_GBE)
 +              adapter->num_rxd = MAX_RCV_DESCRIPTORS_1G;
  
 -      case NETXEN_BRDTYPE_P3_REF_QG:
 -      case NETXEN_BRDTYPE_P3_4_GB:
 -      case NETXEN_BRDTYPE_P3_4_GB_MM:
 +      if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
                adapter->msix_supported = !!use_msi_x;
 -              adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
 -              break;
 -
 -      case NETXEN_BRDTYPE_P2_SB35_4G:
 -      case NETXEN_BRDTYPE_P2_SB31_2G:
 +      else
                adapter->msix_supported = 0;
 -              adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
 -              break;
 -
 -      case NETXEN_BRDTYPE_P3_10G_TP:
 -              adapter->msix_supported = !!use_msi_x;
 -              if (adapter->ahw.board_type == NETXEN_NIC_XGBE)
 -                      adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_10G;
 -              else
 -                      adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
 -              break;
  
 -      default:
 -              adapter->msix_supported = 0;
 -              adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
 +      adapter->num_txd = MAX_CMD_DESCRIPTORS_HOST;
 +      adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS;
 +      adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS;
  
 -              printk(KERN_WARNING "Unknown board type(0x%x)\n",
 -                              adapter->ahw.boardcfg.board_type);
 -              break;
 -      }
 -
 -      adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS_HOST;
 -      adapter->max_jumbo_rx_desc_count = MAX_JUMBO_RCV_DESCRIPTORS;
 -      adapter->max_lro_rx_desc_count = MAX_LRO_RCV_DESCRIPTORS;
 -
 -      adapter->max_possible_rss_rings = 1;
        return;
  }
  
@@@ -337,7 -336,7 +337,7 @@@ static void netxen_set_port_mode(struc
  {
        u32 val, data;
  
 -      val = adapter->ahw.boardcfg.board_type;
 +      val = adapter->ahw.board_type;
        if ((val == NETXEN_BRDTYPE_P3_HMEZ) ||
                (val == NETXEN_BRDTYPE_P3_XG_LOM)) {
                if (port_mode == NETXEN_PORT_MODE_802_3_AP) {
@@@ -406,9 -405,6 +406,6 @@@ netxen_read_mac_addr(struct netxen_adap
        struct net_device *netdev = adapter->netdev;
        struct pci_dev *pdev = adapter->pdev;
  
-       if (netxen_is_flash_supported(adapter) != 0)
-               return -EIO;
        if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
                if (netxen_p3_get_mac_addr(adapter, &mac_addr) != 0)
                        return -EIO;
@@@ -458,91 -454,91 +455,91 @@@ static const struct net_device_ops netx
  #endif
  };
  
 -/*
 - * netxen_nic_probe()
 - *
 - * The Linux system will invoke this after identifying the vendor ID and
 - * device Id in the pci_tbl supported by this module.
 - *
 - * A quad port card has one operational PCI config space, (function 0),
 - * which is used to access all four ports.
 - *
 - * This routine will initialize the adapter, and setup the global parameters
 - * along with the port's specific structure.
 - */
 -static int __devinit
 -netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 +static void
 +netxen_setup_intr(struct netxen_adapter *adapter)
  {
 -      struct net_device *netdev = NULL;
 -      struct netxen_adapter *adapter = NULL;
 -      void __iomem *mem_ptr0 = NULL;
 -      void __iomem *mem_ptr1 = NULL;
 -      void __iomem *mem_ptr2 = NULL;
 -      unsigned long first_page_group_end;
 -      unsigned long first_page_group_start;
 +      struct netxen_legacy_intr_set *legacy_intrp;
 +      struct pci_dev *pdev = adapter->pdev;
  
 +      adapter->flags &= ~(NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED);
 +      adapter->intr_scheme = -1;
 +      adapter->msi_mode = -1;
  
 -      u8 __iomem *db_ptr = NULL;
 -      unsigned long mem_base, mem_len, db_base, db_len, pci_len0 = 0;
 -      int i = 0, err;
 -      int first_driver, first_boot;
 -      u32 val;
 -      int pci_func_id = PCI_FUNC(pdev->devfn);
 -      struct netxen_legacy_intr_set *legacy_intrp;
 -      uint8_t revision_id;
 +      if (adapter->ahw.revision_id >= NX_P3_B0)
 +              legacy_intrp = &legacy_intr[adapter->ahw.pci_func];
 +      else
 +              legacy_intrp = &legacy_intr[0];
 +      adapter->legacy_intr.int_vec_bit = legacy_intrp->int_vec_bit;
 +      adapter->legacy_intr.tgt_status_reg = legacy_intrp->tgt_status_reg;
 +      adapter->legacy_intr.tgt_mask_reg = legacy_intrp->tgt_mask_reg;
 +      adapter->legacy_intr.pci_int_reg = legacy_intrp->pci_int_reg;
  
 -      if (pci_func_id == 0)
 -              printk(KERN_INFO "%s\n", netxen_nic_driver_string);
 +      netxen_set_msix_bit(pdev, 0);
  
 -      if (pdev->class != 0x020000) {
 -              printk(KERN_DEBUG "NetXen function %d, class %x will not "
 -                              "be enabled.\n",pci_func_id, pdev->class);
 -              return -ENODEV;
 -      }
 +      if (adapter->msix_supported) {
  
 -      if (pdev->revision >= NX_P3_A0 && pdev->revision < NX_P3_B1) {
 -              printk(KERN_WARNING "NetXen chip revisions between 0x%x-0x%x"
 -                              "will not be enabled.\n",
 -                              NX_P3_A0, NX_P3_B1);
 -              return -ENODEV;
 -      }
 +              netxen_init_msix_entries(adapter);
 +              if (pci_enable_msix(pdev, adapter->msix_entries,
 +                                      MSIX_ENTRIES_PER_ADAPTER))
 +                      goto request_msi;
  
 -      if ((err = pci_enable_device(pdev)))
 -              return err;
 +              adapter->flags |= NETXEN_NIC_MSIX_ENABLED;
 +              netxen_set_msix_bit(pdev, 1);
 +              dev_info(&pdev->dev, "using msi-x interrupts\n");
  
 -      if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
 -              err = -ENODEV;
 -              goto err_out_disable_pdev;
 +      } else {
 +request_msi:
 +              if (use_msi && !pci_enable_msi(pdev)) {
 +                      adapter->flags |= NETXEN_NIC_MSI_ENABLED;
 +                      dev_info(&pdev->dev, "using msi interrupts\n");
 +              } else
 +                      dev_info(&pdev->dev, "using legacy interrupts\n");
 +              adapter->msix_entries[0].vector = pdev->irq;
        }
 +}
  
 -      if ((err = pci_request_regions(pdev, netxen_nic_driver_name)))
 -              goto err_out_disable_pdev;
 -
 -      pci_set_master(pdev);
 +static void
 +netxen_teardown_intr(struct netxen_adapter *adapter)
 +{
 +      if (adapter->flags & NETXEN_NIC_MSIX_ENABLED)
 +              pci_disable_msix(adapter->pdev);
 +      if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
 +              pci_disable_msi(adapter->pdev);
 +}
  
 -      netdev = alloc_etherdev(sizeof(struct netxen_adapter));
 -      if(!netdev) {
 -              printk(KERN_ERR"%s: Failed to allocate memory for the "
 -                              "device block.Check system memory resource"
 -                              " usage.\n", netxen_nic_driver_name);
 -              goto err_out_free_res;
 -      }
 +static void
 +netxen_cleanup_pci_map(struct netxen_adapter *adapter)
 +{
 +      if (adapter->ahw.db_base != NULL)
 +              iounmap(adapter->ahw.db_base);
 +      if (adapter->ahw.pci_base0 != NULL)
 +              iounmap(adapter->ahw.pci_base0);
 +      if (adapter->ahw.pci_base1 != NULL)
 +              iounmap(adapter->ahw.pci_base1);
 +      if (adapter->ahw.pci_base2 != NULL)
 +              iounmap(adapter->ahw.pci_base2);
 +}
  
 -      SET_NETDEV_DEV(netdev, &pdev->dev);
 +static int
 +netxen_setup_pci_map(struct netxen_adapter *adapter)
 +{
 +      void __iomem *mem_ptr0 = NULL;
 +      void __iomem *mem_ptr1 = NULL;
 +      void __iomem *mem_ptr2 = NULL;
 +      void __iomem *db_ptr = NULL;
  
 -      adapter = netdev_priv(netdev);
 -      adapter->netdev  = netdev;
 -      adapter->pdev    = pdev;
 -      adapter->ahw.pci_func  = pci_func_id;
 +      unsigned long mem_base, mem_len, db_base, db_len = 0, pci_len0 = 0;
  
 -      revision_id = pdev->revision;
 -      adapter->ahw.revision_id = revision_id;
 +      struct pci_dev *pdev = adapter->pdev;
 +      int pci_func = adapter->ahw.pci_func;
  
 -      err = nx_set_dma_mask(adapter, revision_id);
 -      if (err)
 -              goto err_out_free_netdev;
 +      int err = 0;
  
 -      rwlock_init(&adapter->adapter_lock);
 +      /*
 +       * Set the CRB window to invalid. If any register in window 0 is
 +       * accessed it should set the window to 0 and then reset it to 1.
 +       */
 +      adapter->curr_window = 255;
        adapter->ahw.qdr_sn_window = -1;
        adapter->ahw.ddr_mn_window = -1;
  
                                SECOND_PAGE_GROUP_SIZE);
                mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START,
                                THIRD_PAGE_GROUP_SIZE);
 -              first_page_group_start = FIRST_PAGE_GROUP_START;
 -              first_page_group_end   = FIRST_PAGE_GROUP_END;
        } else if (mem_len == NETXEN_PCI_32MB_SIZE) {
                mem_ptr1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE);
                mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START -
                        SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE);
 -              first_page_group_start = 0;
 -              first_page_group_end   = 0;
        } else if (mem_len == NETXEN_PCI_2MB_SIZE) {
                adapter->hw_write_wx = netxen_nic_hw_write_wx_2M;
                adapter->hw_read_wx = netxen_nic_hw_read_wx_2M;
                        dev_err(&pdev->dev, "failed to map PCI bar 0\n");
                        return -EIO;
                }
 +              pci_len0 = mem_len;
 +
 +              adapter->ahw.ddr_mn_window = 0;
 +              adapter->ahw.qdr_sn_window = 0;
 +
 +              adapter->ahw.mn_win_crb = 0x100000 + PCIX_MN_WINDOW +
 +                      (pci_func * 0x20);
 +              adapter->ahw.ms_win_crb = 0x100000 + PCIX_SN_WINDOW;
 +              if (pci_func < 4)
 +                      adapter->ahw.ms_win_crb += (pci_func * 0x20);
 +              else
 +                      adapter->ahw.ms_win_crb +=
 +                                      0xA0 + ((pci_func - 4) * 0x10);
 +      } else {
 +              return -EIO;
 +      }
 +
 +      dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
 +
 +      adapter->ahw.pci_base0 = mem_ptr0;
 +      adapter->ahw.pci_len0 = pci_len0;
 +      adapter->ahw.pci_base1 = mem_ptr1;
 +      adapter->ahw.pci_base2 = mem_ptr2;
 +
 +      if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
 +              goto skip_doorbell;
 +
 +      db_base = pci_resource_start(pdev, 4);  /* doorbell is on bar 4 */
 +      db_len = pci_resource_len(pdev, 4);
 +
 +      if (db_len == 0) {
 +              printk(KERN_ERR "%s: doorbell is disabled\n",
 +                              netxen_nic_driver_name);
 +              err = -EIO;
 +              goto err_out;
 +      }
 +
 +      db_ptr = ioremap(db_base, NETXEN_DB_MAPSIZE_BYTES);
 +      if (!db_ptr) {
 +              printk(KERN_ERR "%s: Failed to allocate doorbell map.",
 +                              netxen_nic_driver_name);
 +              err = -EIO;
 +              goto err_out;
 +      }
 +
 +skip_doorbell:
 +      adapter->ahw.db_base = db_ptr;
 +      adapter->ahw.db_len = db_len;
 +      return 0;
 +
 +err_out:
 +      netxen_cleanup_pci_map(adapter);
 +      return err;
 +}
 +
 +static int
 +netxen_start_firmware(struct netxen_adapter *adapter)
 +{
 +      int val, err, first_boot;
 +      struct pci_dev *pdev = adapter->pdev;
 +
 +      int first_driver = 0;
 +      if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
 +              if (adapter->ahw.pci_func == 0)
 +                      first_driver = 1;
 +      } else {
 +              if (adapter->portnum == 0)
 +                      first_driver = 1;
 +      }
 +
 +      if (!first_driver)
 +              return 0;
 +
 +      first_boot = adapter->pci_read_normalize(adapter,
 +                      NETXEN_CAM_RAM(0x1fc));
 +
 +      err = netxen_check_hw_init(adapter, first_boot);
 +      if (err) {
 +              dev_err(&pdev->dev, "error in init HW init sequence\n");
 +              return err;
 +      }
 +
 +      if (first_boot != 0x55555555) {
 +              adapter->pci_write_normalize(adapter,
 +                                      CRB_CMDPEG_STATE, 0);
 +              netxen_pinit_from_rom(adapter, 0);
 +              msleep(1);
 +      }
 +
 +      netxen_nic_reg_write(adapter, CRB_DMA_SHIFT, 0x55555555);
 +      if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
 +              netxen_set_port_mode(adapter);
 +
 +      netxen_load_firmware(adapter);
 +
 +      if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
 +
 +              /* Initialize multicast addr pool owners */
 +              val = 0x7654;
 +              if (adapter->ahw.port_type == NETXEN_NIC_XGBE)
 +                      val |= 0x0f000000;
 +              netxen_crb_writelit_adapter(adapter,
 +                              NETXEN_MAC_ADDR_CNTL_REG, val);
 +
 +      }
 +
 +      err = netxen_initialize_adapter_offload(adapter);
 +      if (err)
 +              return err;
 +
 +      /*
 +       * Tell the hardware our version number.
 +       */
 +      val = (_NETXEN_NIC_LINUX_MAJOR << 16)
 +              | ((_NETXEN_NIC_LINUX_MINOR << 8))
 +              | (_NETXEN_NIC_LINUX_SUBVERSION);
 +      adapter->pci_write_normalize(adapter, CRB_DRIVER_VERSION, val);
 +
 +      /* Handshake with the card before we register the devices. */
 +      err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
 +      if (err) {
 +              netxen_free_adapter_offload(adapter);
 +              return err;
 +      }
 +
 +      return 0;
 +}
 +
 +static int
 +netxen_nic_request_irq(struct netxen_adapter *adapter)
 +{
 +      irq_handler_t handler;
 +      struct nx_host_sds_ring *sds_ring;
 +      int err, ring;
 +
 +      unsigned long flags = IRQF_SAMPLE_RANDOM;
 +      struct net_device *netdev = adapter->netdev;
 +      struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
 +
 +      if ((adapter->msi_mode != MSI_MODE_MULTIFUNC) ||
 +              (adapter->intr_scheme != INTR_SCHEME_PERPORT)) {
 +              printk(KERN_ERR "%s: Firmware interrupt scheme is "
 +                              "incompatible with driver\n",
 +                              netdev->name);
 +              adapter->driver_mismatch = 1;
 +              return -EINVAL;
 +      }
 +
 +      if (adapter->flags & NETXEN_NIC_MSIX_ENABLED)
 +              handler = netxen_msix_intr;
 +      else if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
 +              handler = netxen_msi_intr;
 +      else {
 +              flags |= IRQF_SHARED;
 +              handler = netxen_intr;
 +      }
 +      adapter->irq = netdev->irq;
 +
 +      for (ring = 0; ring < adapter->max_sds_rings; ring++) {
 +              sds_ring = &recv_ctx->sds_rings[ring];
 +              sprintf(sds_ring->name, "%16s[%d]", netdev->name, ring);
 +              err = request_irq(sds_ring->irq, handler,
 +                                flags, sds_ring->name, sds_ring);
 +              if (err)
 +                      return err;
 +      }
 +
 +      return 0;
 +}
 +
 +static void
 +netxen_nic_free_irq(struct netxen_adapter *adapter)
 +{
 +      int ring;
 +      struct nx_host_sds_ring *sds_ring;
 +
 +      struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
 +
 +      for (ring = 0; ring < adapter->max_sds_rings; ring++) {
 +              sds_ring = &recv_ctx->sds_rings[ring];
 +              free_irq(sds_ring->irq, sds_ring);
 +      }
 +}
 +
 +static int
 +netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev)
 +{
 +      int err;
 +
 +      err = adapter->init_port(adapter, adapter->physical_port);
 +      if (err) {
 +              printk(KERN_ERR "%s: Failed to initialize port %d\n",
 +                              netxen_nic_driver_name, adapter->portnum);
 +              return err;
 +      }
 +      adapter->macaddr_set(adapter, netdev->dev_addr);
 +
 +      netxen_nic_set_link_parameters(adapter);
 +
 +      netxen_set_multicast_list(netdev);
 +      if (adapter->set_mtu)
 +              adapter->set_mtu(adapter, netdev->mtu);
 +
 +      adapter->ahw.linkup = 0;
 +      mod_timer(&adapter->watchdog_timer, jiffies);
 +
 +      netxen_napi_enable(adapter);
 +
 +      if (adapter->max_sds_rings > 1)
 +              netxen_config_rss(adapter, 1);
 +
 +      return 0;
 +}
 +
 +static void
 +netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev)
 +{
 +      netif_carrier_off(netdev);
 +      netif_stop_queue(netdev);
 +      netxen_napi_disable(adapter);
 +
 +      if (adapter->stop_port)
 +              adapter->stop_port(adapter);
 +
 +      netxen_release_tx_buffers(adapter);
 +
 +      FLUSH_SCHEDULED_WORK();
 +      del_timer_sync(&adapter->watchdog_timer);
 +}
 +
 +
 +static int
 +netxen_nic_attach(struct netxen_adapter *adapter)
 +{
 +      struct net_device *netdev = adapter->netdev;
 +      struct pci_dev *pdev = adapter->pdev;
 +      int err, ring;
 +      struct nx_host_rds_ring *rds_ring;
 +
 +      err = netxen_init_firmware(adapter);
 +      if (err != 0) {
 +              printk(KERN_ERR "Failed to init firmware\n");
 +              return -EIO;
 +      }
 +
 +      if (adapter->fw_major < 4)
 +              adapter->max_rds_rings = 3;
 +      else
 +              adapter->max_rds_rings = 2;
 +
 +      err = netxen_alloc_sw_resources(adapter);
 +      if (err) {
 +              printk(KERN_ERR "%s: Error in setting sw resources\n",
 +                              netdev->name);
 +              return err;
 +      }
 +
 +      netxen_nic_clear_stats(adapter);
 +
 +      err = netxen_alloc_hw_resources(adapter);
 +      if (err) {
 +              printk(KERN_ERR "%s: Error in setting hw resources\n",
 +                              netdev->name);
 +              goto err_out_free_sw;
 +      }
 +
 +      if (adapter->fw_major < 4) {
 +              adapter->crb_addr_cmd_producer =
 +                      crb_cmd_producer[adapter->portnum];
 +              adapter->crb_addr_cmd_consumer =
 +                      crb_cmd_consumer[adapter->portnum];
 +
 +              netxen_nic_update_cmd_producer(adapter, 0);
 +              netxen_nic_update_cmd_consumer(adapter, 0);
 +      }
 +
 +      for (ring = 0; ring < adapter->max_rds_rings; ring++) {
 +              rds_ring = &adapter->recv_ctx.rds_rings[ring];
 +              netxen_post_rx_buffers(adapter, ring, rds_ring);
 +      }
 +
 +      err = netxen_nic_request_irq(adapter);
 +      if (err) {
 +              dev_err(&pdev->dev, "%s: failed to setup interrupt\n",
 +                              netdev->name);
 +              goto err_out_free_rxbuf;
 +      }
 +
 +      adapter->is_up = NETXEN_ADAPTER_UP_MAGIC;
 +      return 0;
 +
 +err_out_free_rxbuf:
 +      netxen_release_rx_buffers(adapter);
 +      netxen_free_hw_resources(adapter);
 +err_out_free_sw:
 +      netxen_free_sw_resources(adapter);
 +      return err;
 +}
 +
 +static void
 +netxen_nic_detach(struct netxen_adapter *adapter)
 +{
 +      netxen_nic_free_irq(adapter);
 +
 +      netxen_release_rx_buffers(adapter);
 +      netxen_free_hw_resources(adapter);
 +      netxen_free_sw_resources(adapter);
 +
 +      adapter->is_up = 0;
 +}
 +
 +static int __devinit
 +netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 +{
 +      struct net_device *netdev = NULL;
 +      struct netxen_adapter *adapter = NULL;
 +      int i = 0, err;
 +      int pci_func_id = PCI_FUNC(pdev->devfn);
 +      uint8_t revision_id;
  
 -              pci_len0 = mem_len;
 -              first_page_group_start = 0;
 -              first_page_group_end   = 0;
 +      if (pdev->class != 0x020000) {
 +              printk(KERN_DEBUG "NetXen function %d, class %x will not "
 +                              "be enabled.\n",pci_func_id, pdev->class);
 +              return -ENODEV;
 +      }
  
 -              adapter->ahw.ddr_mn_window = 0;
 -              adapter->ahw.qdr_sn_window = 0;
 +      if (pdev->revision >= NX_P3_A0 && pdev->revision < NX_P3_B1) {
 +              printk(KERN_WARNING "NetXen chip revisions between 0x%x-0x%x"
 +                              "will not be enabled.\n",
 +                              NX_P3_A0, NX_P3_B1);
 +              return -ENODEV;
 +      }
  
 -              adapter->ahw.mn_win_crb = 0x100000 + PCIX_MN_WINDOW +
 -                      (pci_func_id * 0x20);
 -              adapter->ahw.ms_win_crb = 0x100000 + PCIX_SN_WINDOW;
 -              if (pci_func_id < 4)
 -                      adapter->ahw.ms_win_crb += (pci_func_id * 0x20);
 -              else
 -                      adapter->ahw.ms_win_crb +=
 -                                      0xA0 + ((pci_func_id - 4) * 0x10);
 -      } else {
 -              err = -EIO;
 -              goto err_out_free_netdev;
 +      if ((err = pci_enable_device(pdev)))
 +              return err;
 +
 +      if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
 +              err = -ENODEV;
 +              goto err_out_disable_pdev;
        }
  
 -      dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
 +      if ((err = pci_request_regions(pdev, netxen_nic_driver_name)))
 +              goto err_out_disable_pdev;
  
 -      db_base = pci_resource_start(pdev, 4);  /* doorbell is on bar 4 */
 -      db_len = pci_resource_len(pdev, 4);
 +      pci_set_master(pdev);
  
 -      if (db_len == 0) {
 -              printk(KERN_ERR "%s: doorbell is disabled\n",
 -                              netxen_nic_driver_name);
 -              err = -EIO;
 -              goto err_out_iounmap;
 +      netdev = alloc_etherdev(sizeof(struct netxen_adapter));
 +      if(!netdev) {
 +              printk(KERN_ERR"%s: Failed to allocate memory for the "
 +                              "device block.Check system memory resource"
 +                              " usage.\n", netxen_nic_driver_name);
 +              goto err_out_free_res;
        }
 -      DPRINTK(INFO, "doorbell ioremap from %lx a size of %lx\n", db_base,
 -              db_len);
  
 -      db_ptr = ioremap(db_base, NETXEN_DB_MAPSIZE_BYTES);
 -      if (!db_ptr) {
 -              printk(KERN_ERR "%s: Failed to allocate doorbell map.",
 -                              netxen_nic_driver_name);
 -              err = -EIO;
 -              goto err_out_iounmap;
 -      }
 -      DPRINTK(INFO, "doorbell ioremaped at %p\n", db_ptr);
 +      SET_NETDEV_DEV(netdev, &pdev->dev);
  
 -      adapter->ahw.pci_base0 = mem_ptr0;
 -      adapter->ahw.pci_len0 = pci_len0;
 -      adapter->ahw.first_page_group_start = first_page_group_start;
 -      adapter->ahw.first_page_group_end   = first_page_group_end;
 -      adapter->ahw.pci_base1 = mem_ptr1;
 -      adapter->ahw.pci_base2 = mem_ptr2;
 -      adapter->ahw.db_base = db_ptr;
 -      adapter->ahw.db_len = db_len;
 +      adapter = netdev_priv(netdev);
 +      adapter->netdev  = netdev;
 +      adapter->pdev    = pdev;
 +      adapter->ahw.pci_func  = pci_func_id;
  
 -      netif_napi_add(netdev, &adapter->napi,
 -                      netxen_nic_poll, NETXEN_NETDEV_WEIGHT);
 +      revision_id = pdev->revision;
 +      adapter->ahw.revision_id = revision_id;
  
 -      if (revision_id >= NX_P3_B0)
 -              legacy_intrp = &legacy_intr[pci_func_id];
 -      else
 -              legacy_intrp = &legacy_intr[0];
 +      err = nx_set_dma_mask(adapter, revision_id);
 +      if (err)
 +              goto err_out_free_netdev;
  
 -      adapter->legacy_intr.int_vec_bit = legacy_intrp->int_vec_bit;
 -      adapter->legacy_intr.tgt_status_reg = legacy_intrp->tgt_status_reg;
 -      adapter->legacy_intr.tgt_mask_reg = legacy_intrp->tgt_mask_reg;
 -      adapter->legacy_intr.pci_int_reg = legacy_intrp->pci_int_reg;
 +      rwlock_init(&adapter->adapter_lock);
 +      spin_lock_init(&adapter->tx_clean_lock);
  
 -      /* this will be read from FW later */
 -      adapter->intr_scheme = -1;
 -      adapter->msi_mode = -1;
 +      err = netxen_setup_pci_map(adapter);
 +      if (err)
 +              goto err_out_free_netdev;
  
        /* This will be reset for mezz cards  */
        adapter->portnum = pci_func_id;
 -      adapter->status   &= ~NETXEN_NETDEV_STATUS;
        adapter->rx_csum = 1;
        adapter->mc_enabled = 0;
        if (NX_IS_REVISION_P3(revision_id))
                netdev->vlan_features |= NETIF_F_HIGHDMA;
        }
  
 -      /*
 -       * Set the CRB window to invalid. If any register in window 0 is
 -       * accessed it should set the window to 0 and then reset it to 1.
 -       */
 -      adapter->curr_window = 255;
 -
        if (netxen_nic_get_board_info(adapter) != 0) {
                printk("%s: Error getting board config info.\n",
                                netxen_nic_driver_name);
        netxen_initialize_adapter_ops(adapter);
  
        /* Mezz cards have PCI function 0,2,3 enabled */
 -      switch (adapter->ahw.boardcfg.board_type) {
 +      switch (adapter->ahw.board_type) {
        case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ:
        case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ:
                if (pci_func_id >= 2)
                break;
        }
  
 -      /*
 -       * This call will setup various max rx/tx counts.
 -       * It must be done before any buffer/ring allocations.
 -       */
 -      netxen_check_options(adapter);
 -
 -      first_driver = 0;
 -      if (NX_IS_REVISION_P3(revision_id)) {
 -              if (adapter->ahw.pci_func == 0)
 -                      first_driver = 1;
 -      } else {
 -              if (adapter->portnum == 0)
 -                      first_driver = 1;
 -      }
 -
 -      if (first_driver) {
 -              first_boot = adapter->pci_read_normalize(adapter,
 -                              NETXEN_CAM_RAM(0x1fc));
 -
 -              err = netxen_check_hw_init(adapter, first_boot);
 -              if (err) {
 -                      printk(KERN_ERR "%s: error in init HW init sequence\n",
 -                                      netxen_nic_driver_name);
 -                      goto err_out_iounmap;
 -              }
 -
 -              if (NX_IS_REVISION_P3(revision_id))
 -                      netxen_set_port_mode(adapter);
 -
 -              if (first_boot != 0x55555555) {
 -                      adapter->pci_write_normalize(adapter,
 -                                              CRB_CMDPEG_STATE, 0);
 -                      netxen_pinit_from_rom(adapter, 0);
 -                      msleep(1);
 -              }
 -              netxen_load_firmware(adapter);
 -
 -              if (NX_IS_REVISION_P2(revision_id)) {
 -
 -                      /* Initialize multicast addr pool owners */
 -                      val = 0x7654;
 -                      if (adapter->ahw.board_type == NETXEN_NIC_XGBE)
 -                              val |= 0x0f000000;
 -                      netxen_crb_writelit_adapter(adapter,
 -                                      NETXEN_MAC_ADDR_CNTL_REG, val);
 -
 -              }
 -
 -              err = netxen_initialize_adapter_offload(adapter);
 -              if (err)
 -                      goto err_out_iounmap;
 -
 -              /*
 -               * Tell the hardware our version number.
 -               */
 -              i = (_NETXEN_NIC_LINUX_MAJOR << 16)
 -                      | ((_NETXEN_NIC_LINUX_MINOR << 8))
 -                      | (_NETXEN_NIC_LINUX_SUBVERSION);
 -              adapter->pci_write_normalize(adapter, CRB_DRIVER_VERSION, i);
 -
 -              /* Handshake with the card before we register the devices. */
 -              err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
 -              if (err)
 -                      goto err_out_free_offload;
 -
 -      }       /* first_driver */
 +      err = netxen_start_firmware(adapter);
 +      if (err)
 +              goto err_out_iounmap;
  
 -      netxen_nic_flash_print(adapter);
 +      nx_update_dma_mask(adapter);
  
 -      if (NX_IS_REVISION_P3(revision_id)) {
 -              adapter->hw_read_wx(adapter,
 -                              NETXEN_MIU_MN_CONTROL, &val, 4);
 -              adapter->ahw.cut_through = (val & 0x4) ? 1 : 0;
 -              dev_info(&pdev->dev, "firmware running in %s mode\n",
 -              adapter->ahw.cut_through ? "cut through" : "legacy");
 -      }
 +      netxen_nic_get_firmware_info(adapter);
  
        /*
         * See if the firmware gave us a virtual-physical port mapping.
                        adapter->physical_port = i;
        }
  
 -      adapter->flags &= ~(NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED);
 -
 -      netxen_set_msix_bit(pdev, 0);
 -
 -      if (NX_IS_REVISION_P3(revision_id)) {
 -              if ((mem_len != NETXEN_PCI_128MB_SIZE) &&
 -                      mem_len != NETXEN_PCI_2MB_SIZE)
 -                      adapter->msix_supported = 0;
 -      }
 -
 -      if (adapter->msix_supported) {
 -
 -              netxen_init_msix_entries(adapter);
 -
 -              if (pci_enable_msix(pdev, adapter->msix_entries,
 -                                      MSIX_ENTRIES_PER_ADAPTER))
 -                      goto request_msi;
 +      netxen_check_options(adapter);
  
 -              adapter->flags |= NETXEN_NIC_MSIX_ENABLED;
 -              netxen_set_msix_bit(pdev, 1);
 -              dev_info(&pdev->dev, "using msi-x interrupts\n");
 +      netxen_setup_intr(adapter);
  
 -      } else {
 -request_msi:
 -              if (use_msi && !pci_enable_msi(pdev)) {
 -                      adapter->flags |= NETXEN_NIC_MSI_ENABLED;
 -                      dev_info(&pdev->dev, "using msi interrupts\n");
 -              } else
 -                      dev_info(&pdev->dev, "using legacy interrupts\n");
 -      }
 +      netdev->irq = adapter->msix_entries[0].vector;
  
 -      if (adapter->flags & NETXEN_NIC_MSIX_ENABLED)
 -              netdev->irq = adapter->msix_entries[0].vector;
 -      else
 -              netdev->irq = pdev->irq;
 +      netxen_napi_add(adapter, netdev);
  
        err = netxen_receive_peg_ready(adapter);
        if (err)
  
        pci_set_drvdata(pdev, adapter);
  
 -      switch (adapter->ahw.board_type) {
 +      switch (adapter->ahw.port_type) {
        case NETXEN_NIC_GBE:
                dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n",
                                adapter->netdev->name);
        return 0;
  
  err_out_disable_msi:
 -      if (adapter->flags & NETXEN_NIC_MSIX_ENABLED)
 -              pci_disable_msix(pdev);
 -      if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
 -              pci_disable_msi(pdev);
 +      netxen_teardown_intr(adapter);
  
 -err_out_free_offload:
 -      if (first_driver)
 -              netxen_free_adapter_offload(adapter);
 +      netxen_free_adapter_offload(adapter);
  
  err_out_iounmap:
 -      if (db_ptr)
 -              iounmap(db_ptr);
 -
 -      if (mem_ptr0)
 -              iounmap(mem_ptr0);
 -      if (mem_ptr1)
 -              iounmap(mem_ptr1);
 -      if (mem_ptr2)
 -              iounmap(mem_ptr2);
 +      netxen_cleanup_pci_map(adapter);
  
  err_out_free_netdev:
        free_netdev(netdev);
@@@ -1115,7 -927,9 +1112,7 @@@ static void __devexit netxen_nic_remove
        unregister_netdev(netdev);
  
        if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
 -              netxen_free_hw_resources(adapter);
 -              netxen_release_rx_buffers(adapter);
 -              netxen_free_sw_resources(adapter);
 +              netxen_nic_detach(adapter);
  
                if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
                        netxen_p3_free_mac_list(adapter);
        if (adapter->portnum == 0)
                netxen_free_adapter_offload(adapter);
  
 -      if (adapter->irq)
 -              free_irq(adapter->irq, adapter);
 +      netxen_teardown_intr(adapter);
  
 -      if (adapter->flags & NETXEN_NIC_MSIX_ENABLED)
 -              pci_disable_msix(pdev);
 -      if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
 -              pci_disable_msi(pdev);
 -
 -      iounmap(adapter->ahw.db_base);
 -      iounmap(adapter->ahw.pci_base0);
 -      if (adapter->ahw.pci_base1 != NULL)
 -              iounmap(adapter->ahw.pci_base1);
 -      if (adapter->ahw.pci_base2 != NULL)
 -              iounmap(adapter->ahw.pci_base2);
 +      netxen_cleanup_pci_map(adapter);
  
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        free_netdev(netdev);
  }
  
 -/*
 - * Called when a network interface is made active
 - * @returns 0 on success, negative value on failure
 - */
 -static int netxen_nic_open(struct net_device *netdev)
 +static int
 +netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state)
  {
 -      struct netxen_adapter *adapter = netdev_priv(netdev);
 -      int err = 0;
 -      int ctx, ring;
 -      irq_handler_t handler;
 -      unsigned long flags = IRQF_SAMPLE_RANDOM;
  
 -      if (adapter->driver_mismatch)
 -              return -EIO;
 +      struct netxen_adapter *adapter = pci_get_drvdata(pdev);
 +      struct net_device *netdev = adapter->netdev;
  
 -      if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) {
 -              err = netxen_init_firmware(adapter);
 -              if (err != 0) {
 -                      printk(KERN_ERR "Failed to init firmware\n");
 -                      return -EIO;
 -              }
 +      netif_device_detach(netdev);
  
 -              if (adapter->fw_major < 4)
 -                      adapter->max_rds_rings = 3;
 -              else
 -                      adapter->max_rds_rings = 2;
 +      if (netif_running(netdev))
 +              netxen_nic_down(adapter, netdev);
  
 -              err = netxen_alloc_sw_resources(adapter);
 -              if (err) {
 -                      printk(KERN_ERR "%s: Error in setting sw resources\n",
 -                                      netdev->name);
 -                      return err;
 -              }
 +      if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
 +              netxen_nic_detach(adapter);
  
 -              netxen_nic_clear_stats(adapter);
 +      pci_save_state(pdev);
  
 -              err = netxen_alloc_hw_resources(adapter);
 -              if (err) {
 -                      printk(KERN_ERR "%s: Error in setting hw resources\n",
 -                                      netdev->name);
 -                      goto err_out_free_sw;
 -              }
 +      if (netxen_nic_wol_supported(adapter)) {
 +              pci_enable_wake(pdev, PCI_D3cold, 1);
 +              pci_enable_wake(pdev, PCI_D3hot, 1);
 +      }
  
 -              if ((adapter->msi_mode != MSI_MODE_MULTIFUNC) ||
 -                      (adapter->intr_scheme != INTR_SCHEME_PERPORT)) {
 -                      printk(KERN_ERR "%s: Firmware interrupt scheme is "
 -                                      "incompatible with driver\n",
 -                                      netdev->name);
 -                      adapter->driver_mismatch = 1;
 -                      goto err_out_free_hw;
 -              }
 +      pci_disable_device(pdev);
 +      pci_set_power_state(pdev, pci_choose_state(pdev, state));
  
 -              if (adapter->fw_major < 4) {
 -                      adapter->crb_addr_cmd_producer =
 -                              crb_cmd_producer[adapter->portnum];
 -                      adapter->crb_addr_cmd_consumer =
 -                              crb_cmd_consumer[adapter->portnum];
 +      return 0;
 +}
  
 -                      netxen_nic_update_cmd_producer(adapter, 0);
 -                      netxen_nic_update_cmd_consumer(adapter, 0);
 -              }
 +static int
 +netxen_nic_resume(struct pci_dev *pdev)
 +{
 +      struct netxen_adapter *adapter = pci_get_drvdata(pdev);
 +      struct net_device *netdev = adapter->netdev;
 +      int err;
  
 -              for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
 -                      for (ring = 0; ring < adapter->max_rds_rings; ring++)
 -                              netxen_post_rx_buffers(adapter, ctx, ring);
 -              }
 -              if (adapter->flags & NETXEN_NIC_MSIX_ENABLED)
 -                      handler = netxen_msix_intr;
 -              else if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
 -                      handler = netxen_msi_intr;
 -              else {
 -                      flags |= IRQF_SHARED;
 -                      handler = netxen_intr;
 -              }
 -              adapter->irq = netdev->irq;
 -              err = request_irq(adapter->irq, handler,
 -                                flags, netdev->name, adapter);
 -              if (err) {
 -                      printk(KERN_ERR "request_irq failed with: %d\n", err);
 -                      goto err_out_free_rxbuf;
 -              }
 +      pci_set_power_state(pdev, PCI_D0);
 +      pci_restore_state(pdev);
  
 -              adapter->is_up = NETXEN_ADAPTER_UP_MAGIC;
 -      }
 +      err = pci_enable_device(pdev);
 +      if (err)
 +              return err;
  
 -      /* Done here again so that even if phantom sw overwrote it,
 -       * we set it */
 -      err = adapter->init_port(adapter, adapter->physical_port);
 +      adapter->curr_window = 255;
 +
 +      err = netxen_start_firmware(adapter);
        if (err) {
 -              printk(KERN_ERR "%s: Failed to initialize port %d\n",
 -                              netxen_nic_driver_name, adapter->portnum);
 -              goto err_out_free_irq;
 +              dev_err(&pdev->dev, "failed to start firmware\n");
 +              return err;
        }
 -      adapter->macaddr_set(adapter, netdev->dev_addr);
  
 -      netxen_nic_set_link_parameters(adapter);
 +      if (netif_running(netdev)) {
 +              err = netxen_nic_attach(adapter);
 +              if (err)
 +                      return err;
  
 -      netxen_set_multicast_list(netdev);
 -      if (adapter->set_mtu)
 -              adapter->set_mtu(adapter, netdev->mtu);
 +              err = netxen_nic_up(adapter, netdev);
 +              if (err)
 +                      return err;
  
 -      adapter->ahw.linkup = 0;
 -      mod_timer(&adapter->watchdog_timer, jiffies);
 +              netif_device_attach(netdev);
 +      }
 +
 +      return 0;
 +}
 +
 +static int netxen_nic_open(struct net_device *netdev)
 +{
 +      struct netxen_adapter *adapter = netdev_priv(netdev);
 +      int err = 0;
 +
 +      if (adapter->driver_mismatch)
 +              return -EIO;
 +
 +      if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) {
 +              err = netxen_nic_attach(adapter);
 +              if (err)
 +                      return err;
 +      }
  
 -      napi_enable(&adapter->napi);
 -      netxen_nic_enable_int(adapter);
 +      err = netxen_nic_up(adapter, netdev);
 +      if (err)
 +              goto err_out;
  
        netif_start_queue(netdev);
  
        return 0;
  
 -err_out_free_irq:
 -      free_irq(adapter->irq, adapter);
 -err_out_free_rxbuf:
 -      netxen_release_rx_buffers(adapter);
 -err_out_free_hw:
 -      netxen_free_hw_resources(adapter);
 -err_out_free_sw:
 -      netxen_free_sw_resources(adapter);
 +err_out:
 +      netxen_nic_detach(adapter);
        return err;
  }
  
@@@ -1234,7 -1089,20 +1231,7 @@@ static int netxen_nic_close(struct net_
  {
        struct netxen_adapter *adapter = netdev_priv(netdev);
  
 -      netif_carrier_off(netdev);
 -      netif_stop_queue(netdev);
 -      napi_disable(&adapter->napi);
 -
 -      if (adapter->stop_port)
 -              adapter->stop_port(adapter);
 -
 -      netxen_nic_disable_int(adapter);
 -
 -      netxen_release_tx_buffers(adapter);
 -
 -      FLUSH_SCHEDULED_WORK();
 -      del_timer_sync(&adapter->watchdog_timer);
 -
 +      netxen_nic_down(adapter, netdev);
        return 0;
  }
  
@@@ -1246,7 -1114,7 +1243,7 @@@ static bool netxen_tso_check(struct net
        __be16 protocol = skb->protocol;
        u16 flags = 0;
  
 -      if (protocol == __constant_htons(ETH_P_8021Q)) {
 +      if (protocol == cpu_to_be16(ETH_P_8021Q)) {
                struct vlan_ethhdr *vh = (struct vlan_ethhdr *)skb->data;
                protocol = vh->h_vlan_encapsulated_proto;
                flags = FLAGS_VLAN_TAGGED;
                desc->total_hdr_length =
                        skb_transport_offset(skb) + tcp_hdrlen(skb);
  
 -              opcode = (protocol == __constant_htons(ETH_P_IPV6)) ?
 +              opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ?
                                TX_TCP_LSO6 : TX_TCP_LSO;
                tso = true;
  
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
                u8 l4proto;
  
 -              if (protocol == __constant_htons(ETH_P_IP)) {
 +              if (protocol == cpu_to_be16(ETH_P_IP)) {
                        l4proto = ip_hdr(skb)->protocol;
  
                        if (l4proto == IPPROTO_TCP)
                                opcode = TX_TCP_PKT;
                        else if(l4proto == IPPROTO_UDP)
                                opcode = TX_UDP_PKT;
 -              } else if (protocol == __constant_htons(ETH_P_IPV6)) {
 +              } else if (protocol == cpu_to_be16(ETH_P_IPV6)) {
                        l4proto = ipv6_hdr(skb)->nexthdr;
  
                        if (l4proto == IPPROTO_TCP)
@@@ -1306,16 -1174,7 +1303,16 @@@ netxen_clean_tx_dma_mapping(struct pci_
        }
  }
  
 -static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 +static inline void
 +netxen_clear_cmddesc(u64 *desc)
 +{
 +      int i;
 +      for (i = 0; i < 8; i++)
 +              desc[i] = 0ULL;
 +}
 +
 +static int
 +netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
  {
        struct netxen_adapter *adapter = netdev_priv(netdev);
        struct netxen_hardware_context *hw = &adapter->ahw;
  
        u32 producer, consumer;
        int frag_count, no_of_desc;
 -      u32 num_txd = adapter->max_tx_desc_count;
 +      u32 num_txd = adapter->num_txd;
        bool is_tso = false;
  
        frag_count = skb_shinfo(skb)->nr_frags + 1;
  
        /* Copy the descriptors into the hardware    */
        hwdesc = &hw->cmd_desc_head[producer];
 -      memset(hwdesc, 0, sizeof(struct cmd_desc_type0));
 +      netxen_clear_cmddesc((u64 *)hwdesc);
        /* Take skb->data itself */
        pbuf = &adapter->cmd_buf_arr[producer];
  
        netxen_set_tx_frags_len(hwdesc, frag_count, skb->len);
        netxen_set_tx_port(hwdesc, adapter->portnum);
  
 -      hwdesc->buffer1_length = cpu_to_le16(first_seg_len);
 +      hwdesc->buffer_length[0] = cpu_to_le16(first_seg_len);
        hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
  
        for (i = 1, k = 1; i < frag_count; i++, k++) {
                        k = 0;
                        producer = get_next_index(producer, num_txd);
                        hwdesc = &hw->cmd_desc_head[producer];
 -                      memset(hwdesc, 0, sizeof(struct cmd_desc_type0));
 +                      netxen_clear_cmddesc((u64 *)hwdesc);
                        pbuf = &adapter->cmd_buf_arr[producer];
                        pbuf->skb = NULL;
                }
                buffrag->dma = temp_dma;
                buffrag->length = temp_len;
  
 +              hwdesc->buffer_length[k] = cpu_to_le16(temp_len);
                switch (k) {
                case 0:
 -                      hwdesc->buffer1_length = cpu_to_le16(temp_len);
                        hwdesc->addr_buffer1 = cpu_to_le64(temp_dma);
                        break;
                case 1:
 -                      hwdesc->buffer2_length = cpu_to_le16(temp_len);
                        hwdesc->addr_buffer2 = cpu_to_le64(temp_dma);
                        break;
                case 2:
 -                      hwdesc->buffer3_length = cpu_to_le16(temp_len);
                        hwdesc->addr_buffer3 = cpu_to_le64(temp_dma);
                        break;
                case 3:
 -                      hwdesc->buffer4_length = cpu_to_le16(temp_len);
                        hwdesc->addr_buffer4 = cpu_to_le64(temp_dma);
                        break;
                }
@@@ -1526,7 -1388,7 +1523,7 @@@ static void netxen_nic_handle_phy_intr(
                linkup = (val == XG_LINK_UP_P3);
        } else {
                val = adapter->pci_read_normalize(adapter, CRB_XG_STATE);
 -              if (adapter->ahw.board_type == NETXEN_NIC_GBE)
 +              if (adapter->ahw.port_type == NETXEN_NIC_GBE)
                        linkup = (val >> port) & 1;
                else {
                        val = (val >> port*8) & 0xff;
@@@ -1593,11 -1455,13 +1590,11 @@@ static void netxen_tx_timeout_task(stru
        printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
               netxen_nic_driver_name, adapter->netdev->name);
  
 -      netxen_nic_disable_int(adapter);
 -      napi_disable(&adapter->napi);
 +      netxen_napi_disable(adapter);
  
        adapter->netdev->trans_start = jiffies;
  
 -      napi_enable(&adapter->napi);
 -      netxen_nic_enable_int(adapter);
 +      netxen_napi_enable(adapter);
        netif_wake_queue(adapter->netdev);
  }
  
@@@ -1635,8 -1499,7 +1632,8 @@@ struct net_device_stats *netxen_nic_get
  
  static irqreturn_t netxen_intr(int irq, void *data)
  {
 -      struct netxen_adapter *adapter = data;
 +      struct nx_host_sds_ring *sds_ring = data;
 +      struct netxen_adapter *adapter = sds_ring->adapter;
        u32 status = 0;
  
        status = adapter->pci_read_immediate(adapter, ISR_INT_VECTOR);
  
        /* clear interrupt */
        if (adapter->fw_major < 4)
 -              netxen_nic_disable_int(adapter);
 +              netxen_nic_disable_int(sds_ring);
  
        adapter->pci_write_immediate(adapter,
                        adapter->legacy_intr.tgt_status_reg,
        adapter->pci_read_immediate(adapter, ISR_INT_VECTOR);
        adapter->pci_read_immediate(adapter, ISR_INT_VECTOR);
  
 -      napi_schedule(&adapter->napi);
 +      napi_schedule(&sds_ring->napi);
  
        return IRQ_HANDLED;
  }
  
  static irqreturn_t netxen_msi_intr(int irq, void *data)
  {
 -      struct netxen_adapter *adapter = data;
 +      struct nx_host_sds_ring *sds_ring = data;
 +      struct netxen_adapter *adapter = sds_ring->adapter;
  
        /* clear interrupt */
        adapter->pci_write_immediate(adapter,
                        msi_tgt_status[adapter->ahw.pci_func], 0xffffffff);
  
 -      napi_schedule(&adapter->napi);
 +      napi_schedule(&sds_ring->napi);
        return IRQ_HANDLED;
  }
  
  static irqreturn_t netxen_msix_intr(int irq, void *data)
  {
 -      struct netxen_adapter *adapter = data;
 +      struct nx_host_sds_ring *sds_ring = data;
  
 -      napi_schedule(&adapter->napi);
 +      napi_schedule(&sds_ring->napi);
        return IRQ_HANDLED;
  }
  
  static int netxen_nic_poll(struct napi_struct *napi, int budget)
  {
 -      struct netxen_adapter *adapter = container_of(napi, struct netxen_adapter, napi);
 +      struct nx_host_sds_ring *sds_ring =
 +              container_of(napi, struct nx_host_sds_ring, napi);
 +
 +      struct netxen_adapter *adapter = sds_ring->adapter;
 +
        int tx_complete;
 -      int ctx;
        int work_done;
  
        tx_complete = netxen_process_cmd_ring(adapter);
  
 -      work_done = 0;
 -      for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
 -              /*
 -               * Fairness issue. This will give undue weight to the
 -               * receive context 0.
 -               */
 -
 -              /*
 -               * To avoid starvation, we give each of our receivers,
 -               * a fraction of the quota. Sometimes, it might happen that we
 -               * have enough quota to process every packet, but since all the
 -               * packets are on one context, it gets only half of the quota,
 -               * and ends up not processing it.
 -               */
 -              work_done += netxen_process_rcv_ring(adapter, ctx,
 -                                                   budget / MAX_RCV_CTX);
 -      }
 +      work_done = netxen_process_rcv_ring(sds_ring, budget);
  
        if ((work_done < budget) && tx_complete) {
 -              netif_rx_complete(&adapter->napi);
 -              netxen_nic_enable_int(adapter);
 +              napi_complete(&sds_ring->napi);
 +              netxen_nic_enable_int(sds_ring);
        }
  
        return work_done;
@@@ -1738,17 -1613,13 +1735,17 @@@ static struct pci_driver netxen_driver 
        .name = netxen_nic_driver_name,
        .id_table = netxen_pci_tbl,
        .probe = netxen_nic_probe,
 -      .remove = __devexit_p(netxen_nic_remove)
 +      .remove = __devexit_p(netxen_nic_remove),
 +      .suspend = netxen_nic_suspend,
 +      .resume = netxen_nic_resume
  };
  
  /* Driver Registration on NetXen card    */
  
  static int __init netxen_init_module(void)
  {
 +      printk(KERN_INFO "%s\n", netxen_nic_driver_string);
 +
        if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL)
                return -ENOMEM;
  
index b91b700a081b0053b81e056aaa5b95b4ce818c55,91191f761fbaae3ae1bc15c0d9a05560c885b3da..170d3540f9c9fb7185d66c9c0af5ce872a3f66e5
@@@ -58,8 -58,8 +58,8 @@@ static const u32 default_msg 
      NETIF_MSG_IFUP |
      NETIF_MSG_RX_ERR |
      NETIF_MSG_TX_ERR |
 -    NETIF_MSG_TX_QUEUED |
 -    NETIF_MSG_INTR | NETIF_MSG_TX_DONE | NETIF_MSG_RX_STATUS |
 +/*  NETIF_MSG_TX_QUEUED | */
 +/*  NETIF_MSG_INTR | NETIF_MSG_TX_DONE | NETIF_MSG_RX_STATUS | */
  /* NETIF_MSG_PKTDATA | */
      NETIF_MSG_HW | NETIF_MSG_WOL | 0;
  
@@@ -75,8 -75,7 +75,8 @@@ module_param(irq_type, int, MSIX_IRQ)
  MODULE_PARM_DESC(irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy.");
  
  static struct pci_device_id qlge_pci_tbl[] __devinitdata = {
 -      {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID)},
 +      {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)},
 +      {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)},
        /* required last entry */
        {0,}
  };
@@@ -248,6 -247,9 +248,6 @@@ int ql_get_mac_addr_reg(struct ql_adapt
        u32 offset = 0;
        int status;
  
 -      status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
 -      if (status)
 -              return status;
        switch (type) {
        case MAC_ADDR_TYPE_MULTI_MAC:
        case MAC_ADDR_TYPE_CAM_MAC:
                status = -EPERM;
        }
  exit:
 -      ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
        return status;
  }
  
@@@ -318,6 -321,9 +318,6 @@@ static int ql_set_mac_addr_reg(struct q
        u32 offset = 0;
        int status = 0;
  
 -      status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
 -      if (status)
 -              return status;
        switch (type) {
        case MAC_ADDR_TYPE_MULTI_MAC:
        case MAC_ADDR_TYPE_CAM_MAC:
                            (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) |
                            (addr[5]);
  
 -                      QPRINTK(qdev, IFUP, INFO,
 +                      QPRINTK(qdev, IFUP, DEBUG,
                                "Adding %s address %pM"
                                " at index %d in the CAM.\n",
                                ((type ==
                status = -EPERM;
        }
  exit:
 -      ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
        return status;
  }
  
@@@ -419,6 -426,10 +419,6 @@@ int ql_get_routing_reg(struct ql_adapte
  {
        int status = 0;
  
 -      status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
 -      if (status)
 -              goto exit;
 -
        status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MW, 0);
        if (status)
                goto exit;
                goto exit;
        *value = ql_read32(qdev, RT_DATA);
  exit:
 -      ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
        return status;
  }
  
  static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask,
                              int enable)
  {
 -      int status;
 +      int status = -EINVAL; /* Return error if no mask match. */
        u32 value = 0;
  
 -      status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
 -      if (status)
 -              return status;
 -
        QPRINTK(qdev, IFUP, DEBUG,
                "%s %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s mask %s the routing reg.\n",
                (enable ? "Adding" : "Removing"),
                ql_write32(qdev, RT_DATA, enable ? mask : 0);
        }
  exit:
 -      ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
        return status;
  }
  
@@@ -587,6 -604,7 +587,6 @@@ u32 ql_enable_completion_interrupt(stru
  static u32 ql_disable_completion_interrupt(struct ql_adapter *qdev, u32 intr)
  {
        u32 var = 0;
 -      unsigned long hw_flags;
        struct intr_context *ctx;
  
        /* HW disables for us if we're MSIX multi interrupts and
                return 0;
  
        ctx = qdev->intr_context + intr;
 -      spin_lock_irqsave(&qdev->hw_lock, hw_flags);
 +      spin_lock(&qdev->hw_lock);
        if (!atomic_read(&ctx->irq_cnt)) {
                ql_write32(qdev, INTR_EN,
                ctx->intr_dis_mask);
                var = ql_read32(qdev, STS);
        }
        atomic_inc(&ctx->irq_cnt);
 -      spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
 +      spin_unlock(&qdev->hw_lock);
        return var;
  }
  
@@@ -623,28 -641,6 +623,28 @@@ static void ql_enable_all_completion_in
  
  }
  
 +static int ql_validate_flash(struct ql_adapter *qdev, u32 size, const char *str)
 +{
 +      int status, i;
 +      u16 csum = 0;
 +      __le16 *flash = (__le16 *)&qdev->flash;
 +
 +      status = strncmp((char *)&qdev->flash, str, 4);
 +      if (status) {
 +              QPRINTK(qdev, IFUP, ERR, "Invalid flash signature.\n");
 +              return  status;
 +      }
 +
 +      for (i = 0; i < size; i++)
 +              csum += le16_to_cpu(*flash++);
 +
 +      if (csum)
 +              QPRINTK(qdev, IFUP, ERR,
 +                      "Invalid flash checksum, csum = 0x%.04x.\n", csum);
 +
 +      return csum;
 +}
 +
  static int ql_read_flash_word(struct ql_adapter *qdev, int offset, __le32 *data)
  {
        int status = 0;
@@@ -669,75 -665,23 +669,75 @@@ exit
        return status;
  }
  
 -static int ql_get_flash_params(struct ql_adapter *qdev)
 +static int ql_get_8000_flash_params(struct ql_adapter *qdev)
 +{
 +      u32 i, size;
 +      int status;
 +      __le32 *p = (__le32 *)&qdev->flash;
 +      u32 offset;
 +
 +      /* Get flash offset for function and adjust
 +       * for dword access.
 +       */
 +      if (!qdev->func)
 +              offset = FUNC0_FLASH_OFFSET / sizeof(u32);
 +      else
 +              offset = FUNC1_FLASH_OFFSET / sizeof(u32);
 +
 +      if (ql_sem_spinlock(qdev, SEM_FLASH_MASK))
 +              return -ETIMEDOUT;
 +
 +      size = sizeof(struct flash_params_8000) / sizeof(u32);
 +      for (i = 0; i < size; i++, p++) {
 +              status = ql_read_flash_word(qdev, i+offset, p);
 +              if (status) {
 +                      QPRINTK(qdev, IFUP, ERR, "Error reading flash.\n");
 +                      goto exit;
 +              }
 +      }
 +
 +      status = ql_validate_flash(qdev,
 +                      sizeof(struct flash_params_8000) / sizeof(u16),
 +                      "8000");
 +      if (status) {
 +              QPRINTK(qdev, IFUP, ERR, "Invalid flash.\n");
 +              status = -EINVAL;
 +              goto exit;
 +      }
 +
 +      if (!is_valid_ether_addr(qdev->flash.flash_params_8000.mac_addr)) {
 +              QPRINTK(qdev, IFUP, ERR, "Invalid MAC address.\n");
 +              status = -EINVAL;
 +              goto exit;
 +      }
 +
 +      memcpy(qdev->ndev->dev_addr,
 +              qdev->flash.flash_params_8000.mac_addr,
 +              qdev->ndev->addr_len);
 +
 +exit:
 +      ql_sem_unlock(qdev, SEM_FLASH_MASK);
 +      return status;
 +}
 +
 +static int ql_get_8012_flash_params(struct ql_adapter *qdev)
  {
        int i;
        int status;
        __le32 *p = (__le32 *)&qdev->flash;
        u32 offset = 0;
 +      u32 size = sizeof(struct flash_params_8012) / sizeof(u32);
  
        /* Second function's parameters follow the first
         * function's.
         */
        if (qdev->func)
 -              offset = sizeof(qdev->flash) / sizeof(u32);
 +              offset = size;
  
        if (ql_sem_spinlock(qdev, SEM_FLASH_MASK))
                return -ETIMEDOUT;
  
 -      for (i = 0; i < sizeof(qdev->flash) / sizeof(u32); i++, p++) {
 +      for (i = 0; i < size; i++, p++) {
                status = ql_read_flash_word(qdev, i+offset, p);
                if (status) {
                        QPRINTK(qdev, IFUP, ERR, "Error reading flash.\n");
                }
  
        }
 +
 +      status = ql_validate_flash(qdev,
 +                      sizeof(struct flash_params_8012) / sizeof(u16),
 +                      "8012");
 +      if (status) {
 +              QPRINTK(qdev, IFUP, ERR, "Invalid flash.\n");
 +              status = -EINVAL;
 +              goto exit;
 +      }
 +
 +      if (!is_valid_ether_addr(qdev->flash.flash_params_8012.mac_addr)) {
 +              status = -EINVAL;
 +              goto exit;
 +      }
 +
 +      memcpy(qdev->ndev->dev_addr,
 +              qdev->flash.flash_params_8012.mac_addr,
 +              qdev->ndev->addr_len);
 +
  exit:
        ql_sem_unlock(qdev, SEM_FLASH_MASK);
        return status;
@@@ -834,25 -759,13 +834,25 @@@ exit
        return status;
  }
  
 +static int ql_8000_port_initialize(struct ql_adapter *qdev)
 +{
 +      int status;
 +      status = ql_mb_get_fw_state(qdev);
 +      if (status)
 +              goto exit;
 +      /* Wake up a worker to get/set the TX/RX frame sizes. */
 +      queue_delayed_work(qdev->workqueue, &qdev->mpi_port_cfg_work, 0);
 +exit:
 +      return status;
 +}
 +
  /* Take the MAC Core out of reset.
   * Enable statistics counting.
   * Take the transmitter/receiver out of reset.
   * This functionality may be done in the MPI firmware at a
   * later date.
   */
 -static int ql_port_initialize(struct ql_adapter *qdev)
 +static int ql_8012_port_initialize(struct ql_adapter *qdev)
  {
        int status = 0;
        u32 data;
@@@ -968,8 -881,7 +968,8 @@@ static void ql_write_cq_idx(struct rx_r
  /* Process (refill) a large buffer queue. */
  static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
  {
 -      int clean_idx = rx_ring->lbq_clean_idx;
 +      u32 clean_idx = rx_ring->lbq_clean_idx;
 +      u32 start_idx = clean_idx;
        struct bq_desc *lbq_desc;
        u64 map;
        int i;
                rx_ring->lbq_prod_idx += 16;
                if (rx_ring->lbq_prod_idx == rx_ring->lbq_len)
                        rx_ring->lbq_prod_idx = 0;
 +              rx_ring->lbq_free_cnt -= 16;
 +      }
 +
 +      if (start_idx != clean_idx) {
                QPRINTK(qdev, RX_STATUS, DEBUG,
                        "lbq: updating prod idx = %d.\n",
                        rx_ring->lbq_prod_idx);
                ql_write_db_reg(rx_ring->lbq_prod_idx,
                                rx_ring->lbq_prod_idx_db_reg);
 -              rx_ring->lbq_free_cnt -= 16;
        }
  }
  
  /* Process (refill) a small buffer queue. */
  static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
  {
 -      int clean_idx = rx_ring->sbq_clean_idx;
 +      u32 clean_idx = rx_ring->sbq_clean_idx;
 +      u32 start_idx = clean_idx;
        struct bq_desc *sbq_desc;
        u64 map;
        int i;
                rx_ring->sbq_prod_idx += 16;
                if (rx_ring->sbq_prod_idx == rx_ring->sbq_len)
                        rx_ring->sbq_prod_idx = 0;
 +              rx_ring->sbq_free_cnt -= 16;
 +      }
 +
 +      if (start_idx != clean_idx) {
                QPRINTK(qdev, RX_STATUS, DEBUG,
                        "sbq: updating prod idx = %d.\n",
                        rx_ring->sbq_prod_idx);
                ql_write_db_reg(rx_ring->sbq_prod_idx,
                                rx_ring->sbq_prod_idx_db_reg);
 -
 -              rx_ring->sbq_free_cnt -= 16;
        }
  }
  
@@@ -1506,8 -1412,6 +1506,8 @@@ static void ql_process_mac_rx_intr(stru
  {
        struct net_device *ndev = qdev->ndev;
        struct sk_buff *skb = NULL;
 +      u16 vlan_id = (le16_to_cpu(ib_mac_rsp->vlan_id) &
 +                      IB_MAC_IOCB_RSP_VLAN_MASK)
  
        QL_DUMP_IB_MAC_RSP(ib_mac_rsp);
  
                QPRINTK(qdev, RX_STATUS, DEBUG, "Promiscuous Packet.\n");
        }
  
        skb->protocol = eth_type_trans(skb, ndev);
        skb->ip_summed = CHECKSUM_NONE;
  
                        }
                }
        }
 +
        qdev->stats.rx_packets++;
        qdev->stats.rx_bytes += skb->len;
 -      skb->protocol = eth_type_trans(skb, ndev);
 -      if (qdev->vlgrp && (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V)) {
 -              QPRINTK(qdev, RX_STATUS, DEBUG,
 -                      "Passing a VLAN packet upstream.\n");
 -              vlan_hwaccel_receive_skb(skb, qdev->vlgrp,
 -                              le16_to_cpu(ib_mac_rsp->vlan_id));
 +      skb_record_rx_queue(skb,
 +              rx_ring->cq_id - qdev->rss_ring_first_cq_id);
 +      if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
 +              if (qdev->vlgrp &&
 +                      (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) &&
 +                      (vlan_id != 0))
 +                      vlan_gro_receive(&rx_ring->napi, qdev->vlgrp,
 +                              vlan_id, skb);
 +              else
 +                      napi_gro_receive(&rx_ring->napi, skb);
        } else {
 -              QPRINTK(qdev, RX_STATUS, DEBUG,
 -                      "Passing a normal packet upstream.\n");
 -              netif_receive_skb(skb);
 +              if (qdev->vlgrp &&
 +                      (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) &&
 +                      (vlan_id != 0))
 +                      vlan_hwaccel_receive_skb(skb, qdev->vlgrp, vlan_id);
 +              else
 +                      netif_receive_skb(skb);
        }
  }
  
@@@ -1626,12 -1521,14 +1625,12 @@@ static void ql_process_mac_tx_intr(stru
  /* Fire up a handler to reset the MPI processor. */
  void ql_queue_fw_error(struct ql_adapter *qdev)
  {
 -      netif_stop_queue(qdev->ndev);
        netif_carrier_off(qdev->ndev);
        queue_delayed_work(qdev->workqueue, &qdev->mpi_reset_work, 0);
  }
  
  void ql_queue_asic_error(struct ql_adapter *qdev)
  {
 -      netif_stop_queue(qdev->ndev);
        netif_carrier_off(qdev->ndev);
        ql_disable_interrupts(qdev);
        /* Clear adapter up bit to signal the recovery
@@@ -1686,7 -1583,6 +1685,7 @@@ static int ql_clean_outbound_rx_ring(st
        struct ob_mac_iocb_rsp *net_rsp = NULL;
        int count = 0;
  
 +      struct tx_ring *tx_ring;
        /* While there are entries in the completion queue. */
        while (prod != rx_ring->cnsmr_idx) {
  
                prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
        }
        ql_write_cq_idx(rx_ring);
 -      if (netif_queue_stopped(qdev->ndev) && net_rsp != NULL) {
 -              struct tx_ring *tx_ring = &qdev->tx_ring[net_rsp->txq_idx];
 +      tx_ring = &qdev->tx_ring[net_rsp->txq_idx];
 +      if (__netif_subqueue_stopped(qdev->ndev, tx_ring->wq_id) &&
 +                                      net_rsp != NULL) {
                if (atomic_read(&tx_ring->queue_stopped) &&
                    (atomic_read(&tx_ring->tx_count) > (tx_ring->wq_len / 4)))
                        /*
                         * The queue got stopped because the tx_ring was full.
                         * Wake it up, because it's now at least 25% empty.
                         */
 -                      netif_wake_queue(qdev->ndev);
 +                      netif_wake_subqueue(qdev->ndev, tx_ring->wq_id);
        }
  
        return count;
@@@ -1782,7 -1677,7 +1781,7 @@@ static int ql_napi_poll_msix(struct nap
                rx_ring->cq_id);
  
        if (work_done < budget) {
 -              __netif_rx_complete(napi);
 +              napi_complete(napi);
                ql_enable_completion_interrupt(qdev, rx_ring->irq);
        }
        return work_done;
@@@ -1808,29 -1703,19 +1807,29 @@@ static void ql_vlan_rx_add_vid(struct n
  {
        struct ql_adapter *qdev = netdev_priv(ndev);
        u32 enable_bit = MAC_ADDR_E;
 +      int status;
  
 +      status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
 +      if (status)
 +              return;
        spin_lock(&qdev->hw_lock);
        if (ql_set_mac_addr_reg
            (qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) {
                QPRINTK(qdev, IFUP, ERR, "Failed to init vlan address.\n");
        }
        spin_unlock(&qdev->hw_lock);
 +      ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
  }
  
  static void ql_vlan_rx_kill_vid(struct net_device *ndev, u16 vid)
  {
        struct ql_adapter *qdev = netdev_priv(ndev);
        u32 enable_bit = 0;
 +      int status;
 +
 +      status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
 +      if (status)
 +              return;
  
        spin_lock(&qdev->hw_lock);
        if (ql_set_mac_addr_reg
                QPRINTK(qdev, IFUP, ERR, "Failed to clear vlan address.\n");
        }
        spin_unlock(&qdev->hw_lock);
 +      ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
  
  }
  
@@@ -1878,7 -1762,7 +1877,7 @@@ static irqreturn_t qlge_msix_tx_isr(in
  static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id)
  {
        struct rx_ring *rx_ring = dev_id;
 -      netif_rx_schedule(&rx_ring->napi);
 +      napi_schedule(&rx_ring->napi);
        return IRQ_HANDLED;
  }
  
@@@ -1964,7 -1848,7 +1963,7 @@@ static irqreturn_t qlge_isr(int irq, vo
                                                              &rx_ring->rx_work,
                                                              0);
                                else
 -                                      netif_rx_schedule(&rx_ring->napi);
 +                                      napi_schedule(&rx_ring->napi);
                                work_done++;
                        }
                }
@@@ -2053,7 -1937,7 +2052,7 @@@ static int qlge_send(struct sk_buff *sk
        struct ql_adapter *qdev = netdev_priv(ndev);
        int tso;
        struct tx_ring *tx_ring;
 -      u32 tx_ring_idx = (u32) QL_TXQ_IDX(qdev, skb);
 +      u32 tx_ring_idx = (u32) skb->queue_mapping;
  
        tx_ring = &qdev->tx_ring[tx_ring_idx];
  
                QPRINTK(qdev, TX_QUEUED, INFO,
                        "%s: shutting down tx queue %d du to lack of resources.\n",
                        __func__, tx_ring_idx);
 -              netif_stop_queue(ndev);
 +              netif_stop_subqueue(ndev, tx_ring->wq_id);
                atomic_inc(&tx_ring->queue_stopped);
                return NETDEV_TX_BUSY;
        }
@@@ -2145,7 -2029,6 +2144,7 @@@ static int ql_alloc_shadow_space(struc
                        "Allocation of RX shadow space failed.\n");
                return -ENOMEM;
        }
 +      memset(qdev->rx_ring_shadow_reg_area, 0, PAGE_SIZE);
        qdev->tx_ring_shadow_reg_area =
            pci_alloc_consistent(qdev->pdev, PAGE_SIZE,
                                 &qdev->tx_ring_shadow_reg_dma);
                        "Allocation of TX shadow space failed.\n");
                goto err_wqp_sh_area;
        }
 +      memset(qdev->tx_ring_shadow_reg_area, 0, PAGE_SIZE);
        return 0;
  
  err_wqp_sh_area:
@@@ -2239,6 -2121,47 +2238,6 @@@ static void ql_free_lbq_buffers(struct 
        }
  }
  
 -/*
 - * Allocate and map a page for each element of the lbq.
 - */
 -static int ql_alloc_lbq_buffers(struct ql_adapter *qdev,
 -                              struct rx_ring *rx_ring)
 -{
 -      int i;
 -      struct bq_desc *lbq_desc;
 -      u64 map;
 -      __le64 *bq = rx_ring->lbq_base;
 -
 -      for (i = 0; i < rx_ring->lbq_len; i++) {
 -              lbq_desc = &rx_ring->lbq[i];
 -              memset(lbq_desc, 0, sizeof(lbq_desc));
 -              lbq_desc->addr = bq;
 -              lbq_desc->index = i;
 -              lbq_desc->p.lbq_page = alloc_page(GFP_ATOMIC);
 -              if (unlikely(!lbq_desc->p.lbq_page)) {
 -                      QPRINTK(qdev, IFUP, ERR, "failed alloc_page().\n");
 -                      goto mem_error;
 -              } else {
 -                      map = pci_map_page(qdev->pdev,
 -                                         lbq_desc->p.lbq_page,
 -                                         0, PAGE_SIZE, PCI_DMA_FROMDEVICE);
 -                      if (pci_dma_mapping_error(qdev->pdev, map)) {
 -                              QPRINTK(qdev, IFUP, ERR,
 -                                      "PCI mapping failed.\n");
 -                              goto mem_error;
 -                      }
 -                      pci_unmap_addr_set(lbq_desc, mapaddr, map);
 -                      pci_unmap_len_set(lbq_desc, maplen, PAGE_SIZE);
 -                      *lbq_desc->addr = cpu_to_le64(map);
 -              }
 -              bq++;
 -      }
 -      return 0;
 -mem_error:
 -      ql_free_lbq_buffers(qdev, rx_ring);
 -      return -ENOMEM;
 -}
 -
  static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring)
  {
        int i;
        }
  }
  
 -/* Allocate and map an skb for each element of the sbq. */
 -static int ql_alloc_sbq_buffers(struct ql_adapter *qdev,
 +/* Free all large and small rx buffers associated
 + * with the completion queues for this device.
 + */
 +static void ql_free_rx_buffers(struct ql_adapter *qdev)
 +{
 +      int i;
 +      struct rx_ring *rx_ring;
 +
 +      for (i = 0; i < qdev->rx_ring_count; i++) {
 +              rx_ring = &qdev->rx_ring[i];
 +              if (rx_ring->lbq)
 +                      ql_free_lbq_buffers(qdev, rx_ring);
 +              if (rx_ring->sbq)
 +                      ql_free_sbq_buffers(qdev, rx_ring);
 +      }
 +}
 +
 +static void ql_alloc_rx_buffers(struct ql_adapter *qdev)
 +{
 +      struct rx_ring *rx_ring;
 +      int i;
 +
 +      for (i = 0; i < qdev->rx_ring_count; i++) {
 +              rx_ring = &qdev->rx_ring[i];
 +              if (rx_ring->type != TX_Q)
 +                      ql_update_buffer_queues(qdev, rx_ring);
 +      }
 +}
 +
 +static void ql_init_lbq_ring(struct ql_adapter *qdev,
 +                              struct rx_ring *rx_ring)
 +{
 +      int i;
 +      struct bq_desc *lbq_desc;
 +      __le64 *bq = rx_ring->lbq_base;
 +
 +      memset(rx_ring->lbq, 0, rx_ring->lbq_len * sizeof(struct bq_desc));
 +      for (i = 0; i < rx_ring->lbq_len; i++) {
 +              lbq_desc = &rx_ring->lbq[i];
 +              memset(lbq_desc, 0, sizeof(*lbq_desc));
 +              lbq_desc->index = i;
 +              lbq_desc->addr = bq;
 +              bq++;
 +      }
 +}
 +
 +static void ql_init_sbq_ring(struct ql_adapter *qdev,
                                struct rx_ring *rx_ring)
  {
        int i;
        struct bq_desc *sbq_desc;
 -      struct sk_buff *skb;
 -      u64 map;
        __le64 *bq = rx_ring->sbq_base;
  
 +      memset(rx_ring->sbq, 0, rx_ring->sbq_len * sizeof(struct bq_desc));
        for (i = 0; i < rx_ring->sbq_len; i++) {
                sbq_desc = &rx_ring->sbq[i];
 -              memset(sbq_desc, 0, sizeof(sbq_desc));
 +              memset(sbq_desc, 0, sizeof(*sbq_desc));
                sbq_desc->index = i;
                sbq_desc->addr = bq;
 -              skb = netdev_alloc_skb(qdev->ndev, rx_ring->sbq_buf_size);
 -              if (unlikely(!skb)) {
 -                      /* Better luck next round */
 -                      QPRINTK(qdev, IFUP, ERR,
 -                              "small buff alloc failed for %d bytes at index %d.\n",
 -                              rx_ring->sbq_buf_size, i);
 -                      goto mem_err;
 -              }
 -              skb_reserve(skb, QLGE_SB_PAD);
 -              sbq_desc->p.skb = skb;
 -              /*
 -               * Map only half the buffer. Because the
 -               * other half may get some data copied to it
 -               * when the completion arrives.
 -               */
 -              map = pci_map_single(qdev->pdev,
 -                                   skb->data,
 -                                   rx_ring->sbq_buf_size / 2,
 -                                   PCI_DMA_FROMDEVICE);
 -              if (pci_dma_mapping_error(qdev->pdev, map)) {
 -                      QPRINTK(qdev, IFUP, ERR, "PCI mapping failed.\n");
 -                      goto mem_err;
 -              }
 -              pci_unmap_addr_set(sbq_desc, mapaddr, map);
 -              pci_unmap_len_set(sbq_desc, maplen, rx_ring->sbq_buf_size / 2);
 -              *sbq_desc->addr = cpu_to_le64(map);
                bq++;
        }
 -      return 0;
 -mem_err:
 -      ql_free_sbq_buffers(qdev, rx_ring);
 -      return -ENOMEM;
  }
  
  static void ql_free_rx_resources(struct ql_adapter *qdev,
                                 struct rx_ring *rx_ring)
  {
 -      if (rx_ring->sbq_len)
 -              ql_free_sbq_buffers(qdev, rx_ring);
 -      if (rx_ring->lbq_len)
 -              ql_free_lbq_buffers(qdev, rx_ring);
 -
        /* Free the small buffer queue. */
        if (rx_ring->sbq_base) {
                pci_free_consistent(qdev->pdev,
@@@ -2404,7 -2318,11 +2403,7 @@@ static int ql_alloc_rx_resources(struc
                        goto err_mem;
                }
  
 -              if (ql_alloc_sbq_buffers(qdev, rx_ring)) {
 -                      QPRINTK(qdev, IFUP, ERR,
 -                              "Small buffer allocation failed.\n");
 -                      goto err_mem;
 -              }
 +              ql_init_sbq_ring(qdev, rx_ring);
        }
  
        if (rx_ring->lbq_len) {
                        goto err_mem;
                }
  
 -              /*
 -               * Allocate the buffers.
 -               */
 -              if (ql_alloc_lbq_buffers(qdev, rx_ring)) {
 -                      QPRINTK(qdev, IFUP, ERR,
 -                              "Large buffer allocation failed.\n");
 -                      goto err_mem;
 -              }
 +              ql_init_lbq_ring(qdev, rx_ring);
        }
  
        return 0;
@@@ -2526,7 -2451,6 +2525,7 @@@ static int ql_start_rx_ring(struct ql_a
            qdev->doorbell_area + (DB_PAGE_SIZE * (128 + rx_ring->cq_id));
        int err = 0;
        u16 bq_len;
 +      u64 tmp;
  
        /* Set up the shadow registers for this ring. */
        rx_ring->prod_idx_sh_reg = shadow_reg;
            FLAGS_LI;           /* Load irq delay values */
        if (rx_ring->lbq_len) {
                cqicb->flags |= FLAGS_LL;       /* Load lbq values */
 -              *((u64 *) rx_ring->lbq_base_indirect) = rx_ring->lbq_base_dma;
 +              tmp = (u64)rx_ring->lbq_base_dma;;
 +              *((__le64 *) rx_ring->lbq_base_indirect) = cpu_to_le64(tmp);
                cqicb->lbq_addr =
                    cpu_to_le64(rx_ring->lbq_base_indirect_dma);
                bq_len = (rx_ring->lbq_buf_size == 65536) ? 0 :
                bq_len = (rx_ring->lbq_len == 65536) ? 0 :
                        (u16) rx_ring->lbq_len;
                cqicb->lbq_len = cpu_to_le16(bq_len);
 -              rx_ring->lbq_prod_idx = rx_ring->lbq_len - 16;
 +              rx_ring->lbq_prod_idx = 0;
                rx_ring->lbq_curr_idx = 0;
 -              rx_ring->lbq_clean_idx = rx_ring->lbq_prod_idx;
 -              rx_ring->lbq_free_cnt = 16;
 +              rx_ring->lbq_clean_idx = 0;
 +              rx_ring->lbq_free_cnt = rx_ring->lbq_len;
        }
        if (rx_ring->sbq_len) {
                cqicb->flags |= FLAGS_LS;       /* Load sbq values */
 -              *((u64 *) rx_ring->sbq_base_indirect) = rx_ring->sbq_base_dma;
 +              tmp = (u64)rx_ring->sbq_base_dma;;
 +              *((__le64 *) rx_ring->sbq_base_indirect) = cpu_to_le64(tmp);
                cqicb->sbq_addr =
                    cpu_to_le64(rx_ring->sbq_base_indirect_dma);
                cqicb->sbq_buf_size =
 -                  cpu_to_le16(((rx_ring->sbq_buf_size / 2) + 8) & 0xfffffff8);
 +                  cpu_to_le16((u16)(rx_ring->sbq_buf_size/2));
                bq_len = (rx_ring->sbq_len == 65536) ? 0 :
                        (u16) rx_ring->sbq_len;
                cqicb->sbq_len = cpu_to_le16(bq_len);
 -              rx_ring->sbq_prod_idx = rx_ring->sbq_len - 16;
 +              rx_ring->sbq_prod_idx = 0;
                rx_ring->sbq_curr_idx = 0;
 -              rx_ring->sbq_clean_idx = rx_ring->sbq_prod_idx;
 -              rx_ring->sbq_free_cnt = 16;
 +              rx_ring->sbq_clean_idx = 0;
 +              rx_ring->sbq_free_cnt = rx_ring->sbq_len;
        }
        switch (rx_ring->type) {
        case TX_Q:
                QPRINTK(qdev, IFUP, DEBUG, "Invalid rx_ring->type = %d.\n",
                        rx_ring->type);
        }
 -      QPRINTK(qdev, IFUP, INFO, "Initializing rx work queue.\n");
 +      QPRINTK(qdev, IFUP, DEBUG, "Initializing rx work queue.\n");
        err = ql_write_cfg(qdev, cqicb, sizeof(struct cqicb),
                           CFG_LCQ, rx_ring->cq_id);
        if (err) {
                QPRINTK(qdev, IFUP, ERR, "Failed to load CQICB.\n");
                return err;
        }
 -      QPRINTK(qdev, IFUP, INFO, "Successfully loaded CQICB.\n");
 -      /*
 -       * Advance the producer index for the buffer queues.
 -       */
 -      wmb();
 -      if (rx_ring->lbq_len)
 -              ql_write_db_reg(rx_ring->lbq_prod_idx,
 -                              rx_ring->lbq_prod_idx_db_reg);
 -      if (rx_ring->sbq_len)
 -              ql_write_db_reg(rx_ring->sbq_prod_idx,
 -                              rx_ring->sbq_prod_idx_db_reg);
        return err;
  }
  
@@@ -2700,7 -2633,7 +2699,7 @@@ static int ql_start_tx_ring(struct ql_a
                QPRINTK(qdev, IFUP, ERR, "Failed to load tx_ring.\n");
                return err;
        }
 -      QPRINTK(qdev, IFUP, INFO, "Successfully loaded WQICB.\n");
 +      QPRINTK(qdev, IFUP, DEBUG, "Successfully loaded WQICB.\n");
        return err;
  }
  
@@@ -2742,7 -2675,7 +2741,7 @@@ static void ql_enable_msix(struct ql_ad
                    (qdev->pdev, qdev->msi_x_entry, qdev->rx_ring_count)) {
                        set_bit(QL_MSIX_ENABLED, &qdev->flags);
                        qdev->intr_count = qdev->rx_ring_count;
 -                      QPRINTK(qdev, IFUP, INFO,
 +                      QPRINTK(qdev, IFUP, DEBUG,
                                "MSI-X Enabled, got %d vectors.\n",
                                qdev->intr_count);
                        return;
@@@ -2869,11 -2802,11 +2868,11 @@@ static void ql_free_irq(struct ql_adapt
                        if (test_bit(QL_MSIX_ENABLED, &qdev->flags)) {
                                free_irq(qdev->msi_x_entry[i].vector,
                                         &qdev->rx_ring[i]);
 -                              QPRINTK(qdev, IFDOWN, ERR,
 +                              QPRINTK(qdev, IFDOWN, DEBUG,
                                        "freeing msix interrupt %d.\n", i);
                        } else {
                                free_irq(qdev->pdev->irq, &qdev->rx_ring[0]);
 -                              QPRINTK(qdev, IFDOWN, ERR,
 +                              QPRINTK(qdev, IFDOWN, DEBUG,
                                        "freeing msi interrupt %d.\n", i);
                        }
                }
@@@ -2904,7 -2837,7 +2903,7 @@@ static int ql_request_irq(struct ql_ada
                                        i);
                                goto err_irq;
                        } else {
 -                              QPRINTK(qdev, IFUP, INFO,
 +                              QPRINTK(qdev, IFUP, DEBUG,
                                        "Hooked intr %d, queue type %s%s%s, with name %s.\n",
                                        i,
                                        qdev->rx_ring[i].type ==
@@@ -2979,14 -2912,14 +2978,14 @@@ static int ql_start_rss(struct ql_adapt
        get_random_bytes((void *)&ricb->ipv6_hash_key[0], 40);
        get_random_bytes((void *)&ricb->ipv4_hash_key[0], 16);
  
 -      QPRINTK(qdev, IFUP, INFO, "Initializing RSS.\n");
 +      QPRINTK(qdev, IFUP, DEBUG, "Initializing RSS.\n");
  
        status = ql_write_cfg(qdev, ricb, sizeof(ricb), CFG_LR, 0);
        if (status) {
                QPRINTK(qdev, IFUP, ERR, "Failed to load RICB.\n");
                return status;
        }
 -      QPRINTK(qdev, IFUP, INFO, "Successfully loaded RICB.\n");
 +      QPRINTK(qdev, IFUP, DEBUG, "Successfully loaded RICB.\n");
        return status;
  }
  
@@@ -2996,17 -2929,13 +2995,17 @@@ static int ql_route_initialize(struct q
        int status = 0;
        int i;
  
 +      status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
 +      if (status)
 +              return status;
 +
        /* Clear all the entries in the routing table. */
        for (i = 0; i < 16; i++) {
                status = ql_set_routing_reg(qdev, i, 0, 0);
                if (status) {
                        QPRINTK(qdev, IFUP, ERR,
                                "Failed to init routing register for CAM packets.\n");
 -                      return status;
 +                      goto exit;
                }
        }
  
        if (status) {
                QPRINTK(qdev, IFUP, ERR,
                        "Failed to init routing register for error packets.\n");
 -              return status;
 +              goto exit;
        }
        status = ql_set_routing_reg(qdev, RT_IDX_BCAST_SLOT, RT_IDX_BCAST, 1);
        if (status) {
                QPRINTK(qdev, IFUP, ERR,
                        "Failed to init routing register for broadcast packets.\n");
 -              return status;
 +              goto exit;
        }
        /* If we have more than one inbound queue, then turn on RSS in the
         * routing block.
                if (status) {
                        QPRINTK(qdev, IFUP, ERR,
                                "Failed to init routing register for MATCH RSS packets.\n");
 -                      return status;
 +                      goto exit;
                }
        }
  
        status = ql_set_routing_reg(qdev, RT_IDX_CAM_HIT_SLOT,
                                    RT_IDX_CAM_HIT, 1);
 -      if (status) {
 +      if (status)
                QPRINTK(qdev, IFUP, ERR,
                        "Failed to init routing register for CAM packets.\n");
 +exit:
 +      ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
 +      return status;
 +}
 +
 +int ql_cam_route_initialize(struct ql_adapter *qdev)
 +{
 +      int status;
 +
 +      status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
 +      if (status)
 +              return status;
 +      status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr,
 +                           MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ);
 +      ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
 +      if (status) {
 +              QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n");
                return status;
        }
 +
 +      status = ql_route_initialize(qdev);
 +      if (status)
 +              QPRINTK(qdev, IFUP, ERR, "Failed to init routing table.\n");
 +
        return status;
  }
  
@@@ -3131,24 -3038,28 +3130,24 @@@ static int ql_adapter_initialize(struc
                }
        }
  
 -      status = ql_port_initialize(qdev);
 -      if (status) {
 -              QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n");
 -              return status;
 -      }
 +      /* Initialize the port and set the max framesize. */
 +      status = qdev->nic_ops->port_initialize(qdev);
 +       if (status) {
 +              QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n");
 +              return status;
 +       }
  
 -      status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr,
 -                                   MAC_ADDR_TYPE_CAM_MAC, qdev->func);
 +      /* Set up the MAC address and frame routing filter. */
 +      status = ql_cam_route_initialize(qdev);
        if (status) {
 -              QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n");
 -              return status;
 -      }
 -
 -      status = ql_route_initialize(qdev);
 -      if (status) {
 -              QPRINTK(qdev, IFUP, ERR, "Failed to init routing table.\n");
 +              QPRINTK(qdev, IFUP, ERR,
 +                              "Failed to init CAM/Routing tables.\n");
                return status;
        }
  
        /* Start NAPI for the RSS queues. */
        for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++) {
 -              QPRINTK(qdev, IFUP, INFO, "Enabling NAPI for rx_ring[%d].\n",
 +              QPRINTK(qdev, IFUP, DEBUG, "Enabling NAPI for rx_ring[%d].\n",
                        i);
                napi_enable(&qdev->rx_ring[i].napi);
        }
  static int ql_adapter_reset(struct ql_adapter *qdev)
  {
        u32 value;
 -      int max_wait_time;
        int status = 0;
 -      int resetCnt = 0;
 +      unsigned long end_jiffies = jiffies +
 +              max((unsigned long)1, usecs_to_jiffies(30));
  
 -#define MAX_RESET_CNT   1
 -issueReset:
 -      resetCnt++;
 -      QPRINTK(qdev, IFDOWN, DEBUG, "Issue soft reset to chip.\n");
        ql_write32(qdev, RST_FO, (RST_FO_FR << 16) | RST_FO_FR);
 -      /* Wait for reset to complete. */
 -      max_wait_time = 3;
 -      QPRINTK(qdev, IFDOWN, DEBUG, "Wait %d seconds for reset to complete.\n",
 -              max_wait_time);
 +
        do {
                value = ql_read32(qdev, RST_FO);
                if ((value & RST_FO_FR) == 0)
                        break;
 +              cpu_relax();
 +      } while (time_before(jiffies, end_jiffies));
  
 -              ssleep(1);
 -      } while ((--max_wait_time));
        if (value & RST_FO_FR) {
 -              QPRINTK(qdev, IFDOWN, ERR,
 -                      "Stuck in SoftReset:  FSC_SR:0x%08x\n", value);
 -              if (resetCnt < MAX_RESET_CNT)
 -                      goto issueReset;
 -      }
 -      if (max_wait_time == 0) {
 -              status = -ETIMEDOUT;
                QPRINTK(qdev, IFDOWN, ERR,
                        "ETIMEOUT!!! errored out of resetting the chip!\n");
 +              status = -ETIMEDOUT;
        }
  
        return status;
@@@ -3199,10 -3123,12 +3198,10 @@@ static void ql_display_dev_info(struct 
  
  static int ql_adapter_down(struct ql_adapter *qdev)
  {
 -      struct net_device *ndev = qdev->ndev;
        int i, status = 0;
        struct rx_ring *rx_ring;
  
 -      netif_stop_queue(ndev);
 -      netif_carrier_off(ndev);
 +      netif_carrier_off(qdev->ndev);
  
        /* Don't kill the reset worker thread if we
         * are in the process of recovery.
                cancel_delayed_work_sync(&qdev->asic_reset_work);
        cancel_delayed_work_sync(&qdev->mpi_reset_work);
        cancel_delayed_work_sync(&qdev->mpi_work);
 +      cancel_delayed_work_sync(&qdev->mpi_idc_work);
 +      cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
  
        /* The default queue at index 0 is always processed in
         * a workqueue.
        for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++)
                netif_napi_del(&qdev->rx_ring[i].napi);
  
 +      ql_free_rx_buffers(qdev);
++
        spin_lock(&qdev->hw_lock);
        status = ql_adapter_reset(qdev);
        if (status)
@@@ -3261,19 -3184,21 +3261,19 @@@ static int ql_adapter_up(struct ql_adap
  {
        int err = 0;
  
 -      spin_lock(&qdev->hw_lock);
        err = ql_adapter_initialize(qdev);
        if (err) {
                QPRINTK(qdev, IFUP, INFO, "Unable to initialize adapter.\n");
                spin_unlock(&qdev->hw_lock);
                goto err_init;
        }
 -      spin_unlock(&qdev->hw_lock);
        set_bit(QL_ADAPTER_UP, &qdev->flags);
 +      ql_alloc_rx_buffers(qdev);
 +      if ((ql_read32(qdev, STS) & qdev->port_init))
 +              netif_carrier_on(qdev->ndev);
        ql_enable_interrupts(qdev);
        ql_enable_all_completion_interrupts(qdev);
 -      if ((ql_read32(qdev, STS) & qdev->port_init)) {
 -              netif_carrier_on(qdev->ndev);
 -              netif_start_queue(qdev->ndev);
 -      }
 +      netif_tx_start_all_queues(qdev->ndev);
  
        return 0;
  err_init:
        return err;
  }
  
 -static int ql_cycle_adapter(struct ql_adapter *qdev)
 -{
 -      int status;
 -
 -      status = ql_adapter_down(qdev);
 -      if (status)
 -              goto error;
 -
 -      status = ql_adapter_up(qdev);
 -      if (status)
 -              goto error;
 -
 -      return status;
 -error:
 -      QPRINTK(qdev, IFUP, ALERT,
 -              "Driver up/down cycle failed, closing device\n");
 -      rtnl_lock();
 -      dev_close(qdev->ndev);
 -      rtnl_unlock();
 -      return status;
 -}
 -
  static void ql_release_adapter_resources(struct ql_adapter *qdev)
  {
        ql_free_mem_resources(qdev);
@@@ -3361,7 -3308,6 +3361,7 @@@ static int ql_configure_rings(struct ql
         * completion handler rx_rings.
         */
        qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1;
 +      netif_set_gso_max_size(qdev->ndev, 65536);
  
        for (i = 0; i < qdev->tx_ring_count; i++) {
                tx_ring = &qdev->tx_ring[i];
@@@ -3468,8 -3414,6 +3468,8 @@@ static int qlge_change_mtu(struct net_d
  
        if (ndev->mtu == 1500 && new_mtu == 9000) {
                QPRINTK(qdev, IFUP, ERR, "Changing to jumbo MTU.\n");
 +              queue_delayed_work(qdev->workqueue,
 +                              &qdev->mpi_port_cfg_work, 0);
        } else if (ndev->mtu == 9000 && new_mtu == 1500) {
                QPRINTK(qdev, IFUP, ERR, "Changing to normal MTU.\n");
        } else if ((ndev->mtu == 1500 && new_mtu == 1500) ||
@@@ -3492,11 -3436,8 +3492,11 @@@ static void qlge_set_multicast_list(str
  {
        struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
        struct dev_mc_list *mc_ptr;
 -      int i;
 +      int i, status;
  
 +      status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
 +      if (status)
 +              return;
        spin_lock(&qdev->hw_lock);
        /*
         * Set or clear promiscuous mode if a
        }
  
        if (ndev->mc_count) {
 +              status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
 +              if (status)
 +                      goto exit;
                for (i = 0, mc_ptr = ndev->mc_list; mc_ptr;
                     i++, mc_ptr = mc_ptr->next)
                        if (ql_set_mac_addr_reg(qdev, (u8 *) mc_ptr->dmi_addr,
                                                MAC_ADDR_TYPE_MULTI_MAC, i)) {
                                QPRINTK(qdev, HW, ERR,
                                        "Failed to loadmulticast address.\n");
 +                              ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
                                goto exit;
                        }
 +              ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
                if (ql_set_routing_reg
                    (qdev, RT_IDX_MCAST_MATCH_SLOT, RT_IDX_MCAST_MATCH, 1)) {
                        QPRINTK(qdev, HW, ERR,
        }
  exit:
        spin_unlock(&qdev->hw_lock);
 +      ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
  }
  
  static int qlge_set_mac_address(struct net_device *ndev, void *p)
  {
        struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
        struct sockaddr *addr = p;
 -      int ret = 0;
 +      int status;
  
        if (netif_running(ndev))
                return -EBUSY;
                return -EADDRNOTAVAIL;
        memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
  
 +      status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
 +      if (status)
 +              return status;
        spin_lock(&qdev->hw_lock);
 -      if (ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr,
 -                      MAC_ADDR_TYPE_CAM_MAC, qdev->func)) {/* Unicast */
 -              QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n");
 -              ret = -1;
 -      }
 +      status = ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr,
 +                      MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ);
        spin_unlock(&qdev->hw_lock);
 -
 -      return ret;
 +      if (status)
 +              QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n");
 +      ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
 +      return status;
  }
  
  static void qlge_tx_timeout(struct net_device *ndev)
@@@ -3614,37 -3547,9 +3614,37 @@@ static void ql_asic_reset_work(struct w
  {
        struct ql_adapter *qdev =
            container_of(work, struct ql_adapter, asic_reset_work.work);
 -      ql_cycle_adapter(qdev);
 +      int status;
 +
 +      status = ql_adapter_down(qdev);
 +      if (status)
 +              goto error;
 +
 +      status = ql_adapter_up(qdev);
 +      if (status)
 +              goto error;
 +
 +      return;
 +error:
 +      QPRINTK(qdev, IFUP, ALERT,
 +              "Driver up/down cycle failed, closing device\n");
 +      rtnl_lock();
 +      set_bit(QL_ADAPTER_UP, &qdev->flags);
 +      dev_close(qdev->ndev);
 +      rtnl_unlock();
  }
  
 +static struct nic_operations qla8012_nic_ops = {
 +      .get_flash              = ql_get_8012_flash_params,
 +      .port_initialize        = ql_8012_port_initialize,
 +};
 +
 +static struct nic_operations qla8000_nic_ops = {
 +      .get_flash              = ql_get_8000_flash_params,
 +      .port_initialize        = ql_8000_port_initialize,
 +};
 +
 +
  static void ql_get_board_info(struct ql_adapter *qdev)
  {
        qdev->func =
                qdev->mailbox_out = PROC_ADDR_MPI_RISC | PROC_ADDR_FUNC0_MBO;
        }
        qdev->chip_rev_id = ql_read32(qdev, REV_ID);
 +      qdev->device_id = qdev->pdev->device;
 +      if (qdev->device_id == QLGE_DEVICE_ID_8012)
 +              qdev->nic_ops = &qla8012_nic_ops;
 +      else if (qdev->device_id == QLGE_DEVICE_ID_8000)
 +              qdev->nic_ops = &qla8000_nic_ops;
  }
  
  static void ql_release_all(struct pci_dev *pdev)
@@@ -3760,20 -3660,24 +3760,20 @@@ static int __devinit ql_init_device(str
                goto err_out;
        }
  
 -      ql_get_board_info(qdev);
        qdev->ndev = ndev;
        qdev->pdev = pdev;
 +      ql_get_board_info(qdev);
        qdev->msg_enable = netif_msg_init(debug, default_msg);
        spin_lock_init(&qdev->hw_lock);
        spin_lock_init(&qdev->stats_lock);
  
        /* make sure the EEPROM is good */
 -      err = ql_get_flash_params(qdev);
 +      err = qdev->nic_ops->get_flash(qdev);
        if (err) {
                dev_err(&pdev->dev, "Invalid FLASH.\n");
                goto err_out;
        }
  
 -      if (!is_valid_ether_addr(qdev->flash.mac_addr))
 -              goto err_out;
 -
 -      memcpy(ndev->dev_addr, qdev->flash.mac_addr, ndev->addr_len);
        memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
  
        /* Set up the default ring sizes. */
        INIT_DELAYED_WORK(&qdev->asic_reset_work, ql_asic_reset_work);
        INIT_DELAYED_WORK(&qdev->mpi_reset_work, ql_mpi_reset_work);
        INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work);
 +      INIT_DELAYED_WORK(&qdev->mpi_port_cfg_work, ql_mpi_port_cfg_work);
 +      INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work);
 +      mutex_init(&qdev->mpi_mutex);
 +      init_completion(&qdev->ide_completion);
  
        if (!cards_found) {
                dev_info(&pdev->dev, "%s\n", DRV_STRING);
@@@ -3837,8 -3737,7 +3837,8 @@@ static int __devinit qlge_probe(struct 
        static int cards_found = 0;
        int err = 0;
  
 -      ndev = alloc_etherdev(sizeof(struct ql_adapter));
 +      ndev = alloc_etherdev_mq(sizeof(struct ql_adapter),
 +                      min(MAX_CPUS, (int)num_online_cpus()));
        if (!ndev)
                return -ENOMEM;
  
                          | NETIF_F_TSO_ECN
                          | NETIF_F_HW_VLAN_TX
                          | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER);
 +      ndev->features |= NETIF_F_GRO;
  
        if (test_bit(QL_DMA64, &qdev->flags))
                ndev->features |= NETIF_F_HIGHDMA;
                return err;
        }
        netif_carrier_off(ndev);
 -      netif_stop_queue(ndev);
        ql_display_dev_info(ndev);
        cards_found++;
        return 0;
@@@ -3934,6 -3833,7 +3934,6 @@@ static pci_ers_result_t qlge_io_slot_re
        pci_set_master(pdev);
  
        netif_carrier_off(ndev);
 -      netif_stop_queue(ndev);
        ql_adapter_reset(qdev);
  
        /* Make sure the EEPROM is good */
diff --combined drivers/net/r8169.c
index 7e4b586e306d835e3d23c970c4d2f6a33fd55b68,43fedb9ecedbb3f415286e28e7543ba3d1fb6da8..06c535222666be7e1c5a0f933268cec7b58052a0
@@@ -81,9 -81,9 +81,9 @@@ static const int multicast_filter_limi
  #define RTL8169_TX_TIMEOUT    (6*HZ)
  #define RTL8169_PHY_TIMEOUT   (10*HZ)
  
- #define RTL_EEPROM_SIG                0x8129
+ #define RTL_EEPROM_SIG                cpu_to_le32(0x8129)
+ #define RTL_EEPROM_SIG_MASK   cpu_to_le32(0xffff)
  #define RTL_EEPROM_SIG_ADDR   0x0000
- #define RTL_EEPROM_MAC_ADDR   0x0007
  
  /* write/read MMIO register */
  #define RTL_W8(reg, val8)     writeb ((val8), ioaddr + (reg))
@@@ -293,11 -293,6 +293,6 @@@ enum rtl_register_content 
        /* Cfg9346Bits */
        Cfg9346_Lock    = 0x00,
        Cfg9346_Unlock  = 0xc0,
-       Cfg9346_Program = 0x80,         /* Programming mode */
-       Cfg9346_EECS    = 0x08,         /* Chip select */
-       Cfg9346_EESK    = 0x04,         /* Serial data clock */
-       Cfg9346_EEDI    = 0x02,         /* Data input */
-       Cfg9346_EEDO    = 0x01,         /* Data output */
  
        /* rx_mode_bits */
        AcceptErr       = 0x20,
        /* RxConfigBits */
        RxCfgFIFOShift  = 13,
        RxCfgDMAShift   =  8,
-       RxCfg9356SEL    =  6,           /* EEPROM type: 0 = 9346, 1 = 9356 */
  
        /* TxConfigBits */
        TxInterFrameGapShift = 24,
@@@ -1969,108 -1963,6 +1963,6 @@@ static const struct net_device_ops rtl8
  
  };
  
- /* Delay between EEPROM clock transitions. Force out buffered PCI writes. */
- #define RTL_EEPROM_DELAY()    RTL_R8(Cfg9346)
- #define RTL_EEPROM_READ_CMD   6
- /* read 16bit word stored in EEPROM. EEPROM is addressed by words. */
- static u16 rtl_eeprom_read(void __iomem *ioaddr, int addr)
- {
-       u16 result = 0;
-       int cmd, cmd_len, i;
-       /* check for EEPROM address size (in bits) */
-       if (RTL_R32(RxConfig) & (1 << RxCfg9356SEL)) {
-               /* EEPROM is 93C56 */
-               cmd_len = 3 + 8; /* 3 bits for command id and 8 for address */
-               cmd = (RTL_EEPROM_READ_CMD << 8) | (addr & 0xff);
-       } else {
-               /* EEPROM is 93C46 */
-               cmd_len = 3 + 6; /* 3 bits for command id and 6 for address */
-               cmd = (RTL_EEPROM_READ_CMD << 6) | (addr & 0x3f);
-       }
-       /* enter programming mode */
-       RTL_W8(Cfg9346, Cfg9346_Program | Cfg9346_EECS);
-       RTL_EEPROM_DELAY();
-       /* write command and requested address */
-       while (cmd_len--) {
-               u8 x = Cfg9346_Program | Cfg9346_EECS;
-               x |= (cmd & (1 << cmd_len)) ? Cfg9346_EEDI : 0;
-               /* write a bit */
-               RTL_W8(Cfg9346, x);
-               RTL_EEPROM_DELAY();
-               /* raise clock */
-               RTL_W8(Cfg9346, x | Cfg9346_EESK);
-               RTL_EEPROM_DELAY();
-       }
-       /* lower clock */
-       RTL_W8(Cfg9346, Cfg9346_Program | Cfg9346_EECS);
-       RTL_EEPROM_DELAY();
-       /* read back 16bit value */
-       for (i = 16; i > 0; i--) {
-               /* raise clock */
-               RTL_W8(Cfg9346, Cfg9346_Program | Cfg9346_EECS | Cfg9346_EESK);
-               RTL_EEPROM_DELAY();
-               result <<= 1;
-               result |= (RTL_R8(Cfg9346) & Cfg9346_EEDO) ? 1 : 0;
-               /* lower clock */
-               RTL_W8(Cfg9346, Cfg9346_Program | Cfg9346_EECS);
-               RTL_EEPROM_DELAY();
-       }
-       RTL_W8(Cfg9346, Cfg9346_Program);
-       /* leave programming mode */
-       RTL_W8(Cfg9346, Cfg9346_Lock);
-       return result;
- }
- static void rtl_init_mac_address(struct rtl8169_private *tp,
-                                void __iomem *ioaddr)
- {
-       struct pci_dev *pdev = tp->pci_dev;
-       u16 x;
-       u8 mac[8];
-       /* read EEPROM signature */
-       x = rtl_eeprom_read(ioaddr, RTL_EEPROM_SIG_ADDR);
-       if (x != RTL_EEPROM_SIG) {
-               dev_info(&pdev->dev, "Missing EEPROM signature: %04x\n", x);
-               return;
-       }
-       /* read MAC address */
-       x = rtl_eeprom_read(ioaddr, RTL_EEPROM_MAC_ADDR);
-       mac[0] = x & 0xff;
-       mac[1] = x >> 8;
-       x = rtl_eeprom_read(ioaddr, RTL_EEPROM_MAC_ADDR + 1);
-       mac[2] = x & 0xff;
-       mac[3] = x >> 8;
-       x = rtl_eeprom_read(ioaddr, RTL_EEPROM_MAC_ADDR + 2);
-       mac[4] = x & 0xff;
-       mac[5] = x >> 8;
-       if (netif_msg_probe(tp)) {
-               DECLARE_MAC_BUF(buf);
-               dev_info(&pdev->dev, "MAC address found in EEPROM: %s\n",
-                        print_mac(buf, mac));
-       }
-       if (is_valid_ether_addr(mac))
-               rtl_rar_set(tp, mac);
- }
  static int __devinit
  rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
  {
  
        tp->mmio_addr = ioaddr;
  
-       rtl_init_mac_address(tp, ioaddr);
        /* Get MAC address */
        for (i = 0; i < MAC_ADDR_LEN; i++)
                dev->dev_addr[i] = RTL_R8(MAC0 + i);
@@@ -3363,13 -3253,6 +3253,6 @@@ static int rtl8169_start_xmit(struct sk
                opts1 |= FirstFrag;
        } else {
                len = skb->len;
-               if (unlikely(len < ETH_ZLEN)) {
-                       if (skb_padto(skb, ETH_ZLEN))
-                               goto err_update_stats;
-                       len = ETH_ZLEN;
-               }
                opts1 |= FirstFrag | LastFrag;
                tp->tx_skb[entry].skb = skb;
        }
@@@ -3407,7 -3290,6 +3290,6 @@@ out
  err_stop:
        netif_stop_queue(dev);
        ret = NETDEV_TX_BUSY;
- err_update_stats:
        dev->stats.tx_dropped++;
        goto out;
  }
@@@ -3711,8 -3593,8 +3593,8 @@@ static irqreturn_t rtl8169_interrupt(in
                RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
                tp->intr_mask = ~tp->napi_event;
  
 -              if (likely(netif_rx_schedule_prep(&tp->napi)))
 -                      __netif_rx_schedule(&tp->napi);
 +              if (likely(napi_schedule_prep(&tp->napi)))
 +                      __napi_schedule(&tp->napi);
                else if (netif_msg_intr(tp)) {
                        printk(KERN_INFO "%s: interrupt %04x in poll\n",
                               dev->name, status);
@@@ -3733,7 -3615,7 +3615,7 @@@ static int rtl8169_poll(struct napi_str
        rtl8169_tx_interrupt(dev, tp, ioaddr);
  
        if (work_done < budget) {
 -              netif_rx_complete(napi);
 +              napi_complete(napi);
                tp->intr_mask = 0xffff;
                /*
                 * 20040426: the barrier is not strictly required but the
index f0b105a11ae2b6144fbfe7601775ed3e02c9846f,6650f609ece4eaf82925ceea690b09b0d0cb8a3f..b64be8e9a69029ba067b241de1a771f8a2060803
  #ifndef ATH9K_H
  #define ATH9K_H
  
 -#include <linux/io.h>
 -
 -#define ATHEROS_VENDOR_ID     0x168c
 -
 -#define AR5416_DEVID_PCI      0x0023
 -#define AR5416_DEVID_PCIE     0x0024
 -#define AR9160_DEVID_PCI      0x0027
 -#define AR9280_DEVID_PCI      0x0029
 -#define AR9280_DEVID_PCIE     0x002a
 -#define AR9285_DEVID_PCIE     0x002b
 -
 -#define AR5416_AR9100_DEVID   0x000b
 -
 -#define       AR_SUBVENDOR_ID_NOG     0x0e11
 -#define AR_SUBVENDOR_ID_NEW_A 0x7065
 -
 -#define ATH9K_TXERR_XRETRY         0x01
 -#define ATH9K_TXERR_FILT           0x02
 -#define ATH9K_TXERR_FIFO           0x04
 -#define ATH9K_TXERR_XTXOP          0x08
 -#define ATH9K_TXERR_TIMER_EXPIRED  0x10
 -
 -#define ATH9K_TX_BA                0x01
 -#define ATH9K_TX_PWRMGMT           0x02
 -#define ATH9K_TX_DESC_CFG_ERR      0x04
 -#define ATH9K_TX_DATA_UNDERRUN     0x08
 -#define ATH9K_TX_DELIM_UNDERRUN    0x10
 -#define ATH9K_TX_SW_ABORTED        0x40
 -#define ATH9K_TX_SW_FILTERED       0x80
 -
 -#define NBBY    8
 -
 -struct ath_tx_status {
 -      u32 ts_tstamp;
 -      u16 ts_seqnum;
 -      u8 ts_status;
 -      u8 ts_ratecode;
 -      u8 ts_rateindex;
 -      int8_t ts_rssi;
 -      u8 ts_shortretry;
 -      u8 ts_longretry;
 -      u8 ts_virtcol;
 -      u8 ts_antenna;
 -      u8 ts_flags;
 -      int8_t ts_rssi_ctl0;
 -      int8_t ts_rssi_ctl1;
 -      int8_t ts_rssi_ctl2;
 -      int8_t ts_rssi_ext0;
 -      int8_t ts_rssi_ext1;
 -      int8_t ts_rssi_ext2;
 -      u8 pad[3];
 -      u32 ba_low;
 -      u32 ba_high;
 -      u32 evm0;
 -      u32 evm1;
 -      u32 evm2;
 -};
 -
 -struct ath_rx_status {
 -      u32 rs_tstamp;
 -      u16 rs_datalen;
 -      u8 rs_status;
 -      u8 rs_phyerr;
 -      int8_t rs_rssi;
 -      u8 rs_keyix;
 -      u8 rs_rate;
 -      u8 rs_antenna;
 -      u8 rs_more;
 -      int8_t rs_rssi_ctl0;
 -      int8_t rs_rssi_ctl1;
 -      int8_t rs_rssi_ctl2;
 -      int8_t rs_rssi_ext0;
 -      int8_t rs_rssi_ext1;
 -      int8_t rs_rssi_ext2;
 -      u8 rs_isaggr;
 -      u8 rs_moreaggr;
 -      u8 rs_num_delims;
 -      u8 rs_flags;
 -      u32 evm0;
 -      u32 evm1;
 -      u32 evm2;
 -};
 -
 -#define ATH9K_RXERR_CRC           0x01
 -#define ATH9K_RXERR_PHY           0x02
 -#define ATH9K_RXERR_FIFO          0x04
 -#define ATH9K_RXERR_DECRYPT       0x08
 -#define ATH9K_RXERR_MIC           0x10
 -
 -#define ATH9K_RX_MORE             0x01
 -#define ATH9K_RX_MORE_AGGR        0x02
 -#define ATH9K_RX_GI               0x04
 -#define ATH9K_RX_2040             0x08
 -#define ATH9K_RX_DELIM_CRC_PRE    0x10
 -#define ATH9K_RX_DELIM_CRC_POST   0x20
 -#define ATH9K_RX_DECRYPT_BUSY     0x40
 -
 -#define ATH9K_RXKEYIX_INVALID ((u8)-1)
 -#define ATH9K_TXKEYIX_INVALID ((u32)-1)
 -
 -struct ath_desc {
 -      u32 ds_link;
 -      u32 ds_data;
 -      u32 ds_ctl0;
 -      u32 ds_ctl1;
 -      u32 ds_hw[20];
 -      union {
 -              struct ath_tx_status tx;
 -              struct ath_rx_status rx;
 -              void *stats;
 -      } ds_us;
 -      void *ds_vdata;
 -} __packed;
 -
 -#define       ds_txstat       ds_us.tx
 -#define       ds_rxstat       ds_us.rx
 -#define ds_stat               ds_us.stats
 -
 -#define ATH9K_TXDESC_CLRDMASK         0x0001
 -#define ATH9K_TXDESC_NOACK            0x0002
 -#define ATH9K_TXDESC_RTSENA           0x0004
 -#define ATH9K_TXDESC_CTSENA           0x0008
 -/* ATH9K_TXDESC_INTREQ forces a tx interrupt to be generated for
 - * the descriptor its marked on.  We take a tx interrupt to reap
 - * descriptors when the h/w hits an EOL condition or
 - * when the descriptor is specifically marked to generate
 - * an interrupt with this flag. Descriptors should be
 - * marked periodically to insure timely replenishing of the
 - * supply needed for sending frames. Defering interrupts
 - * reduces system load and potentially allows more concurrent
 - * work to be done but if done to aggressively can cause
 - * senders to backup. When the hardware queue is left too
 - * large rate control information may also be too out of
 - * date. An Alternative for this is TX interrupt mitigation
 - * but this needs more testing. */
 -#define ATH9K_TXDESC_INTREQ           0x0010
 -#define ATH9K_TXDESC_VEOL             0x0020
 -#define ATH9K_TXDESC_EXT_ONLY         0x0040
 -#define ATH9K_TXDESC_EXT_AND_CTL      0x0080
 -#define ATH9K_TXDESC_VMF              0x0100
 -#define ATH9K_TXDESC_FRAG_IS_ON       0x0200
 -#define ATH9K_TXDESC_CAB              0x0400
 -
 -#define ATH9K_RXDESC_INTREQ           0x0020
 -
 -enum wireless_mode {
 -      ATH9K_MODE_11A = 0,
 -      ATH9K_MODE_11B = 2,
 -      ATH9K_MODE_11G = 3,
 -      ATH9K_MODE_11NA_HT20 = 6,
 -      ATH9K_MODE_11NG_HT20 = 7,
 -      ATH9K_MODE_11NA_HT40PLUS = 8,
 -      ATH9K_MODE_11NA_HT40MINUS = 9,
 -      ATH9K_MODE_11NG_HT40PLUS = 10,
 -      ATH9K_MODE_11NG_HT40MINUS = 11,
 -      ATH9K_MODE_MAX
 -};
 -
 -enum ath9k_hw_caps {
 -      ATH9K_HW_CAP_CHAN_SPREAD                = BIT(0),
 -      ATH9K_HW_CAP_MIC_AESCCM                 = BIT(1),
 -      ATH9K_HW_CAP_MIC_CKIP                   = BIT(2),
 -      ATH9K_HW_CAP_MIC_TKIP                   = BIT(3),
 -      ATH9K_HW_CAP_CIPHER_AESCCM              = BIT(4),
 -      ATH9K_HW_CAP_CIPHER_CKIP                = BIT(5),
 -      ATH9K_HW_CAP_CIPHER_TKIP                = BIT(6),
 -      ATH9K_HW_CAP_VEOL                       = BIT(7),
 -      ATH9K_HW_CAP_BSSIDMASK                  = BIT(8),
 -      ATH9K_HW_CAP_MCAST_KEYSEARCH            = BIT(9),
 -      ATH9K_HW_CAP_CHAN_HALFRATE              = BIT(10),
 -      ATH9K_HW_CAP_CHAN_QUARTERRATE           = BIT(11),
 -      ATH9K_HW_CAP_HT                         = BIT(12),
 -      ATH9K_HW_CAP_GTT                        = BIT(13),
 -      ATH9K_HW_CAP_FASTCC                     = BIT(14),
 -      ATH9K_HW_CAP_RFSILENT                   = BIT(15),
 -      ATH9K_HW_CAP_WOW                        = BIT(16),
 -      ATH9K_HW_CAP_CST                        = BIT(17),
 -      ATH9K_HW_CAP_ENHANCEDPM                 = BIT(18),
 -      ATH9K_HW_CAP_AUTOSLEEP                  = BIT(19),
 -      ATH9K_HW_CAP_4KB_SPLITTRANS             = BIT(20),
 -      ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT     = BIT(21),
 -};
 -
 -enum ath9k_capability_type {
 -      ATH9K_CAP_CIPHER = 0,
 -      ATH9K_CAP_TKIP_MIC,
 -      ATH9K_CAP_TKIP_SPLIT,
 -      ATH9K_CAP_PHYCOUNTERS,
 -      ATH9K_CAP_DIVERSITY,
 -      ATH9K_CAP_TXPOW,
 -      ATH9K_CAP_PHYDIAG,
 -      ATH9K_CAP_MCAST_KEYSRCH,
 -      ATH9K_CAP_TSF_ADJUST,
 -      ATH9K_CAP_WME_TKIPMIC,
 -      ATH9K_CAP_RFSILENT,
 -      ATH9K_CAP_ANT_CFG_2GHZ,
 -      ATH9K_CAP_ANT_CFG_5GHZ
 -};
 -
 -struct ath9k_hw_capabilities {
 -      u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */
 -      DECLARE_BITMAP(wireless_modes, ATH9K_MODE_MAX); /* ATH9K_MODE_* */
 -      u16 total_queues;
 -      u16 keycache_size;
 -      u16 low_5ghz_chan, high_5ghz_chan;
 -      u16 low_2ghz_chan, high_2ghz_chan;
 -      u16 num_mr_retries;
 -      u16 rts_aggr_limit;
 -      u8 tx_chainmask;
 -      u8 rx_chainmask;
 -      u16 tx_triglevel_max;
 -      u16 reg_cap;
 -      u8 num_gpio_pins;
 -      u8 num_antcfg_2ghz;
 -      u8 num_antcfg_5ghz;
 -};
 -
 -struct ath9k_ops_config {
 -      int dma_beacon_response_time;
 -      int sw_beacon_response_time;
 -      int additional_swba_backoff;
 -      int ack_6mb;
 -      int cwm_ignore_extcca;
 -      u8 pcie_powersave_enable;
 -      u8 pcie_l1skp_enable;
 -      u8 pcie_clock_req;
 -      u32 pcie_waen;
 -      int pcie_power_reset;
 -      u8 pcie_restore;
 -      u8 analog_shiftreg;
 -      u8 ht_enable;
 -      u32 ofdm_trig_low;
 -      u32 ofdm_trig_high;
 -      u32 cck_trig_high;
 -      u32 cck_trig_low;
 -      u32 enable_ani;
 -      u8 noise_immunity_level;
 -      u32 ofdm_weaksignal_det;
 -      u32 cck_weaksignal_thr;
 -      u8 spur_immunity_level;
 -      u8 firstep_level;
 -      int8_t rssi_thr_high;
 -      int8_t rssi_thr_low;
 -      u16 diversity_control;
 -      u16 antenna_switch_swap;
 -      int serialize_regmode;
 -      int intr_mitigation;
 -#define SPUR_DISABLE          0
 -#define SPUR_ENABLE_IOCTL     1
 -#define SPUR_ENABLE_EEPROM    2
 -#define AR_EEPROM_MODAL_SPURS   5
 -#define AR_SPUR_5413_1        1640
 -#define AR_SPUR_5413_2        1200
 -#define AR_NO_SPUR            0x8000
 -#define AR_BASE_FREQ_2GHZ     2300
 -#define AR_BASE_FREQ_5GHZ     4900
 -#define AR_SPUR_FEEQ_BOUND_HT40 19
 -#define AR_SPUR_FEEQ_BOUND_HT20 10
 -      int spurmode;
 -      u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
 -};
 -
 -enum ath9k_tx_queue {
 -      ATH9K_TX_QUEUE_INACTIVE = 0,
 -      ATH9K_TX_QUEUE_DATA,
 -      ATH9K_TX_QUEUE_BEACON,
 -      ATH9K_TX_QUEUE_CAB,
 -      ATH9K_TX_QUEUE_UAPSD,
 -      ATH9K_TX_QUEUE_PSPOLL
 -};
 -
 -#define       ATH9K_NUM_TX_QUEUES 10
 -
 -enum ath9k_tx_queue_subtype {
 -      ATH9K_WME_AC_BK = 0,
 -      ATH9K_WME_AC_BE,
 -      ATH9K_WME_AC_VI,
 -      ATH9K_WME_AC_VO,
 -      ATH9K_WME_UPSD
 -};
 -
 -enum ath9k_tx_queue_flags {
 -      TXQ_FLAG_TXOKINT_ENABLE = 0x0001,
 -      TXQ_FLAG_TXERRINT_ENABLE = 0x0001,
 -      TXQ_FLAG_TXDESCINT_ENABLE = 0x0002,
 -      TXQ_FLAG_TXEOLINT_ENABLE = 0x0004,
 -      TXQ_FLAG_TXURNINT_ENABLE = 0x0008,
 -      TXQ_FLAG_BACKOFF_DISABLE = 0x0010,
 -      TXQ_FLAG_COMPRESSION_ENABLE = 0x0020,
 -      TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE = 0x0040,
 -      TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE = 0x0080,
 -};
 -
 -#define ATH9K_TXQ_USEDEFAULT ((u32) -1)
 -
 -#define ATH9K_DECOMP_MASK_SIZE     128
 -#define ATH9K_READY_TIME_LO_BOUND  50
 -#define ATH9K_READY_TIME_HI_BOUND  96
 -
 -enum ath9k_pkt_type {
 -      ATH9K_PKT_TYPE_NORMAL = 0,
 -      ATH9K_PKT_TYPE_ATIM,
 -      ATH9K_PKT_TYPE_PSPOLL,
 -      ATH9K_PKT_TYPE_BEACON,
 -      ATH9K_PKT_TYPE_PROBE_RESP,
 -      ATH9K_PKT_TYPE_CHIRP,
 -      ATH9K_PKT_TYPE_GRP_POLL,
 -};
 -
 -struct ath9k_tx_queue_info {
 -      u32 tqi_ver;
 -      enum ath9k_tx_queue tqi_type;
 -      enum ath9k_tx_queue_subtype tqi_subtype;
 -      enum ath9k_tx_queue_flags tqi_qflags;
 -      u32 tqi_priority;
 -      u32 tqi_aifs;
 -      u32 tqi_cwmin;
 -      u32 tqi_cwmax;
 -      u16 tqi_shretry;
 -      u16 tqi_lgretry;
 -      u32 tqi_cbrPeriod;
 -      u32 tqi_cbrOverflowLimit;
 -      u32 tqi_burstTime;
 -      u32 tqi_readyTime;
 -      u32 tqi_physCompBuf;
 -      u32 tqi_intFlags;
 -};
 -
 -enum ath9k_rx_filter {
 -      ATH9K_RX_FILTER_UCAST = 0x00000001,
 -      ATH9K_RX_FILTER_MCAST = 0x00000002,
 -      ATH9K_RX_FILTER_BCAST = 0x00000004,
 -      ATH9K_RX_FILTER_CONTROL = 0x00000008,
 -      ATH9K_RX_FILTER_BEACON = 0x00000010,
 -      ATH9K_RX_FILTER_PROM = 0x00000020,
 -      ATH9K_RX_FILTER_PROBEREQ = 0x00000080,
 -      ATH9K_RX_FILTER_PSPOLL = 0x00004000,
 -      ATH9K_RX_FILTER_PHYERR = 0x00000100,
 -      ATH9K_RX_FILTER_PHYRADAR = 0x00002000,
 -};
 -
 -enum ath9k_int {
 -      ATH9K_INT_RX = 0x00000001,
 -      ATH9K_INT_RXDESC = 0x00000002,
 -      ATH9K_INT_RXNOFRM = 0x00000008,
 -      ATH9K_INT_RXEOL = 0x00000010,
 -      ATH9K_INT_RXORN = 0x00000020,
 -      ATH9K_INT_TX = 0x00000040,
 -      ATH9K_INT_TXDESC = 0x00000080,
 -      ATH9K_INT_TIM_TIMER = 0x00000100,
 -      ATH9K_INT_TXURN = 0x00000800,
 -      ATH9K_INT_MIB = 0x00001000,
 -      ATH9K_INT_RXPHY = 0x00004000,
 -      ATH9K_INT_RXKCM = 0x00008000,
 -      ATH9K_INT_SWBA = 0x00010000,
 -      ATH9K_INT_BMISS = 0x00040000,
 -      ATH9K_INT_BNR = 0x00100000,
 -      ATH9K_INT_TIM = 0x00200000,
 -      ATH9K_INT_DTIM = 0x00400000,
 -      ATH9K_INT_DTIMSYNC = 0x00800000,
 -      ATH9K_INT_GPIO = 0x01000000,
 -      ATH9K_INT_CABEND = 0x02000000,
 -      ATH9K_INT_CST = 0x10000000,
 -      ATH9K_INT_GTT = 0x20000000,
 -      ATH9K_INT_FATAL = 0x40000000,
 -      ATH9K_INT_GLOBAL = 0x80000000,
 -      ATH9K_INT_BMISC = ATH9K_INT_TIM |
 -              ATH9K_INT_DTIM |
 -              ATH9K_INT_DTIMSYNC |
 -              ATH9K_INT_CABEND,
 -      ATH9K_INT_COMMON = ATH9K_INT_RXNOFRM |
 -              ATH9K_INT_RXDESC |
 -              ATH9K_INT_RXEOL |
 -              ATH9K_INT_RXORN |
 -              ATH9K_INT_TXURN |
 -              ATH9K_INT_TXDESC |
 -              ATH9K_INT_MIB |
 -              ATH9K_INT_RXPHY |
 -              ATH9K_INT_RXKCM |
 -              ATH9K_INT_SWBA |
 -              ATH9K_INT_BMISS |
 -              ATH9K_INT_GPIO,
 -      ATH9K_INT_NOCARD = 0xffffffff
 -};
 -
 -#define ATH9K_RATESERIES_RTS_CTS  0x0001
 -#define ATH9K_RATESERIES_2040     0x0002
 -#define ATH9K_RATESERIES_HALFGI   0x0004
 -
 -struct ath9k_11n_rate_series {
 -      u32 Tries;
 -      u32 Rate;
 -      u32 PktDuration;
 -      u32 ChSel;
 -      u32 RateFlags;
 -};
 +#include <linux/etherdevice.h>
 +#include <linux/device.h>
 +#include <net/mac80211.h>
 +#include <linux/leds.h>
 +#include <linux/rfkill.h>
 +
 +#include "hw.h"
 +#include "rc.h"
 +#include "debug.h"
 +
 +struct ath_node;
 +
 +/* Macro to expand scalars to 64-bit objects */
 +
 +#define       ito64(x) (sizeof(x) == 8) ?                     \
 +      (((unsigned long long int)(x)) & (0xff)) :      \
 +      (sizeof(x) == 16) ?                             \
 +      (((unsigned long long int)(x)) & 0xffff) :      \
 +      ((sizeof(x) == 32) ?                            \
 +       (((unsigned long long int)(x)) & 0xffffffff) : \
 +       (unsigned long long int)(x))
 +
 +/* increment with wrap-around */
 +#define INCR(_l, _sz)   do {                  \
 +              (_l)++;                         \
 +              (_l) &= ((_sz) - 1);            \
 +      } while (0)
 +
 +/* decrement with wrap-around */
 +#define DECR(_l,  _sz)  do {                  \
 +              (_l)--;                         \
 +              (_l) &= ((_sz) - 1);            \
 +      } while (0)
 +
 +#define A_MAX(a, b) ((a) > (b) ? (a) : (b))
 +
 +#define ASSERT(exp) do {                      \
 +              if (unlikely(!(exp))) {         \
 +                      BUG();                  \
 +              }                               \
 +      } while (0)
 +
 +#define TSF_TO_TU(_h,_l) \
 +      ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
 +
 +#define       ATH_TXQ_SETUP(sc, i)        ((sc)->tx.txqsetup & (1<<i))
 +
 +static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 +
 +struct ath_config {
 +      u32 ath_aggr_prot;
 +      u16 txpowlimit;
 +      u8 cabqReadytime;
 +      u8 swBeaconProcess;
 +};
 +
 +/*************************/
 +/* Descriptor Management */
 +/*************************/
 +
 +#define ATH_TXBUF_RESET(_bf) do {                             \
 +              (_bf)->bf_status = 0;                           \
 +              (_bf)->bf_lastbf = NULL;                        \
 +              (_bf)->bf_next = NULL;                          \
 +              memset(&((_bf)->bf_state), 0,                   \
 +                     sizeof(struct ath_buf_state));           \
 +      } while (0)
 +
 +/**
 + * enum buffer_type - Buffer type flags
 + *
 + * @BUF_HT: Send this buffer using HT capabilities
 + * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX)
 + * @BUF_AGGR: Indicates whether the buffer can be aggregated
 + *    (used in aggregation scheduling)
 + * @BUF_RETRY: Indicates whether the buffer is retried
 + * @BUF_XRETRY: To denote excessive retries of the buffer
 + */
 +enum buffer_type {
 +      BUF_HT                  = BIT(1),
 +      BUF_AMPDU               = BIT(2),
 +      BUF_AGGR                = BIT(3),
 +      BUF_RETRY               = BIT(4),
 +      BUF_XRETRY              = BIT(5),
 +};
 +
 +struct ath_buf_state {
 +      int bfs_nframes;
 +      u16 bfs_al;
 +      u16 bfs_frmlen;
 +      int bfs_seqno;
 +      int bfs_tidno;
 +      int bfs_retries;
 +      u32 bf_type;
 +      u32 bfs_keyix;
 +      enum ath9k_key_type bfs_keytype;
 +};
 +
 +#define bf_nframes            bf_state.bfs_nframes
 +#define bf_al                 bf_state.bfs_al
 +#define bf_frmlen             bf_state.bfs_frmlen
 +#define bf_retries            bf_state.bfs_retries
 +#define bf_seqno              bf_state.bfs_seqno
 +#define bf_tidno              bf_state.bfs_tidno
 +#define bf_keyix                bf_state.bfs_keyix
 +#define bf_keytype            bf_state.bfs_keytype
 +#define bf_isht(bf)           (bf->bf_state.bf_type & BUF_HT)
 +#define bf_isampdu(bf)                (bf->bf_state.bf_type & BUF_AMPDU)
 +#define bf_isaggr(bf)         (bf->bf_state.bf_type & BUF_AGGR)
 +#define bf_isretried(bf)      (bf->bf_state.bf_type & BUF_RETRY)
 +#define bf_isxretried(bf)     (bf->bf_state.bf_type & BUF_XRETRY)
 +
 +struct ath_buf {
 +      struct list_head list;
 +      struct ath_buf *bf_lastbf;      /* last buf of this unit (a frame or
 +                                         an aggregate) */
 +      struct ath_buf *bf_next;        /* next subframe in the aggregate */
 +      void *bf_mpdu;                  /* enclosing frame structure */
 +      struct ath_desc *bf_desc;       /* virtual addr of desc */
 +      dma_addr_t bf_daddr;            /* physical addr of desc */
 +      dma_addr_t bf_buf_addr;         /* physical addr of data buffer */
 +      u32 bf_status;
 +      u16 bf_flags;
 +      struct ath_buf_state bf_state;
 +      dma_addr_t bf_dmacontext;
 +};
 +
 +#define ATH_RXBUF_RESET(_bf)    ((_bf)->bf_status = 0)
 +#define ATH_BUFSTATUS_STALE     0x00000002
 +
 +struct ath_descdma {
 +      const char *dd_name;
 +      struct ath_desc *dd_desc;
 +      dma_addr_t dd_desc_paddr;
 +      u32 dd_desc_len;
 +      struct ath_buf *dd_bufptr;
 +      dma_addr_t dd_dmacontext;
 +};
 +
 +int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 +                    struct list_head *head, const char *name,
 +                    int nbuf, int ndesc);
 +void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
 +                       struct list_head *head);
 +
 +/***********/
 +/* RX / TX */
 +/***********/
 +
 +#define ATH_MAX_ANTENNA         3
 +#define ATH_RXBUF               512
 +#define WME_NUM_TID             16
 +#define ATH_TXBUF               512
 +#define ATH_TXMAXTRY            13
 +#define ATH_11N_TXMAXTRY        10
 +#define ATH_MGT_TXMAXTRY        4
 +#define WME_BA_BMP_SIZE         64
 +#define WME_MAX_BA              WME_BA_BMP_SIZE
 +#define ATH_TID_MAX_BUFS        (2 * WME_MAX_BA)
 +
 +#define TID_TO_WME_AC(_tid)                           \
 +      ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
 +       (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
 +       (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
 +       WME_AC_VO)
 +
 +#define WME_AC_BE   0
 +#define WME_AC_BK   1
 +#define WME_AC_VI   2
 +#define WME_AC_VO   3
 +#define WME_NUM_AC  4
 +
 +#define ADDBA_EXCHANGE_ATTEMPTS    10
 +#define ATH_AGGR_DELIM_SZ          4
 +#define ATH_AGGR_MINPLEN           256 /* in bytes, minimum packet length */
 +/* number of delimiters for encryption padding */
 +#define ATH_AGGR_ENCRYPTDELIM      10
 +/* minimum h/w qdepth to be sustained to maximize aggregation */
 +#define ATH_AGGR_MIN_QDEPTH        2
 +#define ATH_AMPDU_SUBFRAME_DEFAULT 32
 +#define ATH_AMPDU_LIMIT_MAX        (64 * 1024 - 1)
 +#define ATH_AMPDU_LIMIT_DEFAULT    ATH_AMPDU_LIMIT_MAX
 +
 +#define IEEE80211_SEQ_SEQ_SHIFT    4
 +#define IEEE80211_SEQ_MAX          4096
 +#define IEEE80211_MIN_AMPDU_BUF    0x8
 +#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
 +#define IEEE80211_WEP_IVLEN        3
 +#define IEEE80211_WEP_KIDLEN       1
 +#define IEEE80211_WEP_CRCLEN       4
 +#define IEEE80211_MAX_MPDU_LEN     (3840 + FCS_LEN +          \
 +                                  (IEEE80211_WEP_IVLEN +      \
 +                                   IEEE80211_WEP_KIDLEN +     \
 +                                   IEEE80211_WEP_CRCLEN))
 +
 +/* return whether a bit at index _n in bitmap _bm is set
 + * _sz is the size of the bitmap  */
 +#define ATH_BA_ISSET(_bm, _n)  (((_n) < (WME_BA_BMP_SIZE)) &&         \
 +                              ((_bm)[(_n) >> 5] & (1 << ((_n) & 31))))
 +
 +/* return block-ack bitmap index given sequence and starting sequence */
 +#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1))
 +
 +/* returns delimiter padding required given the packet length */
 +#define ATH_AGGR_GET_NDELIM(_len)                                     \
 +      (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ?           \
 +        (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2)
 +
 +#define BAW_WITHIN(_start, _bawsz, _seqno) \
 +      ((((_seqno) - (_start)) & 4095) < (_bawsz))
 +
 +#define ATH_DS_BA_SEQ(_ds)         ((_ds)->ds_us.tx.ts_seqnum)
 +#define ATH_DS_BA_BITMAP(_ds)      (&(_ds)->ds_us.tx.ba_low)
 +#define ATH_DS_TX_BA(_ds)          ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
 +#define ATH_AN_2_TID(_an, _tidno)  (&(_an)->tid[(_tidno)])
 +
 +enum ATH_AGGR_STATUS {
 +      ATH_AGGR_DONE,
 +      ATH_AGGR_BAW_CLOSED,
 +      ATH_AGGR_LIMITED,
 +};
 +
 +struct ath_txq {
 +      u32 axq_qnum;
 +      u32 *axq_link;
 +      struct list_head axq_q;
 +      spinlock_t axq_lock;
 +      u32 axq_depth;
 +      u8 axq_aggr_depth;
 +      u32 axq_totalqueued;
 +      bool stopped;
 +      struct ath_buf *axq_linkbuf;
 +
 +      /* first desc of the last descriptor that contains CTS */
 +      struct ath_desc *axq_lastdsWithCTS;
 +
 +      /* final desc of the gating desc that determines whether
 +         lastdsWithCTS has been DMA'ed or not */
 +      struct ath_desc *axq_gatingds;
 +
 +      struct list_head axq_acq;
 +};
 +
 +#define AGGR_CLEANUP         BIT(1)
 +#define AGGR_ADDBA_COMPLETE  BIT(2)
 +#define AGGR_ADDBA_PROGRESS  BIT(3)
 +
 +struct ath_atx_tid {
 +      struct list_head list;
 +      struct list_head buf_q;
 +      struct ath_node *an;
 +      struct ath_atx_ac *ac;
 +      struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
 +      u16 seq_start;
 +      u16 seq_next;
 +      u16 baw_size;
 +      int tidno;
 +      int baw_head;   /* first un-acked tx buffer */
 +      int baw_tail;   /* next unused tx buffer slot */
 +      int sched;
 +      int paused;
 +      u8 state;
 +      int addba_exchangeattempts;
 +};
 +
 +struct ath_atx_ac {
 +      int sched;
 +      int qnum;
 +      struct list_head list;
 +      struct list_head tid_q;
 +};
 +
 +struct ath_tx_control {
 +      struct ath_txq *txq;
 +      int if_id;
 +      enum ath9k_internal_frame_type frame_type;
 +};
 +
 +struct ath_xmit_status {
 +      int retries;
 +      int flags;
 +#define ATH_TX_ERROR        0x01
 +#define ATH_TX_XRETRY       0x02
 +#define ATH_TX_BAR          0x04
 +};
 +
 +/* All RSSI values are noise floor adjusted */
 +struct ath_tx_stat {
 +      int rssi;
 +      int rssictl[ATH_MAX_ANTENNA];
 +      int rssiextn[ATH_MAX_ANTENNA];
 +      int rateieee;
 +      int rateKbps;
 +      int ratecode;
 +      int flags;
 +      u32 airtime;    /* time on air per final tx rate */
 +};
 +
 +struct aggr_rifs_param {
 +      int param_max_frames;
 +      int param_max_len;
 +      int param_rl;
 +      int param_al;
 +      struct ath_rc_series *param_rcs;
 +};
 +
 +struct ath_node {
 +      struct ath_softc *an_sc;
 +      struct ath_atx_tid tid[WME_NUM_TID];
 +      struct ath_atx_ac ac[WME_NUM_AC];
 +      u16 maxampdu;
 +      u8 mpdudensity;
 +};
 +
 +struct ath_tx {
 +      u16 seq_no;
 +      u32 txqsetup;
 +      int hwq_map[ATH9K_WME_AC_VO+1];
 +      spinlock_t txbuflock;
 +      struct list_head txbuf;
 +      struct ath_txq txq[ATH9K_NUM_TX_QUEUES];
 +      struct ath_descdma txdma;
 +};
 +
 +struct ath_rx {
 +      u8 defant;
 +      u8 rxotherant;
 +      u32 *rxlink;
 +      int bufsize;
 +      unsigned int rxfilter;
 +      spinlock_t rxflushlock;
 +      spinlock_t rxbuflock;
 +      struct list_head rxbuf;
 +      struct ath_descdma rxdma;
 +};
 +
 +int ath_startrecv(struct ath_softc *sc);
 +bool ath_stoprecv(struct ath_softc *sc);
 +void ath_flushrecv(struct ath_softc *sc);
 +u32 ath_calcrxfilter(struct ath_softc *sc);
 +int ath_rx_init(struct ath_softc *sc, int nbufs);
 +void ath_rx_cleanup(struct ath_softc *sc);
 +int ath_rx_tasklet(struct ath_softc *sc, int flush);
 +struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
 +void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
 +int ath_tx_setup(struct ath_softc *sc, int haltype);
 +void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
 +void ath_draintxq(struct ath_softc *sc,
 +                   struct ath_txq *txq, bool retry_tx);
 +void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
 +void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
 +void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
 +int ath_tx_init(struct ath_softc *sc, int nbufs);
 +int ath_tx_cleanup(struct ath_softc *sc);
 +struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb);
 +int ath_txq_update(struct ath_softc *sc, int qnum,
 +                 struct ath9k_tx_queue_info *q);
 +int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 +               struct ath_tx_control *txctl);
 +void ath_tx_tasklet(struct ath_softc *sc);
 +void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb);
 +bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
 +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
 +                    u16 tid, u16 *ssn);
 +int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
 +void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
 +
 +/********/
 +/* VIFs */
 +/********/
 +
 +struct ath_vif {
 +      int av_bslot;
 +      enum nl80211_iftype av_opmode;
 +      struct ath_buf *av_bcbuf;
 +      struct ath_tx_control av_btxctl;
 +      u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */
 +};
 +
 +/*******************/
 +/* Beacon Handling */
 +/*******************/
  
 -#define CHANNEL_CW_INT    0x00002
 -#define CHANNEL_CCK       0x00020
 -#define CHANNEL_OFDM      0x00040
 -#define CHANNEL_2GHZ      0x00080
 -#define CHANNEL_5GHZ      0x00100
 -#define CHANNEL_PASSIVE   0x00200
 -#define CHANNEL_DYN       0x00400
 -#define CHANNEL_HALF      0x04000
 -#define CHANNEL_QUARTER   0x08000
 -#define CHANNEL_HT20      0x10000
 -#define CHANNEL_HT40PLUS  0x20000
 -#define CHANNEL_HT40MINUS 0x40000
 -
 -#define CHANNEL_INTERFERENCE    0x01
 -#define CHANNEL_DFS             0x02
 -#define CHANNEL_4MS_LIMIT       0x04
 -#define CHANNEL_DFS_CLEAR       0x08
 -#define CHANNEL_DISALLOW_ADHOC  0x10
 -#define CHANNEL_PER_11D_ADHOC   0x20
 -
 -#define CHANNEL_A           (CHANNEL_5GHZ|CHANNEL_OFDM)
 -#define CHANNEL_B           (CHANNEL_2GHZ|CHANNEL_CCK)
 -#define CHANNEL_G           (CHANNEL_2GHZ|CHANNEL_OFDM)
 -#define CHANNEL_G_HT20      (CHANNEL_2GHZ|CHANNEL_HT20)
 -#define CHANNEL_A_HT20      (CHANNEL_5GHZ|CHANNEL_HT20)
 -#define CHANNEL_G_HT40PLUS  (CHANNEL_2GHZ|CHANNEL_HT40PLUS)
 -#define CHANNEL_G_HT40MINUS (CHANNEL_2GHZ|CHANNEL_HT40MINUS)
 -#define CHANNEL_A_HT40PLUS  (CHANNEL_5GHZ|CHANNEL_HT40PLUS)
 -#define CHANNEL_A_HT40MINUS (CHANNEL_5GHZ|CHANNEL_HT40MINUS)
 -#define CHANNEL_ALL                           \
 -      (CHANNEL_OFDM|                          \
 -       CHANNEL_CCK|                           \
 -       CHANNEL_2GHZ |                         \
 -       CHANNEL_5GHZ |                         \
 -       CHANNEL_HT20 |                         \
 -       CHANNEL_HT40PLUS |                     \
 -       CHANNEL_HT40MINUS)
 -
 -struct ath9k_channel {
 -      u16 channel;
 -      u32 channelFlags;
 -      u8 privFlags;
 -      int8_t maxRegTxPower;
 -      int8_t maxTxPower;
 -      int8_t minTxPower;
 -      u32 chanmode;
 -      int32_t CalValid;
 -      bool oneTimeCalsDone;
 -      int8_t iCoff;
 -      int8_t qCoff;
 -      int16_t rawNoiseFloor;
 -      int8_t antennaMax;
 -      u32 regDmnFlags;
 -      u32 conformanceTestLimit[3]; /* 0:11a, 1: 11b, 2:11g */
 -#ifdef ATH_NF_PER_CHAN
 -      struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
 -#endif
 -};
 +/*
 + * Regardless of the number of beacons we stagger, (i.e. regardless of the
 + * number of BSSIDs) if a given beacon does not go out even after waiting this
 + * number of beacon intervals, the game's up.
 + */
 +#define BSTUCK_THRESH                 (9 * ATH_BCBUF)
 +#define       ATH_BCBUF                       1
 +#define ATH_DEFAULT_BINTVAL           100 /* TU */
 +#define ATH_DEFAULT_BMISS_LIMIT       10
 +#define IEEE80211_MS_TO_TU(x)           (((x) * 1000) / 1024)
 +
 +struct ath_beacon_config {
 +      u16 beacon_interval;
 +      u16 listen_interval;
 +      u16 dtim_period;
 +      u16 bmiss_timeout;
 +      u8 dtim_count;
 +};
 +
 +struct ath_beacon {
 +      enum {
 +              OK,             /* no change needed */
 +              UPDATE,         /* update pending */
 +              COMMIT          /* beacon sent, commit change */
 +      } updateslot;           /* slot time update fsm */
 +
 +      u32 beaconq;
 +      u32 bmisscnt;
 +      u32 ast_be_xmit;
 +      u64 bc_tstamp;
 +      struct ieee80211_vif *bslot[ATH_BCBUF];
 +      struct ath_wiphy *bslot_aphy[ATH_BCBUF];
 +      int slottime;
 +      int slotupdate;
 +      struct ath9k_tx_queue_info beacon_qi;
 +      struct ath_descdma bdma;
 +      struct ath_txq *cabq;
 +      struct list_head bbuf;
 +};
 +
 +void ath_beacon_tasklet(unsigned long data);
 +void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
 +int ath_beaconq_setup(struct ath_hw *ah);
 +int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif);
 +void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
 +
 +/*******/
 +/* ANI */
 +/*******/
  
 -#define IS_CHAN_A(_c) ((((_c)->channelFlags & CHANNEL_A) == CHANNEL_A) || \
 -       (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \
 -       (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \
 -       (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS))
 -#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
 -       (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \
 -       (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \
 -       (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS))
 -#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0)
 -#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0)
 -#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0)
 -#define IS_CHAN_PASSIVE(_c) (((_c)->channelFlags & CHANNEL_PASSIVE) != 0)
 -#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0)
 -#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
 -
 -/* These macros check chanmode and not channelFlags */
 -#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B)
 -#define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) ||       \
 -                        ((_c)->chanmode == CHANNEL_G_HT20))
 -#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) ||   \
 -                        ((_c)->chanmode == CHANNEL_A_HT40MINUS) ||    \
 -                        ((_c)->chanmode == CHANNEL_G_HT40PLUS) ||     \
 -                        ((_c)->chanmode == CHANNEL_G_HT40MINUS))
 -#define IS_CHAN_HT(_c) (IS_CHAN_HT20((_c)) || IS_CHAN_HT40((_c)))
 -
 -#define IS_CHAN_IN_PUBLIC_SAFETY_BAND(_c) ((_c) > 4940 && (_c) < 4990)
 -#define IS_CHAN_A_5MHZ_SPACED(_c)                     \
 -      ((((_c)->channelFlags & CHANNEL_5GHZ) != 0) &&  \
 -       (((_c)->channel % 20) != 0) &&                 \
 -       (((_c)->channel % 10) != 0))
 -
 -struct ath9k_keyval {
 -      u8 kv_type;
 -      u8 kv_pad;
 -      u16 kv_len;
 -      u8 kv_val[16];
 -      u8 kv_mic[8];
 -      u8 kv_txmic[8];
 -};
 +#define ATH_STA_SHORT_CALINTERVAL 1000    /* 1 second */
 +#define ATH_AP_SHORT_CALINTERVAL  100     /* 100 ms */
 +#define ATH_ANI_POLLINTERVAL      100     /* 100 ms */
 +#define ATH_LONG_CALINTERVAL      30000   /* 30 seconds */
 +#define ATH_RESTART_CALINTERVAL   1200000 /* 20 minutes */
  
 -enum ath9k_key_type {
 -      ATH9K_KEY_TYPE_CLEAR,
 -      ATH9K_KEY_TYPE_WEP,
 -      ATH9K_KEY_TYPE_AES,
 -      ATH9K_KEY_TYPE_TKIP,
 +struct ath_ani {
 +      bool caldone;
 +      int16_t noise_floor;
 +      unsigned int longcal_timer;
 +      unsigned int shortcal_timer;
 +      unsigned int resetcal_timer;
 +      unsigned int checkani_timer;
 +      struct timer_list timer;
  };
  
 -enum ath9k_cipher {
 -      ATH9K_CIPHER_WEP = 0,
 -      ATH9K_CIPHER_AES_OCB = 1,
 -      ATH9K_CIPHER_AES_CCM = 2,
 -      ATH9K_CIPHER_CKIP = 3,
 -      ATH9K_CIPHER_TKIP = 4,
 -      ATH9K_CIPHER_CLR = 5,
 -      ATH9K_CIPHER_MIC = 127
 -};
 +/********************/
 +/*   LED Control    */
 +/********************/
  
 -#define AR_EEPROM_EEPCAP_COMPRESS_DIS   0x0001
 -#define AR_EEPROM_EEPCAP_AES_DIS        0x0002
 -#define AR_EEPROM_EEPCAP_FASTFRAME_DIS  0x0004
 -#define AR_EEPROM_EEPCAP_BURST_DIS      0x0008
 -#define AR_EEPROM_EEPCAP_MAXQCU         0x01F0
 -#define AR_EEPROM_EEPCAP_MAXQCU_S       4
 -#define AR_EEPROM_EEPCAP_HEAVY_CLIP_EN  0x0200
 -#define AR_EEPROM_EEPCAP_KC_ENTRIES     0xF000
 -#define AR_EEPROM_EEPCAP_KC_ENTRIES_S   12
 -
 -#define AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND   0x0040
 -#define AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN    0x0080
 -#define AR_EEPROM_EEREGCAP_EN_KK_U2         0x0100
 -#define AR_EEPROM_EEREGCAP_EN_KK_MIDBAND    0x0200
 -#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD     0x0400
 -#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A    0x0800
 -
 -#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD_PRE4_0  0x4000
 -#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0 0x8000
 -
 -#define SD_NO_CTL               0xE0
 -#define NO_CTL                  0xff
 -#define CTL_MODE_M              7
 -#define CTL_11A                 0
 -#define CTL_11B                 1
 -#define CTL_11G                 2
 -#define CTL_2GHT20              5
 -#define CTL_5GHT20              6
 -#define CTL_2GHT40              7
 -#define CTL_5GHT40              8
 -
 -#define AR_EEPROM_MAC(i)        (0x1d+(i))
 -
 -#define AR_EEPROM_RFSILENT_GPIO_SEL     0x001c
 -#define AR_EEPROM_RFSILENT_GPIO_SEL_S   2
 -#define AR_EEPROM_RFSILENT_POLARITY     0x0002
 -#define AR_EEPROM_RFSILENT_POLARITY_S   1
 -
 -#define CTRY_DEBUG 0x1ff
 -#define       CTRY_DEFAULT 0
 -
 -enum reg_ext_bitmap {
 -      REG_EXT_JAPAN_MIDBAND = 1,
 -      REG_EXT_FCC_DFS_HT40 = 2,
 -      REG_EXT_JAPAN_NONDFS_HT40 = 3,
 -      REG_EXT_JAPAN_DFS_HT40 = 4
 -};
 +#define ATH_LED_PIN   1
 +#define ATH_LED_ON_DURATION_IDLE      350     /* in msecs */
 +#define ATH_LED_OFF_DURATION_IDLE     250     /* in msecs */
  
 -struct ath9k_country_entry {
 -      u16 countryCode;
 -      u16 regDmnEnum;
 -      u16 regDmn5G;
 -      u16 regDmn2G;
 -      u8 isMultidomain;
 -      u8 iso[3];
 +enum ath_led_type {
 +      ATH_LED_RADIO,
 +      ATH_LED_ASSOC,
 +      ATH_LED_TX,
 +      ATH_LED_RX
  };
  
 -#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val))
 -#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg))
 -
 -#define SM(_v, _f)  (((_v) << _f##_S) & _f)
 -#define MS(_v, _f)  (((_v) & _f) >> _f##_S)
 -#define REG_RMW(_a, _r, _set, _clr)    \
 -      REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set))
 -#define REG_RMW_FIELD(_a, _r, _f, _v) \
 -      REG_WRITE(_a, _r, \
 -      (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f))
 -#define REG_SET_BIT(_a, _r, _f) \
 -      REG_WRITE(_a, _r, REG_READ(_a, _r) | _f)
 -#define REG_CLR_BIT(_a, _r, _f) \
 -      REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f)
 -
 -#define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS   0x00000001
 -
 -#define INIT_AIFS       2
 -#define INIT_CWMIN      15
 -#define INIT_CWMIN_11B  31
 -#define INIT_CWMAX      1023
 -#define INIT_SH_RETRY   10
 -#define INIT_LG_RETRY   10
 -#define INIT_SSH_RETRY  32
 -#define INIT_SLG_RETRY  32
 -
 -#define WLAN_CTRL_FRAME_SIZE (2+2+6+4)
 -
 -#define ATH_AMPDU_LIMIT_MAX      (64 * 1024 - 1)
 -#define ATH_AMPDU_LIMIT_DEFAULT  ATH_AMPDU_LIMIT_MAX
 -
 -#define IEEE80211_WEP_IVLEN      3
 -#define IEEE80211_WEP_KIDLEN     1
 -#define IEEE80211_WEP_CRCLEN     4
 -#define IEEE80211_MAX_MPDU_LEN  (3840 + FCS_LEN +             \
 -                               (IEEE80211_WEP_IVLEN +         \
 -                                IEEE80211_WEP_KIDLEN +        \
 -                                IEEE80211_WEP_CRCLEN))
 -#define MAX_RATE_POWER 63
 -
 -enum ath9k_power_mode {
 -      ATH9K_PM_AWAKE = 0,
 -      ATH9K_PM_FULL_SLEEP,
 -      ATH9K_PM_NETWORK_SLEEP,
 -      ATH9K_PM_UNDEFINED
 +struct ath_led {
 +      struct ath_softc *sc;
 +      struct led_classdev led_cdev;
 +      enum ath_led_type led_type;
 +      char name[32];
 +      bool registered;
  };
  
 -struct ath9k_mib_stats {
 -      u32 ackrcv_bad;
 -      u32 rts_bad;
 -      u32 rts_good;
 -      u32 fcs_bad;
 -      u32 beacons;
 -};
 +/* Rfkill */
 +#define ATH_RFKILL_POLL_INTERVAL      2000 /* msecs */
  
 -enum ath9k_ant_setting {
 -      ATH9K_ANT_VARIABLE = 0,
 -      ATH9K_ANT_FIXED_A,
 -      ATH9K_ANT_FIXED_B
 +struct ath_rfkill {
 +      struct rfkill *rfkill;
 +      struct delayed_work rfkill_poll;
 +      char rfkill_name[32];
  };
  
 -#define ATH9K_SLOT_TIME_6 6
 -#define ATH9K_SLOT_TIME_9 9
 -#define ATH9K_SLOT_TIME_20 20
 -
 -enum ath9k_ht_macmode {
 -      ATH9K_HT_MACMODE_20 = 0,
 -      ATH9K_HT_MACMODE_2040 = 1,
 -};
 +/********************/
 +/* Main driver core */
 +/********************/
  
 -enum ath9k_ht_extprotspacing {
 -      ATH9K_HT_EXTPROTSPACING_20 = 0,
 -      ATH9K_HT_EXTPROTSPACING_25 = 1,
 -};
 +/*
 + * Default cache line size, in bytes.
 + * Used when PCI device not fully initialized by bootrom/BIOS
 +*/
 +#define DEFAULT_CACHELINE       32
 +#define       ATH_DEFAULT_NOISE_FLOOR -95
 +#define ATH_REGCLASSIDS_MAX     10
 +#define ATH_CABQ_READY_TIME     80      /* % of beacon interval */
 +#define ATH_MAX_SW_RETRIES      10
 +#define ATH_CHAN_MAX            255
 +#define IEEE80211_WEP_NKID      4       /* number of key ids */
  
 -struct ath9k_ht_cwm {
 -      enum ath9k_ht_macmode ht_macmode;
 +/*
 + * The key cache is used for h/w cipher state and also for
 + * tracking station state such as the current tx antenna.
 + * We also setup a mapping table between key cache slot indices
 + * and station state to short-circuit node lookups on rx.
 + * Different parts have different size key caches.  We handle
 + * up to ATH_KEYMAX entries (could dynamically allocate state).
 + */
 +#define       ATH_KEYMAX              128     /* max key cache size we handle */
 +
 +#define ATH_TXPOWER_MAX         100     /* .5 dBm units */
 +#define ATH_RSSI_DUMMY_MARKER   0x127
 +#define ATH_RATE_DUMMY_MARKER   0
 +
 +#define SC_OP_INVALID           BIT(0)
 +#define SC_OP_BEACONS           BIT(1)
 +#define SC_OP_RXAGGR            BIT(2)
 +#define SC_OP_TXAGGR            BIT(3)
 +#define SC_OP_CHAINMASK_UPDATE  BIT(4)
 +#define SC_OP_FULL_RESET        BIT(5)
 +#define SC_OP_PREAMBLE_SHORT    BIT(6)
 +#define SC_OP_PROTECT_ENABLE    BIT(7)
 +#define SC_OP_RXFLUSH           BIT(8)
 +#define SC_OP_LED_ASSOCIATED    BIT(9)
 +#define SC_OP_RFKILL_REGISTERED BIT(10)
 +#define SC_OP_RFKILL_SW_BLOCKED BIT(11)
 +#define SC_OP_RFKILL_HW_BLOCKED BIT(12)
 +#define SC_OP_WAIT_FOR_BEACON   BIT(13)
 +#define SC_OP_LED_ON            BIT(14)
 +#define SC_OP_SCANNING          BIT(15)
 +#define SC_OP_TSF_RESET         BIT(16)
 +
 +struct ath_bus_ops {
 +      void            (*read_cachesize)(struct ath_softc *sc, int *csz);
 +      void            (*cleanup)(struct ath_softc *sc);
 +      bool            (*eeprom_read)(struct ath_hw *ah, u32 off, u16 *data);
 +};
 +
 +struct ath_wiphy;
 +
 +struct ath_softc {
 +      struct ieee80211_hw *hw;
 +      struct device *dev;
 +
 +      spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */
 +      struct ath_wiphy *pri_wiphy;
 +      struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may
 +                                     * have NULL entries */
 +      int num_sec_wiphy; /* number of sec_wiphy pointers in the array */
 +      int chan_idx;
 +      int chan_is_ht;
 +      struct ath_wiphy *next_wiphy;
 +      struct work_struct chan_work;
 +      int wiphy_select_failures;
 +      unsigned long wiphy_select_first_fail;
 +      struct delayed_work wiphy_work;
 +      unsigned long wiphy_scheduler_int;
 +      int wiphy_scheduler_index;
 +
 +      struct tasklet_struct intr_tq;
 +      struct tasklet_struct bcon_tasklet;
 +      struct ath_hw *sc_ah;
 +      void __iomem *mem;
 +      int irq;
 +      spinlock_t sc_resetlock;
++      spinlock_t sc_serial_rw;
 +      struct mutex mutex;
 +
 +      u8 curbssid[ETH_ALEN];
 +      u8 bssidmask[ETH_ALEN];
 +      u32 intrstatus;
 +      u32 sc_flags; /* SC_OP_* */
 +      u16 curtxpow;
 +      u16 curaid;
 +      u16 cachelsz;
 +      u8 nbcnvifs;
 +      u16 nvifs;
 +      u8 tx_chainmask;
 +      u8 rx_chainmask;
 +      u32 keymax;
 +      DECLARE_BITMAP(keymap, ATH_KEYMAX);
 +      u8 splitmic;
 +      atomic_t ps_usecount;
 +      enum ath9k_int imask;
        enum ath9k_ht_extprotspacing ht_extprotspacing;
 -};
 -
 -enum ath9k_ani_cmd {
 -      ATH9K_ANI_PRESENT = 0x1,
 -      ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2,
 -      ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION = 0x4,
 -      ATH9K_ANI_CCK_WEAK_SIGNAL_THR = 0x8,
 -      ATH9K_ANI_FIRSTEP_LEVEL = 0x10,
 -      ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20,
 -      ATH9K_ANI_MODE = 0x40,
 -      ATH9K_ANI_PHYERR_RESET = 0x80,
 -      ATH9K_ANI_ALL = 0xff
 -};
 -
 -enum {
 -      WLAN_RC_PHY_OFDM,
 -      WLAN_RC_PHY_CCK,
 -      WLAN_RC_PHY_HT_20_SS,
 -      WLAN_RC_PHY_HT_20_DS,
 -      WLAN_RC_PHY_HT_40_SS,
 -      WLAN_RC_PHY_HT_40_DS,
 -      WLAN_RC_PHY_HT_20_SS_HGI,
 -      WLAN_RC_PHY_HT_20_DS_HGI,
 -      WLAN_RC_PHY_HT_40_SS_HGI,
 -      WLAN_RC_PHY_HT_40_DS_HGI,
 -      WLAN_RC_PHY_MAX
 -};
 -
 -enum ath9k_tp_scale {
 -      ATH9K_TP_SCALE_MAX = 0,
 -      ATH9K_TP_SCALE_50,
 -      ATH9K_TP_SCALE_25,
 -      ATH9K_TP_SCALE_12,
 -      ATH9K_TP_SCALE_MIN
 -};
 -
 -enum ser_reg_mode {
 -      SER_REG_MODE_OFF = 0,
 -      SER_REG_MODE_ON = 1,
 -      SER_REG_MODE_AUTO = 2,
 -};
 -
 -#define AR_PHY_CCA_MAX_GOOD_VALUE                     -85
 -#define AR_PHY_CCA_MAX_HIGH_VALUE                     -62
 -#define AR_PHY_CCA_MIN_BAD_VALUE                      -121
 -#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT     3
 -#define AR_PHY_CCA_FILTERWINDOW_LENGTH          5
 -
 -#define ATH9K_NF_CAL_HIST_MAX           5
 -#define NUM_NF_READINGS                 6
 -
 -struct ath9k_nfcal_hist {
 -      int16_t nfCalBuffer[ATH9K_NF_CAL_HIST_MAX];
 -      u8 currIndex;
 -      int16_t privNF;
 -      u8 invalidNFcount;
 -};
 -
 -struct ath9k_beacon_state {
 -      u32 bs_nexttbtt;
 -      u32 bs_nextdtim;
 -      u32 bs_intval;
 -#define ATH9K_BEACON_PERIOD       0x0000ffff
 -#define ATH9K_BEACON_ENA          0x00800000
 -#define ATH9K_BEACON_RESET_TSF    0x01000000
 -      u32 bs_dtimperiod;
 -      u16 bs_cfpperiod;
 -      u16 bs_cfpmaxduration;
 -      u32 bs_cfpnext;
 -      u16 bs_timoffset;
 -      u16 bs_bmissthreshold;
 -      u32 bs_sleepduration;
 -};
 -
 -struct ath9k_node_stats {
 -      u32 ns_avgbrssi;
 -      u32 ns_avgrssi;
 -      u32 ns_avgtxrssi;
 -      u32 ns_avgtxrate;
 -};
 -
 -#define ATH9K_RSSI_EP_MULTIPLIER  (1<<7)
 -
 -#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT             0
 -#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
 -#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED     2
 -#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED    5
 -#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED      6
 -
 -enum {
 -      ATH9K_RESET_POWER_ON,
 -      ATH9K_RESET_WARM,
 -      ATH9K_RESET_COLD,
 -};
 -
 -#define AH_USE_EEPROM   0x1
 -
 -struct ath_hal {
 -      u32 ah_magic;
 -      u16 ah_devid;
 -      u16 ah_subvendorid;
 -      u32 ah_macVersion;
 -      u16 ah_macRev;
 -      u16 ah_phyRev;
 -      u16 ah_analog5GhzRev;
 -      u16 ah_analog2GhzRev;
 -
 -      void __iomem *ah_sh;
 -      struct ath_softc *ah_sc;
 -
 -      enum nl80211_iftype ah_opmode;
 -      struct ath9k_ops_config ah_config;
 -      struct ath9k_hw_capabilities ah_caps;
 -
 -      u16 ah_countryCode;
 -      u32 ah_flags;
 -      int16_t ah_powerLimit;
 -      u16 ah_maxPowerLevel;
 -      u32 ah_tpScale;
 -      u16 ah_currentRD;
 -      u16 ah_currentRDExt;
 -      u16 ah_currentRDInUse;
 -      u16 ah_currentRD5G;
 -      u16 ah_currentRD2G;
 -      char ah_iso[4];
 -
 -      struct ath9k_channel ah_channels[150];
 -      struct ath9k_channel *ah_curchan;
 -      u32 ah_nchan;
 -
 -      bool ah_isPciExpress;
 -      u16 ah_txTrigLevel;
 -      u16 ah_rfsilent;
 -      u32 ah_rfkill_gpio;
 -      u32 ah_rfkill_polarity;
 -
 -#ifndef ATH_NF_PER_CHAN
 -      struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
 +      enum ath9k_ht_macmode tx_chan_width;
 +
 +      struct ath_config config;
 +      struct ath_rx rx;
 +      struct ath_tx tx;
 +      struct ath_beacon beacon;
 +      struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
 +      struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX];
 +      struct ath_rate_table *cur_rate_table;
 +      struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
 +
 +      struct ath_led radio_led;
 +      struct ath_led assoc_led;
 +      struct ath_led tx_led;
 +      struct ath_led rx_led;
 +      struct delayed_work ath_led_blink_work;
 +      int led_on_duration;
 +      int led_off_duration;
 +      int led_on_cnt;
 +      int led_off_cnt;
 +
 +      struct ath_rfkill rf_kill;
 +      struct ath_ani ani;
 +      struct ath9k_node_stats nodestats;
 +#ifdef CONFIG_ATH9K_DEBUG
 +      struct ath9k_debug debug;
 +#endif
 +      struct ath_bus_ops *bus_ops;
 +};
 +
 +struct ath_wiphy {
 +      struct ath_softc *sc; /* shared for all virtual wiphys */
 +      struct ieee80211_hw *hw;
 +      enum ath_wiphy_state {
 +              ATH_WIPHY_INACTIVE,
 +              ATH_WIPHY_ACTIVE,
 +              ATH_WIPHY_PAUSING,
 +              ATH_WIPHY_PAUSED,
 +              ATH_WIPHY_SCAN,
 +      } state;
 +      int chan_idx;
 +      int chan_is_ht;
 +};
 +
 +int ath_reset(struct ath_softc *sc, bool retry_tx);
 +int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
 +int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
 +int ath_cabq_update(struct ath_softc *);
 +
 +static inline void ath_read_cachesize(struct ath_softc *sc, int *csz)
 +{
 +      sc->bus_ops->read_cachesize(sc, csz);
 +}
 +
 +static inline void ath_bus_cleanup(struct ath_softc *sc)
 +{
 +      sc->bus_ops->cleanup(sc);
 +}
 +
 +extern struct ieee80211_ops ath9k_ops;
 +
 +irqreturn_t ath_isr(int irq, void *dev);
 +void ath_cleanup(struct ath_softc *sc);
 +int ath_attach(u16 devid, struct ath_softc *sc);
 +void ath_detach(struct ath_softc *sc);
 +const char *ath_mac_bb_name(u32 mac_bb_version);
 +const char *ath_rf_name(u16 rf_version);
 +void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
 +void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
 +                         struct ath9k_channel *ichan);
 +void ath_update_chainmask(struct ath_softc *sc, int is_ht);
 +int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 +                  struct ath9k_channel *hchan);
 +void ath_radio_enable(struct ath_softc *sc);
 +void ath_radio_disable(struct ath_softc *sc);
 +
 +#ifdef CONFIG_PCI
 +int ath_pci_init(void);
 +void ath_pci_exit(void);
 +#else
 +static inline int ath_pci_init(void) { return 0; };
 +static inline void ath_pci_exit(void) {};
  #endif
 -};
 -
 -struct chan_centers {
 -      u16 synth_center;
 -      u16 ctl_center;
 -      u16 ext_center;
 -};
  
 -struct ath_rate_table;
 -
 -/* Helpers */
 -
 -enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
 -                             const struct ath9k_channel *chan);
 -bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val);
 -u32 ath9k_hw_reverse_bits(u32 val, u32 n);
 -bool ath9k_get_channel_edges(struct ath_hal *ah,
 -                           u16 flags, u16 *low,
 -                           u16 *high);
 -u16 ath9k_hw_computetxtime(struct ath_hal *ah,
 -                         struct ath_rate_table *rates,
 -                         u32 frameLen, u16 rateix,
 -                         bool shortPreamble);
 -u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
 -void ath9k_hw_get_channel_centers(struct ath_hal *ah,
 -                                struct ath9k_channel *chan,
 -                                struct chan_centers *centers);
 -
 -/* Attach, Detach */
 -
 -const char *ath9k_hw_probe(u16 vendorid, u16 devid);
 -void ath9k_hw_detach(struct ath_hal *ah);
 -struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
 -                              void __iomem *mem, int *error);
 -void ath9k_hw_rfdetach(struct ath_hal *ah);
 -
 -
 -/* HW Reset */
 -
 -bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
 -                  enum ath9k_ht_macmode macmode,
 -                  u8 txchainmask, u8 rxchainmask,
 -                  enum ath9k_ht_extprotspacing extprotspacing,
 -                  bool bChannelChange, int *status);
 -
 -/* Key Cache Management */
 -
 -bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry);
 -bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac);
 -bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
 -                               const struct ath9k_keyval *k,
 -                               const u8 *mac, int xorKey);
 -bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry);
 -
 -/* Power Management */
 -
 -bool ath9k_hw_setpower(struct ath_hal *ah,
 -                     enum ath9k_power_mode mode);
 -void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore);
 -
 -/* Beacon timers */
 -
 -void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period);
 -void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
 -                                  const struct ath9k_beacon_state *bs);
 -/* HW Capabilities */
 -
 -bool ath9k_hw_fill_cap_info(struct ath_hal *ah);
 -bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
 -                          u32 capability, u32 *result);
 -bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type,
 -                          u32 capability, u32 setting, int *status);
 -
 -/* GPIO / RFKILL / Antennae */
 -
 -void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio);
 -u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio);
 -void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
 -                       u32 ah_signal_type);
 -void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val);
 -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 -void ath9k_enable_rfkill(struct ath_hal *ah);
 +#ifdef CONFIG_ATHEROS_AR71XX
 +int ath_ahb_init(void);
 +void ath_ahb_exit(void);
 +#else
 +static inline int ath_ahb_init(void) { return 0; };
 +static inline void ath_ahb_exit(void) {};
  #endif
 -int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg);
 -u32 ath9k_hw_getdefantenna(struct ath_hal *ah);
 -void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna);
 -bool ath9k_hw_setantennaswitch(struct ath_hal *ah,
 -                             enum ath9k_ant_setting settings,
 -                             struct ath9k_channel *chan,
 -                             u8 *tx_chainmask,
 -                             u8 *rx_chainmask,
 -                             u8 *antenna_cfgd);
 -
 -/* General Operation */
 -
 -u32 ath9k_hw_getrxfilter(struct ath_hal *ah);
 -void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits);
 -bool ath9k_hw_phy_disable(struct ath_hal *ah);
 -bool ath9k_hw_disable(struct ath_hal *ah);
 -bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit);
 -void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac);
 -bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac);
 -void ath9k_hw_setopmode(struct ath_hal *ah);
 -void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1);
 -void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask);
 -bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask);
 -void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId);
 -u64 ath9k_hw_gettsf64(struct ath_hal *ah);
 -void ath9k_hw_reset_tsf(struct ath_hal *ah);
 -bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting);
 -bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us);
 -void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode);
 -
 -/* Regulatory */
 -
 -bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah);
 -struct ath9k_channel* ath9k_regd_check_channel(struct ath_hal *ah,
 -                       const struct ath9k_channel *c);
 -u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan);
 -u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
 -                                 struct ath9k_channel *chan);
 -bool ath9k_regd_init_channels(struct ath_hal *ah,
 -                            u32 maxchans, u32 *nchans, u8 *regclassids,
 -                            u32 maxregids, u32 *nregids, u16 cc,
 -                            bool enableOutdoor, bool enableExtendedChannels);
  
 -/* ANI */
 +static inline void ath9k_ps_wakeup(struct ath_softc *sc)
 +{
 +      if (atomic_inc_return(&sc->ps_usecount) == 1)
 +              if (sc->sc_ah->power_mode !=  ATH9K_PM_AWAKE) {
 +                      sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
 +                      ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
 +              }
 +}
 +
 +static inline void ath9k_ps_restore(struct ath_softc *sc)
 +{
 +      if (atomic_dec_and_test(&sc->ps_usecount))
 +              if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
 +                  !(sc->sc_flags & SC_OP_WAIT_FOR_BEACON))
 +                      ath9k_hw_setpower(sc->sc_ah,
 +                                        sc->sc_ah->restore_mode);
 +}
 +
 +
 +void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
 +int ath9k_wiphy_add(struct ath_softc *sc);
 +int ath9k_wiphy_del(struct ath_wiphy *aphy);
 +void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb);
 +int ath9k_wiphy_pause(struct ath_wiphy *aphy);
 +int ath9k_wiphy_unpause(struct ath_wiphy *aphy);
 +int ath9k_wiphy_select(struct ath_wiphy *aphy);
 +void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int);
 +void ath9k_wiphy_chan_work(struct work_struct *work);
 +bool ath9k_wiphy_started(struct ath_softc *sc);
 +void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
 +                                struct ath_wiphy *selected);
 +bool ath9k_wiphy_scanning(struct ath_softc *sc);
 +void ath9k_wiphy_work(struct work_struct *work);
  
 -void ath9k_ani_reset(struct ath_hal *ah);
 -void ath9k_hw_ani_monitor(struct ath_hal *ah,
 -                        const struct ath9k_node_stats *stats,
 -                        struct ath9k_channel *chan);
 -bool ath9k_hw_phycounters(struct ath_hal *ah);
 -void ath9k_enable_mib_counters(struct ath_hal *ah);
 -void ath9k_hw_disable_mib_counters(struct ath_hal *ah);
 -u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
 -                                u32 *rxc_pcnt,
 -                                u32 *rxf_pcnt,
 -                                u32 *txf_pcnt);
 -void ath9k_hw_procmibevent(struct ath_hal *ah,
 -                         const struct ath9k_node_stats *stats);
 -void ath9k_hw_ani_setup(struct ath_hal *ah);
 -void ath9k_hw_ani_attach(struct ath_hal *ah);
 -void ath9k_hw_ani_detach(struct ath_hal *ah);
 -
 -/* Calibration */
 -
 -void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
 -                           bool *isCalDone);
 -void ath9k_hw_start_nfcal(struct ath_hal *ah);
 -void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan);
 -int16_t ath9k_hw_getnf(struct ath_hal *ah,
 -                     struct ath9k_channel *chan);
 -void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah);
 -s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan);
 -bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
 -                      u8 rxchainmask, bool longcal,
 -                      bool *isCalDone);
 -bool ath9k_hw_init_cal(struct ath_hal *ah,
 -                     struct ath9k_channel *chan);
 -
 -
 -/* EEPROM */
 -
 -int ath9k_hw_set_txpower(struct ath_hal *ah,
 -                       struct ath9k_channel *chan,
 -                       u16 cfgCtl,
 -                       u8 twiceAntennaReduction,
 -                       u8 twiceMaxRegulatoryPower,
 -                       u8 powerLimit);
 -void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan);
 -bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah,
 -                                     struct ath9k_channel *chan,
 -                                     int16_t *ratesArray,
 -                                     u16 cfgCtl,
 -                                     u8 AntennaReduction,
 -                                     u8 twiceMaxRegulatoryPower,
 -                                     u8 powerLimit);
 -bool ath9k_hw_set_power_cal_table(struct ath_hal *ah,
 -                                struct ath9k_channel *chan,
 -                                int16_t *pTxPowerIndexOffset);
 -bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
 -                                    struct ath9k_channel *chan);
 -int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah,
 -                                  struct ath9k_channel *chan,
 -                                  u8 index, u16 *config);
 -u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah,
 -                             enum ieee80211_band freq_band);
 -u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz);
 -int ath9k_hw_eeprom_attach(struct ath_hal *ah);
 -
 -/* Interrupt Handling */
 -
 -bool ath9k_hw_intrpend(struct ath_hal *ah);
 -bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked);
 -enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah);
 -enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints);
 -
 -/* MAC (PCU/QCU) */
 -
 -u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q);
 -bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp);
 -bool ath9k_hw_txstart(struct ath_hal *ah, u32 q);
 -u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q);
 -bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel);
 -bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q);
 -bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
 -                       u32 segLen, bool firstSeg,
 -                       bool lastSeg, const struct ath_desc *ds0);
 -void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds);
 -int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds);
 -void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
 -                          u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
 -                          u32 keyIx, enum ath9k_key_type keyType, u32 flags);
 -void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
 -                                struct ath_desc *lastds,
 -                                u32 durUpdateEn, u32 rtsctsRate,
 -                                u32 rtsctsDuration,
 -                                struct ath9k_11n_rate_series series[],
 -                                u32 nseries, u32 flags);
 -void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
 -                              u32 aggrLen);
 -void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
 -                               u32 numDelims);
 -void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds);
 -void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds);
 -void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
 -                                 u32 burstDuration);
 -void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
 -                                   u32 vmf);
 -void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs);
 -bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
 -                          const struct ath9k_tx_queue_info *qinfo);
 -bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
 -                          struct ath9k_tx_queue_info *qinfo);
 -int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
 -                        const struct ath9k_tx_queue_info *qinfo);
 -bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q);
 -bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q);
 -int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
 -                      u32 pa, struct ath_desc *nds, u64 tsf);
 -bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
 -                        u32 size, u32 flags);
 -bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set);
 -void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp);
 -void ath9k_hw_rxena(struct ath_hal *ah);
 -void ath9k_hw_startpcureceive(struct ath_hal *ah);
 -void ath9k_hw_stoppcurecv(struct ath_hal *ah);
 -bool ath9k_hw_stopdmarecv(struct ath_hal *ah);
++/*
++ * Read and write, they both share the same lock. We do this to serialize
++ * reads and writes on Atheros 802.11n PCI devices only. This is required
++ * as the FIFO on these devices can only accept sanely 2 requests. After
++ * that the device goes bananas. Serializing the reads/writes prevents this
++ * from happening.
++ */
 -#endif
++static inline void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val)
++{
++      if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
++              unsigned long flags;
++              spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags);
++              iowrite32(val, ah->ah_sc->mem + reg_offset);
++              spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags);
++      } else
++              iowrite32(val, ah->ah_sc->mem + reg_offset);
++}
++
++static inline unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset)
++{
++      u32 val;
++      if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
++              unsigned long flags;
++              spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags);
++              val = ioread32(ah->ah_sc->mem + reg_offset);
++              spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags);
++      } else
++              val = ioread32(ah->ah_sc->mem + reg_offset);
++      return val;
++}
++
 +#endif /* ATH9K_H */
index eb750a503999aac80853b6cb0c7a69eea4aba54e,c38a00bbce64664caa1042be4ee37da97e1f6c46..60e55d8c510ba2efe3692a1fe498bf477373ec21
  #include <linux/io.h>
  #include <asm/unaligned.h>
  
 -#include "core.h"
 -#include "hw.h"
 -#include "reg.h"
 -#include "phy.h"
 +#include "ath9k.h"
  #include "initvals.h"
  
 -static const u8 CLOCK_RATE[] = { 40, 80, 22, 44, 88, 40 };
 +static int btcoex_enable;
 +module_param(btcoex_enable, bool, 0);
 +MODULE_PARM_DESC(btcoex_enable, "Enable Bluetooth coexistence support");
  
 -extern struct hal_percal_data iq_cal_multi_sample;
 -extern struct hal_percal_data iq_cal_single_sample;
 -extern struct hal_percal_data adc_gain_cal_multi_sample;
 -extern struct hal_percal_data adc_gain_cal_single_sample;
 -extern struct hal_percal_data adc_dc_cal_multi_sample;
 -extern struct hal_percal_data adc_dc_cal_single_sample;
 -extern struct hal_percal_data adc_init_dc_cal;
 +#define ATH9K_CLOCK_RATE_CCK          22
 +#define ATH9K_CLOCK_RATE_5GHZ_OFDM    40
 +#define ATH9K_CLOCK_RATE_2GHZ_OFDM    44
  
 -static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type);
 -static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
 +static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
 +static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan,
                              enum ath9k_ht_macmode macmode);
 -static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
 +static u32 ath9k_hw_ini_fixup(struct ath_hw *ah,
                              struct ar5416_eeprom_def *pEepData,
                              u32 reg, u32 value);
 -static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan);
 -static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan);
 +static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan);
 +static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan);
  
  /********************/
  /* Helper Functions */
  /********************/
  
 -static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks)
 +static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks)
  {
 -      if (ah->ah_curchan != NULL)
 -              return clks / CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)];
 -      else
 -              return clks / CLOCK_RATE[ATH9K_MODE_11B];
 +      struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
 +
 +      if (!ah->curchan) /* should really check for CCK instead */
 +              return clks / ATH9K_CLOCK_RATE_CCK;
 +      if (conf->channel->band == IEEE80211_BAND_2GHZ)
 +              return clks / ATH9K_CLOCK_RATE_2GHZ_OFDM;
 +
 +      return clks / ATH9K_CLOCK_RATE_5GHZ_OFDM;
  }
  
 -static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks)
 +static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks)
  {
 -      struct ath9k_channel *chan = ah->ah_curchan;
 +      struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
  
 -      if (chan && IS_CHAN_HT40(chan))
 +      if (conf_is_ht40(conf))
                return ath9k_hw_mac_usec(ah, clks) / 2;
        else
                return ath9k_hw_mac_usec(ah, clks);
  }
  
 -static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs)
 +static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs)
  {
 -      if (ah->ah_curchan != NULL)
 -              return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah,
 -                      ah->ah_curchan)];
 -      else
 -              return usecs * CLOCK_RATE[ATH9K_MODE_11B];
 +      struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
 +
 +      if (!ah->curchan) /* should really check for CCK instead */
 +              return usecs *ATH9K_CLOCK_RATE_CCK;
 +      if (conf->channel->band == IEEE80211_BAND_2GHZ)
 +              return usecs *ATH9K_CLOCK_RATE_2GHZ_OFDM;
 +      return usecs *ATH9K_CLOCK_RATE_5GHZ_OFDM;
  }
  
 -static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs)
 +static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
  {
 -      struct ath9k_channel *chan = ah->ah_curchan;
 +      struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
  
 -      if (chan && IS_CHAN_HT40(chan))
 +      if (conf_is_ht40(conf))
                return ath9k_hw_mac_clks(ah, usecs) * 2;
        else
                return ath9k_hw_mac_clks(ah, usecs);
  }
  
 -enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
 -                             const struct ath9k_channel *chan)
 -{
 -      if (IS_CHAN_B(chan))
 -              return ATH9K_MODE_11B;
 -      if (IS_CHAN_G(chan))
 -              return ATH9K_MODE_11G;
 -
 -      return ATH9K_MODE_11A;
 -}
 -
 -bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val)
 +bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
  {
        int i;
  
 -      for (i = 0; i < (AH_TIMEOUT / AH_TIME_QUANTUM); i++) {
 +      BUG_ON(timeout < AH_TIME_QUANTUM);
 +
 +      for (i = 0; i < (timeout / AH_TIME_QUANTUM); i++) {
                if ((REG_READ(ah, reg) & mask) == val)
                        return true;
  
        }
  
        DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
 -              "timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
 -              reg, REG_READ(ah, reg), mask, val);
 +              "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
 +              timeout, reg, REG_READ(ah, reg), mask, val);
  
        return false;
  }
@@@ -116,11 -124,11 +116,11 @@@ u32 ath9k_hw_reverse_bits(u32 val, u32 
        return retval;
  }
  
 -bool ath9k_get_channel_edges(struct ath_hal *ah,
 +bool ath9k_get_channel_edges(struct ath_hw *ah,
                             u16 flags, u16 *low,
                             u16 *high)
  {
 -      struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
 +      struct ath9k_hw_capabilities *pCap = &ah->caps;
  
        if (flags & CHANNEL_5GHZ) {
                *low = pCap->low_5ghz_chan;
        return false;
  }
  
 -u16 ath9k_hw_computetxtime(struct ath_hal *ah,
 +u16 ath9k_hw_computetxtime(struct ath_hw *ah,
                           struct ath_rate_table *rates,
                           u32 frameLen, u16 rateix,
                           bool shortPreamble)
                txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps);
                break;
        case WLAN_RC_PHY_OFDM:
 -              if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) {
 +              if (ah->curchan && IS_CHAN_QUARTER_RATE(ah->curchan)) {
                        bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
                        numBits = OFDM_PLCP_BITS + (frameLen << 3);
                        numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
                        txTime = OFDM_SIFS_TIME_QUARTER
                                + OFDM_PREAMBLE_TIME_QUARTER
                                + (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
 -              } else if (ah->ah_curchan &&
 -                         IS_CHAN_HALF_RATE(ah->ah_curchan)) {
 +              } else if (ah->curchan &&
 +                         IS_CHAN_HALF_RATE(ah->curchan)) {
                        bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000;
                        numBits = OFDM_PLCP_BITS + (frameLen << 3);
                        numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
        return txTime;
  }
  
 -u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags)
 -{
 -      if (flags & CHANNEL_2GHZ) {
 -              if (freq == 2484)
 -                      return 14;
 -              if (freq < 2484)
 -                      return (freq - 2407) / 5;
 -              else
 -                      return 15 + ((freq - 2512) / 20);
 -      } else if (flags & CHANNEL_5GHZ) {
 -              if (ath9k_regd_is_public_safety_sku(ah) &&
 -                  IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
 -                      return ((freq * 10) +
 -                              (((freq % 5) == 2) ? 5 : 0) - 49400) / 5;
 -              } else if ((flags & CHANNEL_A) && (freq <= 5000)) {
 -                      return (freq - 4000) / 5;
 -              } else {
 -                      return (freq - 5000) / 5;
 -              }
 -      } else {
 -              if (freq == 2484)
 -                      return 14;
 -              if (freq < 2484)
 -                      return (freq - 2407) / 5;
 -              if (freq < 5000) {
 -                      if (ath9k_regd_is_public_safety_sku(ah)
 -                          && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
 -                              return ((freq * 10) +
 -                                      (((freq % 5) ==
 -                                        2) ? 5 : 0) - 49400) / 5;
 -                      } else if (freq > 4900) {
 -                              return (freq - 4000) / 5;
 -                      } else {
 -                              return 15 + ((freq - 2512) / 20);
 -                      }
 -              }
 -              return (freq - 5000) / 5;
 -      }
 -}
 -
 -void ath9k_hw_get_channel_centers(struct ath_hal *ah,
 +void ath9k_hw_get_channel_centers(struct ath_hw *ah,
                                  struct ath9k_channel *chan,
                                  struct chan_centers *centers)
  {
        int8_t extoff;
 -      struct ath_hal_5416 *ahp = AH5416(ah);
  
        if (!IS_CHAN_HT40(chan)) {
                centers->ctl_center = centers->ext_center =
                centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT);
        centers->ext_center =
                centers->synth_center + (extoff *
 -                       ((ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ?
 +                       ((ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ?
                          HT40_CHANNEL_CENTER_SHIFT : 15));
 -
  }
  
  /******************/
  /* Chip Revisions */
  /******************/
  
 -static void ath9k_hw_read_revisions(struct ath_hal *ah)
 +static void ath9k_hw_read_revisions(struct ath_hw *ah)
  {
        u32 val;
  
  
        if (val == 0xFF) {
                val = REG_READ(ah, AR_SREV);
 -              ah->ah_macVersion = (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
 -              ah->ah_macRev = MS(val, AR_SREV_REVISION2);
 -              ah->ah_isPciExpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
 +              ah->hw_version.macVersion =
 +                      (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
 +              ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
 +              ah->is_pciexpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
        } else {
                if (!AR_SREV_9100(ah))
 -                      ah->ah_macVersion = MS(val, AR_SREV_VERSION);
 +                      ah->hw_version.macVersion = MS(val, AR_SREV_VERSION);
  
 -              ah->ah_macRev = val & AR_SREV_REVISION;
 +              ah->hw_version.macRev = val & AR_SREV_REVISION;
  
 -              if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE)
 -                      ah->ah_isPciExpress = true;
 +              if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE)
 +                      ah->is_pciexpress = true;
        }
  }
  
 -static int ath9k_hw_get_radiorev(struct ath_hal *ah)
 +static int ath9k_hw_get_radiorev(struct ath_hw *ah)
  {
        u32 val;
        int i;
  /* HW Attach, Detach, Init Routines */
  /************************************/
  
 -static void ath9k_hw_disablepcie(struct ath_hal *ah)
 +static void ath9k_hw_disablepcie(struct ath_hw *ah)
  {
 -      if (!AR_SREV_9100(ah))
 +      if (AR_SREV_9100(ah))
                return;
  
        REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
        REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
  }
  
 -static bool ath9k_hw_chip_test(struct ath_hal *ah)
 +static bool ath9k_hw_chip_test(struct ath_hw *ah)
  {
        u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) };
        u32 regHold[2];
                REG_WRITE(ah, regAddr[i], regHold[i]);
        }
        udelay(100);
 +
        return true;
  }
  
@@@ -341,8 -389,6 +341,8 @@@ static const char *ath9k_hw_devname(u1
                return "Atheros 5418";
        case AR9160_DEVID_PCI:
                return "Atheros 9160";
 +      case AR5416_AR9100_DEVID:
 +              return "Atheros 9100";
        case AR9280_DEVID_PCI:
        case AR9280_DEVID_PCIE:
                return "Atheros 9280";
        return NULL;
  }
  
 -static void ath9k_hw_set_defaults(struct ath_hal *ah)
 +static void ath9k_hw_set_defaults(struct ath_hw *ah)
  {
        int i;
  
 -      ah->ah_config.dma_beacon_response_time = 2;
 -      ah->ah_config.sw_beacon_response_time = 10;
 -      ah->ah_config.additional_swba_backoff = 0;
 -      ah->ah_config.ack_6mb = 0x0;
 -      ah->ah_config.cwm_ignore_extcca = 0;
 -      ah->ah_config.pcie_powersave_enable = 0;
 -      ah->ah_config.pcie_l1skp_enable = 0;
 -      ah->ah_config.pcie_clock_req = 0;
 -      ah->ah_config.pcie_power_reset = 0x100;
 -      ah->ah_config.pcie_restore = 0;
 -      ah->ah_config.pcie_waen = 0;
 -      ah->ah_config.analog_shiftreg = 1;
 -      ah->ah_config.ht_enable = 1;
 -      ah->ah_config.ofdm_trig_low = 200;
 -      ah->ah_config.ofdm_trig_high = 500;
 -      ah->ah_config.cck_trig_high = 200;
 -      ah->ah_config.cck_trig_low = 100;
 -      ah->ah_config.enable_ani = 1;
 -      ah->ah_config.noise_immunity_level = 4;
 -      ah->ah_config.ofdm_weaksignal_det = 1;
 -      ah->ah_config.cck_weaksignal_thr = 0;
 -      ah->ah_config.spur_immunity_level = 2;
 -      ah->ah_config.firstep_level = 0;
 -      ah->ah_config.rssi_thr_high = 40;
 -      ah->ah_config.rssi_thr_low = 7;
 -      ah->ah_config.diversity_control = 0;
 -      ah->ah_config.antenna_switch_swap = 0;
 +      ah->config.dma_beacon_response_time = 2;
 +      ah->config.sw_beacon_response_time = 10;
 +      ah->config.additional_swba_backoff = 0;
 +      ah->config.ack_6mb = 0x0;
 +      ah->config.cwm_ignore_extcca = 0;
 +      ah->config.pcie_powersave_enable = 0;
 +      ah->config.pcie_l1skp_enable = 0;
 +      ah->config.pcie_clock_req = 0;
 +      ah->config.pcie_power_reset = 0x100;
 +      ah->config.pcie_restore = 0;
 +      ah->config.pcie_waen = 0;
 +      ah->config.analog_shiftreg = 1;
 +      ah->config.ht_enable = 1;
 +      ah->config.ofdm_trig_low = 200;
 +      ah->config.ofdm_trig_high = 500;
 +      ah->config.cck_trig_high = 200;
 +      ah->config.cck_trig_low = 100;
 +      ah->config.enable_ani = 1;
 +      ah->config.noise_immunity_level = 4;
 +      ah->config.ofdm_weaksignal_det = 1;
 +      ah->config.cck_weaksignal_thr = 0;
 +      ah->config.spur_immunity_level = 2;
 +      ah->config.firstep_level = 0;
 +      ah->config.rssi_thr_high = 40;
 +      ah->config.rssi_thr_low = 7;
 +      ah->config.diversity_control = 0;
 +      ah->config.antenna_switch_swap = 0;
  
        for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
 -              ah->ah_config.spurchans[i][0] = AR_NO_SPUR;
 -              ah->ah_config.spurchans[i][1] = AR_NO_SPUR;
 +              ah->config.spurchans[i][0] = AR_NO_SPUR;
 +              ah->config.spurchans[i][1] = AR_NO_SPUR;
        }
  
 -      ah->ah_config.intr_mitigation = 1;
 +      ah->config.intr_mitigation = 1;
+       /*
+        * We need this for PCI devices only (Cardbus, PCI, miniPCI)
+        * _and_ if on non-uniprocessor systems (Multiprocessor/HT).
+        * This means we use it for all AR5416 devices, and the few
+        * minor PCI AR9280 devices out there.
+        *
+        * Serialization is required because these devices do not handle
+        * well the case of two concurrent reads/writes due to the latency
+        * involved. During one read/write another read/write can be issued
+        * on another CPU while the previous read/write may still be working
+        * on our hardware, if we hit this case the hardware poops in a loop.
+        * We prevent this by serializing reads and writes.
+        *
+        * This issue is not present on PCI-Express devices or pre-AR5416
+        * devices (legacy, 802.11abg).
+        */
+       if (num_possible_cpus() > 1)
 -              ah->ah_config.serialize_regmode = SER_REG_MODE_AUTO;
++              ah->config.serialize_regmode = SER_REG_MODE_AUTO;
  }
  
 -static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid,
 -                                            struct ath_softc *sc,
 -                                            void __iomem *mem,
 -                                            int *status)
 +static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
 +                                      int *status)
  {
 -      static const u8 defbssidmask[ETH_ALEN] =
 -              { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 -      struct ath_hal_5416 *ahp;
 -      struct ath_hal *ah;
 +      struct ath_hw *ah;
  
 -      ahp = kzalloc(sizeof(struct ath_hal_5416), GFP_KERNEL);
 -      if (ahp == NULL) {
 +      ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
 +      if (ah == NULL) {
                DPRINTF(sc, ATH_DBG_FATAL,
                        "Cannot allocate memory for state block\n");
                *status = -ENOMEM;
                return NULL;
        }
  
 -      ah = &ahp->ah;
        ah->ah_sc = sc;
 -      ah->ah_sh = mem;
 -      ah->ah_magic = AR5416_MAGIC;
 -      ah->ah_countryCode = CTRY_DEFAULT;
 -      ah->ah_devid = devid;
 -      ah->ah_subvendorid = 0;
 +      ah->hw_version.magic = AR5416_MAGIC;
 +      ah->regulatory.country_code = CTRY_DEFAULT;
 +      ah->hw_version.devid = devid;
 +      ah->hw_version.subvendorid = 0;
  
        ah->ah_flags = 0;
        if ((devid == AR5416_AR9100_DEVID))
 -              ah->ah_macVersion = AR_SREV_VERSION_9100;
 +              ah->hw_version.macVersion = AR_SREV_VERSION_9100;
        if (!AR_SREV_9100(ah))
                ah->ah_flags = AH_USE_EEPROM;
  
 -      ah->ah_powerLimit = MAX_RATE_POWER;
 -      ah->ah_tpScale = ATH9K_TP_SCALE_MAX;
 -      ahp->ah_atimWindow = 0;
 -      ahp->ah_diversityControl = ah->ah_config.diversity_control;
 -      ahp->ah_antennaSwitchSwap =
 -              ah->ah_config.antenna_switch_swap;
 -      ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
 -      ahp->ah_beaconInterval = 100;
 -      ahp->ah_enable32kHzClock = DONT_USE_32KHZ;
 -      ahp->ah_slottime = (u32) -1;
 -      ahp->ah_acktimeout = (u32) -1;
 -      ahp->ah_ctstimeout = (u32) -1;
 -      ahp->ah_globaltxtimeout = (u32) -1;
 -      memcpy(&ahp->ah_bssidmask, defbssidmask, ETH_ALEN);
 -
 -      ahp->ah_gBeaconRate = 0;
 +      ah->regulatory.power_limit = MAX_RATE_POWER;
 +      ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX;
 +      ah->atim_window = 0;
 +      ah->diversity_control = ah->config.diversity_control;
 +      ah->antenna_switch_swap =
 +              ah->config.antenna_switch_swap;
 +      ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
 +      ah->beacon_interval = 100;
 +      ah->enable_32kHz_clock = DONT_USE_32KHZ;
 +      ah->slottime = (u32) -1;
 +      ah->acktimeout = (u32) -1;
 +      ah->ctstimeout = (u32) -1;
 +      ah->globaltxtimeout = (u32) -1;
 +
 +      ah->gbeacon_rate = 0;
  
 -      return ahp;
 +      return ah;
  }
  
 -static int ath9k_hw_rfattach(struct ath_hal *ah)
 +static int ath9k_hw_rfattach(struct ath_hw *ah)
  {
        bool rfStatus = false;
        int ecode = 0;
        return 0;
  }
  
 -static int ath9k_hw_rf_claim(struct ath_hal *ah)
 +static int ath9k_hw_rf_claim(struct ath_hw *ah)
  {
        u32 val;
  
                DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
                        "5G Radio Chip Rev 0x%02X is not "
                        "supported by this driver\n",
 -                      ah->ah_analog5GhzRev);
 +                      ah->hw_version.analog5GhzRev);
                return -EOPNOTSUPP;
        }
  
 -      ah->ah_analog5GhzRev = val;
 +      ah->hw_version.analog5GhzRev = val;
  
        return 0;
  }
  
 -static int ath9k_hw_init_macaddr(struct ath_hal *ah)
 +static int ath9k_hw_init_macaddr(struct ath_hw *ah)
  {
        u32 sum;
        int i;
        u16 eeval;
 -      struct ath_hal_5416 *ahp = AH5416(ah);
  
        sum = 0;
        for (i = 0; i < 3; i++) {
 -              eeval = ath9k_hw_get_eeprom(ah, AR_EEPROM_MAC(i));
 +              eeval = ah->eep_ops->get_eeprom(ah, AR_EEPROM_MAC(i));
                sum += eeval;
 -              ahp->ah_macaddr[2 * i] = eeval >> 8;
 -              ahp->ah_macaddr[2 * i + 1] = eeval & 0xff;
 +              ah->macaddr[2 * i] = eeval >> 8;
 +              ah->macaddr[2 * i + 1] = eeval & 0xff;
        }
        if (sum == 0 || sum == 0xffff * 3) {
                DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
                        "mac address read failed: %pM\n",
 -                      ahp->ah_macaddr);
 +                      ah->macaddr);
                return -EADDRNOTAVAIL;
        }
  
        return 0;
  }
  
 -static void ath9k_hw_init_rxgain_ini(struct ath_hal *ah)
 +static void ath9k_hw_init_rxgain_ini(struct ath_hw *ah)
  {
        u32 rxgain_type;
 -      struct ath_hal_5416 *ahp = AH5416(ah);
  
 -      if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) {
 -              rxgain_type = ath9k_hw_get_eeprom(ah, EEP_RXGAIN_TYPE);
 +      if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) {
 +              rxgain_type = ah->eep_ops->get_eeprom(ah, EEP_RXGAIN_TYPE);
  
                if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF)
 -                      INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
 +                      INIT_INI_ARRAY(&ah->iniModesRxGain,
                        ar9280Modes_backoff_13db_rxgain_9280_2,
                        ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6);
                else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF)
 -                      INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
 +                      INIT_INI_ARRAY(&ah->iniModesRxGain,
                        ar9280Modes_backoff_23db_rxgain_9280_2,
                        ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6);
                else
 -                      INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
 +                      INIT_INI_ARRAY(&ah->iniModesRxGain,
                        ar9280Modes_original_rxgain_9280_2,
                        ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
 -      } else
 -              INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
 +      } else {
 +              INIT_INI_ARRAY(&ah->iniModesRxGain,
                        ar9280Modes_original_rxgain_9280_2,
                        ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
 +      }
  }
  
 -static void ath9k_hw_init_txgain_ini(struct ath_hal *ah)
 +static void ath9k_hw_init_txgain_ini(struct ath_hw *ah)
  {
        u32 txgain_type;
 -      struct ath_hal_5416 *ahp = AH5416(ah);
  
 -      if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) {
 -              txgain_type = ath9k_hw_get_eeprom(ah, EEP_TXGAIN_TYPE);
 +      if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) {
 +              txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
  
                if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
 -                      INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
 +                      INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9280Modes_high_power_tx_gain_9280_2,
                        ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6);
                else
 -                      INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
 +                      INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9280Modes_original_tx_gain_9280_2,
                        ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
 -      } else
 -              INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
 +      } else {
 +              INIT_INI_ARRAY(&ah->iniModesTxGain,
                ar9280Modes_original_tx_gain_9280_2,
                ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
 +      }
  }
  
 -static int ath9k_hw_post_attach(struct ath_hal *ah)
 +static int ath9k_hw_post_attach(struct ath_hw *ah)
  {
        int ecode;
  
        return 0;
  }
  
 -static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
 -                                        void __iomem *mem, int *status)
 +static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
 +                                       int *status)
  {
 -      struct ath_hal_5416 *ahp;
 -      struct ath_hal *ah;
 +      struct ath_hw *ah;
        int ecode;
        u32 i, j;
  
 -      ahp = ath9k_hw_newstate(devid, sc, mem, status);
 -      if (ahp == NULL)
 +      ah = ath9k_hw_newstate(devid, sc, status);
 +      if (ah == NULL)
                return NULL;
  
 -      ah = &ahp->ah;
 -
        ath9k_hw_set_defaults(ah);
  
 -      if (ah->ah_config.intr_mitigation != 0)
 -              ahp->ah_intrMitigation = true;
 +      if (ah->config.intr_mitigation != 0)
 +              ah->intr_mitigation = true;
  
        if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
 -              DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't reset chip\n");
 +              DPRINTF(sc, ATH_DBG_RESET, "Couldn't reset chip\n");
                ecode = -EIO;
                goto bad;
        }
  
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
 -              DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't wakeup chip\n");
 +              DPRINTF(sc, ATH_DBG_RESET, "Couldn't wakeup chip\n");
                ecode = -EIO;
                goto bad;
        }
  
 -      if (ah->ah_config.serialize_regmode == SER_REG_MODE_AUTO) {
 -              if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI ||
 -                  (AR_SREV_9280(ah) && !ah->ah_isPciExpress)) {
 -                      ah->ah_config.serialize_regmode =
 +      if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
-               if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) {
++              if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
++                  (AR_SREV_9280(ah) && !ah->is_pciexpress)) {
 +                      ah->config.serialize_regmode =
                                SER_REG_MODE_ON;
                } else {
 -                      ah->ah_config.serialize_regmode =
 +                      ah->config.serialize_regmode =
                                SER_REG_MODE_OFF;
                }
        }
  
 -      DPRINTF(ah->ah_sc, ATH_DBG_RESET,
 -              "serialize_regmode is %d\n",
 -              ah->ah_config.serialize_regmode);
 +      DPRINTF(sc, ATH_DBG_RESET, "serialize_regmode is %d\n",
 +              ah->config.serialize_regmode);
  
 -      if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) &&
 -          (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) &&
 -          (ah->ah_macVersion != AR_SREV_VERSION_9160) &&
 +      if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) &&
 +          (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) &&
 +          (ah->hw_version.macVersion != AR_SREV_VERSION_9160) &&
            (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) {
 -              DPRINTF(ah->ah_sc, ATH_DBG_RESET,
 +              DPRINTF(sc, ATH_DBG_RESET,
                        "Mac Chip Rev 0x%02x.%x is not supported by "
 -                      "this driver\n", ah->ah_macVersion, ah->ah_macRev);
 +                      "this driver\n", ah->hw_version.macVersion,
 +                      ah->hw_version.macRev);
                ecode = -EOPNOTSUPP;
                goto bad;
        }
  
        if (AR_SREV_9100(ah)) {
 -              ahp->ah_iqCalData.calData = &iq_cal_multi_sample;
 -              ahp->ah_suppCals = IQ_MISMATCH_CAL;
 -              ah->ah_isPciExpress = false;
 +              ah->iq_caldata.calData = &iq_cal_multi_sample;
 +              ah->supp_cals = IQ_MISMATCH_CAL;
 +              ah->is_pciexpress = false;
        }
 -      ah->ah_phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
 +      ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
  
        if (AR_SREV_9160_10_OR_LATER(ah)) {
                if (AR_SREV_9280_10_OR_LATER(ah)) {
 -                      ahp->ah_iqCalData.calData = &iq_cal_single_sample;
 -                      ahp->ah_adcGainCalData.calData =
 +                      ah->iq_caldata.calData = &iq_cal_single_sample;
 +                      ah->adcgain_caldata.calData =
                                &adc_gain_cal_single_sample;
 -                      ahp->ah_adcDcCalData.calData =
 +                      ah->adcdc_caldata.calData =
                                &adc_dc_cal_single_sample;
 -                      ahp->ah_adcDcCalInitData.calData =
 +                      ah->adcdc_calinitdata.calData =
                                &adc_init_dc_cal;
                } else {
 -                      ahp->ah_iqCalData.calData = &iq_cal_multi_sample;
 -                      ahp->ah_adcGainCalData.calData =
 +                      ah->iq_caldata.calData = &iq_cal_multi_sample;
 +                      ah->adcgain_caldata.calData =
                                &adc_gain_cal_multi_sample;
 -                      ahp->ah_adcDcCalData.calData =
 +                      ah->adcdc_caldata.calData =
                                &adc_dc_cal_multi_sample;
 -                      ahp->ah_adcDcCalInitData.calData =
 +                      ah->adcdc_calinitdata.calData =
                                &adc_init_dc_cal;
                }
 -              ahp->ah_suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
 +              ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
        }
  
        if (AR_SREV_9160(ah)) {
 -              ah->ah_config.enable_ani = 1;
 -              ahp->ah_ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
 +              ah->config.enable_ani = 1;
 +              ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
                                        ATH9K_ANI_FIRSTEP_LEVEL);
        } else {
 -              ahp->ah_ani_function = ATH9K_ANI_ALL;
 +              ah->ani_function = ATH9K_ANI_ALL;
                if (AR_SREV_9280_10_OR_LATER(ah)) {
 -                      ahp->ah_ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
 +                      ah->ani_function &=     ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
                }
        }
  
 -      DPRINTF(ah->ah_sc, ATH_DBG_RESET,
 +      DPRINTF(sc, ATH_DBG_RESET,
                "This Mac Chip Rev 0x%02x.%x is \n",
 -              ah->ah_macVersion, ah->ah_macRev);
 +              ah->hw_version.macVersion, ah->hw_version.macRev);
  
        if (AR_SREV_9285_12_OR_LATER(ah)) {
 -              INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285_1_2,
 +              INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
                               ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
 -              INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285_1_2,
 +              INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2,
                               ARRAY_SIZE(ar9285Common_9285_1_2), 2);
  
 -              if (ah->ah_config.pcie_clock_req) {
 -                      INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
 +              if (ah->config.pcie_clock_req) {
 +                      INIT_INI_ARRAY(&ah->iniPcieSerdes,
                        ar9285PciePhy_clkreq_off_L1_9285_1_2,
                        ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2);
                } else {
 -                      INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
 +                      INIT_INI_ARRAY(&ah->iniPcieSerdes,
                        ar9285PciePhy_clkreq_always_on_L1_9285_1_2,
                        ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2),
                                  2);
                }
        } else if (AR_SREV_9285_10_OR_LATER(ah)) {
 -              INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285,
 +              INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285,
                               ARRAY_SIZE(ar9285Modes_9285), 6);
 -              INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285,
 +              INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285,
                               ARRAY_SIZE(ar9285Common_9285), 2);
  
 -              if (ah->ah_config.pcie_clock_req) {
 -                      INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
 +              if (ah->config.pcie_clock_req) {
 +                      INIT_INI_ARRAY(&ah->iniPcieSerdes,
                        ar9285PciePhy_clkreq_off_L1_9285,
                        ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2);
                } else {
 -                      INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
 +                      INIT_INI_ARRAY(&ah->iniPcieSerdes,
                        ar9285PciePhy_clkreq_always_on_L1_9285,
                        ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2);
                }
        } else if (AR_SREV_9280_20_OR_LATER(ah)) {
 -              INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2,
 +              INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2,
                               ARRAY_SIZE(ar9280Modes_9280_2), 6);
 -              INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2,
 +              INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2,
                               ARRAY_SIZE(ar9280Common_9280_2), 2);
  
 -              if (ah->ah_config.pcie_clock_req) {
 -                      INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
 +              if (ah->config.pcie_clock_req) {
 +                      INIT_INI_ARRAY(&ah->iniPcieSerdes,
                               ar9280PciePhy_clkreq_off_L1_9280,
                               ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280),2);
                } else {
 -                      INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
 +                      INIT_INI_ARRAY(&ah->iniPcieSerdes,
                               ar9280PciePhy_clkreq_always_on_L1_9280,
                               ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2);
                }
 -              INIT_INI_ARRAY(&ahp->ah_iniModesAdditional,
 +              INIT_INI_ARRAY(&ah->iniModesAdditional,
                               ar9280Modes_fast_clock_9280_2,
                               ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
        } else if (AR_SREV_9280_10_OR_LATER(ah)) {
 -              INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280,
 +              INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280,
                               ARRAY_SIZE(ar9280Modes_9280), 6);
 -              INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280,
 +              INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280,
                               ARRAY_SIZE(ar9280Common_9280), 2);
        } else if (AR_SREV_9160_10_OR_LATER(ah)) {
 -              INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9160,
 +              INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160,
                               ARRAY_SIZE(ar5416Modes_9160), 6);
 -              INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9160,
 +              INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160,
                               ARRAY_SIZE(ar5416Common_9160), 2);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9160,
 +              INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160,
                               ARRAY_SIZE(ar5416Bank0_9160), 2);
 -              INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9160,
 +              INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9160,
                               ARRAY_SIZE(ar5416BB_RfGain_9160), 3);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9160,
 +              INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9160,
                               ARRAY_SIZE(ar5416Bank1_9160), 2);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9160,
 +              INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9160,
                               ARRAY_SIZE(ar5416Bank2_9160), 2);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9160,
 +              INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9160,
                               ARRAY_SIZE(ar5416Bank3_9160), 3);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9160,
 +              INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9160,
                               ARRAY_SIZE(ar5416Bank6_9160), 3);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9160,
 +              INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9160,
                               ARRAY_SIZE(ar5416Bank6TPC_9160), 3);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9160,
 +              INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9160,
                               ARRAY_SIZE(ar5416Bank7_9160), 2);
                if (AR_SREV_9160_11(ah)) {
 -                      INIT_INI_ARRAY(&ahp->ah_iniAddac,
 +                      INIT_INI_ARRAY(&ah->iniAddac,
                                       ar5416Addac_91601_1,
                                       ARRAY_SIZE(ar5416Addac_91601_1), 2);
                } else {
 -                      INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9160,
 +                      INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160,
                                       ARRAY_SIZE(ar5416Addac_9160), 2);
                }
        } else if (AR_SREV_9100_OR_LATER(ah)) {
 -              INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9100,
 +              INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100,
                               ARRAY_SIZE(ar5416Modes_9100), 6);
 -              INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9100,
 +              INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100,
                               ARRAY_SIZE(ar5416Common_9100), 2);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9100,
 +              INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100,
                               ARRAY_SIZE(ar5416Bank0_9100), 2);
 -              INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9100,
 +              INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9100,
                               ARRAY_SIZE(ar5416BB_RfGain_9100), 3);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9100,
 +              INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9100,
                               ARRAY_SIZE(ar5416Bank1_9100), 2);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9100,
 +              INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9100,
                               ARRAY_SIZE(ar5416Bank2_9100), 2);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9100,
 +              INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9100,
                               ARRAY_SIZE(ar5416Bank3_9100), 3);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9100,
 +              INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100,
                               ARRAY_SIZE(ar5416Bank6_9100), 3);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9100,
 +              INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100,
                               ARRAY_SIZE(ar5416Bank6TPC_9100), 3);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9100,
 +              INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9100,
                               ARRAY_SIZE(ar5416Bank7_9100), 2);
 -              INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9100,
 +              INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100,
                               ARRAY_SIZE(ar5416Addac_9100), 2);
        } else {
 -              INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes,
 +              INIT_INI_ARRAY(&ah->iniModes, ar5416Modes,
                               ARRAY_SIZE(ar5416Modes), 6);
 -              INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common,
 +              INIT_INI_ARRAY(&ah->iniCommon, ar5416Common,
                               ARRAY_SIZE(ar5416Common), 2);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0,
 +              INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0,
                               ARRAY_SIZE(ar5416Bank0), 2);
 -              INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain,
 +              INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain,
                               ARRAY_SIZE(ar5416BB_RfGain), 3);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1,
 +              INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1,
                               ARRAY_SIZE(ar5416Bank1), 2);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2,
 +              INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2,
                               ARRAY_SIZE(ar5416Bank2), 2);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3,
 +              INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3,
                               ARRAY_SIZE(ar5416Bank3), 3);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6,
 +              INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6,
                               ARRAY_SIZE(ar5416Bank6), 3);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC,
 +              INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC,
                               ARRAY_SIZE(ar5416Bank6TPC), 3);
 -              INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7,
 +              INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7,
                               ARRAY_SIZE(ar5416Bank7), 2);
 -              INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac,
 +              INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac,
                               ARRAY_SIZE(ar5416Addac), 2);
        }
  
 -      if (ah->ah_isPciExpress)
 +      if (ah->is_pciexpress)
                ath9k_hw_configpcipowersave(ah, 0);
        else
                ath9k_hw_disablepcie(ah);
        if (AR_SREV_9280_20(ah))
                ath9k_hw_init_txgain_ini(ah);
  
 -      if (ah->ah_devid == AR9280_DEVID_PCI) {
 -              for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
 -                      u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
 +      if (!ath9k_hw_fill_cap_info(ah)) {
 +              DPRINTF(sc, ATH_DBG_RESET, "failed ath9k_hw_fill_cap_info\n");
 +              ecode = -EINVAL;
 +              goto bad;
 +      }
 +
 +      if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
 +          test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) {
 +
 +              /* EEPROM Fixup */
 +              for (i = 0; i < ah->iniModes.ia_rows; i++) {
 +                      u32 reg = INI_RA(&ah->iniModes, i, 0);
  
 -                      for (j = 1; j < ahp->ah_iniModes.ia_columns; j++) {
 -                              u32 val = INI_RA(&ahp->ah_iniModes, i, j);
 +                      for (j = 1; j < ah->iniModes.ia_columns; j++) {
 +                              u32 val = INI_RA(&ah->iniModes, i, j);
  
 -                              INI_RA(&ahp->ah_iniModes, i, j) =
 +                              INI_RA(&ah->iniModes, i, j) =
                                        ath9k_hw_ini_fixup(ah,
 -                                                         &ahp->ah_eeprom.def,
 +                                                         &ah->eeprom.def,
                                                           reg, val);
                        }
                }
        }
  
 -      if (!ath9k_hw_fill_cap_info(ah)) {
 -              DPRINTF(ah->ah_sc, ATH_DBG_RESET,
 -                      "failed ath9k_hw_fill_cap_info\n");
 -              ecode = -EINVAL;
 -              goto bad;
 -      }
 -
        ecode = ath9k_hw_init_macaddr(ah);
        if (ecode != 0) {
 -              DPRINTF(ah->ah_sc, ATH_DBG_RESET,
 +              DPRINTF(sc, ATH_DBG_RESET,
                        "failed initializing mac address\n");
                goto bad;
        }
  
        if (AR_SREV_9285(ah))
 -              ah->ah_txTrigLevel = (AR_FTRIG_256B >> AR_FTRIG_S);
 +              ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S);
        else
 -              ah->ah_txTrigLevel = (AR_FTRIG_512B >> AR_FTRIG_S);
 +              ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
  
        ath9k_init_nfcal_hist_buffer(ah);
  
        return ah;
  bad:
 -      if (ahp)
 -              ath9k_hw_detach((struct ath_hal *) ahp);
 +      if (ah)
 +              ath9k_hw_detach(ah);
        if (status)
                *status = ecode;
  
        return NULL;
  }
  
 -static void ath9k_hw_init_bb(struct ath_hal *ah,
 +static void ath9k_hw_init_bb(struct ath_hw *ah,
                             struct ath9k_channel *chan)
  {
        u32 synthDelay;
        udelay(synthDelay + BASE_ACTIVATE_DELAY);
  }
  
 -static void ath9k_hw_init_qos(struct ath_hal *ah)
 +static void ath9k_hw_init_qos(struct ath_hw *ah)
  {
        REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
        REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
        REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
  }
  
 -static void ath9k_hw_init_pll(struct ath_hal *ah,
 +static void ath9k_hw_init_pll(struct ath_hw *ah,
                              struct ath9k_channel *chan)
  {
        u32 pll;
                                pll |= SM(0xb, AR_RTC_PLL_DIV);
                }
        }
 -      REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll);
 +      REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
  
        udelay(RTC_PLL_SETTLE_DELAY);
  
        REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
  }
  
 -static void ath9k_hw_init_chain_masks(struct ath_hal *ah)
 +static void ath9k_hw_init_chain_masks(struct ath_hw *ah)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
        int rx_chainmask, tx_chainmask;
  
 -      rx_chainmask = ahp->ah_rxchainmask;
 -      tx_chainmask = ahp->ah_txchainmask;
 +      rx_chainmask = ah->rxchainmask;
 +      tx_chainmask = ah->txchainmask;
  
        switch (rx_chainmask) {
        case 0x5:
                REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
                            AR_PHY_SWAP_ALT_CHAIN);
        case 0x3:
 -              if (((ah)->ah_macVersion <= AR_SREV_VERSION_9160)) {
 +              if (((ah)->hw_version.macVersion <= AR_SREV_VERSION_9160)) {
                        REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
                        REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
                        break;
                          REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001);
  }
  
 -static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah,
 +static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
                                          enum nl80211_iftype opmode)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -
 -      ahp->ah_maskReg = AR_IMR_TXERR |
 +      ah->mask_reg = AR_IMR_TXERR |
                AR_IMR_TXURN |
                AR_IMR_RXERR |
                AR_IMR_RXORN |
                AR_IMR_BCNMISC;
  
 -      if (ahp->ah_intrMitigation)
 -              ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
 +      if (ah->intr_mitigation)
 +              ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
        else
 -              ahp->ah_maskReg |= AR_IMR_RXOK;
 +              ah->mask_reg |= AR_IMR_RXOK;
  
 -      ahp->ah_maskReg |= AR_IMR_TXOK;
 +      ah->mask_reg |= AR_IMR_TXOK;
  
        if (opmode == NL80211_IFTYPE_AP)
 -              ahp->ah_maskReg |= AR_IMR_MIB;
 +              ah->mask_reg |= AR_IMR_MIB;
  
 -      REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);
 +      REG_WRITE(ah, AR_IMR, ah->mask_reg);
        REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT);
  
        if (!AR_SREV_9100(ah)) {
        }
  }
  
 -static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us)
 +static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -
        if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad ack timeout %u\n", us);
 -              ahp->ah_acktimeout = (u32) -1;
 +              ah->acktimeout = (u32) -1;
                return false;
        } else {
                REG_RMW_FIELD(ah, AR_TIME_OUT,
                              AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us));
 -              ahp->ah_acktimeout = us;
 +              ah->acktimeout = us;
                return true;
        }
  }
  
 -static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us)
 +static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -
        if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad cts timeout %u\n", us);
 -              ahp->ah_ctstimeout = (u32) -1;
 +              ah->ctstimeout = (u32) -1;
                return false;
        } else {
                REG_RMW_FIELD(ah, AR_TIME_OUT,
                              AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us));
 -              ahp->ah_ctstimeout = us;
 +              ah->ctstimeout = us;
                return true;
        }
  }
  
 -static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, u32 tu)
 +static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -
        if (tu > 0xFFFF) {
                DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
                        "bad global tx timeout %u\n", tu);
 -              ahp->ah_globaltxtimeout = (u32) -1;
 +              ah->globaltxtimeout = (u32) -1;
                return false;
        } else {
                REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu);
 -              ahp->ah_globaltxtimeout = tu;
 +              ah->globaltxtimeout = tu;
                return true;
        }
  }
  
 -static void ath9k_hw_init_user_settings(struct ath_hal *ah)
 +static void ath9k_hw_init_user_settings(struct ath_hw *ah)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 +      DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ah->misc_mode 0x%x\n",
 +              ah->misc_mode);
  
 -      DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ahp->ah_miscMode 0x%x\n",
 -              ahp->ah_miscMode);
 -
 -      if (ahp->ah_miscMode != 0)
 +      if (ah->misc_mode != 0)
                REG_WRITE(ah, AR_PCU_MISC,
 -                        REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode);
 -      if (ahp->ah_slottime != (u32) -1)
 -              ath9k_hw_setslottime(ah, ahp->ah_slottime);
 -      if (ahp->ah_acktimeout != (u32) -1)
 -              ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout);
 -      if (ahp->ah_ctstimeout != (u32) -1)
 -              ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout);
 -      if (ahp->ah_globaltxtimeout != (u32) -1)
 -              ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout);
 +                        REG_READ(ah, AR_PCU_MISC) | ah->misc_mode);
 +      if (ah->slottime != (u32) -1)
 +              ath9k_hw_setslottime(ah, ah->slottime);
 +      if (ah->acktimeout != (u32) -1)
 +              ath9k_hw_set_ack_timeout(ah, ah->acktimeout);
 +      if (ah->ctstimeout != (u32) -1)
 +              ath9k_hw_set_cts_timeout(ah, ah->ctstimeout);
 +      if (ah->globaltxtimeout != (u32) -1)
 +              ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout);
  }
  
  const char *ath9k_hw_probe(u16 vendorid, u16 devid)
                ath9k_hw_devname(devid) : NULL;
  }
  
 -void ath9k_hw_detach(struct ath_hal *ah)
 +void ath9k_hw_detach(struct ath_hw *ah)
  {
        if (!AR_SREV_9100(ah))
                ath9k_hw_ani_detach(ah);
        kfree(ah);
  }
  
 -struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
 -                              void __iomem *mem, int *error)
 +struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error)
  {
 -      struct ath_hal *ah = NULL;
 +      struct ath_hw *ah = NULL;
  
        switch (devid) {
        case AR5416_DEVID_PCI:
        case AR5416_DEVID_PCIE:
 +      case AR5416_AR9100_DEVID:
        case AR9160_DEVID_PCI:
        case AR9280_DEVID_PCI:
        case AR9280_DEVID_PCIE:
        case AR9285_DEVID_PCIE:
 -              ah = ath9k_hw_do_attach(devid, sc, mem, error);
 +              ah = ath9k_hw_do_attach(devid, sc, error);
                break;
        default:
                *error = -ENXIO;
  /* INI */
  /*******/
  
 -static void ath9k_hw_override_ini(struct ath_hal *ah,
 +static void ath9k_hw_override_ini(struct ath_hw *ah,
                                  struct ath9k_channel *chan)
  {
        /*
        REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
  }
  
 -static u32 ath9k_hw_def_ini_fixup(struct ath_hal *ah,
 +static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah,
                              struct ar5416_eeprom_def *pEepData,
                              u32 reg, u32 value)
  {
        struct base_eep_header *pBase = &(pEepData->baseEepHeader);
  
 -      switch (ah->ah_devid) {
 +      switch (ah->hw_version.devid) {
        case AR9280_DEVID_PCI:
                if (reg == 0x7894) {
                        DPRINTF(ah->ah_sc, ATH_DBG_ANY,
        return value;
  }
  
 -static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
 +static u32 ath9k_hw_ini_fixup(struct ath_hw *ah,
                              struct ar5416_eeprom_def *pEepData,
                              u32 reg, u32 value)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -
 -      if (ahp->ah_eep_map == EEP_MAP_4KBITS)
 +      if (ah->eep_map == EEP_MAP_4KBITS)
                return value;
        else
                return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value);
  }
  
 -static int ath9k_hw_process_ini(struct ath_hal *ah,
 +static void ath9k_olc_init(struct ath_hw *ah)
 +{
 +      u32 i;
 +
 +      for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++)
 +              ah->originalGain[i] =
 +                      MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4),
 +                                      AR_PHY_TX_GAIN);
 +      ah->PDADCdelta = 0;
 +}
 +
 +static int ath9k_hw_process_ini(struct ath_hw *ah,
                                struct ath9k_channel *chan,
                                enum ath9k_ht_macmode macmode)
  {
        int i, regWrites = 0;
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 +      struct ieee80211_channel *channel = chan->chan;
        u32 modesIndex, freqIndex;
        int status;
  
        }
  
        REG_WRITE(ah, AR_PHY(0), 0x00000007);
 -
        REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO);
 -
 -      ath9k_hw_set_addac(ah, chan);
 +      ah->eep_ops->set_addac(ah, chan);
  
        if (AR_SREV_5416_V22_OR_LATER(ah)) {
 -              REG_WRITE_ARRAY(&ahp->ah_iniAddac, 1, regWrites);
 +              REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites);
        } else {
                struct ar5416IniArray temp;
                u32 addacSize =
 -                      sizeof(u32) * ahp->ah_iniAddac.ia_rows *
 -                      ahp->ah_iniAddac.ia_columns;
 +                      sizeof(u32) * ah->iniAddac.ia_rows *
 +                      ah->iniAddac.ia_columns;
  
 -              memcpy(ahp->ah_addac5416_21,
 -                     ahp->ah_iniAddac.ia_array, addacSize);
 +              memcpy(ah->addac5416_21,
 +                     ah->iniAddac.ia_array, addacSize);
  
 -              (ahp->ah_addac5416_21)[31 * ahp->ah_iniAddac.ia_columns + 1] = 0;
 +              (ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0;
  
 -              temp.ia_array = ahp->ah_addac5416_21;
 -              temp.ia_columns = ahp->ah_iniAddac.ia_columns;
 -              temp.ia_rows = ahp->ah_iniAddac.ia_rows;
 +              temp.ia_array = ah->addac5416_21;
 +              temp.ia_columns = ah->iniAddac.ia_columns;
 +              temp.ia_rows = ah->iniAddac.ia_rows;
                REG_WRITE_ARRAY(&temp, 1, regWrites);
        }
  
        REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC);
  
 -      for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
 -              u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
 -              u32 val = INI_RA(&ahp->ah_iniModes, i, modesIndex);
 +      for (i = 0; i < ah->iniModes.ia_rows; i++) {
 +              u32 reg = INI_RA(&ah->iniModes, i, 0);
 +              u32 val = INI_RA(&ah->iniModes, i, modesIndex);
  
                REG_WRITE(ah, reg, val);
  
                if (reg >= 0x7800 && reg < 0x78a0
 -                  && ah->ah_config.analog_shiftreg) {
 +                  && ah->config.analog_shiftreg) {
                        udelay(100);
                }
  
        }
  
        if (AR_SREV_9280(ah))
 -              REG_WRITE_ARRAY(&ahp->ah_iniModesRxGain, modesIndex, regWrites);
 +              REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
  
        if (AR_SREV_9280(ah))
 -              REG_WRITE_ARRAY(&ahp->ah_iniModesTxGain, modesIndex, regWrites);
 +              REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
  
 -      for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) {
 -              u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0);
 -              u32 val = INI_RA(&ahp->ah_iniCommon, i, 1);
 +      for (i = 0; i < ah->iniCommon.ia_rows; i++) {
 +              u32 reg = INI_RA(&ah->iniCommon, i, 0);
 +              u32 val = INI_RA(&ah->iniCommon, i, 1);
  
                REG_WRITE(ah, reg, val);
  
                if (reg >= 0x7800 && reg < 0x78a0
 -                  && ah->ah_config.analog_shiftreg) {
 +                  && ah->config.analog_shiftreg) {
                        udelay(100);
                }
  
        ath9k_hw_write_regs(ah, modesIndex, freqIndex, regWrites);
  
        if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) {
 -              REG_WRITE_ARRAY(&ahp->ah_iniModesAdditional, modesIndex,
 +              REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex,
                                regWrites);
        }
  
        ath9k_hw_set_regs(ah, chan, macmode);
        ath9k_hw_init_chain_masks(ah);
  
 -      status = ath9k_hw_set_txpower(ah, chan,
 -                                    ath9k_regd_get_ctl(ah, chan),
 -                                    ath9k_regd_get_antenna_allowed(ah,
 -                                                                   chan),
 -                                    chan->maxRegTxPower * 2,
 -                                    min((u32) MAX_RATE_POWER,
 -                                        (u32) ah->ah_powerLimit));
 +      if (OLC_FOR_AR9280_20_LATER)
 +              ath9k_olc_init(ah);
 +
 +      status = ah->eep_ops->set_txpower(ah, chan,
 +                                ath9k_regd_get_ctl(ah, chan),
 +                                channel->max_antenna_gain * 2,
 +                                channel->max_power * 2,
 +                                min((u32) MAX_RATE_POWER,
 +                                    (u32) ah->regulatory.power_limit));
        if (status != 0) {
                DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
                        "error init'ing transmit power\n");
  /* Reset and Channel Switching Routines */
  /****************************************/
  
 -static void ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan)
 +static void ath9k_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan)
  {
        u32 rfMode = 0;
  
        REG_WRITE(ah, AR_PHY_MODE, rfMode);
  }
  
 -static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah)
 +static void ath9k_hw_mark_phy_inactive(struct ath_hw *ah)
  {
        REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
  }
  
 -static inline void ath9k_hw_set_dma(struct ath_hal *ah)
 +static inline void ath9k_hw_set_dma(struct ath_hw *ah)
  {
        u32 regval;
  
        regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
        REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
  
 -      REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel);
 +      REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level);
  
        regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
        REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
        }
  }
  
 -static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode)
 +static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
  {
        u32 val;
  
        }
  }
  
 -static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah,
 +static inline void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah,
                                                 u32 coef_scaled,
                                                 u32 *coef_mantissa,
                                                 u32 *coef_exponent)
        *coef_exponent = coef_exp - 16;
  }
  
 -static void ath9k_hw_set_delta_slope(struct ath_hal *ah,
 +static void ath9k_hw_set_delta_slope(struct ath_hw *ah,
                                     struct ath9k_channel *chan)
  {
        u32 coef_scaled, ds_coef_exp, ds_coef_man;
                      AR_PHY_HALFGI_DSC_EXP, ds_coef_exp);
  }
  
 -static bool ath9k_hw_set_reset(struct ath_hal *ah, int type)
 +static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
  {
        u32 rst_flags;
        u32 tmpReg;
  
 +      if (AR_SREV_9100(ah)) {
 +              u32 val = REG_READ(ah, AR_RTC_DERIVED_CLK);
 +              val &= ~AR_RTC_DERIVED_CLK_PERIOD;
 +              val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD);
 +              REG_WRITE(ah, AR_RTC_DERIVED_CLK, val);
 +              (void)REG_READ(ah, AR_RTC_DERIVED_CLK);
 +      }
 +
        REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
                  AR_RTC_FORCE_WAKE_ON_INT);
  
                        rst_flags |= AR_RTC_RC_MAC_COLD;
        }
  
 -      REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags);
 +      REG_WRITE(ah, AR_RTC_RC, rst_flags);
        udelay(50);
  
 -      REG_WRITE(ah, (u16) (AR_RTC_RC), 0);
 -      if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) {
 +      REG_WRITE(ah, AR_RTC_RC, 0);
 +      if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET,
                        "RTC stuck in MAC reset\n");
                return false;
        return true;
  }
  
 -static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
 +static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
  {
        REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
                  AR_RTC_FORCE_WAKE_ON_INT);
  
 -      REG_WRITE(ah, (u16) (AR_RTC_RESET), 0);
 -      REG_WRITE(ah, (u16) (AR_RTC_RESET), 1);
 +      REG_WRITE(ah, AR_RTC_RESET, 0);
 +      udelay(2);
 +      REG_WRITE(ah, AR_RTC_RESET, 1);
  
        if (!ath9k_hw_wait(ah,
                           AR_RTC_STATUS,
                           AR_RTC_STATUS_M,
 -                         AR_RTC_STATUS_ON)) {
 +                         AR_RTC_STATUS_ON,
 +                         AH_WAIT_TIMEOUT)) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n");
                return false;
        }
        return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM);
  }
  
 -static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type)
 +static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
  {
        REG_WRITE(ah, AR_RTC_FORCE_WAKE,
                  AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
        }
  }
  
 -static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
 +static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan,
                              enum ath9k_ht_macmode macmode)
  {
        u32 phymode;
        u32 enableDacFifo = 0;
 -      struct ath_hal_5416 *ahp = AH5416(ah);
  
        if (AR_SREV_9285_10_OR_LATER(ah))
                enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) &
                    (chan->chanmode == CHANNEL_G_HT40PLUS))
                        phymode |= AR_PHY_FC_DYN2040_PRI_CH;
  
 -              if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25)
 +              if (ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_25)
                        phymode |= AR_PHY_FC_DYN2040_EXT_CH;
        }
        REG_WRITE(ah, AR_PHY_TURBO, phymode);
        REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
  }
  
 -static bool ath9k_hw_chip_reset(struct ath_hal *ah,
 +static bool ath9k_hw_chip_reset(struct ath_hw *ah,
                                struct ath9k_channel *chan)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -
 -      if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
 +      if (OLC_FOR_AR9280_20_LATER) {
 +              if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON))
 +                      return false;
 +      } else if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
                return false;
  
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
                return false;
  
 -      ahp->ah_chipFullSleep = false;
 -
 +      ah->chip_fullsleep = false;
        ath9k_hw_init_pll(ah, chan);
 -
        ath9k_hw_set_rfmode(ah, chan);
  
        return true;
  }
  
 -static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah,
 -                                               struct ath9k_channel *chan)
 -{
 -      if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) {
 -              DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
 -                      "invalid channel %u/0x%x; not marked as "
 -                      "2GHz or 5GHz\n", chan->channel, chan->channelFlags);
 -              return NULL;
 -      }
 -
 -      if (!IS_CHAN_OFDM(chan) &&
 -          !IS_CHAN_B(chan) &&
 -          !IS_CHAN_HT20(chan) &&
 -          !IS_CHAN_HT40(chan)) {
 -              DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
 -                      "invalid channel %u/0x%x; not marked as "
 -                      "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n",
 -                      chan->channel, chan->channelFlags);
 -              return NULL;
 -      }
 -
 -      return ath9k_regd_check_channel(ah, chan);
 -}
 -
 -static bool ath9k_hw_channel_change(struct ath_hal *ah,
 +static bool ath9k_hw_channel_change(struct ath_hw *ah,
                                    struct ath9k_channel *chan,
                                    enum ath9k_ht_macmode macmode)
  {
 +      struct ieee80211_channel *channel = chan->chan;
        u32 synthDelay, qnum;
  
        for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
  
        REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
        if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
 -                         AR_PHY_RFBUS_GRANT_EN)) {
 +                         AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) {
                DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
                        "Could not kill baseband RX\n");
                return false;
                }
        }
  
 -      if (ath9k_hw_set_txpower(ah, chan,
 -                               ath9k_regd_get_ctl(ah, chan),
 -                               ath9k_regd_get_antenna_allowed(ah, chan),
 -                               chan->maxRegTxPower * 2,
 -                               min((u32) MAX_RATE_POWER,
 -                                   (u32) ah->ah_powerLimit)) != 0) {
 +      if (ah->eep_ops->set_txpower(ah, chan,
 +                           ath9k_regd_get_ctl(ah, chan),
 +                           channel->max_antenna_gain * 2,
 +                           channel->max_power * 2,
 +                           min((u32) MAX_RATE_POWER,
 +                               (u32) ah->regulatory.power_limit)) != 0) {
                DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
                        "error init'ing transmit power\n");
                return false;
        return true;
  }
  
 -static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan)
 +static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan)
  {
        int bb_spur = AR_NO_SPUR;
        int freq;
        ath9k_hw_get_channel_centers(ah, chan, &centers);
        freq = centers.synth_center;
  
 -      ah->ah_config.spurmode = SPUR_ENABLE_EEPROM;
 +      ah->config.spurmode = SPUR_ENABLE_EEPROM;
        for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
 -              cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz);
 +              cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
  
                if (is2GHz)
                        cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ;
                if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
  
                        /* workaround for gcc bug #37014 */
 -                      volatile int tmp = abs(cur_vit_mask - bin);
 +                      volatile int tmp_v = abs(cur_vit_mask - bin);
  
 -                      if (tmp < 75)
 +                      if (tmp_v < 75)
                                mask_amt = 1;
                        else
                                mask_amt = 0;
        REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
  }
  
 -static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan)
 +static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan)
  {
        int bb_spur = AR_NO_SPUR;
        int bin, cur_bin;
        memset(&mask_p, 0, sizeof(int8_t) * 123);
  
        for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
 -              cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz);
 +              cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
                if (AR_NO_SPUR == cur_bb_spur)
                        break;
                cur_bb_spur = cur_bb_spur - (chan->channel * 10);
                if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
  
                        /* workaround for gcc bug #37014 */
 -                      volatile int tmp = abs(cur_vit_mask - bin);
 +                      volatile int tmp_v = abs(cur_vit_mask - bin);
  
 -                      if (tmp < 75)
 +                      if (tmp_v < 75)
                                mask_amt = 1;
                        else
                                mask_amt = 0;
        REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
  }
  
 -bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
 -                  enum ath9k_ht_macmode macmode,
 -                  u8 txchainmask, u8 rxchainmask,
 -                  enum ath9k_ht_extprotspacing extprotspacing,
 -                  bool bChannelChange, int *status)
 +int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 +                  bool bChannelChange)
  {
        u32 saveLedState;
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -      struct ath9k_channel *curchan = ah->ah_curchan;
 +      struct ath_softc *sc = ah->ah_sc;
 +      struct ath9k_channel *curchan = ah->curchan;
        u32 saveDefAntenna;
        u32 macStaId1;
 -      int ecode;
 -      int i, rx_chainmask;
 +      int i, rx_chainmask, r;
  
 -      ahp->ah_extprotspacing = extprotspacing;
 -      ahp->ah_txchainmask = txchainmask;
 -      ahp->ah_rxchainmask = rxchainmask;
 -
 -      if (AR_SREV_9280(ah)) {
 -              ahp->ah_txchainmask &= 0x3;
 -              ahp->ah_rxchainmask &= 0x3;
 -      }
 +      ah->extprotspacing = sc->ht_extprotspacing;
 +      ah->txchainmask = sc->tx_chainmask;
 +      ah->rxchainmask = sc->rx_chainmask;
  
 -      if (ath9k_hw_check_chan(ah, chan) == NULL) {
 -              DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
 -                      "invalid channel %u/0x%x; no mapping\n",
 -                      chan->channel, chan->channelFlags);
 -              ecode = -EINVAL;
 -              goto bad;
 +      if (AR_SREV_9285(ah)) {
 +              ah->txchainmask &= 0x1;
 +              ah->rxchainmask &= 0x1;
 +      } else if (AR_SREV_9280(ah)) {
 +              ah->txchainmask &= 0x3;
 +              ah->rxchainmask &= 0x3;
        }
  
 -      if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
 -              ecode = -EIO;
 -              goto bad;
 -      }
 +      if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
 +              return -EIO;
  
        if (curchan)
                ath9k_hw_getnf(ah, curchan);
  
        if (bChannelChange &&
 -          (ahp->ah_chipFullSleep != true) &&
 -          (ah->ah_curchan != NULL) &&
 -          (chan->channel != ah->ah_curchan->channel) &&
 +          (ah->chip_fullsleep != true) &&
 +          (ah->curchan != NULL) &&
 +          (chan->channel != ah->curchan->channel) &&
            ((chan->channelFlags & CHANNEL_ALL) ==
 -           (ah->ah_curchan->channelFlags & CHANNEL_ALL)) &&
 +           (ah->curchan->channelFlags & CHANNEL_ALL)) &&
            (!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) &&
 -                                 !IS_CHAN_A_5MHZ_SPACED(ah->ah_curchan)))) {
 +                                 !IS_CHAN_A_5MHZ_SPACED(ah->curchan)))) {
  
 -              if (ath9k_hw_channel_change(ah, chan, macmode)) {
 -                      ath9k_hw_loadnf(ah, ah->ah_curchan);
 +              if (ath9k_hw_channel_change(ah, chan, sc->tx_chan_width)) {
 +                      ath9k_hw_loadnf(ah, ah->curchan);
                        ath9k_hw_start_nfcal(ah);
 -                      return true;
 +                      return 0;
                }
        }
  
  
        if (!ath9k_hw_chip_reset(ah, chan)) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET, "chip reset failed\n");
 -              ecode = -EINVAL;
 -              goto bad;
 +              return -EINVAL;
        }
  
 -      if (AR_SREV_9280(ah)) {
 -              REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
 -                          AR_GPIO_JTAG_DISABLE);
 +      if (AR_SREV_9280_10_OR_LATER(ah))
 +              REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
  
 -              if (test_bit(ATH9K_MODE_11A, ah->ah_caps.wireless_modes)) {
 -                      if (IS_CHAN_5GHZ(chan))
 -                              ath9k_hw_set_gpio(ah, 9, 0);
 -                      else
 -                              ath9k_hw_set_gpio(ah, 9, 1);
 -              }
 -              ath9k_hw_cfg_output(ah, 9, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 -      }
 +      r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width);
 +      if (r)
 +              return r;
  
 -      ecode = ath9k_hw_process_ini(ah, chan, macmode);
 -      if (ecode != 0) {
 -              ecode = -EINVAL;
 -              goto bad;
 -      }
 +      /* Setup MFP options for CCMP */
 +      if (AR_SREV_9280_20_OR_LATER(ah)) {
 +              /* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt
 +               * frames when constructing CCMP AAD. */
 +              REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT,
 +                            0xc7ff);
 +              ah->sw_mgmt_crypto = false;
 +      } else if (AR_SREV_9160_10_OR_LATER(ah)) {
 +              /* Disable hardware crypto for management frames */
 +              REG_CLR_BIT(ah, AR_PCU_MISC_MODE2,
 +                          AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE);
 +              REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
 +                          AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT);
 +              ah->sw_mgmt_crypto = true;
 +      } else
 +              ah->sw_mgmt_crypto = true;
  
        if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
                ath9k_hw_set_delta_slope(ah, chan);
        else
                ath9k_hw_spur_mitigate(ah, chan);
  
 -      if (!ath9k_hw_eeprom_set_board_values(ah, chan)) {
 +      if (!ah->eep_ops->set_board_values(ah, chan)) {
                DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
                        "error setting board options\n");
 -              ecode = -EIO;
 -              goto bad;
 +              return -EIO;
        }
  
        ath9k_hw_decrease_chain_power(ah, chan);
  
 -      REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(ahp->ah_macaddr));
 -      REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(ahp->ah_macaddr + 4)
 +      REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(ah->macaddr));
 +      REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(ah->macaddr + 4)
                  | macStaId1
                  | AR_STA_ID1_RTS_USE_DEF
 -                | (ah->ah_config.
 +                | (ah->config.
                     ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
 -                | ahp->ah_staId1Defaults);
 -      ath9k_hw_set_operating_mode(ah, ah->ah_opmode);
 +                | ah->sta_id1_defaults);
 +      ath9k_hw_set_operating_mode(ah, ah->opmode);
  
 -      REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask));
 -      REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4));
 +      REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask));
 +      REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4));
  
        REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
  
 -      REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid));
 -      REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) |
 -                ((ahp->ah_assocId & 0x3fff) << AR_BSS_ID1_AID_S));
 +      REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid));
 +      REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) |
 +                ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S));
  
        REG_WRITE(ah, AR_ISR, ~0);
  
        REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
  
        if (AR_SREV_9280_10_OR_LATER(ah)) {
 -              if (!(ath9k_hw_ar9280_set_channel(ah, chan))) {
 -                      ecode = -EIO;
 -                      goto bad;
 -              }
 +              if (!(ath9k_hw_ar9280_set_channel(ah, chan)))
 +                      return -EIO;
        } else {
 -              if (!(ath9k_hw_set_channel(ah, chan))) {
 -                      ecode = -EIO;
 -                      goto bad;
 -              }
 +              if (!(ath9k_hw_set_channel(ah, chan)))
 +                      return -EIO;
        }
  
        for (i = 0; i < AR_NUM_DCU; i++)
                REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
  
 -      ahp->ah_intrTxqs = 0;
 -      for (i = 0; i < ah->ah_caps.total_queues; i++)
 +      ah->intr_txqs = 0;
 +      for (i = 0; i < ah->caps.total_queues; i++)
                ath9k_hw_resettxqueue(ah, i);
  
 -      ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode);
 +      ath9k_hw_init_interrupt_masks(ah, ah->opmode);
        ath9k_hw_init_qos(ah);
  
  #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 -      if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 +      if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
                ath9k_enable_rfkill(ah);
  #endif
        ath9k_hw_init_user_settings(ah);
  
        REG_WRITE(ah, AR_OBS, 8);
  
 -      if (ahp->ah_intrMitigation) {
 +      if (ah->intr_mitigation) {
  
                REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
                REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
  
        ath9k_hw_init_bb(ah, chan);
  
 -      if (!ath9k_hw_init_cal(ah, chan)){
 -              ecode = -EIO;;
 -              goto bad;
 -      }
 +      if (!ath9k_hw_init_cal(ah, chan))
 +              return -EIO;;
  
 -      rx_chainmask = ahp->ah_rxchainmask;
 +      rx_chainmask = ah->rxchainmask;
        if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
                REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
                REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
  #endif
        }
  
 -      return true;
 -bad:
 -      if (status)
 -              *status = ecode;
 -      return false;
 +      return 0;
  }
  
  /************************/
  /* Key Cache Management */
  /************************/
  
 -bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry)
 +bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
  {
        u32 keyType;
  
 -      if (entry >= ah->ah_caps.keycache_size) {
 +      if (entry >= ah->caps.keycache_size) {
                DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
                        "entry %u out of range\n", entry);
                return false;
  
        }
  
 -      if (ah->ah_curchan == NULL)
 +      if (ah->curchan == NULL)
                return true;
  
        return true;
  }
  
 -bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac)
 +bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
  {
        u32 macHi, macLo;
  
 -      if (entry >= ah->ah_caps.keycache_size) {
 +      if (entry >= ah->caps.keycache_size) {
                DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
                        "entry %u out of range\n", entry);
                return false;
        return true;
  }
  
 -bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
 +bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
                                 const struct ath9k_keyval *k,
 -                               const u8 *mac, int xorKey)
 +                               const u8 *mac)
  {
 -      const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
 +      const struct ath9k_hw_capabilities *pCap = &ah->caps;
        u32 key0, key1, key2, key3, key4;
        u32 keyType;
 -      u32 xorMask = xorKey ?
 -              (ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8
 -               | ATH9K_KEY_XOR) : 0;
 -      struct ath_hal_5416 *ahp = AH5416(ah);
  
        if (entry >= pCap->keycache_size) {
                DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
                if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
                        DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
                                "AES-CCM not supported by mac rev 0x%x\n",
 -                              ah->ah_macRev);
 +                              ah->hw_version.macRev);
                        return false;
                }
                keyType = AR_KEYTABLE_TYPE_CCM;
                return false;
        }
  
 -      key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask;
 -      key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff;
 -      key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask;
 -      key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff;
 -      key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask;
 +      key0 = get_unaligned_le32(k->kv_val + 0);
 +      key1 = get_unaligned_le16(k->kv_val + 4);
 +      key2 = get_unaligned_le32(k->kv_val + 6);
 +      key3 = get_unaligned_le16(k->kv_val + 10);
 +      key4 = get_unaligned_le32(k->kv_val + 12);
        if (k->kv_len <= LEN_WEP104)
                key4 &= 0xff;
  
 +      /*
 +       * Note: Key cache registers access special memory area that requires
 +       * two 32-bit writes to actually update the values in the internal
 +       * memory. Consequently, the exact order and pairs used here must be
 +       * maintained.
 +       */
 +
        if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
                u16 micentry = entry + 64;
  
 +              /*
 +               * Write inverted key[47:0] first to avoid Michael MIC errors
 +               * on frames that could be sent or received at the same time.
 +               * The correct key will be written in the end once everything
 +               * else is ready.
 +               */
                REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
                REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
 +
 +              /* Write key[95:48] */
                REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
                REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
 +
 +              /* Write key[127:96] and key type */
                REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
                REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
 +
 +              /* Write MAC address for the entry */
                (void) ath9k_hw_keysetmac(ah, entry, mac);
  
 -              if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) {
 +              if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) {
 +                      /*
 +                       * TKIP uses two key cache entries:
 +                       * Michael MIC TX/RX keys in the same key cache entry
 +                       * (idx = main index + 64):
 +                       * key0 [31:0] = RX key [31:0]
 +                       * key1 [15:0] = TX key [31:16]
 +                       * key1 [31:16] = reserved
 +                       * key2 [31:0] = RX key [63:32]
 +                       * key3 [15:0] = TX key [15:0]
 +                       * key3 [31:16] = reserved
 +                       * key4 [31:0] = TX key [63:32]
 +                       */
                        u32 mic0, mic1, mic2, mic3, mic4;
  
                        mic0 = get_unaligned_le32(k->kv_mic + 0);
                        mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
                        mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
                        mic4 = get_unaligned_le32(k->kv_txmic + 4);
 +
 +                      /* Write RX[31:0] and TX[31:16] */
                        REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
                        REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
 +
 +                      /* Write RX[63:32] and TX[15:0] */
                        REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
                        REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
 +
 +                      /* Write TX[63:32] and keyType(reserved) */
                        REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
                        REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
                                  AR_KEYTABLE_TYPE_CLR);
  
                } else {
 +                      /*
 +                       * TKIP uses four key cache entries (two for group
 +                       * keys):
 +                       * Michael MIC TX/RX keys are in different key cache
 +                       * entries (idx = main index + 64 for TX and
 +                       * main index + 32 + 96 for RX):
 +                       * key0 [31:0] = TX/RX MIC key [31:0]
 +                       * key1 [31:0] = reserved
 +                       * key2 [31:0] = TX/RX MIC key [63:32]
 +                       * key3 [31:0] = reserved
 +                       * key4 [31:0] = reserved
 +                       *
 +                       * Upper layer code will call this function separately
 +                       * for TX and RX keys when these registers offsets are
 +                       * used.
 +                       */
                        u32 mic0, mic2;
  
                        mic0 = get_unaligned_le32(k->kv_mic + 0);
                        mic2 = get_unaligned_le32(k->kv_mic + 4);
 +
 +                      /* Write MIC key[31:0] */
                        REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
                        REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
 +
 +                      /* Write MIC key[63:32] */
                        REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
                        REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
 +
 +                      /* Write TX[63:32] and keyType(reserved) */
                        REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
                        REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
                                  AR_KEYTABLE_TYPE_CLR);
                }
 +
 +              /* MAC address registers are reserved for the MIC entry */
                REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
                REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
 +
 +              /*
 +               * Write the correct (un-inverted) key[47:0] last to enable
 +               * TKIP now that all other registers are set with correct
 +               * values.
 +               */
                REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
                REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
        } else {
 +              /* Write key[47:0] */
                REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
                REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
 +
 +              /* Write key[95:48] */
                REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
                REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
 +
 +              /* Write key[127:96] and key type */
                REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
                REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
  
 +              /* Write MAC address for the entry */
                (void) ath9k_hw_keysetmac(ah, entry, mac);
        }
  
 -      if (ah->ah_curchan == NULL)
 -              return true;
 -
        return true;
  }
  
 -bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry)
 +bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry)
  {
 -      if (entry < ah->ah_caps.keycache_size) {
 +      if (entry < ah->caps.keycache_size) {
                u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry));
                if (val & AR_KEYTABLE_VALID)
                        return true;
  /* Power Management (Chipset) */
  /******************************/
  
 -static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip)
 +static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
  {
        REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
        if (setChip) {
                if (!AR_SREV_9100(ah))
                        REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
  
 -              REG_CLR_BIT(ah, (u16) (AR_RTC_RESET),
 +              REG_CLR_BIT(ah, (AR_RTC_RESET),
                            AR_RTC_RESET_EN);
        }
  }
  
 -static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip)
 +static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
  {
        REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
        if (setChip) {
 -              struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
 +              struct ath9k_hw_capabilities *pCap = &ah->caps;
  
                if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
                        REG_WRITE(ah, AR_RTC_FORCE_WAKE,
        }
  }
  
 -static bool ath9k_hw_set_power_awake(struct ath_hal *ah,
 -                                   int setChip)
 +static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
  {
        u32 val;
        int i;
        return true;
  }
  
 -bool ath9k_hw_setpower(struct ath_hal *ah,
 -                     enum ath9k_power_mode mode)
 +bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 +      int status = true, setChip = true;
        static const char *modes[] = {
                "AWAKE",
                "FULL-SLEEP",
                "NETWORK SLEEP",
                "UNDEFINED"
        };
 -      int status = true, setChip = true;
  
        DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n",
 -              modes[ahp->ah_powerMode], modes[mode],
 +              modes[ah->power_mode], modes[mode],
                setChip ? "set chip " : "");
  
        switch (mode) {
                break;
        case ATH9K_PM_FULL_SLEEP:
                ath9k_set_power_sleep(ah, setChip);
 -              ahp->ah_chipFullSleep = true;
 +              ah->chip_fullsleep = true;
                break;
        case ATH9K_PM_NETWORK_SLEEP:
                ath9k_set_power_network_sleep(ah, setChip);
                        "Unknown power mode %u\n", mode);
                return false;
        }
 -      ahp->ah_powerMode = mode;
 +      ah->power_mode = mode;
  
        return status;
  }
  
 -void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore)
 +/*
 + * Helper for ASPM support.
 + *
 + * Disable PLL when in L0s as well as receiver clock when in L1.
 + * This power saving option must be enabled through the SerDes.
 + *
 + * Programming the SerDes must go through the same 288 bit serial shift
 + * register as the other analog registers.  Hence the 9 writes.
 + */
 +void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
        u8 i;
  
 -      if (ah->ah_isPciExpress != true)
 +      if (ah->is_pciexpress != true)
                return;
  
 -      if (ah->ah_config.pcie_powersave_enable == 2)
 +      /* Do not touch SerDes registers */
 +      if (ah->config.pcie_powersave_enable == 2)
                return;
  
 +      /* Nothing to do on restore for 11N */
        if (restore)
                return;
  
        if (AR_SREV_9280_20_OR_LATER(ah)) {
 -              for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) {
 -                      REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0),
 -                                INI_RA(&ahp->ah_iniPcieSerdes, i, 1));
 +              /*
 +               * AR9280 2.0 or later chips use SerDes values from the
 +               * initvals.h initialized depending on chipset during
 +               * ath9k_hw_do_attach()
 +               */
 +              for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) {
 +                      REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
 +                                INI_RA(&ah->iniPcieSerdes, i, 1));
                }
 -              udelay(1000);
        } else if (AR_SREV_9280(ah) &&
 -                 (ah->ah_macRev == AR_SREV_REVISION_9280_10)) {
 +                 (ah->hw_version.macRev == AR_SREV_REVISION_9280_10)) {
                REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
                REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
  
 +              /* RX shut off when elecidle is asserted */
                REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
                REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
                REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
  
 -              if (ah->ah_config.pcie_clock_req)
 +              /* Shut off CLKREQ active in L1 */
 +              if (ah->config.pcie_clock_req)
                        REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc);
                else
                        REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd);
                REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
                REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
  
 +              /* Load the new settings */
                REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
  
 -              udelay(1000);
        } else {
                REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
                REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
 +
 +              /* RX shut off when elecidle is asserted */
                REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
                REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
                REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
 +
 +              /*
 +               * Ignore ah->ah_config.pcie_clock_req setting for
 +               * pre-AR9280 11n
 +               */
                REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
 +
                REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
                REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
                REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
 +
 +              /* Load the new settings */
                REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
        }
  
 +      udelay(1000);
 +
 +      /* set bit 19 to allow forcing of pcie core into L1 state */
        REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
  
 -      if (ah->ah_config.pcie_waen) {
 -              REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen);
 +      /* Several PCIe massages to ensure proper behaviour */
 +      if (ah->config.pcie_waen) {
 +              REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
        } else {
                if (AR_SREV_9285(ah))
                        REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT);
 +              /*
 +               * On AR9280 chips bit 22 of 0x4004 needs to be set to
 +               * otherwise card may disappear.
 +               */
                else if (AR_SREV_9280(ah))
                        REG_WRITE(ah, AR_WA, AR9280_WA_DEFAULT);
                else
                        REG_WRITE(ah, AR_WA, AR_WA_DEFAULT);
        }
 -
  }
  
  /**********************/
  /* Interrupt Handling */
  /**********************/
  
 -bool ath9k_hw_intrpend(struct ath_hal *ah)
 +bool ath9k_hw_intrpend(struct ath_hw *ah)
  {
        u32 host_isr;
  
        return false;
  }
  
 -bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
 +bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
  {
        u32 isr = 0;
        u32 mask2 = 0;
 -      struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
 +      struct ath9k_hw_capabilities *pCap = &ah->caps;
        u32 sync_cause = 0;
        bool fatal_int = false;
 -      struct ath_hal_5416 *ahp = AH5416(ah);
  
        if (!AR_SREV_9100(ah)) {
                if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
                                mask2 |= ATH9K_INT_GTT;
                        if (isr2 & AR_ISR_S2_CST)
                                mask2 |= ATH9K_INT_CST;
 +                      if (isr2 & AR_ISR_S2_TSFOOR)
 +                              mask2 |= ATH9K_INT_TSFOOR;
                }
  
                isr = REG_READ(ah, AR_ISR_RAC);
  
                *masked = isr & ATH9K_INT_COMMON;
  
 -              if (ahp->ah_intrMitigation) {
 +              if (ah->intr_mitigation) {
                        if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
                                *masked |= ATH9K_INT_RX;
                }
                        *masked |= ATH9K_INT_TX;
  
                        s0_s = REG_READ(ah, AR_ISR_S0_S);
 -                      ahp->ah_intrTxqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK);
 -                      ahp->ah_intrTxqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC);
 +                      ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK);
 +                      ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC);
  
                        s1_s = REG_READ(ah, AR_ISR_S1_S);
 -                      ahp->ah_intrTxqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR);
 -                      ahp->ah_intrTxqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL);
 +                      ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR);
 +                      ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL);
                }
  
                if (isr & AR_ISR_RXORN) {
        return true;
  }
  
 -enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah)
 +enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah)
  {
 -      return AH5416(ah)->ah_maskReg;
 +      return ah->mask_reg;
  }
  
 -enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints)
 +enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -      u32 omask = ahp->ah_maskReg;
 +      u32 omask = ah->mask_reg;
        u32 mask, mask2;
 -      struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
 +      struct ath9k_hw_capabilities *pCap = &ah->caps;
  
        DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
  
        mask2 = 0;
  
        if (ints & ATH9K_INT_TX) {
 -              if (ahp->ah_txOkInterruptMask)
 +              if (ah->txok_interrupt_mask)
                        mask |= AR_IMR_TXOK;
 -              if (ahp->ah_txDescInterruptMask)
 +              if (ah->txdesc_interrupt_mask)
                        mask |= AR_IMR_TXDESC;
 -              if (ahp->ah_txErrInterruptMask)
 +              if (ah->txerr_interrupt_mask)
                        mask |= AR_IMR_TXERR;
 -              if (ahp->ah_txEolInterruptMask)
 +              if (ah->txeol_interrupt_mask)
                        mask |= AR_IMR_TXEOL;
        }
        if (ints & ATH9K_INT_RX) {
                mask |= AR_IMR_RXERR;
 -              if (ahp->ah_intrMitigation)
 +              if (ah->intr_mitigation)
                        mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
                else
                        mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
                if (ints & ATH9K_INT_DTIMSYNC)
                        mask2 |= AR_IMR_S2_DTIMSYNC;
                if (ints & ATH9K_INT_CABEND)
 -                      mask2 |= (AR_IMR_S2_CABEND);
 +                      mask2 |= AR_IMR_S2_CABEND;
 +              if (ints & ATH9K_INT_TSFOOR)
 +                      mask2 |= AR_IMR_S2_TSFOOR;
        }
  
        if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) {
                                           AR_IMR_S2_TSFOOR |
                                           AR_IMR_S2_GTT | AR_IMR_S2_CST);
        REG_WRITE(ah, AR_IMR_S2, mask | mask2);
 -      ahp->ah_maskReg = ints;
 +      ah->mask_reg = ints;
  
        if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
                if (ints & ATH9K_INT_TIM_TIMER)
  /* Beacon Handling */
  /*******************/
  
 -void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period)
 +void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
        int flags = 0;
  
 -      ahp->ah_beaconInterval = beacon_period;
 +      ah->beacon_interval = beacon_period;
  
 -      switch (ah->ah_opmode) {
 +      switch (ah->opmode) {
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_MONITOR:
                REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
                            AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
                REG_WRITE(ah, AR_NEXT_NDP_TIMER,
                          TU_TO_USEC(next_beacon +
 -                                   (ahp->ah_atimWindow ? ahp->
 -                                    ah_atimWindow : 1)));
 +                                   (ah->atim_window ? ah->
 +                                    atim_window : 1)));
                flags |= AR_NDP_TIMER_EN;
        case NL80211_IFTYPE_AP:
                REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
                REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT,
                          TU_TO_USEC(next_beacon -
 -                                   ah->ah_config.
 +                                   ah->config.
                                     dma_beacon_response_time));
                REG_WRITE(ah, AR_NEXT_SWBA,
                          TU_TO_USEC(next_beacon -
 -                                   ah->ah_config.
 +                                   ah->config.
                                     sw_beacon_response_time));
                flags |=
                        AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN;
        default:
                DPRINTF(ah->ah_sc, ATH_DBG_BEACON,
                        "%s: unsupported opmode: %d\n",
 -                      __func__, ah->ah_opmode);
 +                      __func__, ah->opmode);
                return;
                break;
        }
        REG_SET_BIT(ah, AR_TIMER_MODE, flags);
  }
  
 -void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
 +void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
                                    const struct ath9k_beacon_state *bs)
  {
        u32 nextTbtt, beaconintval, dtimperiod, beacontimeout;
 -      struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
 +      struct ath9k_hw_capabilities *pCap = &ah->caps;
  
        REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
  
                    AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN |
                    AR_DTIM_TIMER_EN);
  
 +      /* TSF Out of Range Threshold */
 +      REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold);
  }
  
  /*******************/
  /* HW Capabilities */
  /*******************/
  
 -bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
 +bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -      struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
 +      struct ath9k_hw_capabilities *pCap = &ah->caps;
        u16 capField = 0, eeval;
  
 -      eeval = ath9k_hw_get_eeprom(ah, EEP_REG_0);
 -
 -      ah->ah_currentRD = eeval;
 -
 -      eeval = ath9k_hw_get_eeprom(ah, EEP_REG_1);
 -      ah->ah_currentRDExt = eeval;
 +      eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
 +      ah->regulatory.current_rd = eeval;
  
 -      capField = ath9k_hw_get_eeprom(ah, EEP_OP_CAP);
 -
 -      if (ah->ah_opmode != NL80211_IFTYPE_AP &&
 -          ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) {
 -              if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65)
 -                      ah->ah_currentRD += 5;
 -              else if (ah->ah_currentRD == 0x41)
 -                      ah->ah_currentRD = 0x43;
 +      eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1);
 +      if (AR_SREV_9285_10_OR_LATER(ah))
 +              eeval |= AR9285_RDEXT_DEFAULT;
 +      ah->regulatory.current_rd_ext = eeval;
 +
 +      capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP);
 +
 +      if (ah->opmode != NL80211_IFTYPE_AP &&
 +          ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) {
 +              if (ah->regulatory.current_rd == 0x64 ||
 +                  ah->regulatory.current_rd == 0x65)
 +                      ah->regulatory.current_rd += 5;
 +              else if (ah->regulatory.current_rd == 0x41)
 +                      ah->regulatory.current_rd = 0x43;
                DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
 -                      "regdomain mapped to 0x%x\n", ah->ah_currentRD);
 +                      "regdomain mapped to 0x%x\n", ah->regulatory.current_rd);
        }
  
 -      eeval = ath9k_hw_get_eeprom(ah, EEP_OP_MODE);
 +      eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
        bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX);
  
        if (eeval & AR5416_OPFLAGS_11A) {
                set_bit(ATH9K_MODE_11A, pCap->wireless_modes);
 -              if (ah->ah_config.ht_enable) {
 +              if (ah->config.ht_enable) {
                        if (!(eeval & AR5416_OPFLAGS_N_5G_HT20))
                                set_bit(ATH9K_MODE_11NA_HT20,
                                        pCap->wireless_modes);
        if (eeval & AR5416_OPFLAGS_11G) {
                set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
                set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
 -              if (ah->ah_config.ht_enable) {
 +              if (ah->config.ht_enable) {
                        if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
                                set_bit(ATH9K_MODE_11NG_HT20,
                                        pCap->wireless_modes);
                }
        }
  
 -      pCap->tx_chainmask = ath9k_hw_get_eeprom(ah, EEP_TX_MASK);
 -      if ((ah->ah_isPciExpress)
 -          || (eeval & AR5416_OPFLAGS_11A)) {
 -              pCap->rx_chainmask =
 -                      ath9k_hw_get_eeprom(ah, EEP_RX_MASK);
 -      } else {
 -              pCap->rx_chainmask =
 -                      (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7;
 -      }
 +      pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK);
 +      if ((ah->hw_version.devid == AR5416_DEVID_PCI) &&
 +          !(eeval & AR5416_OPFLAGS_11A))
 +              pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7;
 +      else
 +              pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK);
  
 -      if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0)))
 -              ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA;
 +      if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0)))
 +              ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA;
  
        pCap->low_2ghz_chan = 2312;
        pCap->high_2ghz_chan = 2732;
  
        pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD;
  
 -      if (ah->ah_config.ht_enable)
 +      if (ah->config.ht_enable)
                pCap->hw_caps |= ATH9K_HW_CAP_HT;
        else
                pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
        pCap->num_mr_retries = 4;
        pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
  
 -      if (AR_SREV_9280_10_OR_LATER(ah))
 +      if (AR_SREV_9285_10_OR_LATER(ah))
 +              pCap->num_gpio_pins = AR9285_NUM_GPIO;
 +      else if (AR_SREV_9280_10_OR_LATER(ah))
                pCap->num_gpio_pins = AR928X_NUM_GPIO;
        else
                pCap->num_gpio_pins = AR_NUM_GPIO;
        pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
  
  #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 -      ah->ah_rfsilent = ath9k_hw_get_eeprom(ah, EEP_RF_SILENT);
 -      if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
 -              ah->ah_rfkill_gpio =
 -                      MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL);
 -              ah->ah_rfkill_polarity =
 -                      MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY);
 +      ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT);
 +      if (ah->rfsilent & EEP_RFSILENT_ENABLED) {
 +              ah->rfkill_gpio =
 +                      MS(ah->rfsilent, EEP_RFSILENT_GPIO_SEL);
 +              ah->rfkill_polarity =
 +                      MS(ah->rfsilent, EEP_RFSILENT_POLARITY);
  
                pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
        }
  #endif
  
 -      if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) ||
 -          (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) ||
 -          (ah->ah_macVersion == AR_SREV_VERSION_9160) ||
 -          (ah->ah_macVersion == AR_SREV_VERSION_9100) ||
 -          (ah->ah_macVersion == AR_SREV_VERSION_9280))
 +      if ((ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) ||
 +          (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) ||
 +          (ah->hw_version.macVersion == AR_SREV_VERSION_9160) ||
 +          (ah->hw_version.macVersion == AR_SREV_VERSION_9100) ||
 +          (ah->hw_version.macVersion == AR_SREV_VERSION_9280))
                pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
        else
                pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
        else
                pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
  
 -      if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) {
 +      if (ah->regulatory.current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) {
                pCap->reg_cap =
                        AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
                        AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
        pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
  
        pCap->num_antcfg_5ghz =
 -              ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ);
 +              ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ);
        pCap->num_antcfg_2ghz =
 -              ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
 +              ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
 +
 +      if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) {
 +              pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX;
 +              ah->btactive_gpio = 6;
 +              ah->wlanactive_gpio = 5;
 +      }
  
        return true;
  }
  
 -bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
 +bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
                            u32 capability, u32 *result)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -      const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
 -
        switch (type) {
        case ATH9K_CAP_CIPHER:
                switch (capability) {
                case 0:
                        return true;
                case 1:
 -                      return (ahp->ah_staId1Defaults &
 +                      return (ah->sta_id1_defaults &
                                AR_STA_ID1_CRPT_MIC_ENABLE) ? true :
                        false;
                }
        case ATH9K_CAP_TKIP_SPLIT:
 -              return (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) ?
 +              return (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) ?
                        false : true;
 -      case ATH9K_CAP_WME_TKIPMIC:
 -              return 0;
 -      case ATH9K_CAP_PHYCOUNTERS:
 -              return ahp->ah_hasHwPhyCounters ? 0 : -ENXIO;
        case ATH9K_CAP_DIVERSITY:
                return (REG_READ(ah, AR_PHY_CCK_DETECT) &
                        AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ?
                        true : false;
 -      case ATH9K_CAP_PHYDIAG:
 -              return true;
        case ATH9K_CAP_MCAST_KEYSRCH:
                switch (capability) {
                case 0:
                        if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) {
                                return false;
                        } else {
 -                              return (ahp->ah_staId1Defaults &
 +                              return (ah->sta_id1_defaults &
                                        AR_STA_ID1_MCAST_KSRCH) ? true :
                                        false;
                        }
                }
                return false;
 -      case ATH9K_CAP_TSF_ADJUST:
 -              return (ahp->ah_miscMode & AR_PCU_TX_ADD_TSF) ?
 -                      true : false;
 -      case ATH9K_CAP_RFSILENT:
 -              if (capability == 3)
 -                      return false;
 -      case ATH9K_CAP_ANT_CFG_2GHZ:
 -              *result = pCap->num_antcfg_2ghz;
 -              return true;
 -      case ATH9K_CAP_ANT_CFG_5GHZ:
 -              *result = pCap->num_antcfg_5ghz;
 -              return true;
        case ATH9K_CAP_TXPOW:
                switch (capability) {
                case 0:
                        return 0;
                case 1:
 -                      *result = ah->ah_powerLimit;
 +                      *result = ah->regulatory.power_limit;
                        return 0;
                case 2:
 -                      *result = ah->ah_maxPowerLevel;
 +                      *result = ah->regulatory.max_power_level;
                        return 0;
                case 3:
 -                      *result = ah->ah_tpScale;
 +                      *result = ah->regulatory.tp_scale;
                        return 0;
                }
                return false;
 +      case ATH9K_CAP_DS:
 +              return (AR_SREV_9280_20_OR_LATER(ah) &&
 +                      (ah->eep_ops->get_eeprom(ah, EEP_RC_CHAIN_MASK) == 1))
 +                      ? false : true;
        default:
                return false;
        }
  }
  
 -bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type,
 +bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
                            u32 capability, u32 setting, int *status)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
        u32 v;
  
        switch (type) {
        case ATH9K_CAP_TKIP_MIC:
                if (setting)
 -                      ahp->ah_staId1Defaults |=
 +                      ah->sta_id1_defaults |=
                                AR_STA_ID1_CRPT_MIC_ENABLE;
                else
 -                      ahp->ah_staId1Defaults &=
 +                      ah->sta_id1_defaults &=
                                ~AR_STA_ID1_CRPT_MIC_ENABLE;
                return true;
        case ATH9K_CAP_DIVERSITY:
                return true;
        case ATH9K_CAP_MCAST_KEYSRCH:
                if (setting)
 -                      ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH;
 -              else
 -                      ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH;
 -              return true;
 -      case ATH9K_CAP_TSF_ADJUST:
 -              if (setting)
 -                      ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
 +                      ah->sta_id1_defaults |= AR_STA_ID1_MCAST_KSRCH;
                else
 -                      ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
 +                      ah->sta_id1_defaults &= ~AR_STA_ID1_MCAST_KSRCH;
                return true;
        default:
                return false;
  /* GPIO / RFKILL / Antennae */
  /****************************/
  
 -static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah,
 +static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah,
                                         u32 gpio, u32 type)
  {
        int addr;
        }
  }
  
 -void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio)
 +void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio)
  {
        u32 gpio_shift;
  
 -      ASSERT(gpio < ah->ah_caps.num_gpio_pins);
 +      ASSERT(gpio < ah->caps.num_gpio_pins);
  
        gpio_shift = gpio << 1;
  
                (AR_GPIO_OE_OUT_DRV << gpio_shift));
  }
  
 -u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
 +u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
  {
 -      if (gpio >= ah->ah_caps.num_gpio_pins)
 +#define MS_REG_READ(x, y) \
 +      (MS(REG_READ(ah, AR_GPIO_IN_OUT), x##_GPIO_IN_VAL) & (AR_GPIO_BIT(y)))
 +
 +      if (gpio >= ah->caps.num_gpio_pins)
                return 0xffffffff;
  
 -      if (AR_SREV_9280_10_OR_LATER(ah)) {
 -              return (MS
 -                      (REG_READ(ah, AR_GPIO_IN_OUT),
 -                       AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0;
 -      } else {
 -              return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) &
 -                      AR_GPIO_BIT(gpio)) != 0;
 -      }
 +      if (AR_SREV_9285_10_OR_LATER(ah))
 +              return MS_REG_READ(AR9285, gpio) != 0;
 +      else if (AR_SREV_9280_10_OR_LATER(ah))
 +              return MS_REG_READ(AR928X, gpio) != 0;
 +      else
 +              return MS_REG_READ(AR, gpio) != 0;
  }
  
 -void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
 +void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
                         u32 ah_signal_type)
  {
        u32 gpio_shift;
                (AR_GPIO_OE_OUT_DRV << gpio_shift));
  }
  
 -void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
 +void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
  {
        REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
                AR_GPIO_BIT(gpio));
  }
  
  #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 -void ath9k_enable_rfkill(struct ath_hal *ah)
 +void ath9k_enable_rfkill(struct ath_hw *ah)
  {
        REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
                    AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
        REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
                    AR_GPIO_INPUT_MUX2_RFSILENT);
  
 -      ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio);
 +      ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
        REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
  }
  #endif
  
 -int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg)
 -{
 -      struct ath9k_channel *chan = ah->ah_curchan;
 -      const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
 -      u16 ant_config;
 -      u32 halNumAntConfig;
 -
 -      halNumAntConfig = IS_CHAN_2GHZ(chan) ?
 -              pCap->num_antcfg_2ghz : pCap->num_antcfg_5ghz;
 -
 -      if (cfg < halNumAntConfig) {
 -              if (!ath9k_hw_get_eeprom_antenna_cfg(ah, chan,
 -                                                   cfg, &ant_config)) {
 -                      REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
 -                      return 0;
 -              }
 -      }
 -
 -      return -EINVAL;
 -}
 -
 -u32 ath9k_hw_getdefantenna(struct ath_hal *ah)
 +u32 ath9k_hw_getdefantenna(struct ath_hw *ah)
  {
        return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
  }
  
 -void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna)
 +void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna)
  {
        REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
  }
  
 -bool ath9k_hw_setantennaswitch(struct ath_hal *ah,
 +bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
                               enum ath9k_ant_setting settings,
                               struct ath9k_channel *chan,
                               u8 *tx_chainmask,
                               u8 *rx_chainmask,
                               u8 *antenna_cfgd)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
        static u8 tx_chainmask_cfg, rx_chainmask_cfg;
  
        if (AR_SREV_9280(ah)) {
                        *antenna_cfgd = true;
                        break;
                case ATH9K_ANT_FIXED_B:
 -                      if (ah->ah_caps.tx_chainmask >
 +                      if (ah->caps.tx_chainmask >
                            ATH9K_ANTENNA1_CHAINMASK) {
                                *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
                        }
                        break;
                }
        } else {
 -              ahp->ah_diversityControl = settings;
 +              ah->diversity_control = settings;
        }
  
        return true;
  /* General Operation */
  /*********************/
  
 -u32 ath9k_hw_getrxfilter(struct ath_hal *ah)
 +u32 ath9k_hw_getrxfilter(struct ath_hw *ah)
  {
        u32 bits = REG_READ(ah, AR_RX_FILTER);
        u32 phybits = REG_READ(ah, AR_PHY_ERR);
        return bits;
  }
  
 -void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits)
 +void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
  {
        u32 phybits;
  
                          REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
  }
  
 -bool ath9k_hw_phy_disable(struct ath_hal *ah)
 +bool ath9k_hw_phy_disable(struct ath_hw *ah)
  {
        return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM);
  }
  
 -bool ath9k_hw_disable(struct ath_hal *ah)
 +bool ath9k_hw_disable(struct ath_hw *ah)
  {
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
                return false;
        return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD);
  }
  
 -bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit)
 +bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
  {
 -      struct ath9k_channel *chan = ah->ah_curchan;
 +      struct ath9k_channel *chan = ah->curchan;
 +      struct ieee80211_channel *channel = chan->chan;
  
 -      ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER);
 +      ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER);
  
 -      if (ath9k_hw_set_txpower(ah, chan,
 -                               ath9k_regd_get_ctl(ah, chan),
 -                               ath9k_regd_get_antenna_allowed(ah, chan),
 -                               chan->maxRegTxPower * 2,
 -                               min((u32) MAX_RATE_POWER,
 -                                   (u32) ah->ah_powerLimit)) != 0)
 +      if (ah->eep_ops->set_txpower(ah, chan,
 +                           ath9k_regd_get_ctl(ah, chan),
 +                           channel->max_antenna_gain * 2,
 +                           channel->max_power * 2,
 +                           min((u32) MAX_RATE_POWER,
 +                               (u32) ah->regulatory.power_limit)) != 0)
                return false;
  
        return true;
  }
  
 -void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac)
 +void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -
 -      memcpy(mac, ahp->ah_macaddr, ETH_ALEN);
 +      memcpy(ah->macaddr, mac, ETH_ALEN);
  }
  
 -bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac)
 +void ath9k_hw_setopmode(struct ath_hw *ah)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -
 -      memcpy(ahp->ah_macaddr, mac, ETH_ALEN);
 -
 -      return true;
 +      ath9k_hw_set_operating_mode(ah, ah->opmode);
  }
  
 -void ath9k_hw_setopmode(struct ath_hal *ah)
 -{
 -      ath9k_hw_set_operating_mode(ah, ah->ah_opmode);
 -}
 -
 -void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1)
 +void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1)
  {
        REG_WRITE(ah, AR_MCAST_FIL0, filter0);
        REG_WRITE(ah, AR_MCAST_FIL1, filter1);
  }
  
 -void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask)
 -{
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -
 -      memcpy(mask, ahp->ah_bssidmask, ETH_ALEN);
 -}
 -
 -bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask)
 +void ath9k_hw_setbssidmask(struct ath_softc *sc)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -
 -      memcpy(ahp->ah_bssidmask, mask, ETH_ALEN);
 -
 -      REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask));
 -      REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4));
 -
 -      return true;
 +      REG_WRITE(sc->sc_ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask));
 +      REG_WRITE(sc->sc_ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4));
  }
  
 -void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId)
 +void ath9k_hw_write_associd(struct ath_softc *sc)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -
 -      memcpy(ahp->ah_bssid, bssid, ETH_ALEN);
 -      ahp->ah_assocId = assocId;
 -
 -      REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid));
 -      REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) |
 -                ((assocId & 0x3fff) << AR_BSS_ID1_AID_S));
 +      REG_WRITE(sc->sc_ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid));
 +      REG_WRITE(sc->sc_ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) |
 +                ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S));
  }
  
 -u64 ath9k_hw_gettsf64(struct ath_hal *ah)
 +u64 ath9k_hw_gettsf64(struct ath_hw *ah)
  {
        u64 tsf;
  
        return tsf;
  }
  
 -void ath9k_hw_reset_tsf(struct ath_hal *ah)
 +void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64)
 +{
 +      REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff);
 +      REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff);
 +}
 +
 +void ath9k_hw_reset_tsf(struct ath_hw *ah)
  {
        int count;
  
        REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
  }
  
 -bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting)
 +bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -
        if (setting)
 -              ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
 +              ah->misc_mode |= AR_PCU_TX_ADD_TSF;
        else
 -              ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
 +              ah->misc_mode &= ~AR_PCU_TX_ADD_TSF;
  
        return true;
  }
  
 -bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us)
 +bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
  {
 -      struct ath_hal_5416 *ahp = AH5416(ah);
 -
        if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad slot time %u\n", us);
 -              ahp->ah_slottime = (u32) -1;
 +              ah->slottime = (u32) -1;
                return false;
        } else {
                REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us));
 -              ahp->ah_slottime = us;
 +              ah->slottime = us;
                return true;
        }
  }
  
 -void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode)
 +void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode)
  {
        u32 macmode;
  
        if (mode == ATH9K_HT_MACMODE_2040 &&
 -          !ah->ah_config.cwm_ignore_extcca)
 +          !ah->config.cwm_ignore_extcca)
                macmode = AR_2040_JOINED_RX_CLEAR;
        else
                macmode = 0;
  
        REG_WRITE(ah, AR_2040_MODE, macmode);
  }
 +
 +/***************************/
 +/*  Bluetooth Coexistence  */
 +/***************************/
 +
 +void ath9k_hw_btcoex_enable(struct ath_hw *ah)
 +{
 +      /* connect bt_active to baseband */
 +      REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
 +                      (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
 +                       AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
 +
 +      REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
 +                      AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
 +
 +      /* Set input mux for bt_active to gpio pin */
 +      REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
 +                      AR_GPIO_INPUT_MUX1_BT_ACTIVE,
 +                      ah->btactive_gpio);
 +
 +      /* Configure the desired gpio port for input */
 +      ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio);
 +
 +      /* Configure the desired GPIO port for TX_FRAME output */
 +      ath9k_hw_cfg_output(ah, ah->wlanactive_gpio,
 +                          AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
 +}
index 89936a038da3604d345c6feb34423a07e67dba26,91d8f594af813a9d1d5100ea117c4ffef0e841d7..dc681f011fdfa1b3be21686c6b1ce0805b7405b7
  
  #include <linux/if_ether.h>
  #include <linux/delay.h>
- #define REG_WRITE(_ah, _reg, _val) iowrite32(_val, _ah->ah_sc->mem + _reg)
- #define REG_READ(_ah, _reg) ioread32(_ah->ah_sc->mem + _reg)
 +#include <linux/io.h>
 +
 +#include "mac.h"
 +#include "ani.h"
 +#include "eeprom.h"
 +#include "calib.h"
 +#include "regd.h"
 +#include "reg.h"
 +#include "phy.h"
 +
 +#define ATHEROS_VENDOR_ID     0x168c
 +#define AR5416_DEVID_PCI      0x0023
 +#define AR5416_DEVID_PCIE     0x0024
 +#define AR9160_DEVID_PCI      0x0027
 +#define AR9280_DEVID_PCI      0x0029
 +#define AR9280_DEVID_PCIE     0x002a
 +#define AR9285_DEVID_PCIE     0x002b
 +#define AR5416_AR9100_DEVID   0x000b
 +#define       AR_SUBVENDOR_ID_NOG     0x0e11
 +#define AR_SUBVENDOR_ID_NEW_A 0x7065
 +#define AR5416_MAGIC          0x19641014
 +
 +/* Register read/write primitives */
++#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val))
++#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg))
 +
 +#define SM(_v, _f)  (((_v) << _f##_S) & _f)
 +#define MS(_v, _f)  (((_v) & _f) >> _f##_S)
 +#define REG_RMW(_a, _r, _set, _clr)    \
 +      REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set))
 +#define REG_RMW_FIELD(_a, _r, _f, _v) \
 +      REG_WRITE(_a, _r, \
 +      (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f))
 +#define REG_SET_BIT(_a, _r, _f) \
 +      REG_WRITE(_a, _r, REG_READ(_a, _r) | _f)
 +#define REG_CLR_BIT(_a, _r, _f) \
 +      REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f)
  
 -struct ar5416_desc {
 -      u32 ds_link;
 -      u32 ds_data;
 -      u32 ds_ctl0;
 -      u32 ds_ctl1;
 -      union {
 -              struct {
 -                      u32 ctl2;
 -                      u32 ctl3;
 -                      u32 ctl4;
 -                      u32 ctl5;
 -                      u32 ctl6;
 -                      u32 ctl7;
 -                      u32 ctl8;
 -                      u32 ctl9;
 -                      u32 ctl10;
 -                      u32 ctl11;
 -                      u32 status0;
 -                      u32 status1;
 -                      u32 status2;
 -                      u32 status3;
 -                      u32 status4;
 -                      u32 status5;
 -                      u32 status6;
 -                      u32 status7;
 -                      u32 status8;
 -                      u32 status9;
 -              } tx;
 -              struct {
 -                      u32 status0;
 -                      u32 status1;
 -                      u32 status2;
 -                      u32 status3;
 -                      u32 status4;
 -                      u32 status5;
 -                      u32 status6;
 -                      u32 status7;
 -                      u32 status8;
 -              } rx;
 -      } u;
 -} __packed;
 -
 -#define AR5416DESC(_ds)         ((struct ar5416_desc *)(_ds))
 -#define AR5416DESC_CONST(_ds)   ((const struct ar5416_desc *)(_ds))
 -
 -#define ds_ctl2     u.tx.ctl2
 -#define ds_ctl3     u.tx.ctl3
 -#define ds_ctl4     u.tx.ctl4
 -#define ds_ctl5     u.tx.ctl5
 -#define ds_ctl6     u.tx.ctl6
 -#define ds_ctl7     u.tx.ctl7
 -#define ds_ctl8     u.tx.ctl8
 -#define ds_ctl9     u.tx.ctl9
 -#define ds_ctl10    u.tx.ctl10
 -#define ds_ctl11    u.tx.ctl11
 -
 -#define ds_txstatus0    u.tx.status0
 -#define ds_txstatus1    u.tx.status1
 -#define ds_txstatus2    u.tx.status2
 -#define ds_txstatus3    u.tx.status3
 -#define ds_txstatus4    u.tx.status4
 -#define ds_txstatus5    u.tx.status5
 -#define ds_txstatus6    u.tx.status6
 -#define ds_txstatus7    u.tx.status7
 -#define ds_txstatus8    u.tx.status8
 -#define ds_txstatus9    u.tx.status9
 -
 -#define ds_rxstatus0    u.rx.status0
 -#define ds_rxstatus1    u.rx.status1
 -#define ds_rxstatus2    u.rx.status2
 -#define ds_rxstatus3    u.rx.status3
 -#define ds_rxstatus4    u.rx.status4
 -#define ds_rxstatus5    u.rx.status5
 -#define ds_rxstatus6    u.rx.status6
 -#define ds_rxstatus7    u.rx.status7
 -#define ds_rxstatus8    u.rx.status8
 -
 -#define AR_FrameLen         0x00000fff
 -#define AR_VirtMoreFrag     0x00001000
 -#define AR_TxCtlRsvd00      0x0000e000
 -#define AR_XmitPower        0x003f0000
 -#define AR_XmitPower_S      16
 -#define AR_RTSEnable        0x00400000
 -#define AR_VEOL             0x00800000
 -#define AR_ClrDestMask      0x01000000
 -#define AR_TxCtlRsvd01      0x1e000000
 -#define AR_TxIntrReq        0x20000000
 -#define AR_DestIdxValid     0x40000000
 -#define AR_CTSEnable        0x80000000
 -
 -#define AR_BufLen           0x00000fff
 -#define AR_TxMore           0x00001000
 -#define AR_DestIdx          0x000fe000
 -#define AR_DestIdx_S        13
 -#define AR_FrameType        0x00f00000
 -#define AR_FrameType_S      20
 -#define AR_NoAck            0x01000000
 -#define AR_InsertTS         0x02000000
 -#define AR_CorruptFCS       0x04000000
 -#define AR_ExtOnly          0x08000000
 -#define AR_ExtAndCtl        0x10000000
 -#define AR_MoreAggr         0x20000000
 -#define AR_IsAggr           0x40000000
 -
 -#define AR_BurstDur         0x00007fff
 -#define AR_BurstDur_S       0
 -#define AR_DurUpdateEna     0x00008000
 -#define AR_XmitDataTries0   0x000f0000
 -#define AR_XmitDataTries0_S 16
 -#define AR_XmitDataTries1   0x00f00000
 -#define AR_XmitDataTries1_S 20
 -#define AR_XmitDataTries2   0x0f000000
 -#define AR_XmitDataTries2_S 24
 -#define AR_XmitDataTries3   0xf0000000
 -#define AR_XmitDataTries3_S 28
 -
 -#define AR_XmitRate0        0x000000ff
 -#define AR_XmitRate0_S      0
 -#define AR_XmitRate1        0x0000ff00
 -#define AR_XmitRate1_S      8
 -#define AR_XmitRate2        0x00ff0000
 -#define AR_XmitRate2_S      16
 -#define AR_XmitRate3        0xff000000
 -#define AR_XmitRate3_S      24
 -
 -#define AR_PacketDur0       0x00007fff
 -#define AR_PacketDur0_S     0
 -#define AR_RTSCTSQual0      0x00008000
 -#define AR_PacketDur1       0x7fff0000
 -#define AR_PacketDur1_S     16
 -#define AR_RTSCTSQual1      0x80000000
 -
 -#define AR_PacketDur2       0x00007fff
 -#define AR_PacketDur2_S     0
 -#define AR_RTSCTSQual2      0x00008000
 -#define AR_PacketDur3       0x7fff0000
 -#define AR_PacketDur3_S     16
 -#define AR_RTSCTSQual3      0x80000000
 -
 -#define AR_AggrLen          0x0000ffff
 -#define AR_AggrLen_S        0
 -#define AR_TxCtlRsvd60      0x00030000
 -#define AR_PadDelim         0x03fc0000
 -#define AR_PadDelim_S       18
 -#define AR_EncrType         0x0c000000
 -#define AR_EncrType_S       26
 -#define AR_TxCtlRsvd61      0xf0000000
 -
 -#define AR_2040_0           0x00000001
 -#define AR_GI0              0x00000002
 -#define AR_ChainSel0        0x0000001c
 -#define AR_ChainSel0_S      2
 -#define AR_2040_1           0x00000020
 -#define AR_GI1              0x00000040
 -#define AR_ChainSel1        0x00000380
 -#define AR_ChainSel1_S      7
 -#define AR_2040_2           0x00000400
 -#define AR_GI2              0x00000800
 -#define AR_ChainSel2        0x00007000
 -#define AR_ChainSel2_S      12
 -#define AR_2040_3           0x00008000
 -#define AR_GI3              0x00010000
 -#define AR_ChainSel3        0x000e0000
 -#define AR_ChainSel3_S      17
 -#define AR_RTSCTSRate       0x0ff00000
 -#define AR_RTSCTSRate_S     20
 -#define AR_TxCtlRsvd70      0xf0000000
 -
 -#define AR_TxRSSIAnt00      0x000000ff
 -#define AR_TxRSSIAnt00_S    0
 -#define AR_TxRSSIAnt01      0x0000ff00
 -#define AR_TxRSSIAnt01_S    8
 -#define AR_TxRSSIAnt02      0x00ff0000
 -#define AR_TxRSSIAnt02_S    16
 -#define AR_TxStatusRsvd00   0x3f000000
 -#define AR_TxBaStatus       0x40000000
 -#define AR_TxStatusRsvd01   0x80000000
 -
 -#define AR_FrmXmitOK            0x00000001
 -#define AR_ExcessiveRetries     0x00000002
 -#define AR_FIFOUnderrun         0x00000004
 -#define AR_Filtered             0x00000008
 -#define AR_RTSFailCnt           0x000000f0
 -#define AR_RTSFailCnt_S         4
 -#define AR_DataFailCnt          0x00000f00
 -#define AR_DataFailCnt_S        8
 -#define AR_VirtRetryCnt         0x0000f000
 -#define AR_VirtRetryCnt_S       12
 -#define AR_TxDelimUnderrun      0x00010000
 -#define AR_TxDataUnderrun       0x00020000
 -#define AR_DescCfgErr           0x00040000
 -#define AR_TxTimerExpired       0x00080000
 -#define AR_TxStatusRsvd10       0xfff00000
 -
 -#define AR_SendTimestamp    ds_txstatus2
 -#define AR_BaBitmapLow      ds_txstatus3
 -#define AR_BaBitmapHigh     ds_txstatus4
 -
 -#define AR_TxRSSIAnt10      0x000000ff
 -#define AR_TxRSSIAnt10_S    0
 -#define AR_TxRSSIAnt11      0x0000ff00
 -#define AR_TxRSSIAnt11_S    8
 -#define AR_TxRSSIAnt12      0x00ff0000
 -#define AR_TxRSSIAnt12_S    16
 -#define AR_TxRSSICombined   0xff000000
 -#define AR_TxRSSICombined_S 24
 -
 -#define AR_TxEVM0           ds_txstatus5
 -#define AR_TxEVM1           ds_txstatus6
 -#define AR_TxEVM2           ds_txstatus7
 -
 -#define AR_TxDone           0x00000001
 -#define AR_SeqNum           0x00001ffe
 -#define AR_SeqNum_S         1
 -#define AR_TxStatusRsvd80   0x0001e000
 -#define AR_TxOpExceeded     0x00020000
 -#define AR_TxStatusRsvd81   0x001c0000
 -#define AR_FinalTxIdx       0x00600000
 -#define AR_FinalTxIdx_S     21
 -#define AR_TxStatusRsvd82   0x01800000
 -#define AR_PowerMgmt        0x02000000
 -#define AR_TxStatusRsvd83   0xfc000000
 -
 -#define AR_RxCTLRsvd00  0xffffffff
 -
 -#define AR_BufLen       0x00000fff
 -#define AR_RxCtlRsvd00  0x00001000
 -#define AR_RxIntrReq    0x00002000
 -#define AR_RxCtlRsvd01  0xffffc000
 -
 -#define AR_RxRSSIAnt00      0x000000ff
 -#define AR_RxRSSIAnt00_S    0
 -#define AR_RxRSSIAnt01      0x0000ff00
 -#define AR_RxRSSIAnt01_S    8
 -#define AR_RxRSSIAnt02      0x00ff0000
 -#define AR_RxRSSIAnt02_S    16
 -#define AR_RxRate           0xff000000
 -#define AR_RxRate_S         24
 -#define AR_RxStatusRsvd00   0xff000000
 -
 -#define AR_DataLen          0x00000fff
 -#define AR_RxMore           0x00001000
 -#define AR_NumDelim         0x003fc000
 -#define AR_NumDelim_S       14
 -#define AR_RxStatusRsvd10   0xff800000
 -
 -#define AR_RcvTimestamp     ds_rxstatus2
 -
 -#define AR_GI               0x00000001
 -#define AR_2040             0x00000002
 -#define AR_Parallel40       0x00000004
 -#define AR_Parallel40_S     2
 -#define AR_RxStatusRsvd30   0x000000f8
 -#define AR_RxAntenna      0xffffff00
 -#define AR_RxAntenna_S            8
 -
 -#define AR_RxRSSIAnt10            0x000000ff
 -#define AR_RxRSSIAnt10_S          0
 -#define AR_RxRSSIAnt11            0x0000ff00
 -#define AR_RxRSSIAnt11_S          8
 -#define AR_RxRSSIAnt12            0x00ff0000
 -#define AR_RxRSSIAnt12_S          16
 -#define AR_RxRSSICombined         0xff000000
 -#define AR_RxRSSICombined_S       24
 -
 -#define AR_RxEVM0           ds_rxstatus4
 -#define AR_RxEVM1           ds_rxstatus5
 -#define AR_RxEVM2           ds_rxstatus6
 -
 -#define AR_RxDone           0x00000001
 -#define AR_RxFrameOK        0x00000002
 -#define AR_CRCErr           0x00000004
 -#define AR_DecryptCRCErr    0x00000008
 -#define AR_PHYErr           0x00000010
 -#define AR_MichaelErr       0x00000020
 -#define AR_PreDelimCRCErr   0x00000040
 -#define AR_RxStatusRsvd70   0x00000080
 -#define AR_RxKeyIdxValid    0x00000100
 -#define AR_KeyIdx           0x0000fe00
 -#define AR_KeyIdx_S         9
 -#define AR_PHYErrCode       0x0000ff00
 -#define AR_PHYErrCode_S     8
 -#define AR_RxMoreAggr       0x00010000
 -#define AR_RxAggr           0x00020000
 -#define AR_PostDelimCRCErr  0x00040000
 -#define AR_RxStatusRsvd71   0x3ff80000
 -#define AR_DecryptBusyErr   0x40000000
 -#define AR_KeyMiss          0x80000000
 -
 -#define AR5416_MAGIC        0x19641014
 -
 -#define RXSTATUS_RATE(ah, ads)  (AR_SREV_5416_V20_OR_LATER(ah) ?      \
 -                               MS(ads->ds_rxstatus0, AR_RxRate) :     \
 -                               (ads->ds_rxstatus3 >> 2) & 0xFF)
 -
 -#define set11nTries(_series, _index) \
 -      (SM((_series)[_index].Tries, AR_XmitDataTries##_index))
 -
 -#define set11nRate(_series, _index) \
 -      (SM((_series)[_index].Rate, AR_XmitRate##_index))
 -
 -#define set11nPktDurRTSCTS(_series, _index)                           \
 -      (SM((_series)[_index].PktDuration, AR_PacketDur##_index) |      \
 -      ((_series)[_index].RateFlags & ATH9K_RATESERIES_RTS_CTS   ?     \
 -              AR_RTSCTSQual##_index : 0))
 +#define DO_DELAY(x) do {                      \
 +              if ((++(x) % 64) == 0)          \
 +                      udelay(1);              \
 +      } while (0)
  
 -#define set11nRateFlags(_series, _index)                              \
 -      (((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ?         \
 -        AR_2040_##_index : 0)                                         \
 -       |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ?      \
 -         AR_GI##_index : 0)                                           \
 -       |SM((_series)[_index].ChSel, AR_ChainSel##_index))
 +#define REG_WRITE_ARRAY(iniarray, column, regWr) do {                   \
 +              int r;                                                  \
 +              for (r = 0; r < ((iniarray)->ia_rows); r++) {           \
 +                      REG_WRITE(ah, INI_RA((iniarray), (r), 0),       \
 +                                INI_RA((iniarray), r, (column)));     \
 +                      DO_DELAY(regWr);                                \
 +              }                                                       \
 +      } while (0)
  
 -#define AR_SREV_9100(ah) ((ah->ah_macVersion) == AR_SREV_VERSION_9100)
 +#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT             0
 +#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
 +#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED     2
 +#define AR_GPIO_OUTPUT_MUX_AS_TX_FRAME           3
 +#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED    5
 +#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED      6
  
 -#define INIT_CONFIG_STATUS  0x00000000
 -#define INIT_RSSI_THR       0x00000700
 -#define INIT_BCON_CNTRL_REG 0x00000000
 +#define AR_GPIOD_MASK               0x00001FFF
 +#define AR_GPIO_BIT(_gpio)          (1 << (_gpio))
  
 -#define MIN_TX_FIFO_THRESHOLD   0x1
 -#define MAX_TX_FIFO_THRESHOLD   ((4096 / 64) - 1)
 -#define INIT_TX_FIFO_THRESHOLD  MIN_TX_FIFO_THRESHOLD
 +#define BASE_ACTIVATE_DELAY         100
 +#define RTC_PLL_SETTLE_DELAY        1000
 +#define COEF_SCALE_S                24
 +#define HT40_CHANNEL_CENTER_SHIFT   10
  
 -struct ar5416AniState {
 -      struct ath9k_channel c;
 -      u8 noiseImmunityLevel;
 -      u8 spurImmunityLevel;
 -      u8 firstepLevel;
 -      u8 ofdmWeakSigDetectOff;
 -      u8 cckWeakSigThreshold;
 -      u32 listenTime;
 -      u32 ofdmTrigHigh;
 -      u32 ofdmTrigLow;
 -      int32_t cckTrigHigh;
 -      int32_t cckTrigLow;
 -      int32_t rssiThrLow;
 -      int32_t rssiThrHigh;
 -      u32 noiseFloor;
 -      u32 txFrameCount;
 -      u32 rxFrameCount;
 -      u32 cycleCount;
 -      u32 ofdmPhyErrCount;
 -      u32 cckPhyErrCount;
 -      u32 ofdmPhyErrBase;
 -      u32 cckPhyErrBase;
 -      int16_t pktRssi[2];
 -      int16_t ofdmErrRssi[2];
 -      int16_t cckErrRssi[2];
 +#define ATH9K_ANTENNA0_CHAINMASK    0x1
 +#define ATH9K_ANTENNA1_CHAINMASK    0x2
 +
 +#define ATH9K_NUM_DMA_DEBUG_REGS    8
 +#define ATH9K_NUM_QUEUES            10
 +
 +#define MAX_RATE_POWER              63
 +#define AH_WAIT_TIMEOUT             100000 /* (us) */
 +#define AH_TIME_QUANTUM             10
 +#define AR_KEYTABLE_SIZE            128
 +#define POWER_UP_TIME               200000
 +#define SPUR_RSSI_THRESH            40
 +
 +#define CAB_TIMEOUT_VAL             10
 +#define BEACON_TIMEOUT_VAL          10
 +#define MIN_BEACON_TIMEOUT_VAL      1
 +#define SLEEP_SLOP                  3
 +
 +#define INIT_CONFIG_STATUS          0x00000000
 +#define INIT_RSSI_THR               0x00000700
 +#define INIT_BCON_CNTRL_REG         0x00000000
 +
 +#define TU_TO_USEC(_tu)             ((_tu) << 10)
 +
 +enum wireless_mode {
 +      ATH9K_MODE_11A = 0,
 +      ATH9K_MODE_11B = 2,
 +      ATH9K_MODE_11G = 3,
 +      ATH9K_MODE_11NA_HT20 = 6,
 +      ATH9K_MODE_11NG_HT20 = 7,
 +      ATH9K_MODE_11NA_HT40PLUS = 8,
 +      ATH9K_MODE_11NA_HT40MINUS = 9,
 +      ATH9K_MODE_11NG_HT40PLUS = 10,
 +      ATH9K_MODE_11NG_HT40MINUS = 11,
 +      ATH9K_MODE_MAX
  };
  
 -#define HAL_PROCESS_ANI     0x00000001
 -#define DO_ANI(ah) \
 -      ((AH5416(ah)->ah_procPhyErr & HAL_PROCESS_ANI))
 -
 -struct ar5416Stats {
 -      u32 ast_ani_niup;
 -      u32 ast_ani_nidown;
 -      u32 ast_ani_spurup;
 -      u32 ast_ani_spurdown;
 -      u32 ast_ani_ofdmon;
 -      u32 ast_ani_ofdmoff;
 -      u32 ast_ani_cckhigh;
 -      u32 ast_ani_ccklow;
 -      u32 ast_ani_stepup;
 -      u32 ast_ani_stepdown;
 -      u32 ast_ani_ofdmerrs;
 -      u32 ast_ani_cckerrs;
 -      u32 ast_ani_reset;
 -      u32 ast_ani_lzero;
 -      u32 ast_ani_lneg;
 -      struct ath9k_mib_stats ast_mibstats;
 -      struct ath9k_node_stats ast_nodestats;
 +enum ath9k_hw_caps {
 +      ATH9K_HW_CAP_CHAN_SPREAD                = BIT(0),
 +      ATH9K_HW_CAP_MIC_AESCCM                 = BIT(1),
 +      ATH9K_HW_CAP_MIC_CKIP                   = BIT(2),
 +      ATH9K_HW_CAP_MIC_TKIP                   = BIT(3),
 +      ATH9K_HW_CAP_CIPHER_AESCCM              = BIT(4),
 +      ATH9K_HW_CAP_CIPHER_CKIP                = BIT(5),
 +      ATH9K_HW_CAP_CIPHER_TKIP                = BIT(6),
 +      ATH9K_HW_CAP_VEOL                       = BIT(7),
 +      ATH9K_HW_CAP_BSSIDMASK                  = BIT(8),
 +      ATH9K_HW_CAP_MCAST_KEYSEARCH            = BIT(9),
 +      ATH9K_HW_CAP_CHAN_HALFRATE              = BIT(10),
 +      ATH9K_HW_CAP_CHAN_QUARTERRATE           = BIT(11),
 +      ATH9K_HW_CAP_HT                         = BIT(12),
 +      ATH9K_HW_CAP_GTT                        = BIT(13),
 +      ATH9K_HW_CAP_FASTCC                     = BIT(14),
 +      ATH9K_HW_CAP_RFSILENT                   = BIT(15),
 +      ATH9K_HW_CAP_WOW                        = BIT(16),
 +      ATH9K_HW_CAP_CST                        = BIT(17),
 +      ATH9K_HW_CAP_ENHANCEDPM                 = BIT(18),
 +      ATH9K_HW_CAP_AUTOSLEEP                  = BIT(19),
 +      ATH9K_HW_CAP_4KB_SPLITTRANS             = BIT(20),
 +      ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT     = BIT(21),
 +      ATH9K_HW_CAP_BT_COEX                    = BIT(22)
  };
  
 -#define AR5416_OPFLAGS_11A           0x01
 -#define AR5416_OPFLAGS_11G           0x02
 -#define AR5416_OPFLAGS_N_5G_HT40     0x04
 -#define AR5416_OPFLAGS_N_2G_HT40     0x08
 -#define AR5416_OPFLAGS_N_5G_HT20     0x10
 -#define AR5416_OPFLAGS_N_2G_HT20     0x20
 -
 -#define EEP_RFSILENT_ENABLED        0x0001
 -#define EEP_RFSILENT_ENABLED_S      0
 -#define EEP_RFSILENT_POLARITY       0x0002
 -#define EEP_RFSILENT_POLARITY_S     1
 -#define EEP_RFSILENT_GPIO_SEL       0x001c
 -#define EEP_RFSILENT_GPIO_SEL_S     2
 -
 -#define AR5416_EEP_NO_BACK_VER       0x1
 -#define AR5416_EEP_VER               0xE
 -#define AR5416_EEP_VER_MINOR_MASK    0x0FFF
 -#define AR5416_EEP_MINOR_VER_2       0x2
 -#define AR5416_EEP_MINOR_VER_3       0x3
 -#define AR5416_EEP_MINOR_VER_7       0x7
 -#define AR5416_EEP_MINOR_VER_9       0x9
 -#define AR5416_EEP_MINOR_VER_16      0x10
 -#define AR5416_EEP_MINOR_VER_17      0x11
 -#define AR5416_EEP_MINOR_VER_19      0x13
 -
 -#define AR5416_NUM_5G_CAL_PIERS         8
 -#define AR5416_NUM_2G_CAL_PIERS         4
 -#define AR5416_NUM_5G_20_TARGET_POWERS  8
 -#define AR5416_NUM_5G_40_TARGET_POWERS  8
 -#define AR5416_NUM_2G_CCK_TARGET_POWERS 3
 -#define AR5416_NUM_2G_20_TARGET_POWERS  4
 -#define AR5416_NUM_2G_40_TARGET_POWERS  4
 -#define AR5416_NUM_CTLS                 24
 -#define AR5416_NUM_BAND_EDGES           8
 -#define AR5416_NUM_PD_GAINS             4
 -#define AR5416_PD_GAINS_IN_MASK         4
 -#define AR5416_PD_GAIN_ICEPTS           5
 -#define AR5416_EEPROM_MODAL_SPURS       5
 -#define AR5416_MAX_RATE_POWER           63
 -#define AR5416_NUM_PDADC_VALUES         128
 -#define AR5416_BCHAN_UNUSED             0xFF
 -#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64
 -#define AR5416_MAX_CHAINS               3
 -#define AR5416_PWR_TABLE_OFFSET         -5
 -
 -/* Rx gain type values */
 -#define AR5416_EEP_RXGAIN_23DB_BACKOFF     0
 -#define AR5416_EEP_RXGAIN_13DB_BACKOFF     1
 -#define AR5416_EEP_RXGAIN_ORIG             2
 -
 -/* Tx gain type values */
 -#define AR5416_EEP_TXGAIN_ORIGINAL         0
 -#define AR5416_EEP_TXGAIN_HIGH_POWER       1
 -
 -#define AR5416_EEP4K_START_LOC         64
 -#define AR5416_EEP4K_NUM_2G_CAL_PIERS      3
 -#define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3
 -#define AR5416_EEP4K_NUM_2G_20_TARGET_POWERS  3
 -#define AR5416_EEP4K_NUM_2G_40_TARGET_POWERS  3
 -#define AR5416_EEP4K_NUM_CTLS              12
 -#define AR5416_EEP4K_NUM_BAND_EDGES        4
 -#define AR5416_EEP4K_NUM_PD_GAINS          2
 -#define AR5416_EEP4K_PD_GAINS_IN_MASK      4
 -#define AR5416_EEP4K_PD_GAIN_ICEPTS        5
 -#define AR5416_EEP4K_MAX_CHAINS            1
 -
 -enum eeprom_param {
 -      EEP_NFTHRESH_5,
 -      EEP_NFTHRESH_2,
 -      EEP_MAC_MSW,
 -      EEP_MAC_MID,
 -      EEP_MAC_LSW,
 -      EEP_REG_0,
 -      EEP_REG_1,
 -      EEP_OP_CAP,
 -      EEP_OP_MODE,
 -      EEP_RF_SILENT,
 -      EEP_OB_5,
 -      EEP_DB_5,
 -      EEP_OB_2,
 -      EEP_DB_2,
 -      EEP_MINOR_REV,
 -      EEP_TX_MASK,
 -      EEP_RX_MASK,
 -      EEP_RXGAIN_TYPE,
 -      EEP_TXGAIN_TYPE,
 +enum ath9k_capability_type {
 +      ATH9K_CAP_CIPHER = 0,
 +      ATH9K_CAP_TKIP_MIC,
 +      ATH9K_CAP_TKIP_SPLIT,
 +      ATH9K_CAP_DIVERSITY,
 +      ATH9K_CAP_TXPOW,
 +      ATH9K_CAP_MCAST_KEYSRCH,
 +      ATH9K_CAP_DS
  };
  
 -enum ar5416_rates {
 -      rate6mb, rate9mb, rate12mb, rate18mb,
 -      rate24mb, rate36mb, rate48mb, rate54mb,
 -      rate1l, rate2l, rate2s, rate5_5l,
 -      rate5_5s, rate11l, rate11s, rateXr,
 -      rateHt20_0, rateHt20_1, rateHt20_2, rateHt20_3,
 -      rateHt20_4, rateHt20_5, rateHt20_6, rateHt20_7,
 -      rateHt40_0, rateHt40_1, rateHt40_2, rateHt40_3,
 -      rateHt40_4, rateHt40_5, rateHt40_6, rateHt40_7,
 -      rateDupCck, rateDupOfdm, rateExtCck, rateExtOfdm,
 -      Ar5416RateSize
 +struct ath9k_hw_capabilities {
 +      u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */
 +      DECLARE_BITMAP(wireless_modes, ATH9K_MODE_MAX); /* ATH9K_MODE_* */
 +      u16 total_queues;
 +      u16 keycache_size;
 +      u16 low_5ghz_chan, high_5ghz_chan;
 +      u16 low_2ghz_chan, high_2ghz_chan;
 +      u16 num_mr_retries;
 +      u16 rts_aggr_limit;
 +      u8 tx_chainmask;
 +      u8 rx_chainmask;
 +      u16 tx_triglevel_max;
 +      u16 reg_cap;
 +      u8 num_gpio_pins;
 +      u8 num_antcfg_2ghz;
 +      u8 num_antcfg_5ghz;
  };
  
 -enum ath9k_hal_freq_band {
 -      ATH9K_HAL_FREQ_BAND_5GHZ = 0,
 -      ATH9K_HAL_FREQ_BAND_2GHZ = 1
 +struct ath9k_ops_config {
 +      int dma_beacon_response_time;
 +      int sw_beacon_response_time;
 +      int additional_swba_backoff;
 +      int ack_6mb;
 +      int cwm_ignore_extcca;
 +      u8 pcie_powersave_enable;
 +      u8 pcie_l1skp_enable;
 +      u8 pcie_clock_req;
 +      u32 pcie_waen;
 +      int pcie_power_reset;
 +      u8 pcie_restore;
 +      u8 analog_shiftreg;
 +      u8 ht_enable;
 +      u32 ofdm_trig_low;
 +      u32 ofdm_trig_high;
 +      u32 cck_trig_high;
 +      u32 cck_trig_low;
 +      u32 enable_ani;
 +      u8 noise_immunity_level;
 +      u32 ofdm_weaksignal_det;
 +      u32 cck_weaksignal_thr;
 +      u8 spur_immunity_level;
 +      u8 firstep_level;
 +      int8_t rssi_thr_high;
 +      int8_t rssi_thr_low;
 +      u16 diversity_control;
 +      u16 antenna_switch_swap;
 +      int serialize_regmode;
 +      int intr_mitigation;
 +#define SPUR_DISABLE          0
 +#define SPUR_ENABLE_IOCTL     1
 +#define SPUR_ENABLE_EEPROM    2
 +#define AR_EEPROM_MODAL_SPURS   5
 +#define AR_SPUR_5413_1        1640
 +#define AR_SPUR_5413_2        1200
 +#define AR_NO_SPUR            0x8000
 +#define AR_BASE_FREQ_2GHZ     2300
 +#define AR_BASE_FREQ_5GHZ     4900
 +#define AR_SPUR_FEEQ_BOUND_HT40 19
 +#define AR_SPUR_FEEQ_BOUND_HT20 10
 +      int spurmode;
 +      u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
  };
  
 -struct base_eep_header {
 -      u16 length;
 -      u16 checksum;
 -      u16 version;
 -      u8 opCapFlags;
 -      u8 eepMisc;
 -      u16 regDmn[2];
 -      u8 macAddr[6];
 -      u8 rxMask;
 -      u8 txMask;
 -      u16 rfSilent;
 -      u16 blueToothOptions;
 -      u16 deviceCap;
 -      u32 binBuildNumber;
 -      u8 deviceType;
 -      u8 pwdclkind;
 -      u8 futureBase_1[2];
 -      u8 rxGainType;
 -      u8 futureBase_2[3];
 -      u8 txGainType;
 -      u8 futureBase_3[25];
 -} __packed;
 -
 -struct base_eep_header_4k {
 -      u16 length;
 -      u16 checksum;
 -      u16 version;
 -      u8 opCapFlags;
 -      u8 eepMisc;
 -      u16 regDmn[2];
 -      u8 macAddr[6];
 -      u8 rxMask;
 -      u8 txMask;
 -      u16 rfSilent;
 -      u16 blueToothOptions;
 -      u16 deviceCap;
 -      u32 binBuildNumber;
 -      u8 deviceType;
 -      u8 futureBase[1];
 -} __packed;
 -
 -
 -struct spur_chan {
 -      u16 spurChan;
 -      u8 spurRangeLow;
 -      u8 spurRangeHigh;
 -} __packed;
 -
 -struct modal_eep_header {
 -      u32 antCtrlChain[AR5416_MAX_CHAINS];
 -      u32 antCtrlCommon;
 -      u8 antennaGainCh[AR5416_MAX_CHAINS];
 -      u8 switchSettling;
 -      u8 txRxAttenCh[AR5416_MAX_CHAINS];
 -      u8 rxTxMarginCh[AR5416_MAX_CHAINS];
 -      u8 adcDesiredSize;
 -      u8 pgaDesiredSize;
 -      u8 xlnaGainCh[AR5416_MAX_CHAINS];
 -      u8 txEndToXpaOff;
 -      u8 txEndToRxOn;
 -      u8 txFrameToXpaOn;
 -      u8 thresh62;
 -      u8 noiseFloorThreshCh[AR5416_MAX_CHAINS];
 -      u8 xpdGain;
 -      u8 xpd;
 -      u8 iqCalICh[AR5416_MAX_CHAINS];
 -      u8 iqCalQCh[AR5416_MAX_CHAINS];
 -      u8 pdGainOverlap;
 -      u8 ob;
 -      u8 db;
 -      u8 xpaBiasLvl;
 -      u8 pwrDecreaseFor2Chain;
 -      u8 pwrDecreaseFor3Chain;
 -      u8 txFrameToDataStart;
 -      u8 txFrameToPaOn;
 -      u8 ht40PowerIncForPdadc;
 -      u8 bswAtten[AR5416_MAX_CHAINS];
 -      u8 bswMargin[AR5416_MAX_CHAINS];
 -      u8 swSettleHt40;
 -      u8 xatten2Db[AR5416_MAX_CHAINS];
 -      u8 xatten2Margin[AR5416_MAX_CHAINS];
 -      u8 ob_ch1;
 -      u8 db_ch1;
 -      u8 useAnt1:1,
 -          force_xpaon:1,
 -          local_bias:1,
 -          femBandSelectUsed:1, xlnabufin:1, xlnaisel:2, xlnabufmode:1;
 -      u8 futureModalar9280;
 -      u16 xpaBiasLvlFreq[3];
 -      u8 futureModal[6];
 -
 -      struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
 -} __packed;
 -
 -struct modal_eep_4k_header {
 -    u32  antCtrlChain[AR5416_EEP4K_MAX_CHAINS];
 -    u32  antCtrlCommon;
 -    u8   antennaGainCh[AR5416_EEP4K_MAX_CHAINS];
 -    u8   switchSettling;
 -    u8   txRxAttenCh[AR5416_EEP4K_MAX_CHAINS];
 -    u8   rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS];
 -    u8   adcDesiredSize;
 -    u8   pgaDesiredSize;
 -    u8   xlnaGainCh[AR5416_EEP4K_MAX_CHAINS];
 -    u8   txEndToXpaOff;
 -    u8   txEndToRxOn;
 -    u8   txFrameToXpaOn;
 -    u8   thresh62;
 -    u8   noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS];
 -    u8   xpdGain;
 -    u8   xpd;
 -    u8   iqCalICh[AR5416_EEP4K_MAX_CHAINS];
 -    u8   iqCalQCh[AR5416_EEP4K_MAX_CHAINS];
 -    u8   pdGainOverlap;
 -    u8   ob_01;
 -    u8   db1_01;
 -    u8   xpaBiasLvl;
 -    u8   txFrameToDataStart;
 -    u8   txFrameToPaOn;
 -    u8   ht40PowerIncForPdadc;
 -    u8   bswAtten[AR5416_EEP4K_MAX_CHAINS];
 -    u8   bswMargin[AR5416_EEP4K_MAX_CHAINS];
 -    u8   swSettleHt40;
 -    u8   xatten2Db[AR5416_EEP4K_MAX_CHAINS];
 -    u8   xatten2Margin[AR5416_EEP4K_MAX_CHAINS];
 -    u8   db2_01;
 -    u8   version;
 -    u16  ob_234;
 -    u16  db1_234;
 -    u16  db2_234;
 -    u8   futureModal[4];
 -
 -    struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
 -} __packed;
 -
 -
 -struct cal_data_per_freq {
 -      u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
 -      u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
 -} __packed;
 -
 -struct cal_data_per_freq_4k {
 -      u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS];
 -      u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS];
 -} __packed;
 -
 -struct cal_target_power_leg {
 -      u8 bChannel;
 -      u8 tPow2x[4];
 -} __packed;
 -
 -struct cal_target_power_ht {
 -      u8 bChannel;
 -      u8 tPow2x[8];
 -} __packed;
 -
 -
 -#ifdef __BIG_ENDIAN_BITFIELD
 -struct cal_ctl_edges {
 -      u8 bChannel;
 -      u8 flag:2, tPower:6;
 -} __packed;
 -#else
 -struct cal_ctl_edges {
 -      u8 bChannel;
 -      u8 tPower:6, flag:2;
 -} __packed;
 -#endif
 -
 -struct cal_ctl_data {
 -      struct cal_ctl_edges
 -      ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
 -} __packed;
 -
 -struct cal_ctl_data_4k {
 -      struct cal_ctl_edges
 -      ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES];
 -} __packed;
 -
 -struct ar5416_eeprom_def {
 -      struct base_eep_header baseEepHeader;
 -      u8 custData[64];
 -      struct modal_eep_header modalHeader[2];
 -      u8 calFreqPier5G[AR5416_NUM_5G_CAL_PIERS];
 -      u8 calFreqPier2G[AR5416_NUM_2G_CAL_PIERS];
 -      struct cal_data_per_freq
 -       calPierData5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS];
 -      struct cal_data_per_freq
 -       calPierData2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS];
 -      struct cal_target_power_leg
 -       calTargetPower5G[AR5416_NUM_5G_20_TARGET_POWERS];
 -      struct cal_target_power_ht
 -       calTargetPower5GHT20[AR5416_NUM_5G_20_TARGET_POWERS];
 -      struct cal_target_power_ht
 -       calTargetPower5GHT40[AR5416_NUM_5G_40_TARGET_POWERS];
 -      struct cal_target_power_leg
 -       calTargetPowerCck[AR5416_NUM_2G_CCK_TARGET_POWERS];
 -      struct cal_target_power_leg
 -       calTargetPower2G[AR5416_NUM_2G_20_TARGET_POWERS];
 -      struct cal_target_power_ht
 -       calTargetPower2GHT20[AR5416_NUM_2G_20_TARGET_POWERS];
 -      struct cal_target_power_ht
 -       calTargetPower2GHT40[AR5416_NUM_2G_40_TARGET_POWERS];
 -      u8 ctlIndex[AR5416_NUM_CTLS];
 -      struct cal_ctl_data ctlData[AR5416_NUM_CTLS];
 -      u8 padding;
 -} __packed;
 -
 -struct ar5416_eeprom_4k {
 -      struct base_eep_header_4k baseEepHeader;
 -      u8 custData[20];
 -      struct modal_eep_4k_header modalHeader;
 -      u8 calFreqPier2G[AR5416_EEP4K_NUM_2G_CAL_PIERS];
 -      struct cal_data_per_freq_4k
 -      calPierData2G[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_2G_CAL_PIERS];
 -      struct cal_target_power_leg
 -      calTargetPowerCck[AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS];
 -      struct cal_target_power_leg
 -      calTargetPower2G[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS];
 -      struct cal_target_power_ht
 -      calTargetPower2GHT20[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS];
 -      struct cal_target_power_ht
 -      calTargetPower2GHT40[AR5416_EEP4K_NUM_2G_40_TARGET_POWERS];
 -      u8 ctlIndex[AR5416_EEP4K_NUM_CTLS];
 -      struct cal_ctl_data_4k ctlData[AR5416_EEP4K_NUM_CTLS];
 -      u8 padding;
 -} __packed;
 -
 -struct ar5416IniArray {
 -      u32 *ia_array;
 -      u32 ia_rows;
 -      u32 ia_columns;
 +enum ath9k_int {
 +      ATH9K_INT_RX = 0x00000001,
 +      ATH9K_INT_RXDESC = 0x00000002,
 +      ATH9K_INT_RXNOFRM = 0x00000008,
 +      ATH9K_INT_RXEOL = 0x00000010,
 +      ATH9K_INT_RXORN = 0x00000020,
 +      ATH9K_INT_TX = 0x00000040,
 +      ATH9K_INT_TXDESC = 0x00000080,
 +      ATH9K_INT_TIM_TIMER = 0x00000100,
 +      ATH9K_INT_TXURN = 0x00000800,
 +      ATH9K_INT_MIB = 0x00001000,
 +      ATH9K_INT_RXPHY = 0x00004000,
 +      ATH9K_INT_RXKCM = 0x00008000,
 +      ATH9K_INT_SWBA = 0x00010000,
 +      ATH9K_INT_BMISS = 0x00040000,
 +      ATH9K_INT_BNR = 0x00100000,
 +      ATH9K_INT_TIM = 0x00200000,
 +      ATH9K_INT_DTIM = 0x00400000,
 +      ATH9K_INT_DTIMSYNC = 0x00800000,
 +      ATH9K_INT_GPIO = 0x01000000,
 +      ATH9K_INT_CABEND = 0x02000000,
 +      ATH9K_INT_TSFOOR = 0x04000000,
 +      ATH9K_INT_CST = 0x10000000,
 +      ATH9K_INT_GTT = 0x20000000,
 +      ATH9K_INT_FATAL = 0x40000000,
 +      ATH9K_INT_GLOBAL = 0x80000000,
 +      ATH9K_INT_BMISC = ATH9K_INT_TIM |
 +              ATH9K_INT_DTIM |
 +              ATH9K_INT_DTIMSYNC |
 +              ATH9K_INT_TSFOOR |
 +              ATH9K_INT_CABEND,
 +      ATH9K_INT_COMMON = ATH9K_INT_RXNOFRM |
 +              ATH9K_INT_RXDESC |
 +              ATH9K_INT_RXEOL |
 +              ATH9K_INT_RXORN |
 +              ATH9K_INT_TXURN |
 +              ATH9K_INT_TXDESC |
 +              ATH9K_INT_MIB |
 +              ATH9K_INT_RXPHY |
 +              ATH9K_INT_RXKCM |
 +              ATH9K_INT_SWBA |
 +              ATH9K_INT_BMISS |
 +              ATH9K_INT_GPIO,
 +      ATH9K_INT_NOCARD = 0xffffffff
  };
  
 -#define INIT_INI_ARRAY(iniarray, array, rows, columns) do {   \
 -              (iniarray)->ia_array = (u32 *)(array);          \
 -              (iniarray)->ia_rows = (rows);                   \
 -              (iniarray)->ia_columns = (columns);             \
 -      } while (0)
 -
 -#define INI_RA(iniarray, row, column) \
 -      (((iniarray)->ia_array)[(row) * ((iniarray)->ia_columns) + (column)])
 +#define CHANNEL_CW_INT    0x00002
 +#define CHANNEL_CCK       0x00020
 +#define CHANNEL_OFDM      0x00040
 +#define CHANNEL_2GHZ      0x00080
 +#define CHANNEL_5GHZ      0x00100
 +#define CHANNEL_PASSIVE   0x00200
 +#define CHANNEL_DYN       0x00400
 +#define CHANNEL_HALF      0x04000
 +#define CHANNEL_QUARTER   0x08000
 +#define CHANNEL_HT20      0x10000
 +#define CHANNEL_HT40PLUS  0x20000
 +#define CHANNEL_HT40MINUS 0x40000
 +
 +#define CHANNEL_INTERFERENCE    0x01
 +#define CHANNEL_DFS             0x02
 +#define CHANNEL_4MS_LIMIT       0x04
 +#define CHANNEL_DFS_CLEAR       0x08
 +#define CHANNEL_DISALLOW_ADHOC  0x10
 +#define CHANNEL_PER_11D_ADHOC   0x20
 +
 +#define CHANNEL_A           (CHANNEL_5GHZ|CHANNEL_OFDM)
 +#define CHANNEL_B           (CHANNEL_2GHZ|CHANNEL_CCK)
 +#define CHANNEL_G           (CHANNEL_2GHZ|CHANNEL_OFDM)
 +#define CHANNEL_G_HT20      (CHANNEL_2GHZ|CHANNEL_HT20)
 +#define CHANNEL_A_HT20      (CHANNEL_5GHZ|CHANNEL_HT20)
 +#define CHANNEL_G_HT40PLUS  (CHANNEL_2GHZ|CHANNEL_HT40PLUS)
 +#define CHANNEL_G_HT40MINUS (CHANNEL_2GHZ|CHANNEL_HT40MINUS)
 +#define CHANNEL_A_HT40PLUS  (CHANNEL_5GHZ|CHANNEL_HT40PLUS)
 +#define CHANNEL_A_HT40MINUS (CHANNEL_5GHZ|CHANNEL_HT40MINUS)
 +#define CHANNEL_ALL                           \
 +      (CHANNEL_OFDM|                          \
 +       CHANNEL_CCK|                           \
 +       CHANNEL_2GHZ |                         \
 +       CHANNEL_5GHZ |                         \
 +       CHANNEL_HT20 |                         \
 +       CHANNEL_HT40PLUS |                     \
 +       CHANNEL_HT40MINUS)
 +
 +struct ath9k_channel {
 +      struct ieee80211_channel *chan;
 +      u16 channel;
 +      u32 channelFlags;
 +      u32 chanmode;
 +      int32_t CalValid;
 +      bool oneTimeCalsDone;
 +      int8_t iCoff;
 +      int8_t qCoff;
 +      int16_t rawNoiseFloor;
 +};
  
 -#define INIT_CAL(_perCal) do {                                \
 -              (_perCal)->calState = CAL_WAITING;      \
 -              (_perCal)->calNext = NULL;              \
 -      } while (0)
 +#define IS_CHAN_A(_c) ((((_c)->channelFlags & CHANNEL_A) == CHANNEL_A) || \
 +       (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \
 +       (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \
 +       (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS))
 +#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
 +       (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \
 +       (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \
 +       (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS))
 +#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0)
 +#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0)
 +#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0)
 +#define IS_CHAN_PASSIVE(_c) (((_c)->channelFlags & CHANNEL_PASSIVE) != 0)
 +#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0)
 +#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
 +#define IS_CHAN_A_5MHZ_SPACED(_c)                     \
 +      ((((_c)->channelFlags & CHANNEL_5GHZ) != 0) &&  \
 +       (((_c)->channel % 20) != 0) &&                 \
 +       (((_c)->channel % 10) != 0))
 +
 +/* These macros check chanmode and not channelFlags */
 +#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B)
 +#define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) ||       \
 +                        ((_c)->chanmode == CHANNEL_G_HT20))
 +#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) ||   \
 +                        ((_c)->chanmode == CHANNEL_A_HT40MINUS) ||    \
 +                        ((_c)->chanmode == CHANNEL_G_HT40PLUS) ||     \
 +                        ((_c)->chanmode == CHANNEL_G_HT40MINUS))
 +#define IS_CHAN_HT(_c) (IS_CHAN_HT20((_c)) || IS_CHAN_HT40((_c)))
 +
 +enum ath9k_power_mode {
 +      ATH9K_PM_AWAKE = 0,
 +      ATH9K_PM_FULL_SLEEP,
 +      ATH9K_PM_NETWORK_SLEEP,
 +      ATH9K_PM_UNDEFINED
 +};
  
 -#define INSERT_CAL(_ahp, _perCal)                                     \
 -      do {                                                            \
 -              if ((_ahp)->ah_cal_list_last == NULL) {                 \
 -                      (_ahp)->ah_cal_list =                           \
 -                              (_ahp)->ah_cal_list_last = (_perCal);   \
 -                      ((_ahp)->ah_cal_list_last)->calNext = (_perCal); \
 -              } else {                                                \
 -                      ((_ahp)->ah_cal_list_last)->calNext = (_perCal); \
 -                      (_ahp)->ah_cal_list_last = (_perCal);           \
 -                      (_perCal)->calNext = (_ahp)->ah_cal_list;       \
 -              }                                                       \
 -      } while (0)
 +enum ath9k_ant_setting {
 +      ATH9K_ANT_VARIABLE = 0,
 +      ATH9K_ANT_FIXED_A,
 +      ATH9K_ANT_FIXED_B
 +};
  
 -enum hal_cal_types {
 -      ADC_DC_INIT_CAL = 0x1,
 -      ADC_GAIN_CAL = 0x2,
 -      ADC_DC_CAL = 0x4,
 -      IQ_MISMATCH_CAL = 0x8
 +enum ath9k_tp_scale {
 +      ATH9K_TP_SCALE_MAX = 0,
 +      ATH9K_TP_SCALE_50,
 +      ATH9K_TP_SCALE_25,
 +      ATH9K_TP_SCALE_12,
 +      ATH9K_TP_SCALE_MIN
  };
  
 -enum hal_cal_state {
 -      CAL_INACTIVE,
 -      CAL_WAITING,
 -      CAL_RUNNING,
 -      CAL_DONE
 +enum ser_reg_mode {
 +      SER_REG_MODE_OFF = 0,
 +      SER_REG_MODE_ON = 1,
 +      SER_REG_MODE_AUTO = 2,
  };
  
 -#define MIN_CAL_SAMPLES     1
 -#define MAX_CAL_SAMPLES    64
 -#define INIT_LOG_COUNT      5
 -#define PER_MIN_LOG_COUNT   2
 -#define PER_MAX_LOG_COUNT  10
 +struct ath9k_beacon_state {
 +      u32 bs_nexttbtt;
 +      u32 bs_nextdtim;
 +      u32 bs_intval;
 +#define ATH9K_BEACON_PERIOD       0x0000ffff
 +#define ATH9K_BEACON_ENA          0x00800000
 +#define ATH9K_BEACON_RESET_TSF    0x01000000
 +#define ATH9K_TSFOOR_THRESHOLD    0x00004240 /* 16k us */
 +      u32 bs_dtimperiod;
 +      u16 bs_cfpperiod;
 +      u16 bs_cfpmaxduration;
 +      u32 bs_cfpnext;
 +      u16 bs_timoffset;
 +      u16 bs_bmissthreshold;
 +      u32 bs_sleepduration;
 +      u32 bs_tsfoor_threshold;
 +};
  
 -struct hal_percal_data {
 -      enum hal_cal_types calType;
 -      u32 calNumSamples;
 -      u32 calCountMax;
 -      void (*calCollect) (struct ath_hal *);
 -      void (*calPostProc) (struct ath_hal *, u8);
 +struct chan_centers {
 +      u16 synth_center;
 +      u16 ctl_center;
 +      u16 ext_center;
  };
  
 -struct hal_cal_list {
 -      const struct hal_percal_data *calData;
 -      enum hal_cal_state calState;
 -      struct hal_cal_list *calNext;
 +enum {
 +      ATH9K_RESET_POWER_ON,
 +      ATH9K_RESET_WARM,
 +      ATH9K_RESET_COLD,
  };
  
 -/*
 - * Enum to indentify the eeprom mappings
 - */
 -enum hal_eep_map {
 -      EEP_MAP_DEFAULT = 0x0,
 -      EEP_MAP_4KBITS,
 -      EEP_MAP_MAX
 +struct ath9k_hw_version {
 +      u32 magic;
 +      u16 devid;
 +      u16 subvendorid;
 +      u32 macVersion;
 +      u16 macRev;
 +      u16 phyRev;
 +      u16 analog5GhzRev;
 +      u16 analog2GhzRev;
  };
  
 +struct ath_hw {
 +      struct ath_softc *ah_sc;
 +      struct ath9k_hw_version hw_version;
 +      struct ath9k_ops_config config;
 +      struct ath9k_hw_capabilities caps;
 +      struct ath9k_regulatory regulatory;
 +      struct ath9k_channel channels[38];
 +      struct ath9k_channel *curchan;
  
 -struct ath_hal_5416 {
 -      struct ath_hal ah;
        union {
                struct ar5416_eeprom_def def;
                struct ar5416_eeprom_4k map4k;
 -      } ah_eeprom;
 -      struct ar5416Stats ah_stats;
 -      struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES];
 -      void __iomem *ah_cal_mem;
 -
 -      u8 ah_macaddr[ETH_ALEN];
 -      u8 ah_bssid[ETH_ALEN];
 -      u8 ah_bssidmask[ETH_ALEN];
 -      u16 ah_assocId;
 -
 -      int16_t ah_curchanRadIndex;
 -      u32 ah_maskReg;
 -      u32 ah_txOkInterruptMask;
 -      u32 ah_txErrInterruptMask;
 -      u32 ah_txDescInterruptMask;
 -      u32 ah_txEolInterruptMask;
 -      u32 ah_txUrnInterruptMask;
 -      bool ah_chipFullSleep;
 -      u32 ah_atimWindow;
 -      u16 ah_antennaSwitchSwap;
 -      enum ath9k_power_mode ah_powerMode;
 -      enum ath9k_ant_setting ah_diversityControl;
 +      } eeprom;
 +      const struct eeprom_ops *eep_ops;
 +      enum ath9k_eep_map eep_map;
 +
 +      bool sw_mgmt_crypto;
 +      bool is_pciexpress;
 +      u8 macaddr[ETH_ALEN];
 +      u16 tx_trig_level;
 +      u16 rfsilent;
 +      u32 rfkill_gpio;
 +      u32 rfkill_polarity;
 +      u32 btactive_gpio;
 +      u32 wlanactive_gpio;
 +      u32 ah_flags;
 +
 +      enum nl80211_iftype opmode;
 +      enum ath9k_power_mode power_mode;
 +      enum ath9k_power_mode restore_mode;
 +
 +      struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
 +      struct ar5416Stats stats;
 +      struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
 +
 +      int16_t curchan_rad_index;
 +      u32 mask_reg;
 +      u32 txok_interrupt_mask;
 +      u32 txerr_interrupt_mask;
 +      u32 txdesc_interrupt_mask;
 +      u32 txeol_interrupt_mask;
 +      u32 txurn_interrupt_mask;
 +      bool chip_fullsleep;
 +      u32 atim_window;
 +      u16 antenna_switch_swap;
 +      enum ath9k_ant_setting diversity_control;
  
        /* Calibration */
 -      enum hal_cal_types ah_suppCals;
 -      struct hal_cal_list ah_iqCalData;
 -      struct hal_cal_list ah_adcGainCalData;
 -      struct hal_cal_list ah_adcDcCalInitData;
 -      struct hal_cal_list ah_adcDcCalData;
 -      struct hal_cal_list *ah_cal_list;
 -      struct hal_cal_list *ah_cal_list_last;
 -      struct hal_cal_list *ah_cal_list_curr;
 -#define ah_totalPowerMeasI ah_Meas0.unsign
 -#define ah_totalPowerMeasQ ah_Meas1.unsign
 -#define ah_totalIqCorrMeas ah_Meas2.sign
 -#define ah_totalAdcIOddPhase  ah_Meas0.unsign
 -#define ah_totalAdcIEvenPhase ah_Meas1.unsign
 -#define ah_totalAdcQOddPhase  ah_Meas2.unsign
 -#define ah_totalAdcQEvenPhase ah_Meas3.unsign
 -#define ah_totalAdcDcOffsetIOddPhase  ah_Meas0.sign
 -#define ah_totalAdcDcOffsetIEvenPhase ah_Meas1.sign
 -#define ah_totalAdcDcOffsetQOddPhase  ah_Meas2.sign
 -#define ah_totalAdcDcOffsetQEvenPhase ah_Meas3.sign
 +      enum hal_cal_types supp_cals;
 +      struct hal_cal_list iq_caldata;
 +      struct hal_cal_list adcgain_caldata;
 +      struct hal_cal_list adcdc_calinitdata;
 +      struct hal_cal_list adcdc_caldata;
 +      struct hal_cal_list *cal_list;
 +      struct hal_cal_list *cal_list_last;
 +      struct hal_cal_list *cal_list_curr;
 +#define totalPowerMeasI meas0.unsign
 +#define totalPowerMeasQ meas1.unsign
 +#define totalIqCorrMeas meas2.sign
 +#define totalAdcIOddPhase  meas0.unsign
 +#define totalAdcIEvenPhase meas1.unsign
 +#define totalAdcQOddPhase  meas2.unsign
 +#define totalAdcQEvenPhase meas3.unsign
 +#define totalAdcDcOffsetIOddPhase  meas0.sign
 +#define totalAdcDcOffsetIEvenPhase meas1.sign
 +#define totalAdcDcOffsetQOddPhase  meas2.sign
 +#define totalAdcDcOffsetQEvenPhase meas3.sign
        union {
                u32 unsign[AR5416_MAX_CHAINS];
                int32_t sign[AR5416_MAX_CHAINS];
 -      } ah_Meas0;
 +      } meas0;
        union {
                u32 unsign[AR5416_MAX_CHAINS];
                int32_t sign[AR5416_MAX_CHAINS];
 -      } ah_Meas1;
 +      } meas1;
        union {
                u32 unsign[AR5416_MAX_CHAINS];
                int32_t sign[AR5416_MAX_CHAINS];
 -      } ah_Meas2;
 +      } meas2;
        union {
                u32 unsign[AR5416_MAX_CHAINS];
                int32_t sign[AR5416_MAX_CHAINS];
 -      } ah_Meas3;
 -      u16 ah_CalSamples;
 +      } meas3;
 +      u16 cal_samples;
  
 -      u32 ah_staId1Defaults;
 -      u32 ah_miscMode;
 +      u32 sta_id1_defaults;
 +      u32 misc_mode;
        enum {
                AUTO_32KHZ,
                USE_32KHZ,
                DONT_USE_32KHZ,
 -      } ah_enable32kHzClock;
 +      } enable_32kHz_clock;
  
        /* RF */
 -      u32 *ah_analogBank0Data;
 -      u32 *ah_analogBank1Data;
 -      u32 *ah_analogBank2Data;
 -      u32 *ah_analogBank3Data;
 -      u32 *ah_analogBank6Data;
 -      u32 *ah_analogBank6TPCData;
 -      u32 *ah_analogBank7Data;
 -      u32 *ah_addac5416_21;
 -      u32 *ah_bank6Temp;
 -
 -      int16_t ah_txPowerIndexOffset;
 -      u32 ah_beaconInterval;
 -      u32 ah_slottime;
 -      u32 ah_acktimeout;
 -      u32 ah_ctstimeout;
 -      u32 ah_globaltxtimeout;
 -      u8 ah_gBeaconRate;
 -      u32 ah_gpioSelect;
 -      u32 ah_polarity;
 -      u32 ah_gpioBit;
 +      u32 *analogBank0Data;
 +      u32 *analogBank1Data;
 +      u32 *analogBank2Data;
 +      u32 *analogBank3Data;
 +      u32 *analogBank6Data;
 +      u32 *analogBank6TPCData;
 +      u32 *analogBank7Data;
 +      u32 *addac5416_21;
 +      u32 *bank6Temp;
 +
 +      int16_t txpower_indexoffset;
 +      u32 beacon_interval;
 +      u32 slottime;
 +      u32 acktimeout;
 +      u32 ctstimeout;
 +      u32 globaltxtimeout;
 +      u8 gbeacon_rate;
  
        /* ANI */
 -      u32 ah_procPhyErr;
 -      bool ah_hasHwPhyCounters;
 -      u32 ah_aniPeriod;
 -      struct ar5416AniState *ah_curani;
 -      struct ar5416AniState ah_ani[255];
 -      int ah_totalSizeDesired[5];
 -      int ah_coarseHigh[5];
 -      int ah_coarseLow[5];
 -      int ah_firpwr[5];
 -      enum ath9k_ani_cmd ah_ani_function;
 -
 -      u32 ah_intrTxqs;
 -      bool ah_intrMitigation;
 -      enum ath9k_ht_extprotspacing ah_extprotspacing;
 -      u8 ah_txchainmask;
 -      u8 ah_rxchainmask;
 -
 -      struct ar5416IniArray ah_iniModes;
 -      struct ar5416IniArray ah_iniCommon;
 -      struct ar5416IniArray ah_iniBank0;
 -      struct ar5416IniArray ah_iniBB_RfGain;
 -      struct ar5416IniArray ah_iniBank1;
 -      struct ar5416IniArray ah_iniBank2;
 -      struct ar5416IniArray ah_iniBank3;
 -      struct ar5416IniArray ah_iniBank6;
 -      struct ar5416IniArray ah_iniBank6TPC;
 -      struct ar5416IniArray ah_iniBank7;
 -      struct ar5416IniArray ah_iniAddac;
 -      struct ar5416IniArray ah_iniPcieSerdes;
 -      struct ar5416IniArray ah_iniModesAdditional;
 -      struct ar5416IniArray ah_iniModesRxGain;
 -      struct ar5416IniArray ah_iniModesTxGain;
 -      /* To indicate EEPROM mapping used */
 -      enum hal_eep_map ah_eep_map;
 +      u32 proc_phyerr;
 +      bool has_hw_phycounters;
 +      u32 aniperiod;
 +      struct ar5416AniState *curani;
 +      struct ar5416AniState ani[255];
 +      int totalSizeDesired[5];
 +      int coarse_high[5];
 +      int coarse_low[5];
 +      int firpwr[5];
 +      enum ath9k_ani_cmd ani_function;
 +
 +      u32 intr_txqs;
 +      bool intr_mitigation;
 +      enum ath9k_ht_extprotspacing extprotspacing;
 +      u8 txchainmask;
 +      u8 rxchainmask;
 +
 +      u32 originalGain[22];
 +      int initPDADC;
 +      int PDADCdelta;
 +
 +      struct ar5416IniArray iniModes;
 +      struct ar5416IniArray iniCommon;
 +      struct ar5416IniArray iniBank0;
 +      struct ar5416IniArray iniBB_RfGain;
 +      struct ar5416IniArray iniBank1;
 +      struct ar5416IniArray iniBank2;
 +      struct ar5416IniArray iniBank3;
 +      struct ar5416IniArray iniBank6;
 +      struct ar5416IniArray iniBank6TPC;
 +      struct ar5416IniArray iniBank7;
 +      struct ar5416IniArray iniAddac;
 +      struct ar5416IniArray iniPcieSerdes;
 +      struct ar5416IniArray iniModesAdditional;
 +      struct ar5416IniArray iniModesRxGain;
 +      struct ar5416IniArray iniModesTxGain;
  };
 -#define AH5416(_ah) ((struct ath_hal_5416 *)(_ah))
 -
 -#define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5))
 -
 -#define ar5416RfDetach(ah) do {                                       \
 -              if (AH5416(ah)->ah_rfHal.rfDetach != NULL)      \
 -                      AH5416(ah)->ah_rfHal.rfDetach(ah);      \
 -      } while (0)
 -
 -#define ath9k_hw_use_flash(_ah)                       \
 -      (!(_ah->ah_flags & AH_USE_EEPROM))
 -
 -
 -#define DO_DELAY(x) do {                      \
 -              if ((++(x) % 64) == 0)          \
 -                      udelay(1);              \
 -      } while (0)
 -
 -#define REG_WRITE_ARRAY(iniarray, column, regWr) do {                   \
 -              int r;                                                  \
 -              for (r = 0; r < ((iniarray)->ia_rows); r++) {           \
 -                      REG_WRITE(ah, INI_RA((iniarray), (r), 0),       \
 -                                INI_RA((iniarray), r, (column)));     \
 -                      DO_DELAY(regWr);                                \
 -              }                                                       \
 -      } while (0)
 -
 -#define BASE_ACTIVATE_DELAY         100
 -#define RTC_PLL_SETTLE_DELAY        1000
 -#define COEF_SCALE_S                24
 -#define HT40_CHANNEL_CENTER_SHIFT   10
 -
 -#define AR5416_EEPROM_MAGIC_OFFSET  0x0
 -
 -#define AR5416_EEPROM_S             2
 -#define AR5416_EEPROM_OFFSET        0x2000
 -#define AR5416_EEPROM_START_ADDR \
 -      (AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200
 -#define AR5416_EEPROM_MAX           0xae0
 -#define ar5416_get_eep_ver(_ahp) \
 -      (((_ahp)->ah_eeprom.def.baseEepHeader.version >> 12) & 0xF)
 -#define ar5416_get_eep_rev(_ahp) \
 -      (((_ahp)->ah_eeprom.def.baseEepHeader.version) & 0xFFF)
 -#define ar5416_get_ntxchains(_txchainmask) \
 -      (((_txchainmask >> 2) & 1) + \
 -              ((_txchainmask >> 1) & 1) + (_txchainmask & 1))
  
 -/* EEPROM 4K bit map definations */
 -#define ar5416_get_eep4k_ver(_ahp)   \
 -    (((_ahp)->ah_eeprom.map4k.baseEepHeader.version >> 12) & 0xF)
 -#define ar5416_get_eep4k_rev(_ahp)   \
 -    (((_ahp)->ah_eeprom.map4k.baseEepHeader.version) & 0xFFF)
 -
 -
 -#ifdef __BIG_ENDIAN
 -#define AR5416_EEPROM_MAGIC 0x5aa5
 -#else
 -#define AR5416_EEPROM_MAGIC 0xa55a
 +/* Attach, Detach, Reset */
 +const char *ath9k_hw_probe(u16 vendorid, u16 devid);
 +void ath9k_hw_detach(struct ath_hw *ah);
 +struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error);
 +void ath9k_hw_rfdetach(struct ath_hw *ah);
 +int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 +                 bool bChannelChange);
 +bool ath9k_hw_fill_cap_info(struct ath_hw *ah);
 +bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
 +                          u32 capability, u32 *result);
 +bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
 +                          u32 capability, u32 setting, int *status);
 +
 +/* Key Cache Management */
 +bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry);
 +bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac);
 +bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
 +                               const struct ath9k_keyval *k,
 +                               const u8 *mac);
 +bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry);
 +
 +/* GPIO / RFKILL / Antennae */
 +void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio);
 +u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio);
 +void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
 +                       u32 ah_signal_type);
 +void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
 +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 +void ath9k_enable_rfkill(struct ath_hw *ah);
  #endif
 -
 -#define ATH9K_POW_SM(_r, _s)     (((_r) & 0x3f) << (_s))
 -
 -#define ATH9K_ANTENNA0_CHAINMASK        0x1
 -#define ATH9K_ANTENNA1_CHAINMASK        0x2
 -
 -#define ATH9K_NUM_DMA_DEBUG_REGS        8
 -#define ATH9K_NUM_QUEUES                10
 -
 -#define HAL_NOISE_IMMUNE_MAX            4
 -#define HAL_SPUR_IMMUNE_MAX             7
 -#define HAL_FIRST_STEP_MAX              2
 -
 -#define ATH9K_ANI_OFDM_TRIG_HIGH          500
 -#define ATH9K_ANI_OFDM_TRIG_LOW           200
 -#define ATH9K_ANI_CCK_TRIG_HIGH           200
 -#define ATH9K_ANI_CCK_TRIG_LOW            100
 -#define ATH9K_ANI_NOISE_IMMUNE_LVL        4
 -#define ATH9K_ANI_USE_OFDM_WEAK_SIG       true
 -#define ATH9K_ANI_CCK_WEAK_SIG_THR        false
 -#define ATH9K_ANI_SPUR_IMMUNE_LVL         7
 -#define ATH9K_ANI_FIRSTEP_LVL             0
 -#define ATH9K_ANI_RSSI_THR_HIGH           40
 -#define ATH9K_ANI_RSSI_THR_LOW            7
 -#define ATH9K_ANI_PERIOD                  100
 -
 -#define AR_GPIOD_MASK                   0x00001FFF
 -#define AR_GPIO_BIT(_gpio)              (1 << (_gpio))
 -
 -#define HAL_EP_RND(x, mul) \
 -      ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
 -#define BEACON_RSSI(ahp) \
 -      HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \
 -              ATH9K_RSSI_EP_MULTIPLIER)
 -
 -#define ah_mibStats     ah_stats.ast_mibstats
 -
 -#define AH_TIMEOUT         100000
 -#define AH_TIME_QUANTUM        10
 -
 -#define AR_KEYTABLE_SIZE 128
 -#define POWER_UP_TIME    200000
 -
 -#define EXT_ADDITIVE (0x8000)
 -#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)
 -#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE)
 -#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE)
 -
 -#define SUB_NUM_CTL_MODES_AT_5G_40 2
 -#define SUB_NUM_CTL_MODES_AT_2G_40 3
 -#define SPUR_RSSI_THRESH 40
 -
 -#define TU_TO_USEC(_tu)         ((_tu) << 10)
 -
 -#define CAB_TIMEOUT_VAL         10
 -#define BEACON_TIMEOUT_VAL      10
 -#define MIN_BEACON_TIMEOUT_VAL   1
 -#define SLEEP_SLOP               3
 -
 -#define CCK_SIFS_TIME        10
 -#define CCK_PREAMBLE_BITS   144
 -#define CCK_PLCP_BITS        48
 -
 -#define OFDM_SIFS_TIME        16
 -#define OFDM_PREAMBLE_TIME    20
 -#define OFDM_PLCP_BITS        22
 -#define OFDM_SYMBOL_TIME      4
 -
 -#define OFDM_SIFS_TIME_HALF     32
 -#define OFDM_PREAMBLE_TIME_HALF 40
 -#define OFDM_PLCP_BITS_HALF     22
 -#define OFDM_SYMBOL_TIME_HALF   8
 -
 -#define OFDM_SIFS_TIME_QUARTER      64
 -#define OFDM_PREAMBLE_TIME_QUARTER  80
 -#define OFDM_PLCP_BITS_QUARTER      22
 -#define OFDM_SYMBOL_TIME_QUARTER    16
 -
 -u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
 -                      enum eeprom_param param);
 +u32 ath9k_hw_getdefantenna(struct ath_hw *ah);
 +void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
 +bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
 +                             enum ath9k_ant_setting settings,
 +                             struct ath9k_channel *chan,
 +                             u8 *tx_chainmask, u8 *rx_chainmask,
 +                             u8 *antenna_cfgd);
 +
 +/* General Operation */
 +bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
 +u32 ath9k_hw_reverse_bits(u32 val, u32 n);
 +bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high);
 +u16 ath9k_hw_computetxtime(struct ath_hw *ah, struct ath_rate_table *rates,
 +                         u32 frameLen, u16 rateix, bool shortPreamble);
 +void ath9k_hw_get_channel_centers(struct ath_hw *ah,
 +                                struct ath9k_channel *chan,
 +                                struct chan_centers *centers);
 +u32 ath9k_hw_getrxfilter(struct ath_hw *ah);
 +void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits);
 +bool ath9k_hw_phy_disable(struct ath_hw *ah);
 +bool ath9k_hw_disable(struct ath_hw *ah);
 +bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit);
 +void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac);
 +void ath9k_hw_setopmode(struct ath_hw *ah);
 +void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1);
 +void ath9k_hw_setbssidmask(struct ath_softc *sc);
 +void ath9k_hw_write_associd(struct ath_softc *sc);
 +u64 ath9k_hw_gettsf64(struct ath_hw *ah);
 +void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
 +void ath9k_hw_reset_tsf(struct ath_hw *ah);
 +bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
 +bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
 +void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode);
 +void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
 +void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
 +                                  const struct ath9k_beacon_state *bs);
 +bool ath9k_hw_setpower(struct ath_hw *ah,
 +                     enum ath9k_power_mode mode);
 +void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore);
 +
 +/* Interrupt Handling */
 +bool ath9k_hw_intrpend(struct ath_hw *ah);
 +bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked);
 +enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah);
 +enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints);
 +
 +void ath9k_hw_btcoex_enable(struct ath_hw *ah);
  
  #endif
index f473fee72a2e49666b0011ae714e55c68ac9953c,3c04044a60bdffe5441c610436fafcf3ff9d4646..a9715f5b0af6f05712a9ed0fd88a29db875e7bf2
@@@ -15,7 -15,9 +15,7 @@@
   */
  
  #include <linux/nl80211.h>
 -#include "core.h"
 -#include "reg.h"
 -#include "hw.h"
 +#include "ath9k.h"
  
  #define ATH_PCI_VERSION "0.1"
  
@@@ -26,129 -28,84 +26,129 @@@ MODULE_DESCRIPTION("Support for Athero
  MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
  MODULE_LICENSE("Dual BSD/GPL");
  
 -static struct pci_device_id ath_pci_id_table[] __devinitdata = {
 -      { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI   */
 -      { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */
 -      { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI   */
 -      { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI   */
 -      { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
 -      { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
 -      { 0 }
 +static int modparam_nohwcrypt;
 +module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
 +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
 +
 +/* We use the hw_value as an index into our private channel structure */
 +
 +#define CHAN2G(_freq, _idx)  { \
 +      .center_freq = (_freq), \
 +      .hw_value = (_idx), \
 +      .max_power = 30, \
 +}
 +
 +#define CHAN5G(_freq, _idx) { \
 +      .band = IEEE80211_BAND_5GHZ, \
 +      .center_freq = (_freq), \
 +      .hw_value = (_idx), \
 +      .max_power = 30, \
 +}
 +
 +/* Some 2 GHz radios are actually tunable on 2312-2732
 + * on 5 MHz steps, we support the channels which we know
 + * we have calibration data for all cards though to make
 + * this static */
 +static struct ieee80211_channel ath9k_2ghz_chantable[] = {
 +      CHAN2G(2412, 0), /* Channel 1 */
 +      CHAN2G(2417, 1), /* Channel 2 */
 +      CHAN2G(2422, 2), /* Channel 3 */
 +      CHAN2G(2427, 3), /* Channel 4 */
 +      CHAN2G(2432, 4), /* Channel 5 */
 +      CHAN2G(2437, 5), /* Channel 6 */
 +      CHAN2G(2442, 6), /* Channel 7 */
 +      CHAN2G(2447, 7), /* Channel 8 */
 +      CHAN2G(2452, 8), /* Channel 9 */
 +      CHAN2G(2457, 9), /* Channel 10 */
 +      CHAN2G(2462, 10), /* Channel 11 */
 +      CHAN2G(2467, 11), /* Channel 12 */
 +      CHAN2G(2472, 12), /* Channel 13 */
 +      CHAN2G(2484, 13), /* Channel 14 */
  };
  
 -static void ath_detach(struct ath_softc *sc);
 -
 -/* return bus cachesize in 4B word units */
 -
 -static void bus_read_cachesize(struct ath_softc *sc, int *csz)
 -{
 -      u8 u8tmp;
 -
 -      pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp);
 -      *csz = (int)u8tmp;
 -
 -      /*
 -       * This check was put in to avoid "unplesant" consequences if
 -       * the bootrom has not fully initialized all PCI devices.
 -       * Sometimes the cache line size register is not set
 -       */
 -
 -      if (*csz == 0)
 -              *csz = DEFAULT_CACHELINE >> 2;   /* Use the default size */
 -}
 -
 -static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
 -{
 -      sc->cur_rate_table = sc->hw_rate_table[mode];
 -      /*
 -       * All protection frames are transmited at 2Mb/s for
 -       * 11g, otherwise at 1Mb/s.
 -       * XXX select protection rate index from rate table.
 -       */
 -      sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0);
 -}
 +/* Some 5 GHz radios are actually tunable on XXXX-YYYY
 + * on 5 MHz steps, we support the channels which we know
 + * we have calibration data for all cards though to make
 + * this static */
 +static struct ieee80211_channel ath9k_5ghz_chantable[] = {
 +      /* _We_ call this UNII 1 */
 +      CHAN5G(5180, 14), /* Channel 36 */
 +      CHAN5G(5200, 15), /* Channel 40 */
 +      CHAN5G(5220, 16), /* Channel 44 */
 +      CHAN5G(5240, 17), /* Channel 48 */
 +      /* _We_ call this UNII 2 */
 +      CHAN5G(5260, 18), /* Channel 52 */
 +      CHAN5G(5280, 19), /* Channel 56 */
 +      CHAN5G(5300, 20), /* Channel 60 */
 +      CHAN5G(5320, 21), /* Channel 64 */
 +      /* _We_ call this "Middle band" */
 +      CHAN5G(5500, 22), /* Channel 100 */
 +      CHAN5G(5520, 23), /* Channel 104 */
 +      CHAN5G(5540, 24), /* Channel 108 */
 +      CHAN5G(5560, 25), /* Channel 112 */
 +      CHAN5G(5580, 26), /* Channel 116 */
 +      CHAN5G(5600, 27), /* Channel 120 */
 +      CHAN5G(5620, 28), /* Channel 124 */
 +      CHAN5G(5640, 29), /* Channel 128 */
 +      CHAN5G(5660, 30), /* Channel 132 */
 +      CHAN5G(5680, 31), /* Channel 136 */
 +      CHAN5G(5700, 32), /* Channel 140 */
 +      /* _We_ call this UNII 3 */
 +      CHAN5G(5745, 33), /* Channel 149 */
 +      CHAN5G(5765, 34), /* Channel 153 */
 +      CHAN5G(5785, 35), /* Channel 157 */
 +      CHAN5G(5805, 36), /* Channel 161 */
 +      CHAN5G(5825, 37), /* Channel 165 */
 +};
  
 -static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan)
 +static void ath_cache_conf_rate(struct ath_softc *sc,
 +                              struct ieee80211_conf *conf)
  {
 -      if (chan->chanmode == CHANNEL_A)
 -              return ATH9K_MODE_11A;
 -      else if (chan->chanmode == CHANNEL_G)
 -              return ATH9K_MODE_11G;
 -      else if (chan->chanmode == CHANNEL_B)
 -              return ATH9K_MODE_11B;
 -      else if (chan->chanmode == CHANNEL_A_HT20)
 -              return ATH9K_MODE_11NA_HT20;
 -      else if (chan->chanmode == CHANNEL_G_HT20)
 -              return ATH9K_MODE_11NG_HT20;
 -      else if (chan->chanmode == CHANNEL_A_HT40PLUS)
 -              return ATH9K_MODE_11NA_HT40PLUS;
 -      else if (chan->chanmode == CHANNEL_A_HT40MINUS)
 -              return ATH9K_MODE_11NA_HT40MINUS;
 -      else if (chan->chanmode == CHANNEL_G_HT40PLUS)
 -              return ATH9K_MODE_11NG_HT40PLUS;
 -      else if (chan->chanmode == CHANNEL_G_HT40MINUS)
 -              return ATH9K_MODE_11NG_HT40MINUS;
 -
 -      WARN_ON(1); /* should not get here */
 -
 -      return ATH9K_MODE_11B;
 +      switch (conf->channel->band) {
 +      case IEEE80211_BAND_2GHZ:
 +              if (conf_is_ht20(conf))
 +                      sc->cur_rate_table =
 +                        sc->hw_rate_table[ATH9K_MODE_11NG_HT20];
 +              else if (conf_is_ht40_minus(conf))
 +                      sc->cur_rate_table =
 +                        sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS];
 +              else if (conf_is_ht40_plus(conf))
 +                      sc->cur_rate_table =
 +                        sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS];
 +              else
 +                      sc->cur_rate_table =
 +                        sc->hw_rate_table[ATH9K_MODE_11G];
 +              break;
 +      case IEEE80211_BAND_5GHZ:
 +              if (conf_is_ht20(conf))
 +                      sc->cur_rate_table =
 +                        sc->hw_rate_table[ATH9K_MODE_11NA_HT20];
 +              else if (conf_is_ht40_minus(conf))
 +                      sc->cur_rate_table =
 +                        sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS];
 +              else if (conf_is_ht40_plus(conf))
 +                      sc->cur_rate_table =
 +                        sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS];
 +              else
 +                      sc->cur_rate_table =
 +                        sc->hw_rate_table[ATH9K_MODE_11A];
 +              break;
 +      default:
 +              BUG_ON(1);
 +              break;
 +      }
  }
  
  static void ath_update_txpow(struct ath_softc *sc)
  {
 -      struct ath_hal *ah = sc->sc_ah;
 +      struct ath_hw *ah = sc->sc_ah;
        u32 txpow;
  
 -      if (sc->sc_curtxpow != sc->sc_config.txpowlimit) {
 -              ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit);
 +      if (sc->curtxpow != sc->config.txpowlimit) {
 +              ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit);
                /* read back in case value is clamped */
                ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
 -              sc->sc_curtxpow = txpow;
 +              sc->curtxpow = txpow;
        }
  }
  
@@@ -219,87 -176,150 +219,87 @@@ static void ath_setup_rates(struct ath_
        for (i = 0; i < maxrates; i++) {
                rate[i].bitrate = rate_table->info[i].ratekbps / 100;
                rate[i].hw_value = rate_table->info[i].ratecode;
 +              if (rate_table->info[i].short_preamble) {
 +                      rate[i].hw_value_short = rate_table->info[i].ratecode |
 +                              rate_table->info[i].short_preamble;
 +                      rate[i].flags = IEEE80211_RATE_SHORT_PREAMBLE;
 +              }
                sband->n_bitrates++;
 +
                DPRINTF(sc, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n",
                        rate[i].bitrate / 10, rate[i].hw_value);
        }
  }
  
 -static int ath_setup_channels(struct ath_softc *sc)
 -{
 -      struct ath_hal *ah = sc->sc_ah;
 -      int nchan, i, a = 0, b = 0;
 -      u8 regclassids[ATH_REGCLASSIDS_MAX];
 -      u32 nregclass = 0;
 -      struct ieee80211_supported_band *band_2ghz;
 -      struct ieee80211_supported_band *band_5ghz;
 -      struct ieee80211_channel *chan_2ghz;
 -      struct ieee80211_channel *chan_5ghz;
 -      struct ath9k_channel *c;
 -
 -      /* Fill in ah->ah_channels */
 -      if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan,
 -                                    regclassids, ATH_REGCLASSIDS_MAX,
 -                                    &nregclass, CTRY_DEFAULT, false, 1)) {
 -              u32 rd = ah->ah_currentRD;
 -              DPRINTF(sc, ATH_DBG_FATAL,
 -                      "Unable to collect channel list; "
 -                      "regdomain likely %u country code %u\n",
 -                      rd, CTRY_DEFAULT);
 -              return -EINVAL;
 -      }
 -
 -      band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ];
 -      band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ];
 -      chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ];
 -      chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ];
 -
 -      for (i = 0; i < nchan; i++) {
 -              c = &ah->ah_channels[i];
 -              if (IS_CHAN_2GHZ(c)) {
 -                      chan_2ghz[a].band = IEEE80211_BAND_2GHZ;
 -                      chan_2ghz[a].center_freq = c->channel;
 -                      chan_2ghz[a].max_power = c->maxTxPower;
 -
 -                      if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
 -                              chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS;
 -                      if (c->channelFlags & CHANNEL_PASSIVE)
 -                              chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
 -
 -                      band_2ghz->n_channels = ++a;
 -
 -                      DPRINTF(sc, ATH_DBG_CONFIG, "2MHz channel: %d, "
 -                              "channelFlags: 0x%x\n",
 -                              c->channel, c->channelFlags);
 -              } else if (IS_CHAN_5GHZ(c)) {
 -                      chan_5ghz[b].band = IEEE80211_BAND_5GHZ;
 -                      chan_5ghz[b].center_freq = c->channel;
 -                      chan_5ghz[b].max_power = c->maxTxPower;
 -
 -                      if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
 -                              chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS;
 -                      if (c->channelFlags & CHANNEL_PASSIVE)
 -                              chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
 -
 -                      band_5ghz->n_channels = ++b;
 -
 -                      DPRINTF(sc, ATH_DBG_CONFIG, "5MHz channel: %d, "
 -                              "channelFlags: 0x%x\n",
 -                              c->channel, c->channelFlags);
 -              }
 -      }
 -
 -      return 0;
 -}
 -
  /*
   * Set/change channels.  If the channel is really being changed, it's done
   * by reseting the chip.  To accomplish this we must first cleanup any pending
   * DMA, then restart stuff.
  */
 -static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan)
 +int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 +                  struct ath9k_channel *hchan)
  {
 -      struct ath_hal *ah = sc->sc_ah;
 +      struct ath_hw *ah = sc->sc_ah;
        bool fastcc = true, stopped;
 +      struct ieee80211_channel *channel = hw->conf.channel;
 +      int r;
  
        if (sc->sc_flags & SC_OP_INVALID)
                return -EIO;
  
 -      if (hchan->channel != sc->sc_ah->ah_curchan->channel ||
 -          hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags ||
 -          (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) ||
 -          (sc->sc_flags & SC_OP_FULL_RESET)) {
 -              int status;
 -              /*
 -               * This is only performed if the channel settings have
 -               * actually changed.
 -               *
 -               * To switch channels clear any pending DMA operations;
 -               * wait long enough for the RX fifo to drain, reset the
 -               * hardware at the new frequency, and then re-enable
 -               * the relevant bits of the h/w.
 -               */
 -              ath9k_hw_set_interrupts(ah, 0);
 -              ath_draintxq(sc, false);
 -              stopped = ath_stoprecv(sc);
 -
 -              /* XXX: do not flush receive queue here. We don't want
 -               * to flush data frames already in queue because of
 -               * changing channel. */
 -
 -              if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET))
 -                      fastcc = false;
 -
 -              DPRINTF(sc, ATH_DBG_CONFIG,
 -                      "(%u MHz) -> (%u MHz), cflags:%x, chanwidth: %d\n",
 -                      sc->sc_ah->ah_curchan->channel,
 -                      hchan->channel, hchan->channelFlags, sc->tx_chan_width);
 -
 -              spin_lock_bh(&sc->sc_resetlock);
 -              if (!ath9k_hw_reset(ah, hchan, sc->tx_chan_width,
 -                                  sc->sc_tx_chainmask, sc->sc_rx_chainmask,
 -                                  sc->sc_ht_extprotspacing, fastcc, &status)) {
 -                      DPRINTF(sc, ATH_DBG_FATAL,
 -                              "Unable to reset channel %u (%uMhz) "
 -                              "flags 0x%x hal status %u\n",
 -                              ath9k_hw_mhz2ieee(ah, hchan->channel,
 -                                                hchan->channelFlags),
 -                              hchan->channel, hchan->channelFlags, status);
 -                      spin_unlock_bh(&sc->sc_resetlock);
 -                      return -EIO;
 -              }
 -              spin_unlock_bh(&sc->sc_resetlock);
 +      ath9k_ps_wakeup(sc);
  
 -              sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE;
 -              sc->sc_flags &= ~SC_OP_FULL_RESET;
 +      /*
 +       * This is only performed if the channel settings have
 +       * actually changed.
 +       *
 +       * To switch channels clear any pending DMA operations;
 +       * wait long enough for the RX fifo to drain, reset the
 +       * hardware at the new frequency, and then re-enable
 +       * the relevant bits of the h/w.
 +       */
 +      ath9k_hw_set_interrupts(ah, 0);
 +      ath_drain_all_txq(sc, false);
 +      stopped = ath_stoprecv(sc);
  
 -              if (ath_startrecv(sc) != 0) {
 -                      DPRINTF(sc, ATH_DBG_FATAL,
 -                              "Unable to restart recv logic\n");
 -                      return -EIO;
 -              }
 +      /* XXX: do not flush receive queue here. We don't want
 +       * to flush data frames already in queue because of
 +       * changing channel. */
 +
 +      if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET))
 +              fastcc = false;
 +
 +      DPRINTF(sc, ATH_DBG_CONFIG,
 +              "(%u MHz) -> (%u MHz), chanwidth: %d\n",
 +              sc->sc_ah->curchan->channel,
 +              channel->center_freq, sc->tx_chan_width);
  
 -              ath_setcurmode(sc, ath_chan2mode(hchan));
 -              ath_update_txpow(sc);
 -              ath9k_hw_set_interrupts(ah, sc->sc_imask);
 +      spin_lock_bh(&sc->sc_resetlock);
 +
 +      r = ath9k_hw_reset(ah, hchan, fastcc);
 +      if (r) {
 +              DPRINTF(sc, ATH_DBG_FATAL,
 +                      "Unable to reset channel (%u Mhz) "
 +                      "reset status %u\n",
 +                      channel->center_freq, r);
 +              spin_unlock_bh(&sc->sc_resetlock);
 +              return r;
        }
 +      spin_unlock_bh(&sc->sc_resetlock);
 +
 +      sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE;
 +      sc->sc_flags &= ~SC_OP_FULL_RESET;
 +
 +      if (ath_startrecv(sc) != 0) {
 +              DPRINTF(sc, ATH_DBG_FATAL,
 +                      "Unable to restart recv logic\n");
 +              return -EIO;
 +      }
 +
 +      ath_cache_conf_rate(sc, &hw->conf);
 +      ath_update_txpow(sc);
 +      ath9k_hw_set_interrupts(ah, sc->imask);
 +      ath9k_ps_restore(sc);
        return 0;
  }
  
   */
  static void ath_ani_calibrate(unsigned long data)
  {
 -      struct ath_softc *sc;
 -      struct ath_hal *ah;
 +      struct ath_softc *sc = (struct ath_softc *)data;
 +      struct ath_hw *ah = sc->sc_ah;
        bool longcal = false;
        bool shortcal = false;
        bool aniflag = false;
        unsigned int timestamp = jiffies_to_msecs(jiffies);
 -      u32 cal_interval;
 +      u32 cal_interval, short_cal_interval;
  
 -      sc = (struct ath_softc *)data;
 -      ah = sc->sc_ah;
 +      short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
 +              ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
  
        /*
        * don't calibrate when we're scanning.
        * we are most likely not on our home channel.
        */
 -      if (sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC)
 -              return;
 +      if (sc->sc_flags & SC_OP_SCANNING)
 +              goto set_timer;
  
        /* Long calibration runs independently of short calibration. */
 -      if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) {
 +      if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
                longcal = true;
                DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
 -              sc->sc_ani.sc_longcal_timer = timestamp;
 +              sc->ani.longcal_timer = timestamp;
        }
  
 -      /* Short calibration applies only while sc_caldone is false */
 -      if (!sc->sc_ani.sc_caldone) {
 -              if ((timestamp - sc->sc_ani.sc_shortcal_timer) >=
 -                  ATH_SHORT_CALINTERVAL) {
 +      /* Short calibration applies only while caldone is false */
 +      if (!sc->ani.caldone) {
 +              if ((timestamp - sc->ani.shortcal_timer) >= short_cal_interval) {
                        shortcal = true;
                        DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies);
 -                      sc->sc_ani.sc_shortcal_timer = timestamp;
 -                      sc->sc_ani.sc_resetcal_timer = timestamp;
 +                      sc->ani.shortcal_timer = timestamp;
 +                      sc->ani.resetcal_timer = timestamp;
                }
        } else {
 -              if ((timestamp - sc->sc_ani.sc_resetcal_timer) >=
 +              if ((timestamp - sc->ani.resetcal_timer) >=
                    ATH_RESTART_CALINTERVAL) {
 -                      ath9k_hw_reset_calvalid(ah, ah->ah_curchan,
 -                                              &sc->sc_ani.sc_caldone);
 -                      if (sc->sc_ani.sc_caldone)
 -                              sc->sc_ani.sc_resetcal_timer = timestamp;
 +                      sc->ani.caldone = ath9k_hw_reset_calvalid(ah);
 +                      if (sc->ani.caldone)
 +                              sc->ani.resetcal_timer = timestamp;
                }
        }
  
        /* Verify whether we must check ANI */
 -      if ((timestamp - sc->sc_ani.sc_checkani_timer) >=
 -         ATH_ANI_POLLINTERVAL) {
 +      if ((timestamp - sc->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
                aniflag = true;
 -              sc->sc_ani.sc_checkani_timer = timestamp;
 +              sc->ani.checkani_timer = timestamp;
        }
  
        /* Skip all processing if there's nothing to do. */
        if (longcal || shortcal || aniflag) {
                /* Call ANI routine if necessary */
                if (aniflag)
 -                      ath9k_hw_ani_monitor(ah, &sc->sc_halstats,
 -                                           ah->ah_curchan);
 +                      ath9k_hw_ani_monitor(ah, &sc->nodestats, ah->curchan);
  
                /* Perform calibration if necessary */
                if (longcal || shortcal) {
                        bool iscaldone = false;
  
 -                      if (ath9k_hw_calibrate(ah, ah->ah_curchan,
 -                                             sc->sc_rx_chainmask, longcal,
 +                      if (ath9k_hw_calibrate(ah, ah->curchan,
 +                                             sc->rx_chainmask, longcal,
                                               &iscaldone)) {
                                if (longcal)
 -                                      sc->sc_ani.sc_noise_floor =
 +                                      sc->ani.noise_floor =
                                                ath9k_hw_getchan_noise(ah,
 -                                                             ah->ah_curchan);
 +                                                             ah->curchan);
  
                                DPRINTF(sc, ATH_DBG_ANI,
                                        "calibrate chan %u/%x nf: %d\n",
 -                                      ah->ah_curchan->channel,
 -                                      ah->ah_curchan->channelFlags,
 -                                      sc->sc_ani.sc_noise_floor);
 +                                      ah->curchan->channel,
 +                                      ah->curchan->channelFlags,
 +                                      sc->ani.noise_floor);
                        } else {
                                DPRINTF(sc, ATH_DBG_ANY,
                                        "calibrate chan %u/%x failed\n",
 -                                      ah->ah_curchan->channel,
 -                                      ah->ah_curchan->channelFlags);
 +                                      ah->curchan->channel,
 +                                      ah->curchan->channelFlags);
                        }
 -                      sc->sc_ani.sc_caldone = iscaldone;
 +                      sc->ani.caldone = iscaldone;
                }
        }
  
 +set_timer:
        /*
        * Set timer interval based on previous results.
        * The interval must be the shortest necessary to satisfy ANI,
        * short calibration and long calibration.
        */
        cal_interval = ATH_LONG_CALINTERVAL;
 -      if (sc->sc_ah->ah_config.enable_ani)
 +      if (sc->sc_ah->config.enable_ani)
                cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
 -      if (!sc->sc_ani.sc_caldone)
 -              cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL);
 +      if (!sc->ani.caldone)
 +              cal_interval = min(cal_interval, (u32)short_cal_interval);
  
 -      mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval));
 +      mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
  }
  
  /*
   * Update tx/rx chainmask. For legacy association,
   * hard code chainmask to 1x1, for 11n association, use
 - * the chainmask configuration.
 + * the chainmask configuration, for bt coexistence, use
 + * the chainmask configuration even in legacy mode.
   */
 -static void ath_update_chainmask(struct ath_softc *sc, int is_ht)
 +void ath_update_chainmask(struct ath_softc *sc, int is_ht)
  {
        sc->sc_flags |= SC_OP_CHAINMASK_UPDATE;
 -      if (is_ht) {
 -              sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask;
 -              sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask;
 +      if (is_ht ||
 +          (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) {
 +              sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
 +              sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
        } else {
 -              sc->sc_tx_chainmask = 1;
 -              sc->sc_rx_chainmask = 1;
 +              sc->tx_chainmask = 1;
 +              sc->rx_chainmask = 1;
        }
  
        DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n",
 -              sc->sc_tx_chainmask, sc->sc_rx_chainmask);
 +              sc->tx_chainmask, sc->rx_chainmask);
  }
  
  static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
@@@ -455,7 -476,7 +455,7 @@@ static void ath_node_detach(struct ath_
  static void ath9k_tasklet(unsigned long data)
  {
        struct ath_softc *sc = (struct ath_softc *)data;
 -      u32 status = sc->sc_intrstatus;
 +      u32 status = sc->intrstatus;
  
        if (status & ATH9K_INT_FATAL) {
                /* need a chip reset */
        }
  
        /* re-enable hardware interrupt */
 -      ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
 +      ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
  }
  
 -static irqreturn_t ath_isr(int irq, void *dev)
 +irqreturn_t ath_isr(int irq, void *dev)
  {
        struct ath_softc *sc = dev;
 -      struct ath_hal *ah = sc->sc_ah;
 +      struct ath_hw *ah = sc->sc_ah;
        enum ath9k_int status;
        bool sched = false;
  
                 */
                ath9k_hw_getisr(ah, &status);   /* NB: clears ISR too */
  
 -              status &= sc->sc_imask; /* discard unasked-for bits */
 +              status &= sc->imask;    /* discard unasked-for bits */
  
                /*
                 * If there are no status bits set, then this interrupt was not
                if (!status)
                        return IRQ_NONE;
  
 -              sc->sc_intrstatus = status;
 +              sc->intrstatus = status;
 +              ath9k_ps_wakeup(sc);
  
                if (status & ATH9K_INT_FATAL) {
                        /* need a chip reset */
                                 * it will clear whatever condition caused
                                 * the interrupt.
                                 */
 -                              ath9k_hw_procmibevent(ah, &sc->sc_halstats);
 -                              ath9k_hw_set_interrupts(ah, sc->sc_imask);
 +                              ath9k_hw_procmibevent(ah, &sc->nodestats);
 +                              ath9k_hw_set_interrupts(ah, sc->imask);
                        }
                        if (status & ATH9K_INT_TIM_TIMER) {
 -                              if (!(ah->ah_caps.hw_caps &
 +                              if (!(ah->caps.hw_caps &
                                      ATH9K_HW_CAP_AUTOSLEEP)) {
                                        /* Clear RxAbort bit so that we can
                                         * receive frames */
 +                                      ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
                                        ath9k_hw_setrxabort(ah, 0);
                                        sched = true;
 +                                      sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
                                }
                        }
 +                      if (status & ATH9K_INT_TSFOOR) {
 +                              /* FIXME: Handle this interrupt for power save */
 +                              sched = true;
 +                      }
                }
 +              ath9k_ps_restore(sc);
        } while (0);
  
        ath_debug_stat_interrupt(sc, status);
  
        if (sched) {
                /* turn off every interrupt except SWBA */
 -              ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA));
 +              ath9k_hw_set_interrupts(ah, (sc->imask & ATH9K_INT_SWBA));
                tasklet_schedule(&sc->intr_tq);
        }
  
        return IRQ_HANDLED;
  }
  
 -static int ath_get_channel(struct ath_softc *sc,
 -                         struct ieee80211_channel *chan)
 -{
 -      int i;
 -
 -      for (i = 0; i < sc->sc_ah->ah_nchan; i++) {
 -              if (sc->sc_ah->ah_channels[i].channel == chan->center_freq)
 -                      return i;
 -      }
 -
 -      return -1;
 -}
 -
  static u32 ath_get_extchanmode(struct ath_softc *sc,
                               struct ieee80211_channel *chan,
                               enum nl80211_channel_type channel_type)
        return chanmode;
  }
  
 -static int ath_keyset(struct ath_softc *sc, u16 keyix,
 -             struct ath9k_keyval *hk, const u8 mac[ETH_ALEN])
 -{
 -      bool status;
 -
 -      status = ath9k_hw_set_keycache_entry(sc->sc_ah,
 -              keyix, hk, mac, false);
 -
 -      return status != false;
 -}
 -
  static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
 -                         struct ath9k_keyval *hk,
 -                         const u8 *addr)
 +                         struct ath9k_keyval *hk, const u8 *addr,
 +                         bool authenticator)
  {
        const u8 *key_rxmic;
        const u8 *key_txmic;
        key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
  
        if (addr == NULL) {
 -              /* Group key installation */
 -              memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
 -              return ath_keyset(sc, keyix, hk, addr);
 -      }
 -      if (!sc->sc_splitmic) {
                /*
 -               * data key goes at first index,
 -               * the hal handles the MIC keys at index+64.
 +               * Group key installation - only two key cache entries are used
 +               * regardless of splitmic capability since group key is only
 +               * used either for TX or RX.
                 */
 +              if (authenticator) {
 +                      memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
 +                      memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic));
 +              } else {
 +                      memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
 +                      memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
 +              }
 +              return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr);
 +      }
 +      if (!sc->splitmic) {
 +              /* TX and RX keys share the same key cache entry. */
                memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
                memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
 -              return ath_keyset(sc, keyix, hk, addr);
 +              return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr);
        }
 -      /*
 -       * TX key goes at first index, RX key at +32.
 -       * The hal handles the MIC keys at index+64.
 -       */
 +
 +      /* Separate key cache entries for TX and RX */
 +
 +      /* TX key goes at first index, RX key at +32. */
        memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
 -      if (!ath_keyset(sc, keyix, hk, NULL)) {
 -              /* Txmic entry failed. No need to proceed further */
 +      if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) {
 +              /* TX MIC entry failed. No need to proceed further */
                DPRINTF(sc, ATH_DBG_KEYCACHE,
                        "Setting TX MIC Key Failed\n");
                return 0;
  
        memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
        /* XXX delete tx key on failure? */
 -      return ath_keyset(sc, keyix + 32, hk, addr);
 +      return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix + 32, hk, addr);
  }
  
  static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc)
  {
        int i;
  
 -      for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) {
 -              if (test_bit(i, sc->sc_keymap) ||
 -                  test_bit(i + 64, sc->sc_keymap))
 +      for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) {
 +              if (test_bit(i, sc->keymap) ||
 +                  test_bit(i + 64, sc->keymap))
                        continue; /* At least one part of TKIP key allocated */
 -              if (sc->sc_splitmic &&
 -                  (test_bit(i + 32, sc->sc_keymap) ||
 -                   test_bit(i + 64 + 32, sc->sc_keymap)))
 +              if (sc->splitmic &&
 +                  (test_bit(i + 32, sc->keymap) ||
 +                   test_bit(i + 64 + 32, sc->keymap)))
                        continue; /* At least one part of TKIP key allocated */
  
                /* Found a free slot for a TKIP key */
@@@ -710,55 -740,55 +710,55 @@@ static int ath_reserve_key_cache_slot(s
        int i;
  
        /* First, try to find slots that would not be available for TKIP. */
 -      if (sc->sc_splitmic) {
 -              for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 4; i++) {
 -                      if (!test_bit(i, sc->sc_keymap) &&
 -                          (test_bit(i + 32, sc->sc_keymap) ||
 -                           test_bit(i + 64, sc->sc_keymap) ||
 -                           test_bit(i + 64 + 32, sc->sc_keymap)))
 +      if (sc->splitmic) {
 +              for (i = IEEE80211_WEP_NKID; i < sc->keymax / 4; i++) {
 +                      if (!test_bit(i, sc->keymap) &&
 +                          (test_bit(i + 32, sc->keymap) ||
 +                           test_bit(i + 64, sc->keymap) ||
 +                           test_bit(i + 64 + 32, sc->keymap)))
                                return i;
 -                      if (!test_bit(i + 32, sc->sc_keymap) &&
 -                          (test_bit(i, sc->sc_keymap) ||
 -                           test_bit(i + 64, sc->sc_keymap) ||
 -                           test_bit(i + 64 + 32, sc->sc_keymap)))
 +                      if (!test_bit(i + 32, sc->keymap) &&
 +                          (test_bit(i, sc->keymap) ||
 +                           test_bit(i + 64, sc->keymap) ||
 +                           test_bit(i + 64 + 32, sc->keymap)))
                                return i + 32;
 -                      if (!test_bit(i + 64, sc->sc_keymap) &&
 -                          (test_bit(i , sc->sc_keymap) ||
 -                           test_bit(i + 32, sc->sc_keymap) ||
 -                           test_bit(i + 64 + 32, sc->sc_keymap)))
 +                      if (!test_bit(i + 64, sc->keymap) &&
 +                          (test_bit(i , sc->keymap) ||
 +                           test_bit(i + 32, sc->keymap) ||
 +                           test_bit(i + 64 + 32, sc->keymap)))
                                return i + 64;
 -                      if (!test_bit(i + 64 + 32, sc->sc_keymap) &&
 -                          (test_bit(i, sc->sc_keymap) ||
 -                           test_bit(i + 32, sc->sc_keymap) ||
 -                           test_bit(i + 64, sc->sc_keymap)))
 +                      if (!test_bit(i + 64 + 32, sc->keymap) &&
 +                          (test_bit(i, sc->keymap) ||
 +                           test_bit(i + 32, sc->keymap) ||
 +                           test_bit(i + 64, sc->keymap)))
                                return i + 64 + 32;
                }
        } else {
 -              for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) {
 -                      if (!test_bit(i, sc->sc_keymap) &&
 -                          test_bit(i + 64, sc->sc_keymap))
 +              for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) {
 +                      if (!test_bit(i, sc->keymap) &&
 +                          test_bit(i + 64, sc->keymap))
                                return i;
 -                      if (test_bit(i, sc->sc_keymap) &&
 -                          !test_bit(i + 64, sc->sc_keymap))
 +                      if (test_bit(i, sc->keymap) &&
 +                          !test_bit(i + 64, sc->keymap))
                                return i + 64;
                }
        }
  
        /* No partially used TKIP slots, pick any available slot */
 -      for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax; i++) {
 +      for (i = IEEE80211_WEP_NKID; i < sc->keymax; i++) {
                /* Do not allow slots that could be needed for TKIP group keys
                 * to be used. This limitation could be removed if we know that
                 * TKIP will not be used. */
                if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
                        continue;
 -              if (sc->sc_splitmic) {
 +              if (sc->splitmic) {
                        if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
                                continue;
                        if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
                                continue;
                }
  
 -              if (!test_bit(i, sc->sc_keymap))
 +              if (!test_bit(i, sc->keymap))
                        return i; /* Found a free slot for a key */
        }
  
  }
  
  static int ath_key_config(struct ath_softc *sc,
 -                        const u8 *addr,
 +                        struct ieee80211_vif *vif,
 +                        struct ieee80211_sta *sta,
                          struct ieee80211_key_conf *key)
  {
        struct ath9k_keyval hk;
                hk.kv_type = ATH9K_CIPHER_AES_CCM;
                break;
        default:
 -              return -EINVAL;
 +              return -EOPNOTSUPP;
        }
  
        hk.kv_len = key->keylen;
                 * need to change with virtual interfaces. */
                idx = key->keyidx;
        } else if (key->keyidx) {
 -              struct ieee80211_vif *vif;
 +              if (WARN_ON(!sta))
 +                      return -EOPNOTSUPP;
 +              mac = sta->addr;
  
 -              mac = addr;
 -              vif = sc->sc_vaps[0];
                if (vif->type != NL80211_IFTYPE_AP) {
                        /* Only keyidx 0 should be used with unicast key, but
                         * allow this for client mode for now. */
                } else
                        return -EIO;
        } else {
 -              mac = addr;
 +              if (WARN_ON(!sta))
 +                      return -EOPNOTSUPP;
 +              mac = sta->addr;
 +
                if (key->alg == ALG_TKIP)
                        idx = ath_reserve_key_cache_slot_tkip(sc);
                else
                        idx = ath_reserve_key_cache_slot(sc);
                if (idx < 0)
 -                      return -EIO; /* no free key cache entries */
 +                      return -ENOSPC; /* no free key cache entries */
        }
  
        if (key->alg == ALG_TKIP)
 -              ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac);
 +              ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac,
 +                                    vif->type == NL80211_IFTYPE_AP);
        else
 -              ret = ath_keyset(sc, idx, &hk, mac);
 +              ret = ath9k_hw_set_keycache_entry(sc->sc_ah, idx, &hk, mac);
  
        if (!ret)
                return -EIO;
  
 -      set_bit(idx, sc->sc_keymap);
 +      set_bit(idx, sc->keymap);
        if (key->alg == ALG_TKIP) {
 -              set_bit(idx + 64, sc->sc_keymap);
 -              if (sc->sc_splitmic) {
 -                      set_bit(idx + 32, sc->sc_keymap);
 -                      set_bit(idx + 64 + 32, sc->sc_keymap);
 +              set_bit(idx + 64, sc->keymap);
 +              if (sc->splitmic) {
 +                      set_bit(idx + 32, sc->keymap);
 +                      set_bit(idx + 64 + 32, sc->keymap);
                }
        }
  
@@@ -850,19 -875,18 +850,19 @@@ static void ath_key_delete(struct ath_s
        if (key->hw_key_idx < IEEE80211_WEP_NKID)
                return;
  
 -      clear_bit(key->hw_key_idx, sc->sc_keymap);
 +      clear_bit(key->hw_key_idx, sc->keymap);
        if (key->alg != ALG_TKIP)
                return;
  
 -      clear_bit(key->hw_key_idx + 64, sc->sc_keymap);
 -      if (sc->sc_splitmic) {
 -              clear_bit(key->hw_key_idx + 32, sc->sc_keymap);
 -              clear_bit(key->hw_key_idx + 64 + 32, sc->sc_keymap);
 +      clear_bit(key->hw_key_idx + 64, sc->keymap);
 +      if (sc->splitmic) {
 +              clear_bit(key->hw_key_idx + 32, sc->keymap);
 +              clear_bit(key->hw_key_idx + 64 + 32, sc->keymap);
        }
  }
  
 -static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info)
 +static void setup_ht_cap(struct ath_softc *sc,
 +                       struct ieee80211_sta_ht_cap *ht_info)
  {
  #define       ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3       /* 2 ^ 16 */
  #define       ATH9K_HT_CAP_MPDUDENSITY_8 0x6          /* 8 usec */
  
        ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536;
        ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8;
 +
        /* set up supported mcs set */
        memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
 -      ht_info->mcs.rx_mask[0] = 0xff;
 -      ht_info->mcs.rx_mask[1] = 0xff;
 +
 +      switch(sc->rx_chainmask) {
 +      case 1:
 +              ht_info->mcs.rx_mask[0] = 0xff;
 +              break;
 +      case 3:
 +      case 5:
 +      case 7:
 +      default:
 +              ht_info->mcs.rx_mask[0] = 0xff;
 +              ht_info->mcs.rx_mask[1] = 0xff;
 +              break;
 +      }
 +
        ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
  }
  
@@@ -899,33 -910,36 +899,33 @@@ static void ath9k_bss_assoc_info(struc
                                 struct ieee80211_vif *vif,
                                 struct ieee80211_bss_conf *bss_conf)
  {
 -      struct ath_vap *avp = (void *)vif->drv_priv;
 +      struct ath_vif *avp = (void *)vif->drv_priv;
  
        if (bss_conf->assoc) {
                DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
 -                      bss_conf->aid, sc->sc_curbssid);
 +                      bss_conf->aid, sc->curbssid);
  
                /* New association, store aid */
                if (avp->av_opmode == NL80211_IFTYPE_STATION) {
 -                      sc->sc_curaid = bss_conf->aid;
 -                      ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid,
 -                                             sc->sc_curaid);
 +                      sc->curaid = bss_conf->aid;
 +                      ath9k_hw_write_associd(sc);
                }
  
                /* Configure the beacon */
 -              ath_beacon_config(sc, 0);
 -              sc->sc_flags |= SC_OP_BEACONS;
 +              ath_beacon_config(sc, vif);
  
                /* Reset rssi stats */
 -              sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
 -              sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
 -              sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
 -              sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
 +              sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
 +              sc->nodestats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
 +              sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
 +              sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
  
                /* Start ANI */
 -              mod_timer(&sc->sc_ani.timer,
 -                      jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
 -
 +              mod_timer(&sc->ani.timer,
 +                        jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
        } else {
                DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n");
 -              sc->sc_curaid = 0;
 +              sc->curaid = 0;
        }
  }
  
  /*     LED functions          */
  /********************************/
  
 +static void ath_led_blink_work(struct work_struct *work)
 +{
 +      struct ath_softc *sc = container_of(work, struct ath_softc,
 +                                          ath_led_blink_work.work);
 +
 +      if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED))
 +              return;
 +      ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
 +                        (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
 +
 +      queue_delayed_work(sc->hw->workqueue, &sc->ath_led_blink_work,
 +                         (sc->sc_flags & SC_OP_LED_ON) ?
 +                         msecs_to_jiffies(sc->led_off_duration) :
 +                         msecs_to_jiffies(sc->led_on_duration));
 +
 +      sc->led_on_duration =
 +                      max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25);
 +      sc->led_off_duration =
 +                      max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10);
 +      sc->led_on_cnt = sc->led_off_cnt = 0;
 +      if (sc->sc_flags & SC_OP_LED_ON)
 +              sc->sc_flags &= ~SC_OP_LED_ON;
 +      else
 +              sc->sc_flags |= SC_OP_LED_ON;
 +}
 +
  static void ath_led_brightness(struct led_classdev *led_cdev,
                               enum led_brightness brightness)
  {
        switch (brightness) {
        case LED_OFF:
                if (led->led_type == ATH_LED_ASSOC ||
 -                  led->led_type == ATH_LED_RADIO)
 +                  led->led_type == ATH_LED_RADIO) {
 +                      ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
 +                              (led->led_type == ATH_LED_RADIO));
                        sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
 -              ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
 -                              (led->led_type == ATH_LED_RADIO) ? 1 :
 -                              !!(sc->sc_flags & SC_OP_LED_ASSOCIATED));
 +                      if (led->led_type == ATH_LED_RADIO)
 +                              sc->sc_flags &= ~SC_OP_LED_ON;
 +              } else {
 +                      sc->led_off_cnt++;
 +              }
                break;
        case LED_FULL:
 -              if (led->led_type == ATH_LED_ASSOC)
 +              if (led->led_type == ATH_LED_ASSOC) {
                        sc->sc_flags |= SC_OP_LED_ASSOCIATED;
 -              ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
 +                      queue_delayed_work(sc->hw->workqueue,
 +                                         &sc->ath_led_blink_work, 0);
 +              } else if (led->led_type == ATH_LED_RADIO) {
 +                      ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
 +                      sc->sc_flags |= SC_OP_LED_ON;
 +              } else {
 +                      sc->led_on_cnt++;
 +              }
                break;
        default:
                break;
@@@ -1024,7 -1001,6 +1024,7 @@@ static void ath_unregister_led(struct a
  
  static void ath_deinit_leds(struct ath_softc *sc)
  {
 +      cancel_delayed_work_sync(&sc->ath_led_blink_work);
        ath_unregister_led(&sc->assoc_led);
        sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
        ath_unregister_led(&sc->tx_led);
@@@ -1044,11 -1020,9 +1044,11 @@@ static void ath_init_leds(struct ath_so
        /* LED off, active low */
        ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
  
 +      INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
 +
        trigger = ieee80211_get_radio_led_name(sc->hw);
        snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
 -              "ath9k-%s:radio", wiphy_name(sc->hw->wiphy));
 +              "ath9k-%s::radio", wiphy_name(sc->hw->wiphy));
        ret = ath_register_led(sc, &sc->radio_led, trigger);
        sc->radio_led.led_type = ATH_LED_RADIO;
        if (ret)
  
        trigger = ieee80211_get_assoc_led_name(sc->hw);
        snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
 -              "ath9k-%s:assoc", wiphy_name(sc->hw->wiphy));
 +              "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy));
        ret = ath_register_led(sc, &sc->assoc_led, trigger);
        sc->assoc_led.led_type = ATH_LED_ASSOC;
        if (ret)
  
        trigger = ieee80211_get_tx_led_name(sc->hw);
        snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
 -              "ath9k-%s:tx", wiphy_name(sc->hw->wiphy));
 +              "ath9k-%s::tx", wiphy_name(sc->hw->wiphy));
        ret = ath_register_led(sc, &sc->tx_led, trigger);
        sc->tx_led.led_type = ATH_LED_TX;
        if (ret)
  
        trigger = ieee80211_get_rx_led_name(sc->hw);
        snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
 -              "ath9k-%s:rx", wiphy_name(sc->hw->wiphy));
 +              "ath9k-%s::rx", wiphy_name(sc->hw->wiphy));
        ret = ath_register_led(sc, &sc->rx_led, trigger);
        sc->rx_led.led_type = ATH_LED_RX;
        if (ret)
@@@ -1090,22 -1064,26 +1090,22 @@@ fail
  /*    Rfkill     */
  /*******************/
  
 -static void ath_radio_enable(struct ath_softc *sc)
 +void ath_radio_enable(struct ath_softc *sc)
  {
 -      struct ath_hal *ah = sc->sc_ah;
 -      int status;
 +      struct ath_hw *ah = sc->sc_ah;
 +      struct ieee80211_channel *channel = sc->hw->conf.channel;
 +      int r;
  
 +      ath9k_ps_wakeup(sc);
        spin_lock_bh(&sc->sc_resetlock);
 -      if (!ath9k_hw_reset(ah, ah->ah_curchan,
 -                          sc->tx_chan_width,
 -                          sc->sc_tx_chainmask,
 -                          sc->sc_rx_chainmask,
 -                          sc->sc_ht_extprotspacing,
 -                          false, &status)) {
 +
 +      r = ath9k_hw_reset(ah, ah->curchan, false);
 +
 +      if (r) {
                DPRINTF(sc, ATH_DBG_FATAL,
 -                      "Unable to reset channel %u (%uMhz) "
 -                      "flags 0x%x hal status %u\n",
 -                      ath9k_hw_mhz2ieee(ah,
 -                                        ah->ah_curchan->channel,
 -                                        ah->ah_curchan->channelFlags),
 -                      ah->ah_curchan->channel,
 -                      ah->ah_curchan->channelFlags, status);
 +                      "Unable to reset channel %u (%uMhz) ",
 +                      "reset status %u\n",
 +                      channel->center_freq, r);
        }
        spin_unlock_bh(&sc->sc_resetlock);
  
        }
  
        if (sc->sc_flags & SC_OP_BEACONS)
 -              ath_beacon_config(sc, ATH_IF_ID_ANY);   /* restart beacons */
 +              ath_beacon_config(sc, NULL);    /* restart beacons */
  
        /* Re-Enable  interrupts */
 -      ath9k_hw_set_interrupts(ah, sc->sc_imask);
 +      ath9k_hw_set_interrupts(ah, sc->imask);
  
        /* Enable LED */
        ath9k_hw_cfg_output(ah, ATH_LED_PIN,
        ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0);
  
        ieee80211_wake_queues(sc->hw);
 +      ath9k_ps_restore(sc);
  }
  
 -static void ath_radio_disable(struct ath_softc *sc)
 +void ath_radio_disable(struct ath_softc *sc)
  {
 -      struct ath_hal *ah = sc->sc_ah;
 -      int status;
 -
 +      struct ath_hw *ah = sc->sc_ah;
 +      struct ieee80211_channel *channel = sc->hw->conf.channel;
 +      int r;
  
 +      ath9k_ps_wakeup(sc);
        ieee80211_stop_queues(sc->hw);
  
        /* Disable LED */
        /* Disable interrupts */
        ath9k_hw_set_interrupts(ah, 0);
  
 -      ath_draintxq(sc, false);        /* clear pending tx frames */
 +      ath_drain_all_txq(sc, false);   /* clear pending tx frames */
        ath_stoprecv(sc);               /* turn off frame recv */
        ath_flushrecv(sc);              /* flush recv queue */
  
        spin_lock_bh(&sc->sc_resetlock);
 -      if (!ath9k_hw_reset(ah, ah->ah_curchan,
 -                          sc->tx_chan_width,
 -                          sc->sc_tx_chainmask,
 -                          sc->sc_rx_chainmask,
 -                          sc->sc_ht_extprotspacing,
 -                          false, &status)) {
 +      r = ath9k_hw_reset(ah, ah->curchan, false);
 +      if (r) {
                DPRINTF(sc, ATH_DBG_FATAL,
                        "Unable to reset channel %u (%uMhz) "
 -                      "flags 0x%x hal status %u\n",
 -                      ath9k_hw_mhz2ieee(ah,
 -                              ah->ah_curchan->channel,
 -                              ah->ah_curchan->channelFlags),
 -                      ah->ah_curchan->channel,
 -                      ah->ah_curchan->channelFlags, status);
 +                      "reset status %u\n",
 +                      channel->center_freq, r);
        }
        spin_unlock_bh(&sc->sc_resetlock);
  
        ath9k_hw_phy_disable(ah);
        ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
 +      ath9k_ps_restore(sc);
  }
  
  static bool ath_is_rfkill_set(struct ath_softc *sc)
  {
 -      struct ath_hal *ah = sc->sc_ah;
 +      struct ath_hw *ah = sc->sc_ah;
  
 -      return ath9k_hw_gpio_get(ah, ah->ah_rfkill_gpio) ==
 -                                ah->ah_rfkill_polarity;
 +      return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
 +                                ah->rfkill_polarity;
  }
  
  /* h/w rfkill poll function */
@@@ -1255,7 -1238,7 +1255,7 @@@ static int ath_init_sw_rfkill(struct at
        }
  
        snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name),
 -              "ath9k-%s:rfkill", wiphy_name(sc->hw->wiphy));
 +              "ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy));
        sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name;
        sc->rf_kill.rfkill->data = sc;
        sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio;
  /* Deinitialize rfkill */
  static void ath_deinit_rfkill(struct ath_softc *sc)
  {
 -      if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 +      if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
                cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
  
        if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) {
  
  static int ath_start_rfkill_poll(struct ath_softc *sc)
  {
 -      if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 +      if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
                queue_delayed_work(sc->hw->workqueue,
                                   &sc->rf_kill.rfkill_poll, 0);
  
                        rfkill_free(sc->rf_kill.rfkill);
  
                        /* Deinitialize the device */
 -                      ath_detach(sc);
 -                      if (sc->pdev->irq)
 -                              free_irq(sc->pdev->irq, sc);
 -                      pci_iounmap(sc->pdev, sc->mem);
 -                      pci_release_region(sc->pdev, 0);
 -                      pci_disable_device(sc->pdev);
 -                      ieee80211_free_hw(sc->hw);
 +                      ath_cleanup(sc);
                        return -EIO;
                } else {
                        sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
  }
  #endif /* CONFIG_RFKILL */
  
 -static void ath_detach(struct ath_softc *sc)
 +void ath_cleanup(struct ath_softc *sc)
 +{
 +      ath_detach(sc);
 +      free_irq(sc->irq, sc);
 +      ath_bus_cleanup(sc);
 +      kfree(sc->sec_wiphy);
 +      ieee80211_free_hw(sc->hw);
 +}
 +
 +void ath_detach(struct ath_softc *sc)
  {
        struct ieee80211_hw *hw = sc->hw;
        int i = 0;
  
 +      ath9k_ps_wakeup(sc);
 +
        DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n");
  
  #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
        ath_deinit_rfkill(sc);
  #endif
        ath_deinit_leds(sc);
 +      cancel_work_sync(&sc->chan_work);
 +      cancel_delayed_work_sync(&sc->wiphy_work);
  
 +      for (i = 0; i < sc->num_sec_wiphy; i++) {
 +              struct ath_wiphy *aphy = sc->sec_wiphy[i];
 +              if (aphy == NULL)
 +                      continue;
 +              sc->sec_wiphy[i] = NULL;
 +              ieee80211_unregister_hw(aphy->hw);
 +              ieee80211_free_hw(aphy->hw);
 +      }
        ieee80211_unregister_hw(hw);
        ath_rx_cleanup(sc);
        ath_tx_cleanup(sc);
  
        ath9k_hw_detach(sc->sc_ah);
        ath9k_exit_debug(sc);
 +      ath9k_ps_restore(sc);
  }
  
  static int ath_init(u16 devid, struct ath_softc *sc)
  {
 -      struct ath_hal *ah = NULL;
 +      struct ath_hw *ah = NULL;
        int status;
        int error = 0, i;
        int csz = 0;
        if (ath9k_init_debug(sc) < 0)
                printk(KERN_ERR "Unable to create debugfs files\n");
  
 +      spin_lock_init(&sc->wiphy_lock);
        spin_lock_init(&sc->sc_resetlock);
+       spin_lock_init(&sc->sc_serial_rw);
        mutex_init(&sc->mutex);
        tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
 -      tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
 +      tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
                     (unsigned long)sc);
  
        /*
         * Cache line size is used to size and align various
         * structures used to communicate with the hardware.
         */
 -      bus_read_cachesize(sc, &csz);
 +      ath_read_cachesize(sc, &csz);
        /* XXX assert csz is non-zero */
 -      sc->sc_cachelsz = csz << 2;     /* convert to bytes */
 +      sc->cachelsz = csz << 2;        /* convert to bytes */
  
 -      ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
 +      ah = ath9k_hw_attach(devid, sc, &status);
        if (ah == NULL) {
                DPRINTF(sc, ATH_DBG_FATAL,
 -                      "Unable to attach hardware; HAL status %u\n", status);
 +                      "Unable to attach hardware; HAL status %d\n", status);
                error = -ENXIO;
                goto bad;
        }
        sc->sc_ah = ah;
  
        /* Get the hardware key cache size. */
 -      sc->sc_keymax = ah->ah_caps.keycache_size;
 -      if (sc->sc_keymax > ATH_KEYMAX) {
 +      sc->keymax = ah->caps.keycache_size;
 +      if (sc->keymax > ATH_KEYMAX) {
                DPRINTF(sc, ATH_DBG_KEYCACHE,
                        "Warning, using only %u entries in %u key cache\n",
 -                      ATH_KEYMAX, sc->sc_keymax);
 -              sc->sc_keymax = ATH_KEYMAX;
 +                      ATH_KEYMAX, sc->keymax);
 +              sc->keymax = ATH_KEYMAX;
        }
  
        /*
         * Reset the key cache since some parts do not
         * reset the contents on initial power up.
         */
 -      for (i = 0; i < sc->sc_keymax; i++)
 +      for (i = 0; i < sc->keymax; i++)
                ath9k_hw_keyreset(ah, (u16) i);
  
 -      /* Collect the channel list using the default country code */
 -
 -      error = ath_setup_channels(sc);
 -      if (error)
 +      if (ath9k_regd_init(sc->sc_ah))
                goto bad;
  
        /* default to MONITOR mode */
 -      sc->sc_ah->ah_opmode = NL80211_IFTYPE_MONITOR;
 -
 +      sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR;
  
        /* Setup rate tables */
  
                goto bad2;
        }
  
 -      sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME;
 +      sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
        ath_cabq_update(sc);
  
        for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++)
        /* Initializes the noise floor to a reasonable default value.
         * Later on this will be updated during ANI processing. */
  
 -      sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR;
 -      setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc);
 +      sc->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR;
 +      setup_timer(&sc->ani.timer, ath_ani_calibrate, (unsigned long)sc);
  
        if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
                                   ATH9K_CIPHER_TKIP, NULL)) {
                                      ATH9K_CIPHER_MIC, NULL)
            && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
                                      0, NULL))
 -              sc->sc_splitmic = 1;
 +              sc->splitmic = 1;
  
        /* turn on mcast key search if possible */
        if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
                (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1,
                                             1, NULL);
  
 -      sc->sc_config.txpowlimit = ATH_TXPOWER_MAX;
 -      sc->sc_config.txpowlimit_override = 0;
 +      sc->config.txpowlimit = ATH_TXPOWER_MAX;
  
        /* 11n Capabilities */
 -      if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
 +      if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
                sc->sc_flags |= SC_OP_TXAGGR;
                sc->sc_flags |= SC_OP_RXAGGR;
        }
  
 -      sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
 -      sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
 +      sc->tx_chainmask = ah->caps.tx_chainmask;
 +      sc->rx_chainmask = ah->caps.rx_chainmask;
  
        ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
        sc->rx.defant = ath9k_hw_getdefantenna(ah);
  
 -      ath9k_hw_getmac(ah, sc->sc_myaddr);
 -      if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) {
 -              ath9k_hw_getbssidmask(ah, sc->sc_bssidmask);
 -              ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask);
 -              ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
 -      }
 +      if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
 +              memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN);
  
        sc->beacon.slottime = ATH9K_SLOT_TIME_9;        /* default to short slot time */
  
        /* initialize beacon slots */
 -      for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)
 -              sc->beacon.bslot[i] = ATH_IF_ID_ANY;
 +      for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
 +              sc->beacon.bslot[i] = NULL;
 +              sc->beacon.bslot_aphy[i] = NULL;
 +      }
  
        /* save MISC configurations */
 -      sc->sc_config.swBeaconProcess = 1;
 +      sc->config.swBeaconProcess = 1;
  
        /* setup channels and rates */
  
 -      sc->sbands[IEEE80211_BAND_2GHZ].channels =
 -              sc->channels[IEEE80211_BAND_2GHZ];
 +      sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable;
        sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
                sc->rates[IEEE80211_BAND_2GHZ];
        sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
 +      sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
 +              ARRAY_SIZE(ath9k_2ghz_chantable);
  
 -      if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
 -              sc->sbands[IEEE80211_BAND_5GHZ].channels =
 -                      sc->channels[IEEE80211_BAND_5GHZ];
 +      if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) {
 +              sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable;
                sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
                        sc->rates[IEEE80211_BAND_5GHZ];
                sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
 +              sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
 +                      ARRAY_SIZE(ath9k_5ghz_chantable);
        }
  
 +      if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)
 +              ath9k_hw_btcoex_enable(sc->sc_ah);
 +
        return 0;
  bad2:
        /* cleanup tx queues */
        return error;
  }
  
 -static int ath_attach(u16 devid, struct ath_softc *sc)
 +void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
  {
 -      struct ieee80211_hw *hw = sc->hw;
 -      int error = 0, i;
 -
 -      DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n");
 -
 -      error = ath_init(devid, sc);
 -      if (error != 0)
 -              return error;
 -
 -      /* get mac address from hardware and set in mac80211 */
 -
 -      SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr);
 -
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
                IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
                IEEE80211_HW_SIGNAL_DBM |
 -              IEEE80211_HW_AMPDU_AGGREGATION;
 +              IEEE80211_HW_AMPDU_AGGREGATION |
 +              IEEE80211_HW_SUPPORTS_PS |
 +              IEEE80211_HW_PS_NULLFUNC_STACK;
 +
 +      if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt)
 +              hw->flags |= IEEE80211_HW_MFP_CAPABLE;
  
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_AP) |
                BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_ADHOC);
  
 +      hw->wiphy->reg_notifier = ath9k_reg_notifier;
 +      hw->wiphy->strict_regulatory = true;
 +
        hw->queues = 4;
        hw->max_rates = 4;
 +      hw->channel_change_time = 5000;
 +      hw->max_listen_interval = 10;
        hw->max_rate_tries = ATH_11N_TXMAXTRY;
        hw->sta_data_size = sizeof(struct ath_node);
 -      hw->vif_data_size = sizeof(struct ath_vap);
 +      hw->vif_data_size = sizeof(struct ath_vif);
  
        hw->rate_control_algorithm = "ath9k_rate_control";
  
 -      if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
 -              setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
 -              if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes))
 -                      setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
 -      }
 -
 -      hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ];
 -      if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes))
 +      hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
 +              &sc->sbands[IEEE80211_BAND_2GHZ];
 +      if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
                hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
                        &sc->sbands[IEEE80211_BAND_5GHZ];
 +}
 +
 +int ath_attach(u16 devid, struct ath_softc *sc)
 +{
 +      struct ieee80211_hw *hw = sc->hw;
 +      const struct ieee80211_regdomain *regd;
 +      int error = 0, i;
 +
 +      DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n");
 +
 +      error = ath_init(devid, sc);
 +      if (error != 0)
 +              return error;
 +
 +      /* get mac address from hardware and set in mac80211 */
 +
 +      SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr);
 +
 +      ath_set_hw_capab(sc, hw);
 +
 +      if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
 +              setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
 +              if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
 +                      setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
 +      }
  
        /* initialize tx/rx engine */
        error = ath_tx_init(sc, ATH_TXBUF);
  
  #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
        /* Initialze h/w Rfkill */
 -      if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 +      if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
                INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll);
  
        /* Initialize s/w rfkill */
                goto error_attach;
  #endif
  
 +      if (ath9k_is_world_regd(sc->sc_ah)) {
 +              /* Anything applied here (prior to wiphy registration) gets
 +               * saved on the wiphy orig_* parameters */
 +              regd = ath9k_world_regdomain(sc->sc_ah);
 +              hw->wiphy->custom_regulatory = true;
 +              hw->wiphy->strict_regulatory = false;
 +      } else {
 +              /* This gets applied in the case of the absense of CRDA,
 +               * it's our own custom world regulatory domain, similar to
 +               * cfg80211's but we enable passive scanning */
 +              regd = ath9k_default_world_regdomain();
 +      }
 +      wiphy_apply_custom_regulatory(hw->wiphy, regd);
 +      ath9k_reg_apply_radar_flags(hw->wiphy);
 +      ath9k_reg_apply_world_flags(hw->wiphy, REGDOM_SET_BY_INIT);
 +
 +      INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
 +      INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
 +      sc->wiphy_scheduler_int = msecs_to_jiffies(500);
 +
        error = ieee80211_register_hw(hw);
  
 +      if (!ath9k_is_world_regd(sc->sc_ah)) {
 +              error = regulatory_hint(hw->wiphy,
 +                      sc->sc_ah->regulatory.alpha2);
 +              if (error)
 +                      goto error_attach;
 +      }
 +
        /* Initialize LED control */
        ath_init_leds(sc);
  
 +
        return 0;
  
  error_attach:
  
  int ath_reset(struct ath_softc *sc, bool retry_tx)
  {
 -      struct ath_hal *ah = sc->sc_ah;
 -      int status;
 -      int error = 0;
 +      struct ath_hw *ah = sc->sc_ah;
 +      struct ieee80211_hw *hw = sc->hw;
 +      int r;
  
        ath9k_hw_set_interrupts(ah, 0);
 -      ath_draintxq(sc, retry_tx);
 +      ath_drain_all_txq(sc, retry_tx);
        ath_stoprecv(sc);
        ath_flushrecv(sc);
  
        spin_lock_bh(&sc->sc_resetlock);
 -      if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan,
 -                          sc->tx_chan_width,
 -                          sc->sc_tx_chainmask, sc->sc_rx_chainmask,
 -                          sc->sc_ht_extprotspacing, false, &status)) {
 +      r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
 +      if (r)
                DPRINTF(sc, ATH_DBG_FATAL,
 -                      "Unable to reset hardware; hal status %u\n", status);
 -              error = -EIO;
 -      }
 +                      "Unable to reset hardware; reset status %u\n", r);
        spin_unlock_bh(&sc->sc_resetlock);
  
        if (ath_startrecv(sc) != 0)
         * that changes the channel so update any state that
         * might change as a result.
         */
 -      ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan));
 +      ath_cache_conf_rate(sc, &hw->conf);
  
        ath_update_txpow(sc);
  
        if (sc->sc_flags & SC_OP_BEACONS)
 -              ath_beacon_config(sc, ATH_IF_ID_ANY);   /* restart beacons */
 +              ath_beacon_config(sc, NULL);    /* restart beacons */
  
 -      ath9k_hw_set_interrupts(ah, sc->sc_imask);
 +      ath9k_hw_set_interrupts(ah, sc->imask);
  
        if (retry_tx) {
                int i;
                }
        }
  
 -      return error;
 +      return r;
  }
  
  /*
@@@ -1789,7 -1717,7 +1790,7 @@@ int ath_descdma_setup(struct ath_softc 
         * descriptors that cross the 4K page boundary. Assume
         * one skipped descriptor per 4K page.
         */
 -      if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
 +      if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
                u32 ndesc_skipped =
                        ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
                u32 dma_len;
        }
  
        /* allocate descriptors */
 -      dd->dd_desc = pci_alloc_consistent(sc->pdev,
 -                            dd->dd_desc_len,
 -                            &dd->dd_desc_paddr);
 +      dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
 +                                       &dd->dd_desc_paddr, GFP_ATOMIC);
        if (dd->dd_desc == NULL) {
                error = -ENOMEM;
                goto fail;
                bf->bf_desc = ds;
                bf->bf_daddr = DS2PHYS(dd, ds);
  
 -              if (!(sc->sc_ah->ah_caps.hw_caps &
 +              if (!(sc->sc_ah->caps.hw_caps &
                      ATH9K_HW_CAP_4KB_SPLITTRANS)) {
                        /*
                         * Skip descriptor addresses which can cause 4KB
        }
        return 0;
  fail2:
 -      pci_free_consistent(sc->pdev,
 -              dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
 +      dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
 +                        dd->dd_desc_paddr);
  fail:
        memset(dd, 0, sizeof(*dd));
        return error;
@@@ -1864,8 -1793,8 +1865,8 @@@ void ath_descdma_cleanup(struct ath_sof
                         struct ath_descdma *dd,
                         struct list_head *head)
  {
 -      pci_free_consistent(sc->pdev,
 -              dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
 +      dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
 +                        dd->dd_desc_paddr);
  
        INIT_LIST_HEAD(head);
        kfree(dd->dd_bufptr);
@@@ -1922,81 -1851,33 +1923,81 @@@ int ath_get_mac80211_qnum(u32 queue, st
        return qnum;
  }
  
 +/* XXX: Remove me once we don't depend on ath9k_channel for all
 + * this redundant data */
 +void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
 +                         struct ath9k_channel *ichan)
 +{
 +      struct ieee80211_channel *chan = hw->conf.channel;
 +      struct ieee80211_conf *conf = &hw->conf;
 +
 +      ichan->channel = chan->center_freq;
 +      ichan->chan = chan;
 +
 +      if (chan->band == IEEE80211_BAND_2GHZ) {
 +              ichan->chanmode = CHANNEL_G;
 +              ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM;
 +      } else {
 +              ichan->chanmode = CHANNEL_A;
 +              ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
 +      }
 +
 +      sc->tx_chan_width = ATH9K_HT_MACMODE_20;
 +
 +      if (conf_is_ht(conf)) {
 +              if (conf_is_ht40(conf))
 +                      sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
 +
 +              ichan->chanmode = ath_get_extchanmode(sc, chan,
 +                                          conf->channel_type);
 +      }
 +}
 +
  /**********************/
  /* mac80211 callbacks */
  /**********************/
  
  static int ath9k_start(struct ieee80211_hw *hw)
  {
 -      struct ath_softc *sc = hw->priv;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
        struct ieee80211_channel *curchan = hw->conf.channel;
        struct ath9k_channel *init_channel;
 -      int error = 0, pos, status;
 +      int r, pos;
  
        DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with "
                "initial channel: %d MHz\n", curchan->center_freq);
  
 -      /* setup initial channel */
 +      mutex_lock(&sc->mutex);
  
 -      pos = ath_get_channel(sc, curchan);
 -      if (pos == -1) {
 -              DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", curchan->center_freq);
 -              error = -EINVAL;
 -              goto error;
 +      if (ath9k_wiphy_started(sc)) {
 +              if (sc->chan_idx == curchan->hw_value) {
 +                      /*
 +                       * Already on the operational channel, the new wiphy
 +                       * can be marked active.
 +                       */
 +                      aphy->state = ATH_WIPHY_ACTIVE;
 +                      ieee80211_wake_queues(hw);
 +              } else {
 +                      /*
 +                       * Another wiphy is on another channel, start the new
 +                       * wiphy in paused state.
 +                       */
 +                      aphy->state = ATH_WIPHY_PAUSED;
 +                      ieee80211_stop_queues(hw);
 +              }
 +              mutex_unlock(&sc->mutex);
 +              return 0;
        }
 +      aphy->state = ATH_WIPHY_ACTIVE;
  
 -      sc->tx_chan_width = ATH9K_HT_MACMODE_20;
 -      sc->sc_ah->ah_channels[pos].chanmode =
 -              (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A;
 -      init_channel = &sc->sc_ah->ah_channels[pos];
 +      /* setup initial channel */
 +
 +      pos = curchan->hw_value;
 +
 +      sc->chan_idx = pos;
 +      init_channel = &sc->sc_ah->channels[pos];
 +      ath9k_update_ichannel(sc, hw, init_channel);
  
        /* Reset SERDES registers */
        ath9k_hw_configpcipowersave(sc->sc_ah, 0);
         * and then setup of the interrupt mask.
         */
        spin_lock_bh(&sc->sc_resetlock);
 -      if (!ath9k_hw_reset(sc->sc_ah, init_channel,
 -                          sc->tx_chan_width,
 -                          sc->sc_tx_chainmask, sc->sc_rx_chainmask,
 -                          sc->sc_ht_extprotspacing, false, &status)) {
 +      r = ath9k_hw_reset(sc->sc_ah, init_channel, false);
 +      if (r) {
                DPRINTF(sc, ATH_DBG_FATAL,
 -                      "Unable to reset hardware; hal status %u "
 -                      "(freq %u flags 0x%x)\n", status,
 -                      init_channel->channel, init_channel->channelFlags);
 -              error = -EIO;
 +                      "Unable to reset hardware; reset status %u "
 +                      "(freq %u MHz)\n", r,
 +                      curchan->center_freq);
                spin_unlock_bh(&sc->sc_resetlock);
 -              goto error;
 +              goto mutex_unlock;
        }
        spin_unlock_bh(&sc->sc_resetlock);
  
        if (ath_startrecv(sc) != 0) {
                DPRINTF(sc, ATH_DBG_FATAL,
                        "Unable to start recv logic\n");
 -              error = -EIO;
 -              goto error;
 +              r = -EIO;
 +              goto mutex_unlock;
        }
  
        /* Setup our intr mask. */
 -      sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX
 +      sc->imask = ATH9K_INT_RX | ATH9K_INT_TX
                | ATH9K_INT_RXEOL | ATH9K_INT_RXORN
                | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL;
  
 -      if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT)
 -              sc->sc_imask |= ATH9K_INT_GTT;
 -
 -      if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
 -              sc->sc_imask |= ATH9K_INT_CST;
 +      if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_GTT)
 +              sc->imask |= ATH9K_INT_GTT;
  
 -      /*
 -       * Enable MIB interrupts when there are hardware phy counters.
 -       * Note we only do this (at the moment) for station mode.
 -       */
 -      if (ath9k_hw_phycounters(sc->sc_ah) &&
 -          ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) ||
 -           (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)))
 -              sc->sc_imask |= ATH9K_INT_MIB;
 -      /*
 -       * Some hardware processes the TIM IE and fires an
 -       * interrupt when the TIM bit is set.  For hardware
 -       * that does, if not overridden by configuration,
 -       * enable the TIM interrupt when operating as station.
 -       */
 -      if ((sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
 -          (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) &&
 -          !sc->sc_config.swBeaconProcess)
 -              sc->sc_imask |= ATH9K_INT_TIM;
 +      if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
 +              sc->imask |= ATH9K_INT_CST;
  
 -      ath_setcurmode(sc, ath_chan2mode(init_channel));
 +      ath_cache_conf_rate(sc, &hw->conf);
  
        sc->sc_flags &= ~SC_OP_INVALID;
  
        /* Disable BMISS interrupt when we're not associated */
 -      sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
 -      ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
 +      sc->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
 +      ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
  
 -      ieee80211_wake_queues(sc->hw);
 +      ieee80211_wake_queues(hw);
  
  #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 -      error = ath_start_rfkill_poll(sc);
 +      r = ath_start_rfkill_poll(sc);
  #endif
  
 -error:
 -      return error;
 +mutex_unlock:
 +      mutex_unlock(&sc->mutex);
 +
 +      return r;
  }
  
  static int ath9k_tx(struct ieee80211_hw *hw,
                    struct sk_buff *skb)
  {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 -      struct ath_softc *sc = hw->priv;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
        struct ath_tx_control txctl;
        int hdrlen, padsize;
  
 +      if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
 +              printk(KERN_DEBUG "ath9k: %s: TX in unexpected wiphy state "
 +                     "%d\n", wiphy_name(hw->wiphy), aphy->state);
 +              goto exit;
 +      }
 +
        memset(&txctl, 0, sizeof(struct ath_tx_control));
  
        /*
  
        DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
  
 -      if (ath_tx_start(sc, skb, &txctl) != 0) {
 +      if (ath_tx_start(hw, skb, &txctl) != 0) {
                DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n");
                goto exit;
        }
@@@ -2132,38 -2026,30 +2133,38 @@@ exit
  
  static void ath9k_stop(struct ieee80211_hw *hw)
  {
 -      struct ath_softc *sc = hw->priv;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
 +
 +      aphy->state = ATH_WIPHY_INACTIVE;
  
        if (sc->sc_flags & SC_OP_INVALID) {
                DPRINTF(sc, ATH_DBG_ANY, "Device not present\n");
                return;
        }
  
 -      DPRINTF(sc, ATH_DBG_CONFIG, "Cleaning up\n");
 +      mutex_lock(&sc->mutex);
  
 -      ieee80211_stop_queues(sc->hw);
 +      ieee80211_stop_queues(hw);
 +
 +      if (ath9k_wiphy_started(sc)) {
 +              mutex_unlock(&sc->mutex);
 +              return; /* another wiphy still in use */
 +      }
  
        /* make sure h/w will not generate any interrupt
         * before setting the invalid flag. */
        ath9k_hw_set_interrupts(sc->sc_ah, 0);
  
        if (!(sc->sc_flags & SC_OP_INVALID)) {
 -              ath_draintxq(sc, false);
 +              ath_drain_all_txq(sc, false);
                ath_stoprecv(sc);
                ath9k_hw_phy_disable(sc->sc_ah);
        } else
                sc->rx.rxlink = NULL;
  
  #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 -      if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 +      if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
                cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
  #endif
        /* disable HAL and put h/w to sleep */
  
        sc->sc_flags |= SC_OP_INVALID;
  
 +      mutex_unlock(&sc->mutex);
 +
        DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n");
  }
  
  static int ath9k_add_interface(struct ieee80211_hw *hw,
                               struct ieee80211_if_init_conf *conf)
  {
 -      struct ath_softc *sc = hw->priv;
 -      struct ath_vap *avp = (void *)conf->vif->drv_priv;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
 +      struct ath_vif *avp = (void *)conf->vif->drv_priv;
        enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
 +      int ret = 0;
  
 -      /* Support only vap for now */
 +      mutex_lock(&sc->mutex);
  
 -      if (sc->sc_nvaps)
 -              return -ENOBUFS;
 +      if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) &&
 +          sc->nvifs > 0) {
 +              ret = -ENOBUFS;
 +              goto out;
 +      }
  
        switch (conf->type) {
        case NL80211_IFTYPE_STATION:
                ic_opmode = NL80211_IFTYPE_STATION;
                break;
        case NL80211_IFTYPE_ADHOC:
 +              if (sc->nbcnvifs >= ATH_BCBUF) {
 +                      ret = -ENOBUFS;
 +                      goto out;
 +              }
                ic_opmode = NL80211_IFTYPE_ADHOC;
                break;
        case NL80211_IFTYPE_AP:
 +              if (sc->nbcnvifs >= ATH_BCBUF) {
 +                      ret = -ENOBUFS;
 +                      goto out;
 +              }
                ic_opmode = NL80211_IFTYPE_AP;
                break;
        default:
                DPRINTF(sc, ATH_DBG_FATAL,
                        "Interface type %d not yet supported\n", conf->type);
 -              return -EOPNOTSUPP;
 +              ret = -EOPNOTSUPP;
 +              goto out;
        }
  
 -      DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VAP of type: %d\n", ic_opmode);
 +      DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", ic_opmode);
  
 -      /* Set the VAP opmode */
 +      /* Set the VIF opmode */
        avp->av_opmode = ic_opmode;
        avp->av_bslot = -1;
  
 -      if (ic_opmode == NL80211_IFTYPE_AP)
 -              ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
 +      sc->nvifs++;
  
 -      sc->sc_vaps[0] = conf->vif;
 -      sc->sc_nvaps++;
 +      if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
 +              ath9k_set_bssid_mask(hw);
 +
 +      if (sc->nvifs > 1)
 +              goto out; /* skip global settings for secondary vif */
 +
 +      if (ic_opmode == NL80211_IFTYPE_AP) {
 +              ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
 +              sc->sc_flags |= SC_OP_TSF_RESET;
 +      }
  
        /* Set the device opmode */
 -      sc->sc_ah->ah_opmode = ic_opmode;
 +      sc->sc_ah->opmode = ic_opmode;
 +
 +      /*
 +       * Enable MIB interrupts when there are hardware phy counters.
 +       * Note we only do this (at the moment) for station mode.
 +       */
 +      if ((conf->type == NL80211_IFTYPE_STATION) ||
 +          (conf->type == NL80211_IFTYPE_ADHOC)) {
 +              if (ath9k_hw_phycounters(sc->sc_ah))
 +                      sc->imask |= ATH9K_INT_MIB;
 +              sc->imask |= ATH9K_INT_TSFOOR;
 +      }
 +
 +      /*
 +       * Some hardware processes the TIM IE and fires an
 +       * interrupt when the TIM bit is set.  For hardware
 +       * that does, if not overridden by configuration,
 +       * enable the TIM interrupt when operating as station.
 +       */
 +      if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
 +          (conf->type == NL80211_IFTYPE_STATION) &&
 +          !sc->config.swBeaconProcess)
 +              sc->imask |= ATH9K_INT_TIM;
 +
 +      ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
  
        if (conf->type == NL80211_IFTYPE_AP) {
                /* TODO: is this a suitable place to start ANI for AP mode? */
                /* Start ANI */
 -              mod_timer(&sc->sc_ani.timer,
 +              mod_timer(&sc->ani.timer,
                          jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
        }
  
 -      return 0;
 +out:
 +      mutex_unlock(&sc->mutex);
 +      return ret;
  }
  
  static void ath9k_remove_interface(struct ieee80211_hw *hw,
                                   struct ieee80211_if_init_conf *conf)
  {
 -      struct ath_softc *sc = hw->priv;
 -      struct ath_vap *avp = (void *)conf->vif->drv_priv;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
 +      struct ath_vif *avp = (void *)conf->vif->drv_priv;
 +      int i;
  
        DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n");
  
 +      mutex_lock(&sc->mutex);
 +
        /* Stop ANI */
 -      del_timer_sync(&sc->sc_ani.timer);
 +      del_timer_sync(&sc->ani.timer);
  
        /* Reclaim beacon resources */
 -      if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP ||
 -          sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) {
 +      if (sc->sc_ah->opmode == NL80211_IFTYPE_AP ||
 +          sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) {
                ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
                ath_beacon_return(sc, avp);
        }
  
        sc->sc_flags &= ~SC_OP_BEACONS;
  
 -      sc->sc_vaps[0] = NULL;
 -      sc->sc_nvaps--;
 +      for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
 +              if (sc->beacon.bslot[i] == conf->vif) {
 +                      printk(KERN_DEBUG "%s: vif had allocated beacon "
 +                             "slot\n", __func__);
 +                      sc->beacon.bslot[i] = NULL;
 +                      sc->beacon.bslot_aphy[i] = NULL;
 +              }
 +      }
 +
 +      sc->nvifs--;
 +
 +      mutex_unlock(&sc->mutex);
  }
  
  static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
  {
 -      struct ath_softc *sc = hw->priv;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
        struct ieee80211_conf *conf = &hw->conf;
  
        mutex_lock(&sc->mutex);
 -      if (changed & (IEEE80211_CONF_CHANGE_CHANNEL |
 -                     IEEE80211_CONF_CHANGE_HT)) {
 -              struct ieee80211_channel *curchan = hw->conf.channel;
 -              int pos;
  
 -              DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
 -                      curchan->center_freq);
 -
 -              pos = ath_get_channel(sc, curchan);
 -              if (pos == -1) {
 -                      DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n",
 -                              curchan->center_freq);
 -                      mutex_unlock(&sc->mutex);
 -                      return -EINVAL;
 +      if (changed & IEEE80211_CONF_CHANGE_PS) {
 +              if (conf->flags & IEEE80211_CONF_PS) {
 +                      if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
 +                              sc->imask |= ATH9K_INT_TIM_TIMER;
 +                              ath9k_hw_set_interrupts(sc->sc_ah,
 +                                              sc->imask);
 +                      }
 +                      ath9k_hw_setrxabort(sc->sc_ah, 1);
 +                      ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
 +              } else {
 +                      ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
 +                      ath9k_hw_setrxabort(sc->sc_ah, 0);
 +                      sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
 +                      if (sc->imask & ATH9K_INT_TIM_TIMER) {
 +                              sc->imask &= ~ATH9K_INT_TIM_TIMER;
 +                              ath9k_hw_set_interrupts(sc->sc_ah,
 +                                              sc->imask);
 +                      }
                }
 +      }
  
 -              sc->tx_chan_width = ATH9K_HT_MACMODE_20;
 -              sc->sc_ah->ah_channels[pos].chanmode =
 -                      (curchan->band == IEEE80211_BAND_2GHZ) ?
 -                      CHANNEL_G : CHANNEL_A;
 +      if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
 +              struct ieee80211_channel *curchan = hw->conf.channel;
 +              int pos = curchan->hw_value;
  
 -              if (conf->ht.enabled) {
 -                      if (conf->ht.channel_type == NL80211_CHAN_HT40PLUS ||
 -                          conf->ht.channel_type == NL80211_CHAN_HT40MINUS)
 -                              sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
 +              aphy->chan_idx = pos;
 +              aphy->chan_is_ht = conf_is_ht(conf);
  
 -                      sc->sc_ah->ah_channels[pos].chanmode =
 -                              ath_get_extchanmode(sc, curchan,
 -                                                  conf->ht.channel_type);
 +              if (aphy->state == ATH_WIPHY_SCAN ||
 +                  aphy->state == ATH_WIPHY_ACTIVE)
 +                      ath9k_wiphy_pause_all_forced(sc, aphy);
 +              else {
 +                      /*
 +                       * Do not change operational channel based on a paused
 +                       * wiphy changes.
 +                       */
 +                      goto skip_chan_change;
                }
  
 -              ath_update_chainmask(sc, conf->ht.enabled);
 +              DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
 +                      curchan->center_freq);
  
 -              if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) {
 +              /* XXX: remove me eventualy */
 +              ath9k_update_ichannel(sc, hw, &sc->sc_ah->channels[pos]);
 +
 +              ath_update_chainmask(sc, conf_is_ht(conf));
 +
 +              if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
                        DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n");
                        mutex_unlock(&sc->mutex);
                        return -EINVAL;
                }
        }
  
 +skip_chan_change:
        if (changed & IEEE80211_CONF_CHANGE_POWER)
 -              sc->sc_config.txpowlimit = 2 * conf->power_level;
 +              sc->config.txpowlimit = 2 * conf->power_level;
 +
 +      /*
 +       * The HW TSF has to be reset when the beacon interval changes.
 +       * We set the flag here, and ath_beacon_config_ap() would take this
 +       * into account when it gets called through the subsequent
 +       * config_interface() call - with IFCC_BEACON in the changed field.
 +       */
 +
 +      if (changed & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
 +              sc->sc_flags |= SC_OP_TSF_RESET;
  
        mutex_unlock(&sc->mutex);
 +
        return 0;
  }
  
@@@ -2400,24 -2195,19 +2401,24 @@@ static int ath9k_config_interface(struc
                                  struct ieee80211_vif *vif,
                                  struct ieee80211_if_conf *conf)
  {
 -      struct ath_softc *sc = hw->priv;
 -      struct ath_hal *ah = sc->sc_ah;
 -      struct ath_vap *avp = (void *)vif->drv_priv;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
 +      struct ath_hw *ah = sc->sc_ah;
 +      struct ath_vif *avp = (void *)vif->drv_priv;
        u32 rfilt = 0;
        int error, i;
  
 +      mutex_lock(&sc->mutex);
 +
        /* TODO: Need to decide which hw opmode to use for multi-interface
         * cases */
        if (vif->type == NL80211_IFTYPE_AP &&
 -          ah->ah_opmode != NL80211_IFTYPE_AP) {
 -              ah->ah_opmode = NL80211_IFTYPE_STATION;
 +          ah->opmode != NL80211_IFTYPE_AP) {
 +              ah->opmode = NL80211_IFTYPE_STATION;
                ath9k_hw_setopmode(ah);
 -              ath9k_hw_write_associd(ah, sc->sc_myaddr, 0);
 +              memcpy(sc->curbssid, sc->sc_ah->macaddr, ETH_ALEN);
 +              sc->curaid = 0;
 +              ath9k_hw_write_associd(sc);
                /* Request full reset to get hw opmode changed properly */
                sc->sc_flags |= SC_OP_FULL_RESET;
        }
                case NL80211_IFTYPE_STATION:
                case NL80211_IFTYPE_ADHOC:
                        /* Set BSSID */
 -                      memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN);
 -                      sc->sc_curaid = 0;
 -                      ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid,
 -                                             sc->sc_curaid);
 +                      memcpy(sc->curbssid, conf->bssid, ETH_ALEN);
 +                      memcpy(avp->bssid, conf->bssid, ETH_ALEN);
 +                      sc->curaid = 0;
 +                      ath9k_hw_write_associd(sc);
  
                        /* Set aggregation protection mode parameters */
 -                      sc->sc_config.ath_aggr_prot = 0;
 +                      sc->config.ath_aggr_prot = 0;
  
                        DPRINTF(sc, ATH_DBG_CONFIG,
                                "RX filter 0x%x bssid %pM aid 0x%x\n",
 -                              rfilt, sc->sc_curbssid, sc->sc_curaid);
 +                              rfilt, sc->curbssid, sc->curaid);
  
                        /* need to reconfigure the beacon */
                        sc->sc_flags &= ~SC_OP_BEACONS ;
                }
        }
  
 -      if ((conf->changed & IEEE80211_IFCC_BEACON) &&
 -          ((vif->type == NL80211_IFTYPE_ADHOC) ||
 -           (vif->type == NL80211_IFTYPE_AP))) {
 -              /*
 -               * Allocate and setup the beacon frame.
 -               *
 -               * Stop any previous beacon DMA.  This may be
 -               * necessary, for example, when an ibss merge
 -               * causes reconfiguration; we may be called
 -               * with beacon transmission active.
 -               */
 -              ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
 +      if ((vif->type == NL80211_IFTYPE_ADHOC) ||
 +          (vif->type == NL80211_IFTYPE_AP)) {
 +              if ((conf->changed & IEEE80211_IFCC_BEACON) ||
 +                  (conf->changed & IEEE80211_IFCC_BEACON_ENABLED &&
 +                   conf->enable_beacon)) {
 +                      /*
 +                       * Allocate and setup the beacon frame.
 +                       *
 +                       * Stop any previous beacon DMA.  This may be
 +                       * necessary, for example, when an ibss merge
 +                       * causes reconfiguration; we may be called
 +                       * with beacon transmission active.
 +                       */
 +                      ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
  
 -              error = ath_beacon_alloc(sc, 0);
 -              if (error != 0)
 -                      return error;
 +                      error = ath_beacon_alloc(aphy, vif);
 +                      if (error != 0) {
 +                              mutex_unlock(&sc->mutex);
 +                              return error;
 +                      }
  
 -              ath_beacon_sync(sc, 0);
 +                      ath_beacon_config(sc, vif);
 +              }
        }
  
        /* Check for WLAN_CAPABILITY_PRIVACY ? */
                        if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i))
                                ath9k_hw_keysetmac(sc->sc_ah,
                                                   (u16)i,
 -                                                 sc->sc_curbssid);
 +                                                 sc->curbssid);
        }
  
        /* Only legacy IBSS for now */
        if (vif->type == NL80211_IFTYPE_ADHOC)
                ath_update_chainmask(sc, 0);
  
 +      mutex_unlock(&sc->mutex);
 +
        return 0;
  }
  
@@@ -2507,8 -2290,7 +2508,8 @@@ static void ath9k_configure_filter(stru
                                   int mc_count,
                                   struct dev_mc_list *mclist)
  {
 -      struct ath_softc *sc = hw->priv;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
        u32 rfilt;
  
        changed_flags &= SUPPORTED_FILTERS;
        rfilt = ath_calcrxfilter(sc);
        ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
  
 -      if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
 -              if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
 -                      ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0);
 -      }
 -
        DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter);
  }
  
@@@ -2526,8 -2313,7 +2527,8 @@@ static void ath9k_sta_notify(struct iee
                             enum sta_notify_cmd cmd,
                             struct ieee80211_sta *sta)
  {
 -      struct ath_softc *sc = hw->priv;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
  
        switch (cmd) {
        case STA_NOTIFY_ADD:
        }
  }
  
 -static int ath9k_conf_tx(struct ieee80211_hw *hw,
 -                       u16 queue,
 +static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
                         const struct ieee80211_tx_queue_params *params)
  {
 -      struct ath_softc *sc = hw->priv;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
        struct ath9k_tx_queue_info qi;
        int ret = 0, qnum;
  
        if (queue >= WME_NUM_AC)
                return 0;
  
 +      mutex_lock(&sc->mutex);
 +
        qi.tqi_aifs = params->aifs;
        qi.tqi_cwmin = params->cw_min;
        qi.tqi_cwmax = params->cw_max;
        if (ret)
                DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n");
  
 +      mutex_unlock(&sc->mutex);
 +
        return ret;
  }
  
  static int ath9k_set_key(struct ieee80211_hw *hw,
                         enum set_key_cmd cmd,
 -                       const u8 *local_addr,
 -                       const u8 *addr,
 +                       struct ieee80211_vif *vif,
 +                       struct ieee80211_sta *sta,
                         struct ieee80211_key_conf *key)
  {
 -      struct ath_softc *sc = hw->priv;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
        int ret = 0;
  
 +      if (modparam_nohwcrypt)
 +              return -ENOSPC;
 +
 +      mutex_lock(&sc->mutex);
 +      ath9k_ps_wakeup(sc);
        DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n");
  
        switch (cmd) {
        case SET_KEY:
 -              ret = ath_key_config(sc, addr, key);
 +              ret = ath_key_config(sc, vif, sta, key);
                if (ret >= 0) {
                        key->hw_key_idx = ret;
                        /* push IV and Michael MIC generation to stack */
                        key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
                        if (key->alg == ALG_TKIP)
                                key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
 +                      if (sc->sc_ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
 +                              key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
                        ret = 0;
                }
                break;
                ret = -EINVAL;
        }
  
 +      ath9k_ps_restore(sc);
 +      mutex_unlock(&sc->mutex);
 +
        return ret;
  }
  
@@@ -2624,10 -2395,7 +2625,10 @@@ static void ath9k_bss_info_changed(stru
                                   struct ieee80211_bss_conf *bss_conf,
                                   u32 changed)
  {
 -      struct ath_softc *sc = hw->priv;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
 +
 +      mutex_lock(&sc->mutex);
  
        if (changed & BSS_CHANGED_ERP_PREAMBLE) {
                DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
                        bss_conf->assoc);
                ath9k_bss_assoc_info(sc, vif, bss_conf);
        }
 +
 +      mutex_unlock(&sc->mutex);
  }
  
  static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
  {
        u64 tsf;
 -      struct ath_softc *sc = hw->priv;
 -      struct ath_hal *ah = sc->sc_ah;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
  
 -      tsf = ath9k_hw_gettsf64(ah);
 +      mutex_lock(&sc->mutex);
 +      tsf = ath9k_hw_gettsf64(sc->sc_ah);
 +      mutex_unlock(&sc->mutex);
  
        return tsf;
  }
  
 +static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
 +{
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
 +
 +      mutex_lock(&sc->mutex);
 +      ath9k_hw_settsf64(sc->sc_ah, tsf);
 +      mutex_unlock(&sc->mutex);
 +}
 +
  static void ath9k_reset_tsf(struct ieee80211_hw *hw)
  {
 -      struct ath_softc *sc = hw->priv;
 -      struct ath_hal *ah = sc->sc_ah;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
  
 -      ath9k_hw_reset_tsf(ah);
 +      mutex_lock(&sc->mutex);
 +      ath9k_hw_reset_tsf(sc->sc_ah);
 +      mutex_unlock(&sc->mutex);
  }
  
  static int ath9k_ampdu_action(struct ieee80211_hw *hw,
 -                     enum ieee80211_ampdu_mlme_action action,
 -                     struct ieee80211_sta *sta,
 -                     u16 tid, u16 *ssn)
 +                            enum ieee80211_ampdu_mlme_action action,
 +                            struct ieee80211_sta *sta,
 +                            u16 tid, u16 *ssn)
  {
 -      struct ath_softc *sc = hw->priv;
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
        int ret = 0;
  
        switch (action) {
        return ret;
  }
  
 -static struct ieee80211_ops ath9k_ops = {
 +static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
 +{
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
 +
 +      if (ath9k_wiphy_scanning(sc)) {
 +              printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the "
 +                     "same time\n");
 +              /*
 +               * Do not allow the concurrent scanning state for now. This
 +               * could be improved with scanning control moved into ath9k.
 +               */
 +              return;
 +      }
 +
 +      aphy->state = ATH_WIPHY_SCAN;
 +      ath9k_wiphy_pause_all_forced(sc, aphy);
 +
 +      mutex_lock(&sc->mutex);
 +      sc->sc_flags |= SC_OP_SCANNING;
 +      mutex_unlock(&sc->mutex);
 +}
 +
 +static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
 +{
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
 +
 +      mutex_lock(&sc->mutex);
 +      aphy->state = ATH_WIPHY_ACTIVE;
 +      sc->sc_flags &= ~SC_OP_SCANNING;
 +      mutex_unlock(&sc->mutex);
 +}
 +
 +struct ieee80211_ops ath9k_ops = {
        .tx                 = ath9k_tx,
        .start              = ath9k_start,
        .stop               = ath9k_stop,
        .bss_info_changed   = ath9k_bss_info_changed,
        .set_key            = ath9k_set_key,
        .get_tsf            = ath9k_get_tsf,
 +      .set_tsf            = ath9k_set_tsf,
        .reset_tsf          = ath9k_reset_tsf,
        .ampdu_action       = ath9k_ampdu_action,
 +      .sw_scan_start      = ath9k_sw_scan_start,
 +      .sw_scan_complete   = ath9k_sw_scan_complete,
  };
  
  static struct {
@@@ -2813,7 -2527,7 +2814,7 @@@ static struct 
  /*
   * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown.
   */
 -static const char *
 +const char *
  ath_mac_bb_name(u32 mac_bb_version)
  {
        int i;
  /*
   * Return the RF name. "????" is returned if the RF is unknown.
   */
 -static const char *
 +const char *
  ath_rf_name(u16 rf_version)
  {
        int i;
        return "????";
  }
  
 -static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 -{
 -      void __iomem *mem;
 -      struct ath_softc *sc;
 -      struct ieee80211_hw *hw;
 -      u8 csz;
 -      u32 val;
 -      int ret = 0;
 -      struct ath_hal *ah;
 -
 -      if (pci_enable_device(pdev))
 -              return -EIO;
 -
 -      ret =  pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 -
 -      if (ret) {
 -              printk(KERN_ERR "ath9k: 32-bit DMA not available\n");
 -              goto bad;
 -      }
 -
 -      ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
 -
 -      if (ret) {
 -              printk(KERN_ERR "ath9k: 32-bit DMA consistent "
 -                      "DMA enable failed\n");
 -              goto bad;
 -      }
 -
 -      /*
 -       * Cache line size is used to size and align various
 -       * structures used to communicate with the hardware.
 -       */
 -      pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
 -      if (csz == 0) {
 -              /*
 -               * Linux 2.4.18 (at least) writes the cache line size
 -               * register as a 16-bit wide register which is wrong.
 -               * We must have this setup properly for rx buffer
 -               * DMA to work so force a reasonable value here if it
 -               * comes up zero.
 -               */
 -              csz = L1_CACHE_BYTES / sizeof(u32);
 -              pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
 -      }
 -      /*
 -       * The default setting of latency timer yields poor results,
 -       * set it to the value used by other systems. It may be worth
 -       * tweaking this setting more.
 -       */
 -      pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
 -
 -      pci_set_master(pdev);
 -
 -      /*
 -       * Disable the RETRY_TIMEOUT register (0x41) to keep
 -       * PCI Tx retries from interfering with C3 CPU state.
 -       */
 -      pci_read_config_dword(pdev, 0x40, &val);
 -      if ((val & 0x0000ff00) != 0)
 -              pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
 -
 -      ret = pci_request_region(pdev, 0, "ath9k");
 -      if (ret) {
 -              dev_err(&pdev->dev, "PCI memory region reserve error\n");
 -              ret = -ENODEV;
 -              goto bad;
 -      }
 -
 -      mem = pci_iomap(pdev, 0, 0);
 -      if (!mem) {
 -              printk(KERN_ERR "PCI memory map error\n") ;
 -              ret = -EIO;
 -              goto bad1;
 -      }
 -
 -      hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
 -      if (hw == NULL) {
 -              printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n");
 -              goto bad2;
 -      }
 -
 -      SET_IEEE80211_DEV(hw, &pdev->dev);
 -      pci_set_drvdata(pdev, hw);
 -
 -      sc = hw->priv;
 -      sc->hw = hw;
 -      sc->pdev = pdev;
 -      sc->mem = mem;
 -
 -      if (ath_attach(id->device, sc) != 0) {
 -              ret = -ENODEV;
 -              goto bad3;
 -      }
 -
 -      /* setup interrupt service routine */
 -
 -      if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) {
 -              printk(KERN_ERR "%s: request_irq failed\n",
 -                      wiphy_name(hw->wiphy));
 -              ret = -EIO;
 -              goto bad4;
 -      }
 -
 -      ah = sc->sc_ah;
 -      printk(KERN_INFO
 -             "%s: Atheros AR%s MAC/BB Rev:%x "
 -             "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n",
 -             wiphy_name(hw->wiphy),
 -             ath_mac_bb_name(ah->ah_macVersion),
 -             ah->ah_macRev,
 -             ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)),
 -             ah->ah_phyRev,
 -             (unsigned long)mem, pdev->irq);
 -
 -      return 0;
 -bad4:
 -      ath_detach(sc);
 -bad3:
 -      ieee80211_free_hw(hw);
 -bad2:
 -      pci_iounmap(pdev, mem);
 -bad1:
 -      pci_release_region(pdev, 0);
 -bad:
 -      pci_disable_device(pdev);
 -      return ret;
 -}
 -
 -static void ath_pci_remove(struct pci_dev *pdev)
 -{
 -      struct ieee80211_hw *hw = pci_get_drvdata(pdev);
 -      struct ath_softc *sc = hw->priv;
 -
 -      ath_detach(sc);
 -      if (pdev->irq)
 -              free_irq(pdev->irq, sc);
 -      pci_iounmap(pdev, sc->mem);
 -      pci_release_region(pdev, 0);
 -      pci_disable_device(pdev);
 -      ieee80211_free_hw(hw);
 -}
 -
 -#ifdef CONFIG_PM
 -
 -static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 -{
 -      struct ieee80211_hw *hw = pci_get_drvdata(pdev);
 -      struct ath_softc *sc = hw->priv;
 -
 -      ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
 -
 -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 -      if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 -              cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
 -#endif
 -
 -      pci_save_state(pdev);
 -      pci_disable_device(pdev);
 -      pci_set_power_state(pdev, 3);
 -
 -      return 0;
 -}
 -
 -static int ath_pci_resume(struct pci_dev *pdev)
 -{
 -      struct ieee80211_hw *hw = pci_get_drvdata(pdev);
 -      struct ath_softc *sc = hw->priv;
 -      u32 val;
 -      int err;
 -
 -      err = pci_enable_device(pdev);
 -      if (err)
 -              return err;
 -      pci_restore_state(pdev);
 -      /*
 -       * Suspend/Resume resets the PCI configuration space, so we have to
 -       * re-disable the RETRY_TIMEOUT register (0x41) to keep
 -       * PCI Tx retries from interfering with C3 CPU state
 -       */
 -      pci_read_config_dword(pdev, 0x40, &val);
 -      if ((val & 0x0000ff00) != 0)
 -              pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
 -
 -      /* Enable LED */
 -      ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
 -                          AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 -      ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
 -
 -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 -      /*
 -       * check the h/w rfkill state on resume
 -       * and start the rfkill poll timer
 -       */
 -      if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 -              queue_delayed_work(sc->hw->workqueue,
 -                                 &sc->rf_kill.rfkill_poll, 0);
 -#endif
 -
 -      return 0;
 -}
 -
 -#endif /* CONFIG_PM */
 -
 -MODULE_DEVICE_TABLE(pci, ath_pci_id_table);
 -
 -static struct pci_driver ath_pci_driver = {
 -      .name       = "ath9k",
 -      .id_table   = ath_pci_id_table,
 -      .probe      = ath_pci_probe,
 -      .remove     = ath_pci_remove,
 -#ifdef CONFIG_PM
 -      .suspend    = ath_pci_suspend,
 -      .resume     = ath_pci_resume,
 -#endif /* CONFIG_PM */
 -};
 -
 -static int __init init_ath_pci(void)
 +static int __init ath9k_init(void)
  {
        int error;
  
 -      printk(KERN_INFO "%s: %s\n", dev_info, ATH_PCI_VERSION);
 -
        /* Register rate control algorithm */
        error = ath_rate_control_register();
        if (error != 0) {
                printk(KERN_ERR
 -                      "Unable to register rate control algorithm: %d\n",
 +                      "ath9k: Unable to register rate control "
 +                      "algorithm: %d\n",
                        error);
 -              ath_rate_control_unregister();
 -              return error;
 +              goto err_out;
        }
  
 -      if (pci_register_driver(&ath_pci_driver) < 0) {
 +      error = ath_pci_init();
 +      if (error < 0) {
                printk(KERN_ERR
 -                      "ath_pci: No devices found, driver not installed.\n");
 -              ath_rate_control_unregister();
 -              pci_unregister_driver(&ath_pci_driver);
 -              return -ENODEV;
 +                      "ath9k: No PCI devices found, driver not installed.\n");
 +              error = -ENODEV;
 +              goto err_rate_unregister;
 +      }
 +
 +      error = ath_ahb_init();
 +      if (error < 0) {
 +              error = -ENODEV;
 +              goto err_pci_exit;
        }
  
        return 0;
 +
 + err_pci_exit:
 +      ath_pci_exit();
 +
 + err_rate_unregister:
 +      ath_rate_control_unregister();
 + err_out:
 +      return error;
  }
 -module_init(init_ath_pci);
 +module_init(ath9k_init);
  
 -static void __exit exit_ath_pci(void)
 +static void __exit ath9k_exit(void)
  {
 +      ath_ahb_exit();
 +      ath_pci_exit();
        ath_rate_control_unregister();
 -      pci_unregister_driver(&ath_pci_driver);
        printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
  }
 -module_exit(exit_ath_pci);
 +module_exit(ath9k_exit);
index 0b01ff036aacf06a40c51731a7e6e6bf3e79355a,847057d682b1cbdff95ca775c2d656083d53d0cd..c3a51266de209c7ad6c47e559f54612ee5dc6d2e
@@@ -170,10 -170,10 +170,10 @@@ int zd_mac_init_hw(struct ieee80211_hw 
                goto disable_int;
  
        r = zd_reg2alpha2(mac->regdomain, alpha2);
 -      if (!r)
 -              regulatory_hint(hw->wiphy, alpha2);
 +      if (r)
 +              goto disable_int;
  
 -      r = 0;
 +      r = regulatory_hint(hw->wiphy, alpha2);
  disable_int:
        zd_chip_disable_int(chip);
  out:
@@@ -575,13 -575,17 +575,17 @@@ static int zd_op_tx(struct ieee80211_h
  
        r = fill_ctrlset(mac, skb);
        if (r)
-               return r;
+               goto fail;
  
        info->rate_driver_data[0] = hw;
  
        r = zd_usb_tx(&mac->chip.usb, skb);
        if (r)
-               return r;
+               goto fail;
+       return 0;
+ fail:
+       dev_kfree_skb(skb);
        return 0;
  }
  
@@@ -768,23 -772,13 +772,23 @@@ static int zd_op_config_interface(struc
                        if (!beacon)
                                return -ENOMEM;
                        r = zd_mac_config_beacon(hw, beacon);
 +                      kfree_skb(beacon);
 +
                        if (r < 0)
                                return r;
 -                      r = zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
 -                                      hw->conf.beacon_int);
 +              }
 +
 +              if (conf->changed & IEEE80211_IFCC_BEACON_ENABLED) {
 +                      u32 interval;
 +
 +                      if (conf->enable_beacon)
 +                              interval = BCN_MODE_IBSS | hw->conf.beacon_int;
 +                      else
 +                              interval = 0;
 +
 +                      r = zd_set_beacon_interval(&mac->chip, interval);
                        if (r < 0)
                                return r;
 -                      kfree_skb(beacon);
                }
        } else
                associated = is_valid_ether_addr(conf->bssid);
@@@ -803,9 -797,10 +807,9 @@@ static void zd_process_intr(struct work
        struct zd_mac *mac = container_of(work, struct zd_mac, process_intr);
  
        int_status = le16_to_cpu(*(__le16 *)(mac->intr_buffer+4));
 -      if (int_status & INT_CFG_NEXT_BCN) {
 -              if (net_ratelimit())
 -                      dev_dbg_f(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");
 -      } else
 +      if (int_status & INT_CFG_NEXT_BCN)
 +              dev_dbg_f_limit(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");
 +      else
                dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n");
  
        zd_chip_enable_hwint(&mac->chip);
@@@ -935,12 -930,6 +939,12 @@@ static void zd_op_bss_info_changed(stru
        }
  }
  
 +static u64 zd_op_get_tsf(struct ieee80211_hw *hw)
 +{
 +      struct zd_mac *mac = zd_hw_mac(hw);
 +      return zd_chip_get_tsf(&mac->chip);
 +}
 +
  static const struct ieee80211_ops zd_ops = {
        .tx                     = zd_op_tx,
        .start                  = zd_op_start,
        .config_interface       = zd_op_config_interface,
        .configure_filter       = zd_op_configure_filter,
        .bss_info_changed       = zd_op_bss_info_changed,
 +      .get_tsf                = zd_op_get_tsf,
  };
  
  struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
        hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band;
  
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
 -                  IEEE80211_HW_SIGNAL_DB;
 +                  IEEE80211_HW_SIGNAL_UNSPEC;
  
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_MESH_POINT) |
diff --combined net/core/dev.c
index 7bd3c29c5a785992d49088d232456876aae3e3e6,2565f6d1d66198abff8a73c7097f19b09e908cc8..c0130312911937c54feb3dae8ef8039cd0e563a0
@@@ -1668,7 -1668,6 +1668,7 @@@ int dev_hard_start_xmit(struct sk_buff 
                        struct netdev_queue *txq)
  {
        const struct net_device_ops *ops = dev->netdev_ops;
 +      int rc;
  
        prefetch(&dev->netdev_ops->ndo_start_xmit);
        if (likely(!skb->next)) {
                                goto gso;
                }
  
 -              return ops->ndo_start_xmit(skb, dev);
 +              rc = ops->ndo_start_xmit(skb, dev);
 +              /*
 +               * TODO: if skb_orphan() was called by
 +               * dev->hard_start_xmit() (for example, the unmodified
 +               * igb driver does that; bnx2 doesn't), then
 +               * skb_tx_software_timestamp() will be unable to send
 +               * back the time stamp.
 +               *
 +               * How can this be prevented? Always create another
 +               * reference to the socket before calling
 +               * dev->hard_start_xmit()? Prevent that skb_orphan()
 +               * does anything in dev->hard_start_xmit() by clearing
 +               * the skb destructor before the call and restoring it
 +               * afterwards, then doing the skb_orphan() ourselves?
 +               */
 +              return rc;
        }
  
  gso:
        do {
                struct sk_buff *nskb = skb->next;
 -              int rc;
  
                skb->next = nskb->next;
                nskb->next = NULL;
@@@ -1723,20 -1708,56 +1723,20 @@@ out_kfree_skb
        return 0;
  }
  
 -static u32 simple_tx_hashrnd;
 -static int simple_tx_hashrnd_initialized = 0;
 +static u32 skb_tx_hashrnd;
  
 -static u16 simple_tx_hash(struct net_device *dev, struct sk_buff *skb)
 +static u16 skb_tx_hash(struct net_device *dev, struct sk_buff *skb)
  {
 -      u32 addr1, addr2, ports;
 -      u32 hash, ihl;
 -      u8 ip_proto = 0;
 -
 -      if (unlikely(!simple_tx_hashrnd_initialized)) {
 -              get_random_bytes(&simple_tx_hashrnd, 4);
 -              simple_tx_hashrnd_initialized = 1;
 -      }
 -
 -      switch (skb->protocol) {
 -      case htons(ETH_P_IP):
 -              if (!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)))
 -                      ip_proto = ip_hdr(skb)->protocol;
 -              addr1 = ip_hdr(skb)->saddr;
 -              addr2 = ip_hdr(skb)->daddr;
 -              ihl = ip_hdr(skb)->ihl;
 -              break;
 -      case htons(ETH_P_IPV6):
 -              ip_proto = ipv6_hdr(skb)->nexthdr;
 -              addr1 = ipv6_hdr(skb)->saddr.s6_addr32[3];
 -              addr2 = ipv6_hdr(skb)->daddr.s6_addr32[3];
 -              ihl = (40 >> 2);
 -              break;
 -      default:
 -              return 0;
 -      }
 -
 +      u32 hash;
  
 -      switch (ip_proto) {
 -      case IPPROTO_TCP:
 -      case IPPROTO_UDP:
 -      case IPPROTO_DCCP:
 -      case IPPROTO_ESP:
 -      case IPPROTO_AH:
 -      case IPPROTO_SCTP:
 -      case IPPROTO_UDPLITE:
 -              ports = *((u32 *) (skb_network_header(skb) + (ihl * 4)));
 -              break;
 -
 -      default:
 -              ports = 0;
 -              break;
 -      }
 +      if (skb_rx_queue_recorded(skb)) {
 +              hash = skb_get_rx_queue(skb);
 +      } else if (skb->sk && skb->sk->sk_hash) {
 +              hash = skb->sk->sk_hash;
 +      } else
 +              hash = skb->protocol;
  
 -      hash = jhash_3words(addr1, addr2, ports, simple_tx_hashrnd);
 +      hash = jhash_1word(hash, skb_tx_hashrnd);
  
        return (u16) (((u64) hash * dev->real_num_tx_queues) >> 32);
  }
@@@ -1750,7 -1771,7 +1750,7 @@@ static struct netdev_queue *dev_pick_tx
        if (ops->ndo_select_queue)
                queue_index = ops->ndo_select_queue(dev, skb);
        else if (dev->real_num_tx_queues > 1)
 -              queue_index = simple_tx_hash(dev, skb);
 +              queue_index = skb_tx_hash(dev, skb);
  
        skb_set_queue_mapping(skb, queue_index);
        return netdev_get_tx_queue(dev, queue_index);
@@@ -2276,8 -2297,6 +2276,8 @@@ ncls
        if (!skb)
                goto out;
  
 +      skb_orphan(skb);
 +
        type = skb->protocol;
        list_for_each_entry_rcu(ptype,
                        &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
@@@ -2347,6 -2366,7 +2347,6 @@@ static int napi_gro_complete(struct sk_
  
  out:
        skb_shinfo(skb)->gso_size = 0;
 -      __skb_push(skb, -skb_network_offset(skb));
        return netif_receive_skb(skb);
  }
  
@@@ -2360,40 -2380,20 +2360,40 @@@ void napi_gro_flush(struct napi_struct 
                napi_gro_complete(skb);
        }
  
 +      napi->gro_count = 0;
        napi->gro_list = NULL;
  }
  EXPORT_SYMBOL(napi_gro_flush);
  
 +void *skb_gro_header(struct sk_buff *skb, unsigned int hlen)
 +{
 +      unsigned int offset = skb_gro_offset(skb);
 +
 +      hlen += offset;
 +      if (hlen <= skb_headlen(skb))
 +              return skb->data + offset;
 +
 +      if (unlikely(!skb_shinfo(skb)->nr_frags ||
 +                   skb_shinfo(skb)->frags[0].size <=
 +                   hlen - skb_headlen(skb) ||
 +                   PageHighMem(skb_shinfo(skb)->frags[0].page)))
 +              return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL;
 +
 +      return page_address(skb_shinfo(skb)->frags[0].page) +
 +             skb_shinfo(skb)->frags[0].page_offset +
 +             offset - skb_headlen(skb);
 +}
 +EXPORT_SYMBOL(skb_gro_header);
 +
  int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
  {
        struct sk_buff **pp = NULL;
        struct packet_type *ptype;
        __be16 type = skb->protocol;
        struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK];
 -      int count = 0;
        int same_flow;
        int mac_len;
 -      int free;
 +      int ret;
  
        if (!(skb->dev->features & NETIF_F_GRO))
                goto normal;
  
        rcu_read_lock();
        list_for_each_entry_rcu(ptype, head, list) {
 -              struct sk_buff *p;
 -
                if (ptype->type != type || ptype->dev || !ptype->gro_receive)
                        continue;
  
 -              skb_reset_network_header(skb);
 +              skb_set_network_header(skb, skb_gro_offset(skb));
                mac_len = skb->network_header - skb->mac_header;
                skb->mac_len = mac_len;
                NAPI_GRO_CB(skb)->same_flow = 0;
                NAPI_GRO_CB(skb)->flush = 0;
                NAPI_GRO_CB(skb)->free = 0;
  
 -              for (p = napi->gro_list; p; p = p->next) {
 -                      count++;
 -
 -                      if (!NAPI_GRO_CB(p)->same_flow)
 -                              continue;
 -
 -                      if (p->mac_len != mac_len ||
 -                          memcmp(skb_mac_header(p), skb_mac_header(skb),
 -                                 mac_len))
 -                              NAPI_GRO_CB(p)->same_flow = 0;
 -              }
 -
                pp = ptype->gro_receive(&napi->gro_list, skb);
                break;
        }
                goto normal;
  
        same_flow = NAPI_GRO_CB(skb)->same_flow;
 -      free = NAPI_GRO_CB(skb)->free;
 +      ret = NAPI_GRO_CB(skb)->free ? GRO_MERGED_FREE : GRO_MERGED;
  
        if (pp) {
                struct sk_buff *nskb = *pp;
                *pp = nskb->next;
                nskb->next = NULL;
                napi_gro_complete(nskb);
 -              count--;
 +              napi->gro_count--;
        }
  
        if (same_flow)
                goto ok;
  
 -      if (NAPI_GRO_CB(skb)->flush || count >= MAX_GRO_SKBS) {
 -              __skb_push(skb, -skb_network_offset(skb));
 +      if (NAPI_GRO_CB(skb)->flush || napi->gro_count >= MAX_GRO_SKBS)
                goto normal;
 -      }
  
 +      napi->gro_count++;
        NAPI_GRO_CB(skb)->count = 1;
 -      skb_shinfo(skb)->gso_size = skb->len;
 +      skb_shinfo(skb)->gso_size = skb_gro_len(skb);
        skb->next = napi->gro_list;
        napi->gro_list = skb;
 +      ret = GRO_HELD;
 +
 +pull:
 +      if (unlikely(!pskb_may_pull(skb, skb_gro_offset(skb)))) {
 +              if (napi->gro_list == skb)
 +                      napi->gro_list = skb->next;
 +              ret = GRO_DROP;
 +      }
  
  ok:
 -      return free;
 +      return ret;
  
  normal:
 -      return -1;
 +      ret = GRO_NORMAL;
 +      goto pull;
  }
  EXPORT_SYMBOL(dev_gro_receive);
  
@@@ -2466,44 -2472,29 +2466,44 @@@ static int __napi_gro_receive(struct na
  {
        struct sk_buff *p;
  
 +      if (netpoll_rx_on(skb))
 +              return GRO_NORMAL;
 +
        for (p = napi->gro_list; p; p = p->next) {
 -              NAPI_GRO_CB(p)->same_flow = 1;
 +              NAPI_GRO_CB(p)->same_flow = !compare_ether_header(
 +                      skb_mac_header(p), skb_gro_mac_header(skb));
                NAPI_GRO_CB(p)->flush = 0;
        }
  
        return dev_gro_receive(napi, skb);
  }
  
 -int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 +int napi_skb_finish(int ret, struct sk_buff *skb)
  {
 -      if (netpoll_receive_skb(skb))
 -              return NET_RX_DROP;
 +      int err = NET_RX_SUCCESS;
  
 -      switch (__napi_gro_receive(napi, skb)) {
 -      case -1:
 +      switch (ret) {
 +      case GRO_NORMAL:
                return netif_receive_skb(skb);
  
 -      case 1:
 +      case GRO_DROP:
 +              err = NET_RX_DROP;
 +              /* fall through */
 +
 +      case GRO_MERGED_FREE:
                kfree_skb(skb);
                break;
        }
  
 -      return NET_RX_SUCCESS;
 +      return err;
 +}
 +EXPORT_SYMBOL(napi_skb_finish);
 +
 +int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 +{
 +      skb_gro_reset_offset(skb);
 +
 +      return napi_skb_finish(__napi_gro_receive(napi, skb), skb);
  }
  EXPORT_SYMBOL(napi_gro_receive);
  
@@@ -2521,9 -2512,6 +2521,9 @@@ struct sk_buff *napi_fraginfo_skb(struc
  {
        struct net_device *dev = napi->dev;
        struct sk_buff *skb = napi->skb;
 +      struct ethhdr *eth;
 +      skb_frag_t *frag;
 +      int i;
  
        napi->skb = NULL;
  
        }
  
        BUG_ON(info->nr_frags > MAX_SKB_FRAGS);
 +      frag = &info->frags[info->nr_frags - 1];
 +
 +      for (i = skb_shinfo(skb)->nr_frags; i < info->nr_frags; i++) {
 +              skb_fill_page_desc(skb, i, frag->page, frag->page_offset,
 +                                 frag->size);
 +              frag++;
 +      }
        skb_shinfo(skb)->nr_frags = info->nr_frags;
 -      memcpy(skb_shinfo(skb)->frags, info->frags, sizeof(info->frags));
  
        skb->data_len = info->len;
        skb->len += info->len;
        skb->truesize += info->len;
  
 -      if (!pskb_may_pull(skb, ETH_HLEN)) {
 +      skb_reset_mac_header(skb);
 +      skb_gro_reset_offset(skb);
 +
 +      eth = skb_gro_header(skb, sizeof(*eth));
 +      if (!eth) {
                napi_reuse_skb(napi, skb);
                skb = NULL;
                goto out;
        }
  
 -      skb->protocol = eth_type_trans(skb, dev);
 +      skb_gro_pull(skb, sizeof(*eth));
 +
 +      /*
 +       * This works because the only protocols we care about don't require
 +       * special handling.  We'll fix it up properly at the end.
 +       */
 +      skb->protocol = eth->h_proto;
  
        skb->ip_summed = info->ip_summed;
        skb->csum = info->csum;
  }
  EXPORT_SYMBOL(napi_fraginfo_skb);
  
 -int napi_gro_frags(struct napi_struct *napi, struct napi_gro_fraginfo *info)
 +int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret)
  {
 -      struct sk_buff *skb = napi_fraginfo_skb(napi, info);
 -      int err = NET_RX_DROP;
 +      int err = NET_RX_SUCCESS;
  
 -      if (!skb)
 -              goto out;
 +      switch (ret) {
 +      case GRO_NORMAL:
 +      case GRO_HELD:
 +              skb->protocol = eth_type_trans(skb, napi->dev);
  
 -      if (netpoll_receive_skb(skb))
 -              goto out;
 +              if (ret == GRO_NORMAL)
 +                      return netif_receive_skb(skb);
  
 -      err = NET_RX_SUCCESS;
 +              skb_gro_pull(skb, -ETH_HLEN);
 +              break;
  
 -      switch (__napi_gro_receive(napi, skb)) {
 -      case -1:
 -              return netif_receive_skb(skb);
 +      case GRO_DROP:
 +              err = NET_RX_DROP;
 +              /* fall through */
  
 -      case 0:
 -              goto out;
 +      case GRO_MERGED_FREE:
 +              napi_reuse_skb(napi, skb);
 +              break;
        }
  
 -      napi_reuse_skb(napi, skb);
 -
 -out:
        return err;
  }
 +EXPORT_SYMBOL(napi_frags_finish);
 +
 +int napi_gro_frags(struct napi_struct *napi, struct napi_gro_fraginfo *info)
 +{
 +      struct sk_buff *skb = napi_fraginfo_skb(napi, info);
 +
 +      if (!skb)
 +              return NET_RX_DROP;
 +
 +      return napi_frags_finish(napi, skb, __napi_gro_receive(napi, skb));
 +}
  EXPORT_SYMBOL(napi_gro_frags);
  
  static int process_backlog(struct napi_struct *napi, int quota)
                local_irq_disable();
                skb = __skb_dequeue(&queue->input_pkt_queue);
                if (!skb) {
-                       __napi_complete(napi);
                        local_irq_enable();
-                       break;
+                       napi_complete(napi);
+                       goto out;
                }
                local_irq_enable();
  
  
        napi_gro_flush(napi);
  
+ out:
        return work;
  }
  
@@@ -2691,7 -2653,6 +2692,7 @@@ void netif_napi_add(struct net_device *
                    int (*poll)(struct napi_struct *, int), int weight)
  {
        INIT_LIST_HEAD(&napi->poll_list);
 +      napi->gro_count = 0;
        napi->gro_list = NULL;
        napi->skb = NULL;
        napi->poll = poll;
@@@ -2720,7 -2681,6 +2721,7 @@@ void netif_napi_del(struct napi_struct 
        }
  
        napi->gro_list = NULL;
 +      napi->gro_count = 0;
  }
  EXPORT_SYMBOL(netif_napi_del);
  
@@@ -3989,7 -3949,6 +3990,7 @@@ static int dev_ifsioc(struct net *net, 
                            cmd == SIOCSMIIREG ||
                            cmd == SIOCBRADDIF ||
                            cmd == SIOCBRDELIF ||
 +                          cmd == SIOCSHWTSTAMP ||
                            cmd == SIOCWANDEV) {
                                err = -EOPNOTSUPP;
                                if (ops->ndo_do_ioctl) {
@@@ -4144,7 -4103,6 +4145,7 @@@ int dev_ioctl(struct net *net, unsigne
                case SIOCBONDCHANGEACTIVE:
                case SIOCBRADDIF:
                case SIOCBRDELIF:
 +              case SIOCSHWTSTAMP:
                        if (!capable(CAP_NET_ADMIN))
                                return -EPERM;
                        /* fall through */
@@@ -5241,7 -5199,6 +5242,7 @@@ static int __init net_dev_init(void
                queue->backlog.poll = process_backlog;
                queue->backlog.weight = weight_p;
                queue->backlog.gro_list = NULL;
 +              queue->backlog.gro_count = 0;
        }
  
        dev_boot_phase = 0;
  
  subsys_initcall(net_dev_init);
  
 +static int __init initialize_hashrnd(void)
 +{
 +      get_random_bytes(&skb_tx_hashrnd, sizeof(skb_tx_hashrnd));
 +      return 0;
 +}
 +
 +late_initcall_sync(initialize_hashrnd);
 +
  EXPORT_SYMBOL(__dev_get_by_index);
  EXPORT_SYMBOL(__dev_get_by_name);
  EXPORT_SYMBOL(__dev_remove_pack);
diff --combined net/ipv6/af_inet6.c
index 3e2ddfaee81a5b1cd2b5f133db31bce0d43528c2,9c8309ed35cf32351517af43ad647f16442cd9e9..fbf533cc9dcefdfb5b41f001224192518f855855
@@@ -803,34 -803,24 +803,34 @@@ static struct sk_buff **ipv6_gro_receiv
        int proto;
        __wsum csum;
  
 -      if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
 +      iph = skb_gro_header(skb, sizeof(*iph));
 +      if (unlikely(!iph))
                goto out;
  
 -      iph = ipv6_hdr(skb);
 -      __skb_pull(skb, sizeof(*iph));
 +      skb_gro_pull(skb, sizeof(*iph));
 +      skb_set_transport_header(skb, skb_gro_offset(skb));
  
 -      flush += ntohs(iph->payload_len) != skb->len;
 +      flush += ntohs(iph->payload_len) != skb_gro_len(skb);
  
        rcu_read_lock();
 -      proto = ipv6_gso_pull_exthdrs(skb, iph->nexthdr);
 -      iph = ipv6_hdr(skb);
 -      IPV6_GRO_CB(skb)->proto = proto;
 +      proto = iph->nexthdr;
        ops = rcu_dereference(inet6_protos[proto]);
 -      if (!ops || !ops->gro_receive)
 -              goto out_unlock;
 +      if (!ops || !ops->gro_receive) {
 +              __pskb_pull(skb, skb_gro_offset(skb));
 +              proto = ipv6_gso_pull_exthdrs(skb, proto);
 +              skb_gro_pull(skb, -skb_transport_offset(skb));
 +              skb_reset_transport_header(skb);
 +              __skb_push(skb, skb_gro_offset(skb));
 +
 +              if (!ops || !ops->gro_receive)
 +                      goto out_unlock;
 +
 +              iph = ipv6_hdr(skb);
 +      }
 +
 +      IPV6_GRO_CB(skb)->proto = proto;
  
        flush--;
 -      skb_reset_transport_header(skb);
        nlen = skb_network_header_len(skb);
  
        for (p = *head; p; p = p->next) {
@@@ -893,8 -883,8 +893,8 @@@ out_unlock
        return err;
  }
  
 -static struct packet_type ipv6_packet_type = {
 -      .type = __constant_htons(ETH_P_IPV6),
 +static struct packet_type ipv6_packet_type __read_mostly = {
 +      .type = cpu_to_be16(ETH_P_IPV6),
        .func = ipv6_rcv,
        .gso_send_check = ipv6_gso_send_check,
        .gso_segment = ipv6_gso_segment,
@@@ -1202,6 -1192,9 +1202,9 @@@ module_init(inet6_init)
  
  static void __exit inet6_exit(void)
  {
+       if (disable_ipv6)
+               return;
        /* First of all disallow new sockets creation. */
        sock_unregister(PF_INET6);
        /* Disallow any further netlink messages */
diff --combined net/mac80211/tx.c
index c3f0e950125b061fc0c301c431cb1238f830ec09,37e3d5ef7e3f350fe18475295cf3ae3c43dc0526..457238a2f3fc392a087944c7edb5808b2b004c37
@@@ -35,7 -35,6 +35,7 @@@
  #define IEEE80211_TX_OK               0
  #define IEEE80211_TX_AGAIN    1
  #define IEEE80211_TX_FRAG_AGAIN       2
 +#define IEEE80211_TX_PENDING  3
  
  /* misc utils */
  
@@@ -331,22 -330,6 +331,22 @@@ ieee80211_tx_h_multicast_ps_buf(struct 
        return TX_CONTINUE;
  }
  
 +static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta,
 +                           struct sk_buff *skb)
 +{
 +      if (!ieee80211_is_mgmt(fc))
 +              return 0;
 +
 +      if (sta == NULL || !test_sta_flags(sta, WLAN_STA_MFP))
 +              return 0;
 +
 +      if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *)
 +                                          skb->data))
 +              return 0;
 +
 +      return 1;
 +}
 +
  static ieee80211_tx_result
  ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
  {
@@@ -426,17 -409,11 +426,17 @@@ ieee80211_tx_h_select_key(struct ieee80
                tx->key = NULL;
        else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
                tx->key = key;
 +      else if (ieee80211_is_mgmt(hdr->frame_control) &&
 +               (key = rcu_dereference(tx->sdata->default_mgmt_key)))
 +              tx->key = key;
        else if ((key = rcu_dereference(tx->sdata->default_key)))
                tx->key = key;
        else if (tx->sdata->drop_unencrypted &&
                 (tx->skb->protocol != cpu_to_be16(ETH_P_PAE)) &&
 -               !(info->flags & IEEE80211_TX_CTL_INJECTED)) {
 +               !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
 +               (!ieee80211_is_robust_mgmt_frame(hdr) ||
 +                (ieee80211_is_action(hdr->frame_control) &&
 +                 tx->sta && test_sta_flags(tx->sta, WLAN_STA_MFP)))) {
                I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
                return TX_DROP;
        } else
                        if (ieee80211_is_auth(hdr->frame_control))
                                break;
                case ALG_TKIP:
 -              case ALG_CCMP:
                        if (!ieee80211_is_data_present(hdr->frame_control))
                                tx->key = NULL;
                        break;
 +              case ALG_CCMP:
 +                      if (!ieee80211_is_data_present(hdr->frame_control) &&
 +                          !ieee80211_use_mfp(hdr->frame_control, tx->sta,
 +                                             tx->skb))
 +                              tx->key = NULL;
 +                      break;
 +              case ALG_AES_CMAC:
 +                      if (!ieee80211_is_mgmt(hdr->frame_control))
 +                              tx->key = NULL;
 +                      break;
                }
        }
  
@@@ -784,6 -752,8 +784,8 @@@ ieee80211_tx_h_fragment(struct ieee8021
                skb_copy_queue_mapping(frag, first);
  
                frag->do_not_encrypt = first->do_not_encrypt;
+               frag->dev = first->dev;
+               frag->iif = first->iif;
  
                pos += copylen;
                left -= copylen;
@@@ -819,8 -789,6 +821,8 @@@ ieee80211_tx_h_encrypt(struct ieee80211
                return ieee80211_crypto_tkip_encrypt(tx);
        case ALG_CCMP:
                return ieee80211_crypto_ccmp_encrypt(tx);
 +      case ALG_AES_CMAC:
 +              return ieee80211_crypto_aes_cmac_encrypt(tx);
        }
  
        /* not reached */
@@@ -876,6 -844,7 +878,6 @@@ ieee80211_tx_h_stats(struct ieee80211_t
        return TX_CONTINUE;
  }
  
 -
  /* actual transmit path */
  
  /*
@@@ -1015,20 -984,12 +1017,20 @@@ __ieee80211_tx_prepare(struct ieee80211
        tx->sta = sta_info_get(local, hdr->addr1);
  
        if (tx->sta && ieee80211_is_data_qos(hdr->frame_control)) {
 +              unsigned long flags;
                qc = ieee80211_get_qos_ctl(hdr);
                tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
  
 +              spin_lock_irqsave(&tx->sta->lock, flags);
                state = &tx->sta->ampdu_mlme.tid_state_tx[tid];
 -              if (*state == HT_AGG_STATE_OPERATIONAL)
 +              if (*state == HT_AGG_STATE_OPERATIONAL) {
                        info->flags |= IEEE80211_TX_CTL_AMPDU;
 +                      if (local->hw.ampdu_queues)
 +                              skb_set_queue_mapping(
 +                                      skb, tx->local->hw.queues +
 +                                           tx->sta->tid_to_tx_q[tid]);
 +              }
 +              spin_unlock_irqrestore(&tx->sta->lock, flags);
        }
  
        if (is_multicast_ether_addr(hdr->addr1)) {
@@@ -1092,9 -1053,9 +1094,9 @@@ static int __ieee80211_tx(struct ieee80
        int ret, i;
  
        if (skb) {
 -              if (netif_subqueue_stopped(local->mdev, skb))
 -                      return IEEE80211_TX_AGAIN;
 -              info =  IEEE80211_SKB_CB(skb);
 +              if (ieee80211_queue_stopped(&local->hw,
 +                                          skb_get_queue_mapping(skb)))
 +                      return IEEE80211_TX_PENDING;
  
                ret = local->ops->tx(local_to_hw(local), skb);
                if (ret)
                        info = IEEE80211_SKB_CB(tx->extra_frag[i]);
                        info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
                                         IEEE80211_TX_CTL_FIRST_FRAGMENT);
 -                      if (netif_subqueue_stopped(local->mdev,
 -                                                 tx->extra_frag[i]))
 +                      if (ieee80211_queue_stopped(&local->hw,
 +                                      skb_get_queue_mapping(tx->extra_frag[i])))
                                return IEEE80211_TX_FRAG_AGAIN;
  
                        ret = local->ops->tx(local_to_hw(local),
@@@ -1220,9 -1181,8 +1222,9 @@@ retry
                 * queues, there's no reason for a driver to reject
                 * a frame there, warn and drop it.
                 */
 -              if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
 -                      goto drop;
 +              if (ret != IEEE80211_TX_PENDING)
 +                      if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
 +                              goto drop;
  
                store = &local->pending_packet[queue];
  
@@@ -1338,19 -1298,6 +1340,19 @@@ int ieee80211_master_start_xmit(struct 
                return 0;
        }
  
 +      if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
 +          local->hw.conf.dynamic_ps_timeout > 0) {
 +              if (local->hw.conf.flags & IEEE80211_CONF_PS) {
 +                      ieee80211_stop_queues_by_reason(&local->hw,
 +                                      IEEE80211_QUEUE_STOP_REASON_PS);
 +                      queue_work(local->hw.workqueue,
 +                                      &local->dynamic_ps_disable_work);
 +              }
 +
 +              mod_timer(&local->dynamic_ps_timer, jiffies +
 +                      msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
 +      }
 +
        memset(info, 0, sizeof(*info));
  
        info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
@@@ -1445,31 -1392,10 +1447,31 @@@ int ieee80211_monitor_start_xmit(struc
                                 struct net_device *dev)
  {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 +      struct ieee80211_channel *chan = local->hw.conf.channel;
        struct ieee80211_radiotap_header *prthdr =
                (struct ieee80211_radiotap_header *)skb->data;
        u16 len_rthdr;
  
 +      /*
 +       * Frame injection is not allowed if beaconing is not allowed
 +       * or if we need radar detection. Beaconing is usually not allowed when
 +       * the mode or operation (Adhoc, AP, Mesh) does not support DFS.
 +       * Passive scan is also used in world regulatory domains where
 +       * your country is not known and as such it should be treated as
 +       * NO TX unless the channel is explicitly allowed in which case
 +       * your current regulatory domain would not have the passive scan
 +       * flag.
 +       *
 +       * Since AP mode uses monitor interfaces to inject/TX management
 +       * frames we can make AP mode the exception to this rule once it
 +       * supports radar detection as its implementation can deal with
 +       * radar detection by itself. We can do that later by adding a
 +       * monitor flag interfaces used for AP support.
 +       */
 +      if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
 +           IEEE80211_CHAN_PASSIVE_SCAN)))
 +              goto fail;
 +
        /* check for not even having the fixed radiotap header part */
        if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
                goto fail; /* too short to be possibly valid */
@@@ -1553,6 -1479,19 +1555,6 @@@ int ieee80211_subif_start_xmit(struct s
                goto fail;
        }
  
 -      if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
 -          local->dynamic_ps_timeout > 0) {
 -              if (local->hw.conf.flags & IEEE80211_CONF_PS) {
 -                      ieee80211_stop_queues_by_reason(&local->hw,
 -                                                      IEEE80211_QUEUE_STOP_REASON_PS);
 -                      queue_work(local->hw.workqueue,
 -                                 &local->dynamic_ps_disable_work);
 -              }
 -
 -              mod_timer(&local->dynamic_ps_timer, jiffies +
 -                        msecs_to_jiffies(local->dynamic_ps_timeout));
 -      }
 -
        nh_pos = skb_network_header(skb) - skb->data;
        h_pos = skb_transport_header(skb) - skb->data;
  
        case NL80211_IFTYPE_STATION:
                fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
                /* BSSID SA DA */
 -              memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN);
 +              memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
                memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
                memcpy(hdr.addr3, skb->data, ETH_ALEN);
                hdrlen = 24;
                /* DA SA BSSID */
                memcpy(hdr.addr1, skb->data, ETH_ALEN);
                memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
 -              memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN);
 +              memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN);
                hdrlen = 24;
                break;
        default:
@@@ -1928,6 -1867,7 +1930,6 @@@ struct sk_buff *ieee80211_beacon_get(st
        struct ieee80211_tx_info *info;
        struct ieee80211_sub_if_data *sdata = NULL;
        struct ieee80211_if_ap *ap = NULL;
 -      struct ieee80211_if_sta *ifsta = NULL;
        struct beacon_data *beacon;
        struct ieee80211_supported_band *sband;
        enum ieee80211_band band = local->hw.conf.channel->band;
                } else
                        goto out;
        } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
 +              struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
                struct ieee80211_hdr *hdr;
 -              ifsta = &sdata->u.sta;
  
 -              if (!ifsta->probe_resp)
 +              if (!ifibss->probe_resp)
                        goto out;
  
 -              skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC);
 +              skb = skb_copy(ifibss->probe_resp, GFP_ATOMIC);
                if (!skb)
                        goto out;