iwlwifi: earlier rx allocation
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / iwlwifi / iwl4965-base.c
index 02433930f7e21063231f9d4097c9cd152392c5d5..14a11bd83e8262ac161a06ae861cae151708bb11 100644 (file)
  *
  *****************************************************************************/
 
-/*
- * NOTE:  This file (iwl-base.c) is used to build to multiple hardware targets
- * by defining IWL to either 3945 or 4965.  The Makefile used when building
- * the base targets will create base-3945.o and base-4965.o
- *
- * The eventual goal is to move as many of the #if IWL / #endif blocks out of
- * this file and into the hardware specific implementation files (iwl-XXXX.c)
- * and leave only the common (non #ifdef sprinkled) code in this file
- */
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/version.h>
@@ -51,7 +41,6 @@
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 
-#include <net/ieee80211_radiotap.h>
 #include <net/mac80211.h>
 
 #include <asm/div64.h>
@@ -73,13 +62,14 @@ static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv,
  ******************************************************************************/
 
 /* module parameters */
-static int iwl4965_param_disable_hw_scan;
-static int iwl4965_param_debug;
-static int iwl4965_param_disable;      /* def: enable radio */
-static int iwl4965_param_antenna;      /* def: 0 = both antennas (use diversity) */
-int iwl4965_param_hwcrypto;     /* def: using software encryption */
-static int iwl4965_param_qos_enable = 1;
-int iwl4965_param_queues_num = IWL_MAX_NUM_QUEUES;
+static int iwl4965_param_disable_hw_scan; /* def: 0 = use 4965's h/w scan */
+static int iwl4965_param_debug;    /* def: 0 = minimal debug log messages */
+static int iwl4965_param_disable;  /* def: enable radio */
+static int iwl4965_param_antenna;  /* def: 0 = both antennas (use diversity) */
+int iwl4965_param_hwcrypto;        /* def: using software encryption */
+static int iwl4965_param_qos_enable = 1; /* def: 1 = use quality of service */
+int iwl4965_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 16 Tx queues */
+int iwl4965_param_amsdu_size_8K;   /* def: enable 8K amsdu size */
 
 /*
  * module name, copyright, version, etc.
@@ -100,7 +90,7 @@ int iwl4965_param_queues_num = IWL_MAX_NUM_QUEUES;
 #define VS
 #endif
 
-#define IWLWIFI_VERSION "1.1.19k" VD VS
+#define IWLWIFI_VERSION "1.2.23k" VD VS
 #define DRV_COPYRIGHT  "Copyright(c) 2003-2007 Intel Corporation"
 #define DRV_VERSION     IWLWIFI_VERSION
 
@@ -193,17 +183,26 @@ static void iwl4965_print_hex_dump(int level, void *p, u32 len)
  *
  * Theory of operation
  *
- * A queue is a circular buffers with 'Read' and 'Write' pointers.
- * 2 empty entries always kept in the buffer to protect from overflow.
+ * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
+ * of buffer descriptors, each of which points to one or more data buffers for
+ * the device to read from or fill.  Driver and device exchange status of each
+ * queue via "read" and "write" pointers.  Driver keeps minimum of 2 empty
+ * entries in each circular buffer, to protect against confusing empty and full
+ * queue states.
+ *
+ * The device reads or writes the data in the queues via the device's several
+ * DMA/FIFO channels.  Each queue is mapped to a single DMA channel.
  *
  * For Tx queue, there are low mark and high mark limits. If, after queuing
  * the packet for Tx, free space become < low mark, Tx queue stopped. When
  * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
  * Tx queue resumed.
  *
- * The IWL operates with six queues, one receive queue in the device's
- * sram, one transmit queue for sending commands to the device firmware,
- * and four transmit queues for data.
+ * The 4965 operates with up to 17 queues:  One receive queue, one transmit
+ * queue (#4) for sending commands to the device firmware, and 15 other
+ * Tx queues that may be mapped to prioritized Tx DMA/FIFO channels.
+ *
+ * See more detailed info in iwl-4965-hw.h.
  ***************************************************/
 
 static int iwl4965_queue_space(const struct iwl4965_queue *q)
@@ -222,13 +221,21 @@ static int iwl4965_queue_space(const struct iwl4965_queue *q)
        return s;
 }
 
-/* XXX: n_bd must be power-of-two size */
+/**
+ * iwl4965_queue_inc_wrap - increment queue index, wrap back to beginning
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
 static inline int iwl4965_queue_inc_wrap(int index, int n_bd)
 {
        return ++index & (n_bd - 1);
 }
 
-/* XXX: n_bd must be power-of-two size */
+/**
+ * iwl4965_queue_dec_wrap - decrement queue index, wrap back to end
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
 static inline int iwl4965_queue_dec_wrap(int index, int n_bd)
 {
        return --index & (n_bd - 1);
@@ -243,12 +250,17 @@ static inline int x2_queue_used(const struct iwl4965_queue *q, int i)
 
 static inline u8 get_cmd_index(struct iwl4965_queue *q, u32 index, int is_huge)
 {
+       /* This is for scan command, the big buffer at end of command array */
        if (is_huge)
-               return q->n_window;
+               return q->n_window;     /* must be power of 2 */
 
+       /* Otherwise, use normal size buffers */
        return index & (q->n_window - 1);
 }
 
+/**
+ * iwl4965_queue_init - Initialize queue's high/low-water and read/write indexes
+ */
 static int iwl4965_queue_init(struct iwl4965_priv *priv, struct iwl4965_queue *q,
                          int count, int slots_num, u32 id)
 {
@@ -277,11 +289,16 @@ static int iwl4965_queue_init(struct iwl4965_priv *priv, struct iwl4965_queue *q
        return 0;
 }
 
+/**
+ * iwl4965_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
+ */
 static int iwl4965_tx_queue_alloc(struct iwl4965_priv *priv,
                              struct iwl4965_tx_queue *txq, u32 id)
 {
        struct pci_dev *dev = priv->pci_dev;
 
+       /* Driver private data, only for Tx (not command) queues,
+        * not shared with device. */
        if (id != IWL_CMD_QUEUE_NUM) {
                txq->txb = kmalloc(sizeof(txq->txb[0]) *
                                   TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
@@ -293,6 +310,8 @@ static int iwl4965_tx_queue_alloc(struct iwl4965_priv *priv,
        } else
                txq->txb = NULL;
 
+       /* Circular buffer of transmit frame descriptors (TFDs),
+        * shared with device */
        txq->bd = pci_alloc_consistent(dev,
                        sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
                        &txq->q.dma_addr);
@@ -315,6 +334,9 @@ static int iwl4965_tx_queue_alloc(struct iwl4965_priv *priv,
        return -ENOMEM;
 }
 
+/**
+ * iwl4965_tx_queue_init - Allocate and initialize one tx/cmd queue
+ */
 int iwl4965_tx_queue_init(struct iwl4965_priv *priv,
                      struct iwl4965_tx_queue *txq, int slots_num, u32 txq_id)
 {
@@ -322,9 +344,14 @@ int iwl4965_tx_queue_init(struct iwl4965_priv *priv,
        int len;
        int rc = 0;
 
-       /* allocate command space + one big command for scan since scan
-        * command is very huge the system will not have two scan at the
-        * same time */
+       /*
+        * Alloc buffer array for commands (Tx or other types of commands).
+        * For the command queue (#4), allocate command space + one big
+        * command for scan, since scan command is very huge; the system will
+        * not have two scans at the same time, so only one is needed.
+        * For normal Tx queues (all other queues), no super-size command
+        * space is needed.
+        */
        len = sizeof(struct iwl4965_cmd) * slots_num;
        if (txq_id == IWL_CMD_QUEUE_NUM)
                len +=  IWL_MAX_SCAN_SIZE;
@@ -332,6 +359,7 @@ int iwl4965_tx_queue_init(struct iwl4965_priv *priv,
        if (!txq->cmd)
                return -ENOMEM;
 
+       /* Alloc driver data array and TFD circular buffer */
        rc = iwl4965_tx_queue_alloc(priv, txq, txq_id);
        if (rc) {
                pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
@@ -343,8 +371,11 @@ int iwl4965_tx_queue_init(struct iwl4965_priv *priv,
        /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
         * iwl4965_queue_inc_wrap and iwl4965_queue_dec_wrap are broken. */
        BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+
+       /* Initialize queue's high/low-water marks, and head/tail indexes */
        iwl4965_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
 
+       /* Tell device where to find queue */
        iwl4965_hw_tx_queue_init(priv, txq);
 
        return 0;
@@ -355,8 +386,8 @@ int iwl4965_tx_queue_init(struct iwl4965_priv *priv,
  * @txq: Transmit queue to deallocate.
  *
  * Empty queue by removing and destroying all BD's.
- * Free all buffers.  txq itself is not freed.
- *
+ * Free all buffers.
+ * 0-fill, but do not free "txq" descriptor structure.
  */
 void iwl4965_tx_queue_free(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq)
 {
@@ -376,36 +407,39 @@ void iwl4965_tx_queue_free(struct iwl4965_priv *priv, struct iwl4965_tx_queue *t
        if (q->id == IWL_CMD_QUEUE_NUM)
                len += IWL_MAX_SCAN_SIZE;
 
+       /* De-alloc array of command/tx buffers */
        pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
 
-       /* free buffers belonging to queue itself */
+       /* De-alloc circular buffer of TFDs */
        if (txq->q.n_bd)
                pci_free_consistent(dev, sizeof(struct iwl4965_tfd_frame) *
                                    txq->q.n_bd, txq->bd, txq->q.dma_addr);
 
+       /* De-alloc array of per-TFD driver data */
        if (txq->txb) {
                kfree(txq->txb);
                txq->txb = NULL;
        }
 
-       /* 0 fill whole structure */
+       /* 0-fill queue descriptor structure */
        memset(txq, 0, sizeof(*txq));
 }
 
 const u8 iwl4965_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
 /*************** STATION TABLE MANAGEMENT ****
- *
- * NOTE:  This needs to be overhauled to better synchronize between
- * how the iwl-4965.c is using iwl4965_hw_find_station vs. iwl-3945.c
- *
- * mac80211 should also be examined to determine if sta_info is duplicating
+ * mac80211 should be examined to determine if sta_info is duplicating
  * the functionality provided here
  */
 
 /**************************************************************/
 
 #if 0 /* temporary disable till we add real remove station */
+/**
+ * iwl4965_remove_station - Remove driver's knowledge of station.
+ *
+ * NOTE:  This does not remove station from device's station table.
+ */
 static u8 iwl4965_remove_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap)
 {
        int index = IWL_INVALID_STATION;
@@ -443,6 +477,11 @@ out:
 }
 #endif
 
+/**
+ * iwl4965_clear_stations_table - Clear the driver's station table
+ *
+ * NOTE:  This does not clear or otherwise alter the device's station table.
+ */
 static void iwl4965_clear_stations_table(struct iwl4965_priv *priv)
 {
        unsigned long flags;
@@ -455,7 +494,11 @@ static void iwl4965_clear_stations_table(struct iwl4965_priv *priv)
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
 
-u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr, int is_ap, u8 flags)
+/**
+ * iwl4965_add_station_flags - Add station to tables in driver and device
+ */
+u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr,
+                               int is_ap, u8 flags, void *ht_data)
 {
        int i;
        int index = IWL_INVALID_STATION;
@@ -482,8 +525,8 @@ u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr, int is_a
                }
 
 
-       /* These two conditions has the same outcome but keep them separate
-         since they have different meaning */
+       /* These two conditions have the same outcome, but keep them separate
+         since they have different meanings */
        if (unlikely(index == IWL_INVALID_STATION)) {
                spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
                return index;
@@ -501,6 +544,7 @@ u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr, int is_a
        station->used = 1;
        priv->num_stations++;
 
+       /* Set up the REPLY_ADD_STA command to send to device */
        memset(&station->sta, 0, sizeof(struct iwl4965_addsta_cmd));
        memcpy(station->sta.sta.addr, addr, ETH_ALEN);
        station->sta.mode = 0;
@@ -511,10 +555,13 @@ u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr, int is_a
        /* BCAST station and IBSS stations do not work in HT mode */
        if (index != priv->hw_setting.bcast_sta_id &&
            priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
-               iwl4965_set_ht_add_station(priv, index);
+               iwl4965_set_ht_add_station(priv, index,
+                                (struct ieee80211_ht_info *) ht_data);
 #endif /*CONFIG_IWL4965_HT*/
 
        spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+
+       /* Add station to device's station table */
        iwl4965_send_add_station(priv, &station->sta, flags);
        return index;
 
@@ -645,6 +692,11 @@ static int iwl4965_enqueue_hcmd(struct iwl4965_priv *priv, struct iwl4965_host_c
        BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
               !(cmd->meta.flags & CMD_SIZE_HUGE));
 
+       if (iwl4965_is_rfkill(priv)) {
+               IWL_DEBUG_INFO("Not sending command - RF KILL");
+               return -EIO;
+       }
+
        if (iwl4965_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
                IWL_ERROR("No space for Tx\n");
                return -ENOSPC;
@@ -684,7 +736,11 @@ static int iwl4965_enqueue_hcmd(struct iwl4965_priv *priv, struct iwl4965_host_c
                     fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
 
        txq->need_update = 1;
+
+       /* Set up entry in queue's byte count circular buffer */
        ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0);
+
+       /* Increment and update queue's write index */
        q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd);
        iwl4965_tx_queue_update_write_ptr(priv, txq);
 
@@ -843,14 +899,29 @@ int iwl4965_send_statistics_request(struct iwl4965_priv *priv)
  * iwl4965_rxon_add_station - add station into station table.
  *
  * there is only one AP station with id= IWL_AP_ID
- * NOTE: mutex must be held before calling the this fnction
-*/
+ * NOTE: mutex must be held before calling this fnction
+ */
 static int iwl4965_rxon_add_station(struct iwl4965_priv *priv,
                                const u8 *addr, int is_ap)
 {
        u8 sta_id;
 
-       sta_id = iwl4965_add_station_flags(priv, addr, is_ap, 0);
+       /* Add station to device's station table */
+#ifdef CONFIG_IWL4965_HT
+       struct ieee80211_conf *conf = &priv->hw->conf;
+       struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf;
+
+       if ((is_ap) &&
+           (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
+           (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+               sta_id = iwl4965_add_station_flags(priv, addr, is_ap,
+                                                  0, cur_ht_config);
+       else
+#endif /* CONFIG_IWL4965_HT */
+               sta_id = iwl4965_add_station_flags(priv, addr, is_ap,
+                                                  0, NULL);
+
+       /* Set up default rate scaling table in device's station table */
        iwl4965_add_station(priv, addr, is_ap);
 
        return sta_id;
@@ -866,7 +937,8 @@ static int iwl4965_rxon_add_station(struct iwl4965_priv *priv,
  * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
  * in the staging RXON flag structure based on the phymode
  */
-static int iwl4965_set_rxon_channel(struct iwl4965_priv *priv, u8 phymode, u16 channel)
+static int iwl4965_set_rxon_channel(struct iwl4965_priv *priv, u8 phymode,
+                                u16 channel)
 {
        if (!iwl4965_get_channel_info(priv, phymode, channel)) {
                IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
@@ -965,12 +1037,12 @@ static int iwl4965_check_rxon_cmd(struct iwl4965_rxon_cmd *rxon)
 }
 
 /**
- * iwl4965_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit
+ * iwl4965_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
  * @priv: staging_rxon is compared to active_rxon
  *
- * If the RXON structure is changing sufficient to require a new
- * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1
- * to indicate a new tune is required.
+ * If the RXON structure is changing enough to require a new tune,
+ * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
+ * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
  */
 static int iwl4965_full_rxon_required(struct iwl4965_priv *priv)
 {
@@ -1267,7 +1339,7 @@ static int iwl4965_card_state_sync_callback(struct iwl4965_priv *priv,
 /*
  * CARD_STATE_CMD
  *
- * Use: Sets the internal card state to enable, disable, or halt
+ * Use: Sets the device's internal card state to enable, disable, or halt
  *
  * When in the 'enable' state the card operates as normal.
  * When in the 'disable' state, the card enters into a low power mode.
@@ -1488,6 +1560,7 @@ int iwl4965_rate_index_from_plcp(int plcp)
 {
        int i = 0;
 
+       /* 4965 HT rate format */
        if (plcp & RATE_MCS_HT_MSK) {
                i = (plcp & 0xff);
 
@@ -1501,6 +1574,8 @@ int iwl4965_rate_index_from_plcp(int plcp)
                if ((i >= IWL_FIRST_OFDM_RATE) &&
                    (i <= IWL_LAST_OFDM_RATE))
                        return i;
+
+       /* 4965 legacy rate format, search for match in table */
        } else {
                for (i = 0; i < ARRAY_SIZE(iwl4965_rates); i++)
                        if (iwl4965_rates[i].plcp == (plcp &0xFF))
@@ -1569,16 +1644,22 @@ static void get_eeprom_mac(struct iwl4965_priv *priv, u8 *mac)
        memcpy(mac, priv->eeprom.mac_address, 6);
 }
 
+static inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv)
+{
+       iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+               CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+}
+
 /**
  * iwl4965_eeprom_init - read EEPROM contents
  *
- * Load the EEPROM from adapter into priv->eeprom
+ * Load the EEPROM contents from adapter into priv->eeprom
  *
  * NOTE:  This routine uses the non-debug IO access functions.
  */
 int iwl4965_eeprom_init(struct iwl4965_priv *priv)
 {
-       u16 *e = (u16 *)&priv->eeprom;
+       __le16 *e = (__le16 *)&priv->eeprom;
        u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP);
        u32 r;
        int sz = sizeof(priv->eeprom);
@@ -1597,6 +1678,7 @@ int iwl4965_eeprom_init(struct iwl4965_priv *priv)
                return -ENOENT;
        }
 
+       /* Make sure driver (instead of uCode) is allowed to read EEPROM */
        rc = iwl4965_eeprom_acquire_semaphore(priv);
        if (rc < 0) {
                IWL_ERROR("Failed to acquire EEPROM semaphore.\n");
@@ -1621,7 +1703,7 @@ int iwl4965_eeprom_init(struct iwl4965_priv *priv)
                        rc = -ETIMEDOUT;
                        goto done;
                }
-               e[addr / 2] = le16_to_cpu(r >> 16);
+               e[addr / 2] = cpu_to_le16(r >> 16);
        }
        rc = 0;
 
@@ -1640,14 +1722,12 @@ done:
 /**
  * iwl4965_report_frame - dump frame to syslog during debug sessions
  *
- * hack this function to show different aspects of received frames,
+ * You may hack this function to show different aspects of received frames,
  * including selective frame dumps.
  * group100 parameter selects whether to show 1 out of 100 good frames.
  *
- * TODO:  ieee80211_hdr stuff is common to 3945 and 4965, so frame type
- *        info output is okay, but some of this stuff (e.g. iwl4965_rx_frame_stats)
- *        is 3945-specific and gives bad output for 4965.  Need to split the
- *        functionality, keep common stuff here.
+ * TODO:  This was originally written for 3945, need to audit for
+ *        proper operation with 4965.
  */
 void iwl4965_report_frame(struct iwl4965_priv *priv,
                      struct iwl4965_rx_packet *pkt,
@@ -1820,8 +1900,8 @@ static u16 iwl4965_supported_rate_to_ie(u8 *ie, u16 supported_rate,
 
 #ifdef CONFIG_IWL4965_HT
 void static iwl4965_set_ht_capab(struct ieee80211_hw *hw,
-                            struct ieee80211_ht_capability *ht_cap,
-                            u8 use_wide_chan);
+                            struct ieee80211_ht_cap *ht_cap,
+                            u8 use_current_config);
 #endif
 
 /**
@@ -1834,6 +1914,9 @@ static u16 iwl4965_fill_probe_req(struct iwl4965_priv *priv,
        int len = 0;
        u8 *pos = NULL;
        u16 active_rates, ret_rates, cck_rates, active_rate_basic;
+#ifdef CONFIG_IWL4965_HT
+       struct ieee80211_hw_mode *mode;
+#endif /* CONFIG_IWL4965_HT */
 
        /* Make sure there is enough space for the probe request,
         * two mandatory IEs and the data */
@@ -1917,17 +2000,14 @@ static u16 iwl4965_fill_probe_req(struct iwl4965_priv *priv,
                len += 2 + *pos;
 
 #ifdef CONFIG_IWL4965_HT
-       if (is_direct && priv->is_ht_enabled) {
-               u8 use_wide_chan = 1;
-
-               if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
-                       use_wide_chan = 0;
+       mode = priv->hw->conf.mode;
+       if (mode->ht_info.ht_supported) {
                pos += (*pos) + 1;
                *pos++ = WLAN_EID_HT_CAPABILITY;
-               *pos++ = sizeof(struct ieee80211_ht_capability);
-               iwl4965_set_ht_capab(NULL, (struct ieee80211_ht_capability *)pos,
-                                use_wide_chan);
-               len += 2 + sizeof(struct ieee80211_ht_capability);
+               *pos++ = sizeof(struct ieee80211_ht_cap);
+               iwl4965_set_ht_capab(priv->hw,
+                               (struct ieee80211_ht_cap *)pos, 0);
+               len += 2 + sizeof(struct ieee80211_ht_cap);
        }
 #endif  /*CONFIG_IWL4965_HT */
 
@@ -2056,7 +2136,7 @@ static void iwl4965_activate_qos(struct iwl4965_priv *priv, u8 force)
                        QOS_PARAM_FLG_UPDATE_EDCA_MSK;
 
 #ifdef CONFIG_IWL4965_HT
-       if (priv->is_ht_enabled && priv->current_assoc_ht.is_ht)
+       if (priv->current_ht_config.is_ht)
                priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
 #endif /* CONFIG_IWL4965_HT */
 
@@ -2594,9 +2674,6 @@ static void iwl4965_connection_init_rx_config(struct iwl4965_priv *priv)
 
 static int iwl4965_set_mode(struct iwl4965_priv *priv, int mode)
 {
-       if (!iwl4965_is_ready_rf(priv))
-               return -EAGAIN;
-
        if (mode == IEEE80211_IF_TYPE_IBSS) {
                const struct iwl4965_channel_info *ch_info;
 
@@ -2611,13 +2688,6 @@ static int iwl4965_set_mode(struct iwl4965_priv *priv, int mode)
                }
        }
 
-       cancel_delayed_work(&priv->scan_check);
-       if (iwl4965_scan_cancel_timeout(priv, 100)) {
-               IWL_WARNING("Aborted scan still in progress after 100ms\n");
-               IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
-               return -EAGAIN;
-       }
-
        priv->iw_mode = mode;
 
        iwl4965_connection_init_rx_config(priv);
@@ -2625,6 +2695,17 @@ static int iwl4965_set_mode(struct iwl4965_priv *priv, int mode)
 
        iwl4965_clear_stations_table(priv);
 
+       /* dont commit rxon if rf-kill is on*/
+       if (!iwl4965_is_ready_rf(priv))
+               return -EAGAIN;
+
+       cancel_delayed_work(&priv->scan_check);
+       if (iwl4965_scan_cancel_timeout(priv, 100)) {
+               IWL_WARNING("Aborted scan still in progress after 100ms\n");
+               IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+               return -EAGAIN;
+       }
+
        iwl4965_commit_rxon(priv);
 
        return 0;
@@ -2702,6 +2783,10 @@ static void iwl4965_build_tx_cmd_basic(struct iwl4965_priv *priv,
                tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
        }
 
+       if (ieee80211_is_back_request(fc))
+               tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
+
+
        cmd->cmd.tx.sta_id = std_id;
        if (ieee80211_get_morefrag(hdr))
                tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
@@ -2739,22 +2824,27 @@ static void iwl4965_build_tx_cmd_basic(struct iwl4965_priv *priv,
        cmd->cmd.tx.next_frame_len = 0;
 }
 
-static int iwl4965_get_sta_id(struct iwl4965_priv *priv, struct ieee80211_hdr *hdr)
+/**
+ * iwl4965_get_sta_id - Find station's index within station table
+ *
+ * If new IBSS station, create new entry in station table
+ */
+static int iwl4965_get_sta_id(struct iwl4965_priv *priv,
+                               struct ieee80211_hdr *hdr)
 {
        int sta_id;
        u16 fc = le16_to_cpu(hdr->frame_control);
        DECLARE_MAC_BUF(mac);
 
-       /* If this frame is broadcast or not data then use the broadcast
-        * station id */
+       /* If this frame is broadcast or management, use broadcast station id */
        if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
            is_multicast_ether_addr(hdr->addr1))
                return priv->hw_setting.bcast_sta_id;
 
        switch (priv->iw_mode) {
 
-       /* If this frame is part of a BSS network (we're a station), then
-        * we use the AP's station id */
+       /* If we are a client station in a BSS network, use the special
+        * AP station entry (that's the only station we communicate with) */
        case IEEE80211_IF_TYPE_STA:
                return IWL_AP_ID;
 
@@ -2765,14 +2855,16 @@ static int iwl4965_get_sta_id(struct iwl4965_priv *priv, struct ieee80211_hdr *h
                        return sta_id;
                return priv->hw_setting.bcast_sta_id;
 
-       /* If this frame is part of a IBSS network, then we use the
-        * target specific station id */
+       /* If this frame is going out to an IBSS network, find the station,
+        * or create a new station table entry */
        case IEEE80211_IF_TYPE_IBSS:
                sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
                if (sta_id != IWL_INVALID_STATION)
                        return sta_id;
 
-               sta_id = iwl4965_add_station_flags(priv, hdr->addr1, 0, CMD_ASYNC);
+               /* Create new station table entry */
+               sta_id = iwl4965_add_station_flags(priv, hdr->addr1,
+                                                  0, CMD_ASYNC, NULL);
 
                if (sta_id != IWL_INVALID_STATION)
                        return sta_id;
@@ -2803,6 +2895,7 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
        struct iwl4965_queue *q = NULL;
        dma_addr_t phys_addr;
        dma_addr_t txcmd_phys;
+       dma_addr_t scratch_phys;
        struct iwl4965_cmd *out_cmd = NULL;
        u16 len, idx, len_org;
        u8 id, hdr_len, unicast;
@@ -2820,8 +2913,8 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
                goto drop_unlock;
        }
 
-       if (!priv->interface_id) {
-               IWL_DEBUG_DROP("Dropping - !priv->interface_id\n");
+       if (!priv->vif) {
+               IWL_DEBUG_DROP("Dropping - !priv->vif\n");
                goto drop_unlock;
        }
 
@@ -2844,8 +2937,11 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
                IWL_DEBUG_TX("Sending REASSOC frame\n");
 #endif
 
-       if (!iwl4965_is_associated(priv) &&
-           ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+       /* drop all data frame if we are not associated */
+       if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+          (!iwl4965_is_associated(priv) ||
+           !priv->assoc_id ||
+           !priv->assoc_station_added)) {
                IWL_DEBUG_DROP("Dropping - !iwl4965_is_associated\n");
                goto drop_unlock;
        }
@@ -2853,6 +2949,8 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
        spin_unlock_irqrestore(&priv->lock, flags);
 
        hdr_len = ieee80211_get_hdrlen(fc);
+
+       /* Find (or create) index into station table for destination station */
        sta_id = iwl4965_get_sta_id(priv, hdr);
        if (sta_id == IWL_INVALID_STATION) {
                DECLARE_MAC_BUF(mac);
@@ -2881,30 +2979,52 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
 #endif /* CONFIG_IWL4965_HT_AGG */
 #endif /* CONFIG_IWL4965_HT */
        }
+
+       /* Descriptor for chosen Tx queue */
        txq = &priv->txq[txq_id];
        q = &txq->q;
 
        spin_lock_irqsave(&priv->lock, flags);
 
+       /* Set up first empty TFD within this queue's circular TFD buffer */
        tfd = &txq->bd[q->write_ptr];
        memset(tfd, 0, sizeof(*tfd));
        control_flags = (u32 *) tfd;
        idx = get_cmd_index(q, q->write_ptr, 0);
 
+       /* Set up driver data for this TFD */
        memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl4965_tx_info));
        txq->txb[q->write_ptr].skb[0] = skb;
        memcpy(&(txq->txb[q->write_ptr].status.control),
               ctl, sizeof(struct ieee80211_tx_control));
+
+       /* Set up first empty entry in queue's array of Tx/cmd buffers */
        out_cmd = &txq->cmd[idx];
        memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
        memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx));
+
+       /*
+        * Set up the Tx-command (not MAC!) header.
+        * Store the chosen Tx queue and TFD index within the sequence field;
+        * after Tx, uCode's Tx response will return this value so driver can
+        * locate the frame within the tx queue and do post-tx processing.
+        */
        out_cmd->hdr.cmd = REPLY_TX;
        out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
                                INDEX_TO_SEQ(q->write_ptr)));
-       /* copy frags header */
+
+       /* Copy MAC header from skb into command buffer */
        memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len);
 
-       /* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */
+       /*
+        * Use the first empty entry in this queue's command buffer array
+        * to contain the Tx command and MAC header concatenated together
+        * (payload data will be in another buffer).
+        * Size of this varies, due to varying MAC header length.
+        * If end is not dword aligned, we'll have 2 extra bytes at the end
+        * of the MAC header (device reads on dword boundaries).
+        * We'll tell device about this padding later.
+        */
        len = priv->hw_setting.tx_cmd_len +
                sizeof(struct iwl4965_cmd_header) + hdr_len;
 
@@ -2916,15 +3036,20 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
        else
                len_org = 0;
 
+       /* Physical address of this Tx command's header (not MAC header!),
+        * within command buffer array. */
        txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl4965_cmd) * idx +
                     offsetof(struct iwl4965_cmd, hdr);
 
+       /* Add buffer containing Tx command and MAC(!) header to TFD's
+        * first entry */
        iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
 
        if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
                iwl4965_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
 
-       /* 802.11 null functions have no payload... */
+       /* Set up TFD's 2nd entry to point directly to remainder of skb,
+        * if any (802.11 null frames have no payload). */
        len = skb->len - hdr_len;
        if (len) {
                phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
@@ -2932,9 +3057,11 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
                iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
        }
 
+       /* Tell 4965 about any 2-byte padding after MAC header */
        if (len_org)
                out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
 
+       /* Total # bytes to be transmitted */
        len = (u16)skb->len;
        out_cmd->cmd.tx.len = cpu_to_le16(len);
 
@@ -2944,8 +3071,18 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
        /* set is_hcca to 0; it probably will never be implemented */
        iwl4965_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
 
-       iwl4965_tx_cmd(priv, out_cmd, sta_id, txcmd_phys,
-                      hdr, hdr_len, ctl, NULL);
+       scratch_phys = txcmd_phys + sizeof(struct iwl4965_cmd_header) +
+               offsetof(struct iwl4965_tx_cmd, scratch);
+       out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys);
+       out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys);
+
+#ifdef CONFIG_IWL4965_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+       /* TODO: move this functionality to rate scaling */
+       iwl4965_tl_get_stats(priv, hdr);
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /*CONFIG_IWL4965_HT */
+
 
        if (!ieee80211_get_morefrag(hdr)) {
                txq->need_update = 1;
@@ -2964,8 +3101,10 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
        iwl4965_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
                           ieee80211_get_hdrlen(fc));
 
+       /* Set up entry for this TFD in Tx byte-count array */
        iwl4965_tx_queue_update_wr_ptr(priv, txq, len);
 
+       /* Tell device the write index *just past* this latest filled TFD */
        q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd);
        rc = iwl4965_tx_queue_update_write_ptr(priv, txq);
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -3135,93 +3274,6 @@ void iwl4965_set_decrypted_flag(struct iwl4965_priv *priv, struct sk_buff *skb,
        }
 }
 
-void iwl4965_handle_data_packet_monitor(struct iwl4965_priv *priv,
-                                   struct iwl4965_rx_mem_buffer *rxb,
-                                   void *data, short len,
-                                   struct ieee80211_rx_status *stats,
-                                   u16 phy_flags)
-{
-       struct iwl4965_rt_rx_hdr *iwl4965_rt;
-
-       /* First cache any information we need before we overwrite
-        * the information provided in the skb from the hardware */
-       s8 signal = stats->ssi;
-       s8 noise = 0;
-       int rate = stats->rate;
-       u64 tsf = stats->mactime;
-       __le16 phy_flags_hw = cpu_to_le16(phy_flags);
-
-       /* We received data from the HW, so stop the watchdog */
-       if (len > IWL_RX_BUF_SIZE - sizeof(*iwl4965_rt)) {
-               IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
-               return;
-       }
-
-       /* copy the frame data to write after where the radiotap header goes */
-       iwl4965_rt = (void *)rxb->skb->data;
-       memmove(iwl4965_rt->payload, data, len);
-
-       iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
-       iwl4965_rt->rt_hdr.it_pad = 0; /* always good to zero */
-
-       /* total header + data */
-       iwl4965_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl4965_rt));
-
-       /* Set the size of the skb to the size of the frame */
-       skb_put(rxb->skb, sizeof(*iwl4965_rt) + len);
-
-       /* Big bitfield of all the fields we provide in radiotap */
-       iwl4965_rt->rt_hdr.it_present =
-           cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
-                       (1 << IEEE80211_RADIOTAP_FLAGS) |
-                       (1 << IEEE80211_RADIOTAP_RATE) |
-                       (1 << IEEE80211_RADIOTAP_CHANNEL) |
-                       (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
-                       (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
-                       (1 << IEEE80211_RADIOTAP_ANTENNA));
-
-       /* Zero the flags, we'll add to them as we go */
-       iwl4965_rt->rt_flags = 0;
-
-       iwl4965_rt->rt_tsf = cpu_to_le64(tsf);
-
-       /* Convert to dBm */
-       iwl4965_rt->rt_dbmsignal = signal;
-       iwl4965_rt->rt_dbmnoise = noise;
-
-       /* Convert the channel frequency and set the flags */
-       iwl4965_rt->rt_channelMHz = cpu_to_le16(stats->freq);
-       if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
-               iwl4965_rt->rt_chbitmask =
-                   cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
-       else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
-               iwl4965_rt->rt_chbitmask =
-                   cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
-       else    /* 802.11g */
-               iwl4965_rt->rt_chbitmask =
-                   cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
-
-       rate = iwl4965_rate_index_from_plcp(rate);
-       if (rate == -1)
-               iwl4965_rt->rt_rate = 0;
-       else
-               iwl4965_rt->rt_rate = iwl4965_rates[rate].ieee;
-
-       /* antenna number */
-       iwl4965_rt->rt_antenna =
-               le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
-
-       /* set the preamble flag if we have it */
-       if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
-               iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
-
-       IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
-
-       stats->flag |= RX_FLAG_RADIOTAP;
-       ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
-       rxb->skb = NULL;
-}
-
 
 #define IWL_PACKET_RETRY_TIME HZ
 
@@ -3442,11 +3494,11 @@ static void iwl4965_txstatus_to_ieee(struct iwl4965_priv *priv,
 }
 
 /**
- * iwl4965_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC.
+ * iwl4965_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
  *
- * When FW advances 'R' index, all entries between old and
- * new 'R' index need to be reclaimed. As result, some free space
- * forms. If there is enough free space (> low mark), wake Tx queue.
+ * When FW advances 'R' index, all entries between old and new 'R' index
+ * need to be reclaimed. As result, some free space forms.  If there is
+ * enough free space (> low mark), wake the stack that feeds us.
  */
 int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index)
 {
@@ -3527,6 +3579,10 @@ static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp)
        return le32_to_cpu(*scd_ssn) & MAX_SN;
 
 }
+
+/**
+ * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue
+ */
 static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv,
                                      struct iwl4965_ht_agg *agg,
                                      struct iwl4965_tx_resp *tx_resp,
@@ -3541,14 +3597,16 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv,
        u16 seq;
 
        if (agg->wait_for_ba)
-               IWL_DEBUG_TX_REPLY("got tx repsons w/o back\n");
+               IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n");
 
        agg->frame_count = tx_resp->frame_count;
        agg->start_idx = start_idx;
        agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
        agg->bitmap0 = agg->bitmap1 = 0;
 
+       /* # frames attempted by Tx command */
        if (agg->frame_count == 1) {
+               /* Only one frame was attempted; no block-ack will arrive */
                struct iwl4965_tx_queue *txq ;
                status = le32_to_cpu(frame_status[0]);
 
@@ -3577,9 +3635,11 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv,
 
                agg->wait_for_ba = 0;
        } else {
+               /* Two or more frames were attempted; expect block-ack */
                u64 bitmap = 0;
                int start = agg->start_idx;
 
+               /* Construct bit-map of pending frames within Tx window */
                for (i = 0; i < agg->frame_count; i++) {
                        u16 sc;
                        status = le32_to_cpu(frame_status[i]);
@@ -3643,6 +3703,9 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv,
 #endif
 #endif
 
+/**
+ * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response
+ */
 static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv,
                            struct iwl4965_rx_mem_buffer *rxb)
 {
@@ -3858,7 +3921,7 @@ static void iwl4965_bg_beacon_update(struct work_struct *work)
        struct sk_buff *beacon;
 
        /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
-       beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL);
+       beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL);
 
        if (!beacon) {
                IWL_ERROR("update beacon failed\n");
@@ -3950,6 +4013,7 @@ static void iwl4965_rx_scan_results_notif(struct iwl4965_priv *priv,
                                        (priv->last_scan_jiffies, jiffies)));
 
        priv->last_scan_jiffies = jiffies;
+       priv->next_scan_jiffies = 0;
 }
 
 /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
@@ -3992,6 +4056,7 @@ static void iwl4965_rx_scan_complete_notif(struct iwl4965_priv *priv,
        }
 
        priv->last_scan_jiffies = jiffies;
+       priv->next_scan_jiffies = 0;
        IWL_DEBUG_INFO("Setting scan to off\n");
 
        clear_bit(STATUS_SCANNING, &priv->status);
@@ -4101,13 +4166,10 @@ static void iwl4965_setup_rx_handlers(struct iwl4965_priv *priv)
            iwl4965_rx_pm_debug_statistics_notif;
        priv->rx_handlers[BEACON_NOTIFICATION] = iwl4965_rx_beacon_notif;
 
-       /* NOTE:  iwl4965_rx_statistics is different based on whether
-        * the build is for the 3945 or the 4965.  See the
-        * corresponding implementation in iwl-XXXX.c
-        *
-        * The same handler is used for both the REPLY to a
-        * discrete statistics request from the host as well as
-        * for the periodic statistics notification from the uCode
+       /*
+        * The same handler is used for both the REPLY to a discrete
+        * statistics request from the host as well as for the periodic
+        * statistics notifications (after received beacons) from the uCode.
         */
        priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl4965_hw_rx_statistics;
        priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl4965_hw_rx_statistics;
@@ -4121,7 +4183,7 @@ static void iwl4965_setup_rx_handlers(struct iwl4965_priv *priv)
        priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif;
        priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx;
 
-       /* Setup hardware specific Rx handlers */
+       /* Set up hardware specific Rx handlers */
        iwl4965_hw_rx_handler_setup(priv);
 }
 
@@ -4175,9 +4237,11 @@ static void iwl4965_tx_cmd_complete(struct iwl4965_priv *priv,
 /*
  * Rx theory of operation
  *
- * The host allocates 32 DMA target addresses and passes the host address
- * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
- * 0 to 31
+ * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
+ * each of which point to Receive Buffers to be filled by 4965.  These get
+ * used not only for Rx frames, but for any command response or notification
+ * from the 4965.  The driver and 4965 manage the Rx buffers by means
+ * of indexes into the circular buffer.
  *
  * Rx Queue Indexes
  * The host/firmware share two index registers for managing the Rx buffers.
@@ -4193,10 +4257,10 @@ static void iwl4965_tx_cmd_complete(struct iwl4965_priv *priv,
  * The queue is empty (no good data) if WRITE = READ - 1, and is full if
  * WRITE = READ.
  *
- * During initialization the host sets up the READ queue position to the first
+ * During initialization, the host sets up the READ queue position to the first
  * INDEX position, and WRITE to the last (READ - 1 wrapped)
  *
- * When the firmware places a packet in a buffer it will advance the READ index
+ * When the firmware places a packet in a buffer, it will advance the READ index
  * and fire the RX interrupt.  The driver can then query the READ index and
  * process as many packets as possible, moving the WRITE index forward as it
  * resets the Rx queue buffers with new memory.
@@ -4218,16 +4282,16 @@ static void iwl4965_tx_cmd_complete(struct iwl4965_priv *priv,
  *
  * Driver sequence:
  *
- * iwl4965_rx_queue_alloc()       Allocates rx_free
- * iwl4965_rx_replenish()         Replenishes rx_free list from rx_used, and calls
+ * iwl4965_rx_queue_alloc()   Allocates rx_free
+ * iwl4965_rx_replenish()     Replenishes rx_free list from rx_used, and calls
  *                            iwl4965_rx_queue_restock
- * iwl4965_rx_queue_restock()     Moves available buffers from rx_free into Rx
+ * iwl4965_rx_queue_restock() Moves available buffers from rx_free into Rx
  *                            queue, updates firmware pointers, and updates
  *                            the WRITE index.  If insufficient rx_free buffers
  *                            are available, schedules iwl4965_rx_replenish
  *
  * -- enable interrupts --
- * ISR - iwl4965_rx()             Detach iwl4965_rx_mem_buffers from pool up to the
+ * ISR - iwl4965_rx()         Detach iwl4965_rx_mem_buffers from pool up to the
  *                            READ INDEX, detaching the SKB from the pool.
  *                            Moves the packet buffer from queue to rx_used.
  *                            Calls iwl4965_rx_queue_restock to refill any empty
@@ -4253,12 +4317,6 @@ static int iwl4965_rx_queue_space(const struct iwl4965_rx_queue *q)
 
 /**
  * iwl4965_rx_queue_update_write_ptr - Update the write pointer for the RX queue
- *
- * NOTE: This function has 3945 and 4965 specific code sections
- * but is declared in base due to the majority of the
- * implementation being the same (only a numeric constant is
- * different)
- *
  */
 int iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv, struct iwl4965_rx_queue *q)
 {
@@ -4271,6 +4329,7 @@ int iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv, struct iwl4965_
        if (q->need_update == 0)
                goto exit_unlock;
 
+       /* If power-saving is in use, make sure device is awake */
        if (test_bit(STATUS_POWER_PMI, &priv->status)) {
                reg = iwl4965_read32(priv, CSR_UCODE_DRV_GP1);
 
@@ -4284,10 +4343,14 @@ int iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv, struct iwl4965_
                if (rc)
                        goto exit_unlock;
 
+               /* Device expects a multiple of 8 */
                iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
                                     q->write & ~0x7);
                iwl4965_release_nic_access(priv);
+
+       /* Else device is assumed to be awake */
        } else
+               /* Device expects a multiple of 8 */
                iwl4965_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
 
 
@@ -4299,9 +4362,7 @@ int iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv, struct iwl4965_
 }
 
 /**
- * iwl4965_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer.
- *
- * NOTE: This function has 3945 and 4965 specific code paths in it.
+ * iwl4965_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
  */
 static inline __le32 iwl4965_dma_addr2rbd_ptr(struct iwl4965_priv *priv,
                                          dma_addr_t dma_addr)
@@ -4313,9 +4374,9 @@ static inline __le32 iwl4965_dma_addr2rbd_ptr(struct iwl4965_priv *priv,
 /**
  * iwl4965_rx_queue_restock - refill RX queue from pre-allocated pool
  *
- * If there are slots in the RX queue that  need to be restocked,
+ * If there are slots in the RX queue that need to be restocked,
  * and we have free pre-allocated buffers, fill the ranks as much
- * as we can pulling from rx_free.
+ * as we can, pulling from rx_free.
  *
  * This moves the 'write' index forward to catch up with 'processed', and
  * also updates the memory address in the firmware to reference the new
@@ -4332,9 +4393,12 @@ static int iwl4965_rx_queue_restock(struct iwl4965_priv *priv)
        spin_lock_irqsave(&rxq->lock, flags);
        write = rxq->write & ~0x7;
        while ((iwl4965_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+               /* Get next free Rx buffer, remove from free list */
                element = rxq->rx_free.next;
                rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list);
                list_del(element);
+
+               /* Point to Rx buffer via next RBD in circular buffer */
                rxq->bd[rxq->write] = iwl4965_dma_addr2rbd_ptr(priv, rxb->dma_addr);
                rxq->queue[rxq->write] = rxb;
                rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
@@ -4347,7 +4411,8 @@ static int iwl4965_rx_queue_restock(struct iwl4965_priv *priv)
                queue_work(priv->workqueue, &priv->rx_replenish);
 
 
-       /* If we've added more space for the firmware to place data, tell it */
+       /* If we've added more space for the firmware to place data, tell it.
+        * Increment device's write pointer in multiples of 8. */
        if ((write != (rxq->write & ~0x7))
            || (abs(rxq->write - rxq->read) > 7)) {
                spin_lock_irqsave(&rxq->lock, flags);
@@ -4369,9 +4434,8 @@ static int iwl4965_rx_queue_restock(struct iwl4965_priv *priv)
  * Also restock the Rx queue via iwl4965_rx_queue_restock.
  * This is called as a scheduled work item (except for during initialization)
  */
-void iwl4965_rx_replenish(void *data)
+static void iwl4965_rx_allocate(struct iwl4965_priv *priv)
 {
-       struct iwl4965_priv *priv = data;
        struct iwl4965_rx_queue *rxq = &priv->rxq;
        struct list_head *element;
        struct iwl4965_rx_mem_buffer *rxb;
@@ -4380,8 +4444,11 @@ void iwl4965_rx_replenish(void *data)
        while (!list_empty(&rxq->rx_used)) {
                element = rxq->rx_used.next;
                rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list);
+
+               /* Alloc a new receive buffer */
                rxb->skb =
-                   alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
+                   alloc_skb(priv->hw_setting.rx_buf_size,
+                               __GFP_NOWARN | GFP_ATOMIC);
                if (!rxb->skb) {
                        if (net_ratelimit())
                                printk(KERN_CRIT DRV_NAME
@@ -4393,13 +4460,35 @@ void iwl4965_rx_replenish(void *data)
                }
                priv->alloc_rxb_skb++;
                list_del(element);
+
+               /* Get physical address of RB/SKB */
                rxb->dma_addr =
                    pci_map_single(priv->pci_dev, rxb->skb->data,
-                                  IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                          priv->hw_setting.rx_buf_size, PCI_DMA_FROMDEVICE);
                list_add_tail(&rxb->list, &rxq->rx_free);
                rxq->free_count++;
        }
        spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/*
+ * this should be called while priv->lock is locked
+*/
+static void __iwl4965_rx_replenish(void *data)
+{
+       struct iwl4965_priv *priv = data;
+
+       iwl4965_rx_allocate(priv);
+       iwl4965_rx_queue_restock(priv);
+}
+
+
+void iwl4965_rx_replenish(void *data)
+{
+       struct iwl4965_priv *priv = data;
+       unsigned long flags;
+
+       iwl4965_rx_allocate(priv);
 
        spin_lock_irqsave(&priv->lock, flags);
        iwl4965_rx_queue_restock(priv);
@@ -4407,7 +4496,7 @@ void iwl4965_rx_replenish(void *data)
 }
 
 /* Assumes that the skb field of the buffers in 'pool' is kept accurate.
- * If an SKB has been detached, the POOL needs to have it's SKB set to NULL
+ * If an SKB has been detached, the POOL needs to have its SKB set to NULL
  * This free routine walks the list of POOL entries and if SKB is set to
  * non NULL it is unmapped and freed
  */
@@ -4418,7 +4507,8 @@ static void iwl4965_rx_queue_free(struct iwl4965_priv *priv, struct iwl4965_rx_q
                if (rxq->pool[i].skb != NULL) {
                        pci_unmap_single(priv->pci_dev,
                                         rxq->pool[i].dma_addr,
-                                        IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                                        priv->hw_setting.rx_buf_size,
+                                        PCI_DMA_FROMDEVICE);
                        dev_kfree_skb(rxq->pool[i].skb);
                }
        }
@@ -4437,12 +4527,16 @@ int iwl4965_rx_queue_alloc(struct iwl4965_priv *priv)
        spin_lock_init(&rxq->lock);
        INIT_LIST_HEAD(&rxq->rx_free);
        INIT_LIST_HEAD(&rxq->rx_used);
+
+       /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
        rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
        if (!rxq->bd)
                return -ENOMEM;
+
        /* Fill the rx_used queue with _all_ of the Rx buffers */
        for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
                list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+
        /* Set us so that we have processed and used all buffers, but have
         * not restocked the Rx queue with fresh buffers */
        rxq->read = rxq->write = 0;
@@ -4465,7 +4559,8 @@ void iwl4965_rx_queue_reset(struct iwl4965_priv *priv, struct iwl4965_rx_queue *
                if (rxq->pool[i].skb != NULL) {
                        pci_unmap_single(priv->pci_dev,
                                         rxq->pool[i].dma_addr,
-                                        IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                                        priv->hw_setting.rx_buf_size,
+                                        PCI_DMA_FROMDEVICE);
                        priv->alloc_rxb_skb--;
                        dev_kfree_skb(rxq->pool[i].skb);
                        rxq->pool[i].skb = NULL;
@@ -4559,7 +4654,7 @@ int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm)
 }
 
 /**
- * iwl4965_rx_handle - Main entry function for receiving responses from the uCode
+ * iwl4965_rx_handle - Main entry function for receiving responses from uCode
  *
  * Uses the priv->rx_handlers callback function array to invoke
  * the appropriate handlers, including command responses,
@@ -4573,7 +4668,11 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv)
        u32 r, i;
        int reclaim;
        unsigned long flags;
+       u8 fill_rx = 0;
+       u32 count = 8;
 
+       /* uCode's read index (stored in shared DRAM) indicates the last Rx
+        * buffer that the driver may process (last buffer filled by ucode). */
        r = iwl4965_hw_get_rx_read(priv);
        i = rxq->read;
 
@@ -4581,10 +4680,13 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv)
        if (i == r)
                IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
 
+       if (iwl4965_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
+               fill_rx = 1;
+
        while (i != r) {
                rxb = rxq->queue[i];
 
-               /* If an RXB doesn't have a queue slot associated with it
+               /* If an RXB doesn't have a Rx queue slot associated with it,
                 * then a bug has been introduced in the queue refilling
                 * routines -- catch it here */
                BUG_ON(rxb == NULL);
@@ -4592,7 +4694,7 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv)
                rxq->queue[i] = NULL;
 
                pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
-                                           IWL_RX_BUF_SIZE,
+                                           priv->hw_setting.rx_buf_size,
                                            PCI_DMA_FROMDEVICE);
                pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
 
@@ -4626,8 +4728,8 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv)
                }
 
                if (reclaim) {
-                       /* Invoke any callbacks, transfer the skb to caller,
-                        * and fire off the (possibly) blocking iwl4965_send_cmd()
+                       /* Invoke any callbacks, transfer the skb to caller, and
+                        * fire off the (possibly) blocking iwl4965_send_cmd()
                         * as we reclaim the driver command queue */
                        if (rxb && rxb->skb)
                                iwl4965_tx_cmd_complete(priv, rxb);
@@ -4645,11 +4747,22 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv)
                }
 
                pci_unmap_single(priv->pci_dev, rxb->dma_addr,
-                                IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                                priv->hw_setting.rx_buf_size,
+                                PCI_DMA_FROMDEVICE);
                spin_lock_irqsave(&rxq->lock, flags);
                list_add_tail(&rxb->list, &priv->rxq.rx_used);
                spin_unlock_irqrestore(&rxq->lock, flags);
                i = (i + 1) & RX_QUEUE_MASK;
+               /* If there are a lot of unused frames,
+                * restock the Rx queue so ucode wont assert. */
+               if (fill_rx) {
+                       count++;
+                       if (count >= 8) {
+                               priv->rxq.read = i;
+                               __iwl4965_rx_replenish(priv);
+                               count = 0;
+                       }
+               }
        }
 
        /* Backtrack one entry */
@@ -4657,6 +4770,9 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv)
        iwl4965_rx_queue_restock(priv);
 }
 
+/**
+ * iwl4965_tx_queue_update_write_ptr - Send new write index to hardware
+ */
 static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv,
                                  struct iwl4965_tx_queue *txq)
 {
@@ -4993,7 +5109,8 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv)
 
 #ifdef CONFIG_IWL4965_DEBUG
        if (iwl4965_debug_level & IWL_DL_ISR) {
-               inta_mask = iwl4965_read32(priv, CSR_INT_MASK); /* just for debug */
+               /* just for debug */
+               inta_mask = iwl4965_read32(priv, CSR_INT_MASK);
                IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
                              inta, inta_mask, inta_fh);
        }
@@ -5027,8 +5144,9 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv)
 #ifdef CONFIG_IWL4965_DEBUG
        if (iwl4965_debug_level & (IWL_DL_ISR)) {
                /* NIC fires this, but we don't use it, redundant with WAKEUP */
-               if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
-                       IWL_DEBUG_ISR("Microcode started or stopped.\n");
+               if (inta & CSR_INT_BIT_SCD)
+                       IWL_DEBUG_ISR("Scheduler finished to transmit "
+                                     "the frame/frames.\n");
 
                /* Alive notification via Rx interrupt will do the real work */
                if (inta & CSR_INT_BIT_ALIVE)
@@ -5036,9 +5154,9 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv)
        }
 #endif
        /* Safely ignore these bits for debug checks below */
-       inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+       inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
 
-       /* HW RF KILL switch toggled (4965 only) */
+       /* HW RF KILL switch toggled */
        if (inta & CSR_INT_BIT_RF_KILL) {
                int hw_rf_kill = 0;
                if (!(iwl4965_read32(priv, CSR_GP_CNTRL) &
@@ -5061,7 +5179,7 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv)
                handled |= CSR_INT_BIT_RF_KILL;
        }
 
-       /* Chip got too hot and stopped itself (4965 only) */
+       /* Chip got too hot and stopped itself */
        if (inta & CSR_INT_BIT_CT_KILL) {
                IWL_ERROR("Microcode CT kill error detected.\n");
                handled |= CSR_INT_BIT_CT_KILL;
@@ -5165,8 +5283,11 @@ static irqreturn_t iwl4965_isr(int irq, void *data)
        IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
                      inta, inta_mask, inta_fh);
 
+       inta &= ~CSR_INT_BIT_SCD;
+
        /* iwl4965_irq_tasklet() will service interrupts and re-enable them */
-       tasklet_schedule(&priv->irq_tasklet);
+       if (likely(inta || inta_fh))
+               tasklet_schedule(&priv->irq_tasklet);
 
  unplugged:
        spin_unlock(&priv->lock);
@@ -5216,11 +5337,11 @@ static const u8 iwl4965_eeprom_band_1[14] = {
 };
 
 /* 5.2 GHz bands */
-static const u8 iwl4965_eeprom_band_2[] = {
+static const u8 iwl4965_eeprom_band_2[] = {    /* 4915-5080MHz */
        183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
 };
 
-static const u8 iwl4965_eeprom_band_3[] = {    /* 5205-5320MHz */
+static const u8 iwl4965_eeprom_band_3[] = {    /* 5170-5320MHz */
        34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
 };
 
@@ -5240,7 +5361,8 @@ static u8 iwl4965_eeprom_band_7[] = {       /* 5.2 FAT channel */
        36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
 };
 
-static void iwl4965_init_band_reference(const struct iwl4965_priv *priv, int band,
+static void iwl4965_init_band_reference(const struct iwl4965_priv *priv,
+                                   int band,
                                    int *eeprom_ch_count,
                                    const struct iwl4965_eeprom_channel
                                    **eeprom_ch_info,
@@ -5252,7 +5374,7 @@ static void iwl4965_init_band_reference(const struct iwl4965_priv *priv, int ban
                *eeprom_ch_info = priv->eeprom.band_1_channels;
                *eeprom_ch_index = iwl4965_eeprom_band_1;
                break;
-       case 2:         /* 5.2GHz band */
+       case 2:         /* 4.9GHz band */
                *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_2);
                *eeprom_ch_info = priv->eeprom.band_2_channels;
                *eeprom_ch_index = iwl4965_eeprom_band_2;
@@ -5262,22 +5384,22 @@ static void iwl4965_init_band_reference(const struct iwl4965_priv *priv, int ban
                *eeprom_ch_info = priv->eeprom.band_3_channels;
                *eeprom_ch_index = iwl4965_eeprom_band_3;
                break;
-       case 4:         /* 5.2GHz band */
+       case 4:         /* 5.5GHz band */
                *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_4);
                *eeprom_ch_info = priv->eeprom.band_4_channels;
                *eeprom_ch_index = iwl4965_eeprom_band_4;
                break;
-       case 5:         /* 5.2GHz band */
+       case 5:         /* 5.7GHz band */
                *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_5);
                *eeprom_ch_info = priv->eeprom.band_5_channels;
                *eeprom_ch_index = iwl4965_eeprom_band_5;
                break;
-       case 6:
+       case 6:         /* 2.4GHz FAT channels */
                *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_6);
                *eeprom_ch_info = priv->eeprom.band_24_channels;
                *eeprom_ch_index = iwl4965_eeprom_band_6;
                break;
-       case 7:
+       case 7:         /* 5 GHz FAT channels */
                *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_7);
                *eeprom_ch_info = priv->eeprom.band_52_channels;
                *eeprom_ch_index = iwl4965_eeprom_band_7;
@@ -5288,6 +5410,11 @@ static void iwl4965_init_band_reference(const struct iwl4965_priv *priv, int ban
        }
 }
 
+/**
+ * iwl4965_get_channel_info - Find driver's private channel info
+ *
+ * Based on band and channel number.
+ */
 const struct iwl4965_channel_info *iwl4965_get_channel_info(const struct iwl4965_priv *priv,
                                                    int phymode, u16 channel)
 {
@@ -5315,6 +5442,9 @@ const struct iwl4965_channel_info *iwl4965_get_channel_info(const struct iwl4965
 #define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
                            ? # x " " : "")
 
+/**
+ * iwl4965_init_channel_map - Set up driver's info for all possible channels
+ */
 static int iwl4965_init_channel_map(struct iwl4965_priv *priv)
 {
        int eeprom_ch_count = 0;
@@ -5424,6 +5554,7 @@ static int iwl4965_init_channel_map(struct iwl4965_priv *priv)
                }
        }
 
+       /* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */
        for (band = 6; band <= 7; band++) {
                int phymode;
                u8 fat_extension_chan;
@@ -5431,7 +5562,9 @@ static int iwl4965_init_channel_map(struct iwl4965_priv *priv)
                iwl4965_init_band_reference(priv, band, &eeprom_ch_count,
                                        &eeprom_ch_info, &eeprom_ch_index);
 
+               /* EEPROM band 6 is 2.4, band 7 is 5 GHz */
                phymode = (band == 6) ? MODE_IEEE80211B : MODE_IEEE80211A;
+
                /* Loop through each band adding each of the channels */
                for (ch = 0; ch < eeprom_ch_count; ch++) {
 
@@ -5443,11 +5576,13 @@ static int iwl4965_init_channel_map(struct iwl4965_priv *priv)
                        else
                                fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE;
 
+                       /* Set up driver's info for lower half */
                        iwl4965_set_fat_chan_info(priv, phymode,
                                                  eeprom_ch_index[ch],
                                                  &(eeprom_ch_info[ch]),
                                                  fat_extension_chan);
 
+                       /* Set up driver's info for upper half */
                        iwl4965_set_fat_chan_info(priv, phymode,
                                                  (eeprom_ch_index[ch] + 4),
                                                  &(eeprom_ch_info[ch]),
@@ -5458,6 +5593,15 @@ static int iwl4965_init_channel_map(struct iwl4965_priv *priv)
        return 0;
 }
 
+/*
+ * iwl4965_free_channel_map - undo allocations in iwl4965_init_channel_map
+ */
+static void iwl4965_free_channel_map(struct iwl4965_priv *priv)
+{
+       kfree(priv->channel_info);
+       priv->channel_count = 0;
+}
+
 /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
  * sending probe req.  This should be set long enough to hear probe responses
  * from more than one AP.  */
@@ -5546,7 +5690,8 @@ static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode,
 
                scan_ch->channel = channels[i].chan;
 
-               ch_info = iwl4965_get_channel_info(priv, phymode, scan_ch->channel);
+               ch_info = iwl4965_get_channel_info(priv, phymode,
+                                        scan_ch->channel);
                if (!is_channel_valid(ch_info)) {
                        IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
                                       scan_ch->channel);
@@ -5568,7 +5713,7 @@ static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode,
                scan_ch->active_dwell = cpu_to_le16(active_dwell);
                scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
 
-               /* Set power levels to defaults */
+               /* Set txpower levels to defaults */
                scan_ch->tpc.dsp_atten = 110;
                /* scan_pwr_info->tpc.dsp_atten; */
 
@@ -5578,8 +5723,8 @@ static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode,
                else {
                        scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
                        /* NOTE: if we were doing 6Mb OFDM for scans we'd use
-                        * power level
-                        scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3;
+                        * power level:
+                        * scan_ch->tpc.tx_gain = ((1 << 5) | (2 << 3)) | 3;
                         */
                }
 
@@ -5650,10 +5795,8 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv)
                A = 0,
                B = 1,
                G = 2,
-               A_11N = 3,
-               G_11N = 4,
        };
-       int mode_count = 5;
+       int mode_count = 3;
 
        if (priv->modes) {
                IWL_DEBUG_INFO("Geography modes already initialized.\n");
@@ -5693,6 +5836,9 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv)
        modes[A].num_rates = 8; /* just OFDM */
        modes[A].rates = &rates[4];
        modes[A].num_channels = 0;
+#ifdef CONFIG_IWL4965_HT
+       iwl4965_init_ht_hw_capab(&modes[A].ht_info, MODE_IEEE80211A);
+#endif
 
        modes[B].mode = MODE_IEEE80211B;
        modes[B].channels = channels;
@@ -5705,18 +5851,9 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv)
        modes[G].rates = rates;
        modes[G].num_rates = 12;        /* OFDM & CCK */
        modes[G].num_channels = 0;
-
-       modes[G_11N].mode = MODE_IEEE80211G;
-       modes[G_11N].channels = channels;
-       modes[G_11N].num_rates = 13;        /* OFDM & CCK */
-       modes[G_11N].rates = rates;
-       modes[G_11N].num_channels = 0;
-
-       modes[A_11N].mode = MODE_IEEE80211A;
-       modes[A_11N].channels = &channels[ARRAY_SIZE(iwl4965_eeprom_band_1)];
-       modes[A_11N].rates = &rates[4];
-       modes[A_11N].num_rates = 9; /* just OFDM */
-       modes[A_11N].num_channels = 0;
+#ifdef CONFIG_IWL4965_HT
+       iwl4965_init_ht_hw_capab(&modes[G].ht_info, MODE_IEEE80211G);
+#endif
 
        priv->ieee_channels = channels;
        priv->ieee_rates = rates;
@@ -5736,11 +5873,9 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv)
 
                if (is_channel_a_band(ch)) {
                        geo_ch = &modes[A].channels[modes[A].num_channels++];
-                       modes[A_11N].num_channels++;
                } else {
                        geo_ch = &modes[B].channels[modes[B].num_channels++];
                        modes[G].num_channels++;
-                       modes[G_11N].num_channels++;
                }
 
                geo_ch->freq = ieee80211chan2mhz(ch->channel);
@@ -5800,6 +5935,17 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv)
        return 0;
 }
 
+/*
+ * iwl4965_free_geos - undo allocations in iwl4965_init_geos
+ */
+static void iwl4965_free_geos(struct iwl4965_priv *priv)
+{
+       kfree(priv->modes);
+       kfree(priv->ieee_channels);
+       kfree(priv->ieee_rates);
+       clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
+}
+
 /******************************************************************************
  *
  * uCode download functions
@@ -5808,55 +5954,20 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv)
 
 static void iwl4965_dealloc_ucode_pci(struct iwl4965_priv *priv)
 {
-       if (priv->ucode_code.v_addr != NULL) {
-               pci_free_consistent(priv->pci_dev,
-                                   priv->ucode_code.len,
-                                   priv->ucode_code.v_addr,
-                                   priv->ucode_code.p_addr);
-               priv->ucode_code.v_addr = NULL;
-       }
-       if (priv->ucode_data.v_addr != NULL) {
-               pci_free_consistent(priv->pci_dev,
-                                   priv->ucode_data.len,
-                                   priv->ucode_data.v_addr,
-                                   priv->ucode_data.p_addr);
-               priv->ucode_data.v_addr = NULL;
-       }
-       if (priv->ucode_data_backup.v_addr != NULL) {
-               pci_free_consistent(priv->pci_dev,
-                                   priv->ucode_data_backup.len,
-                                   priv->ucode_data_backup.v_addr,
-                                   priv->ucode_data_backup.p_addr);
-               priv->ucode_data_backup.v_addr = NULL;
-       }
-       if (priv->ucode_init.v_addr != NULL) {
-               pci_free_consistent(priv->pci_dev,
-                                   priv->ucode_init.len,
-                                   priv->ucode_init.v_addr,
-                                   priv->ucode_init.p_addr);
-               priv->ucode_init.v_addr = NULL;
-       }
-       if (priv->ucode_init_data.v_addr != NULL) {
-               pci_free_consistent(priv->pci_dev,
-                                   priv->ucode_init_data.len,
-                                   priv->ucode_init_data.v_addr,
-                                   priv->ucode_init_data.p_addr);
-               priv->ucode_init_data.v_addr = NULL;
-       }
-       if (priv->ucode_boot.v_addr != NULL) {
-               pci_free_consistent(priv->pci_dev,
-                                   priv->ucode_boot.len,
-                                   priv->ucode_boot.v_addr,
-                                   priv->ucode_boot.p_addr);
-               priv->ucode_boot.v_addr = NULL;
-       }
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
 }
 
 /**
  * iwl4965_verify_inst_full - verify runtime uCode image in card vs. host,
  *     looking at all data.
  */
-static int iwl4965_verify_inst_full(struct iwl4965_priv *priv, __le32 * image, u32 len)
+static int iwl4965_verify_inst_full(struct iwl4965_priv *priv, __le32 *image,
+                                u32 len)
 {
        u32 val;
        u32 save_len = len;
@@ -5981,8 +6092,9 @@ static int iwl4965_verify_ucode(struct iwl4965_priv *priv)
 
        IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
 
-       /* Show first several data entries in instruction SRAM.
-        * Selection of bootstrap image is arbitrary. */
+       /* Since nothing seems to match, show first several data entries in
+        * instruction SRAM, so maybe visual inspection will give a clue.
+        * Selection of bootstrap image (vs. other images) is arbitrary. */
        image = (__le32 *)priv->ucode_boot.v_addr;
        len = priv->ucode_boot.len;
        rc = iwl4965_verify_inst_full(priv, image, len);
@@ -6074,7 +6186,7 @@ static int iwl4965_load_bsm(struct iwl4965_priv *priv)
                return -EINVAL;
 
        /* Tell bootstrap uCode where to find the "Initialize" uCode
-        *   in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965.
+        *   in host DRAM ... host DRAM physical address bits 35:4 for 4965.
         * NOTE:  iwl4965_initialize_alive_start() will replace these values,
         *        after the "initialize" uCode has run, to point to
         *        runtime/protocol instructions and backup data cache. */
@@ -6146,6 +6258,7 @@ static void iwl4965_nic_start(struct iwl4965_priv *priv)
        iwl4965_write32(priv, CSR_RESET, 0);
 }
 
+
 /**
  * iwl4965_read_ucode - Read uCode images from disk file.
  *
@@ -6154,7 +6267,7 @@ static void iwl4965_nic_start(struct iwl4965_priv *priv)
 static int iwl4965_read_ucode(struct iwl4965_priv *priv)
 {
        struct iwl4965_ucode *ucode;
-       int rc = 0;
+       int ret;
        const struct firmware *ucode_raw;
        const char *name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode";
        u8 *src;
@@ -6163,9 +6276,10 @@ static int iwl4965_read_ucode(struct iwl4965_priv *priv)
 
        /* Ask kernel firmware_class module to get the boot firmware off disk.
         * request_firmware() is synchronous, file is in memory on return. */
-       rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
-       if (rc < 0) {
-               IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc);
+       ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
+       if (ret < 0) {
+               IWL_ERROR("%s firmware file req failed: Reason %d\n",
+                                       name, ret);
                goto error;
        }
 
@@ -6175,7 +6289,7 @@ static int iwl4965_read_ucode(struct iwl4965_priv *priv)
        /* Make sure that we got at least our header! */
        if (ucode_raw->size < sizeof(*ucode)) {
                IWL_ERROR("File size way too small!\n");
-               rc = -EINVAL;
+               ret = -EINVAL;
                goto err_release;
        }
 
@@ -6208,43 +6322,43 @@ static int iwl4965_read_ucode(struct iwl4965_priv *priv)
 
                IWL_DEBUG_INFO("uCode file size %d too small\n",
                               (int)ucode_raw->size);
-               rc = -EINVAL;
+               ret = -EINVAL;
                goto err_release;
        }
 
        /* Verify that uCode images will fit in card's SRAM */
        if (inst_size > IWL_MAX_INST_SIZE) {
-               IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n",
-                              (int)inst_size);
-               rc = -EINVAL;
+               IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n",
+                              inst_size);
+               ret = -EINVAL;
                goto err_release;
        }
 
        if (data_size > IWL_MAX_DATA_SIZE) {
-               IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n",
-                              (int)data_size);
-               rc = -EINVAL;
+               IWL_DEBUG_INFO("uCode data len %d too large to fit in\n",
+                               data_size);
+               ret = -EINVAL;
                goto err_release;
        }
        if (init_size > IWL_MAX_INST_SIZE) {
                IWL_DEBUG_INFO
-                   ("uCode init instr len %d too large to fit in card\n",
-                    (int)init_size);
-               rc = -EINVAL;
+                   ("uCode init instr len %d too large to fit in\n",
+                     init_size);
+               ret = -EINVAL;
                goto err_release;
        }
        if (init_data_size > IWL_MAX_DATA_SIZE) {
                IWL_DEBUG_INFO
-                   ("uCode init data len %d too large to fit in card\n",
-                    (int)init_data_size);
-               rc = -EINVAL;
+                   ("uCode init data len %d too large to fit in\n",
+                     init_data_size);
+               ret = -EINVAL;
                goto err_release;
        }
        if (boot_size > IWL_MAX_BSM_SIZE) {
                IWL_DEBUG_INFO
-                   ("uCode boot instr len %d too large to fit in bsm\n",
-                    (int)boot_size);
-               rc = -EINVAL;
+                   ("uCode boot instr len %d too large to fit in\n",
+                     boot_size);
+               ret = -EINVAL;
                goto err_release;
        }
 
@@ -6254,56 +6368,41 @@ static int iwl4965_read_ucode(struct iwl4965_priv *priv)
         * 1) unmodified from disk
         * 2) backup cache for save/restore during power-downs */
        priv->ucode_code.len = inst_size;
-       priv->ucode_code.v_addr =
-           pci_alloc_consistent(priv->pci_dev,
-                                priv->ucode_code.len,
-                                &(priv->ucode_code.p_addr));
+       iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
 
        priv->ucode_data.len = data_size;
-       priv->ucode_data.v_addr =
-           pci_alloc_consistent(priv->pci_dev,
-                                priv->ucode_data.len,
-                                &(priv->ucode_data.p_addr));
+       iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
 
        priv->ucode_data_backup.len = data_size;
-       priv->ucode_data_backup.v_addr =
-           pci_alloc_consistent(priv->pci_dev,
-                                priv->ucode_data_backup.len,
-                                &(priv->ucode_data_backup.p_addr));
-
+       iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
 
        /* Initialization instructions and data */
-       priv->ucode_init.len = init_size;
-       priv->ucode_init.v_addr =
-           pci_alloc_consistent(priv->pci_dev,
-                                priv->ucode_init.len,
-                                &(priv->ucode_init.p_addr));
-
-       priv->ucode_init_data.len = init_data_size;
-       priv->ucode_init_data.v_addr =
-           pci_alloc_consistent(priv->pci_dev,
-                                priv->ucode_init_data.len,
-                                &(priv->ucode_init_data.p_addr));
+       if (init_size && init_data_size) {
+               priv->ucode_init.len = init_size;
+               iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
+
+               priv->ucode_init_data.len = init_data_size;
+               iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
+
+               if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr)
+                       goto err_pci_alloc;
+       }
 
        /* Bootstrap (instructions only, no data) */
-       priv->ucode_boot.len = boot_size;
-       priv->ucode_boot.v_addr =
-           pci_alloc_consistent(priv->pci_dev,
-                                priv->ucode_boot.len,
-                                &(priv->ucode_boot.p_addr));
+       if (boot_size) {
+               priv->ucode_boot.len = boot_size;
+               iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
 
-       if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
-           !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr ||
-           !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr)
-               goto err_pci_alloc;
+               if (!priv->ucode_boot.v_addr)
+                       goto err_pci_alloc;
+       }
 
        /* Copy images into buffers for card's bus-master reads ... */
 
        /* Runtime instructions (first block of data in file) */
        src = &ucode->data[0];
        len = priv->ucode_code.len;
-       IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n",
-                      (int)len);
+       IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %Zd\n", len);
        memcpy(priv->ucode_code.v_addr, src, len);
        IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
                priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
@@ -6312,8 +6411,7 @@ static int iwl4965_read_ucode(struct iwl4965_priv *priv)
         * NOTE:  Copy into backup buffer will be done in iwl4965_up()  */
        src = &ucode->data[inst_size];
        len = priv->ucode_data.len;
-       IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n",
-                      (int)len);
+       IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len);
        memcpy(priv->ucode_data.v_addr, src, len);
        memcpy(priv->ucode_data_backup.v_addr, src, len);
 
@@ -6321,8 +6419,8 @@ static int iwl4965_read_ucode(struct iwl4965_priv *priv)
        if (init_size) {
                src = &ucode->data[inst_size + data_size];
                len = priv->ucode_init.len;
-               IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n",
-                              (int)len);
+               IWL_DEBUG_INFO("Copying (but not loading) init instr len %Zd\n",
+                               len);
                memcpy(priv->ucode_init.v_addr, src, len);
        }
 
@@ -6330,16 +6428,15 @@ static int iwl4965_read_ucode(struct iwl4965_priv *priv)
        if (init_data_size) {
                src = &ucode->data[inst_size + data_size + init_size];
                len = priv->ucode_init_data.len;
-               IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n",
-                              (int)len);
+               IWL_DEBUG_INFO("Copying (but not loading) init data len %Zd\n",
+                              len);
                memcpy(priv->ucode_init_data.v_addr, src, len);
        }
 
        /* Bootstrap instructions (5th block) */
        src = &ucode->data[inst_size + data_size + init_size + init_data_size];
        len = priv->ucode_boot.len;
-       IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n",
-                      (int)len);
+       IWL_DEBUG_INFO("Copying (but not loading) boot instr len %Zd\n", len);
        memcpy(priv->ucode_boot.v_addr, src, len);
 
        /* We have our copies now, allow OS release its copies */
@@ -6348,14 +6445,14 @@ static int iwl4965_read_ucode(struct iwl4965_priv *priv)
 
  err_pci_alloc:
        IWL_ERROR("failed to allocate pci memory\n");
-       rc = -ENOMEM;
+       ret = -ENOMEM;
        iwl4965_dealloc_ucode_pci(priv);
 
  err_release:
        release_firmware(ucode_raw);
 
  error:
-       return rc;
+       return ret;
 }
 
 
@@ -6494,44 +6591,16 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv)
                goto restart;
        }
 
-       /* After the ALIVE response, we can process host commands */
+       /* After the ALIVE response, we can send host commands to 4965 uCode */
        set_bit(STATUS_ALIVE, &priv->status);
 
        /* Clear out the uCode error bit if it is set */
        clear_bit(STATUS_FW_ERROR, &priv->status);
 
-       rc = iwl4965_init_channel_map(priv);
-       if (rc) {
-               IWL_ERROR("initializing regulatory failed: %d\n", rc);
-               return;
-       }
-
-       iwl4965_init_geos(priv);
-
        if (iwl4965_is_rfkill(priv))
                return;
 
-       if (!priv->mac80211_registered) {
-               /* Unlock so any user space entry points can call back into
-                * the driver without a deadlock... */
-               mutex_unlock(&priv->mutex);
-               iwl4965_rate_control_register(priv->hw);
-               rc = ieee80211_register_hw(priv->hw);
-               priv->hw->conf.beacon_int = 100;
-               mutex_lock(&priv->mutex);
-
-               if (rc) {
-                       iwl4965_rate_control_unregister(priv->hw);
-                       IWL_ERROR("Failed to register network "
-                                 "device (error %d)\n", rc);
-                       return;
-               }
-
-               priv->mac80211_registered = 1;
-
-               iwl4965_reset_channel_flag(priv);
-       } else
-               ieee80211_start_queues(priv->hw);
+       ieee80211_start_queues(priv->hw);
 
        priv->active_rate = priv->rates_mask;
        priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
@@ -6551,7 +6620,7 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv)
                memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
        }
 
-       /* Configure BT coexistence */
+       /* Configure Bluetooth device coexistence support */
        iwl4965_send_bt_config(priv);
 
        /* Configure the adapter for unassociated operation */
@@ -6562,7 +6631,9 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv)
        set_bit(STATUS_READY, &priv->status);
 
        iwl4965_rf_kill_ct_config(priv);
+
        IWL_DEBUG_INFO("ALIVE processing complete.\n");
+       wake_up_interruptible(&priv->wait_command_queue);
 
        if (priv->error_recovering)
                iwl4965_error_recovery(priv);
@@ -6614,6 +6685,8 @@ static void __iwl4965_down(struct iwl4965_priv *priv)
                                        STATUS_RF_KILL_HW |
                               test_bit(STATUS_RF_KILL_SW, &priv->status) <<
                                        STATUS_RF_KILL_SW |
+                              test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
+                                       STATUS_GEO_CONFIGURED |
                               test_bit(STATUS_IN_SUSPEND, &priv->status) <<
                                        STATUS_IN_SUSPEND;
                goto exit;
@@ -6625,13 +6698,16 @@ static void __iwl4965_down(struct iwl4965_priv *priv)
                                STATUS_RF_KILL_HW |
                        test_bit(STATUS_RF_KILL_SW, &priv->status) <<
                                STATUS_RF_KILL_SW |
+                       test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
+                               STATUS_GEO_CONFIGURED |
                        test_bit(STATUS_IN_SUSPEND, &priv->status) <<
                                STATUS_IN_SUSPEND |
                        test_bit(STATUS_FW_ERROR, &priv->status) <<
                                STATUS_FW_ERROR;
 
        spin_lock_irqsave(&priv->lock, flags);
-       iwl4965_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+       iwl4965_clear_bit(priv, CSR_GP_CNTRL,
+                        CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
        spin_unlock_irqrestore(&priv->lock, flags);
 
        iwl4965_hw_txq_ctx_stop(priv);
@@ -6675,9 +6751,7 @@ static void iwl4965_down(struct iwl4965_priv *priv)
 
 static int __iwl4965_up(struct iwl4965_priv *priv)
 {
-       DECLARE_MAC_BUF(mac);
        int rc, i;
-       u32 hw_rf_kill = 0;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
                IWL_WARNING("Exit pending; will not bring the NIC up\n");
@@ -6687,7 +6761,7 @@ static int __iwl4965_up(struct iwl4965_priv *priv)
        if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
                IWL_WARNING("Radio disabled by SW RF kill (module "
                            "parameter)\n");
-               return 0;
+               return -ENODEV;
        }
 
        if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
@@ -6695,6 +6769,18 @@ static int __iwl4965_up(struct iwl4965_priv *priv)
                return -EIO;
        }
 
+       /* If platform's RF_KILL switch is NOT set to KILL */
+       if (iwl4965_read32(priv, CSR_GP_CNTRL) &
+                               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
+               clear_bit(STATUS_RF_KILL_HW, &priv->status);
+       else {
+               set_bit(STATUS_RF_KILL_HW, &priv->status);
+               if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) {
+                       IWL_WARNING("Radio disabled by HW RF Kill switch\n");
+                       return -ENODEV;
+               }
+       }
+
        iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF);
 
        rc = iwl4965_hw_nic_init(priv);
@@ -6720,19 +6806,11 @@ static int __iwl4965_up(struct iwl4965_priv *priv)
         * This will be used to initialize the on-board processor's
         * data SRAM for a clean start when the runtime program first loads. */
        memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
-                       priv->ucode_data.len);
+              priv->ucode_data.len);
 
-       /* If platform's RF_KILL switch is set to KILL,
-        * wait for BIT_INT_RF_KILL interrupt before loading uCode
-        * and getting things started */
-       if (!(iwl4965_read32(priv, CSR_GP_CNTRL) &
-                               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
-               hw_rf_kill = 1;
-
-       if (test_bit(STATUS_RF_KILL_HW, &priv->status) || hw_rf_kill) {
-               IWL_WARNING("Radio disabled by HW RF Kill switch\n");
+       /* We return success when we resume from suspend and rf_kill is on. */
+       if (test_bit(STATUS_RF_KILL_HW, &priv->status))
                return 0;
-       }
 
        for (i = 0; i < MAX_HW_RESTARTS; i++) {
 
@@ -6751,13 +6829,6 @@ static int __iwl4965_up(struct iwl4965_priv *priv)
                /* start card; "initialize" will load runtime ucode */
                iwl4965_nic_start(priv);
 
-               /* MAC Address location in EEPROM same for 3945/4965 */
-               get_eeprom_mac(priv, priv->mac_addr);
-               IWL_DEBUG_INFO("MAC address: %s\n",
-                              print_mac(mac, priv->mac_addr));
-
-               SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
-
                IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
 
                return 0;
@@ -6984,7 +7055,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
         * that based on the direct_mask added to each channel entry */
        scan->tx_cmd.len = cpu_to_le16(
                iwl4965_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
-                       IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
+                       IWL_MAX_SCAN_SIZE - sizeof(*scan), 0));
        scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
        scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
        scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
@@ -7101,6 +7172,8 @@ static void iwl4965_bg_rx_replenish(struct work_struct *data)
        mutex_unlock(&priv->mutex);
 }
 
+#define IWL_DELAY_NEXT_SCAN (HZ*2)
+
 static void iwl4965_bg_post_associate(struct work_struct *data)
 {
        struct iwl4965_priv *priv = container_of(data, struct iwl4965_priv,
@@ -7125,7 +7198,7 @@ static void iwl4965_bg_post_associate(struct work_struct *data)
 
        mutex_lock(&priv->mutex);
 
-       if (!priv->interface_id || !priv->is_open) {
+       if (!priv->vif || !priv->is_open) {
                mutex_unlock(&priv->mutex);
                return;
        }
@@ -7147,13 +7220,8 @@ static void iwl4965_bg_post_associate(struct work_struct *data)
        priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
 
 #ifdef CONFIG_IWL4965_HT
-       if (priv->is_ht_enabled && priv->current_assoc_ht.is_ht)
-               iwl4965_set_rxon_ht(priv, &priv->current_assoc_ht);
-       else {
-               priv->active_rate_ht[0] = 0;
-               priv->active_rate_ht[1] = 0;
-               priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ;
-       }
+       if (priv->current_ht_config.is_ht)
+               iwl4965_set_rxon_ht(priv, &priv->current_ht_config);
 #endif /* CONFIG_IWL4965_HT*/
        iwl4965_set_rxon_chain(priv);
        priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
@@ -7216,6 +7284,8 @@ static void iwl4965_bg_post_associate(struct work_struct *data)
 #ifdef CONFIG_IWL4965_QOS
        iwl4965_activate_qos(priv, 0);
 #endif /* CONFIG_IWL4965_QOS */
+       /* we have just associated, don't start scan too early */
+       priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
        mutex_unlock(&priv->mutex);
 }
 
@@ -7234,6 +7304,8 @@ static void iwl4965_bg_abort_scan(struct work_struct *work)
        mutex_unlock(&priv->mutex);
 }
 
+static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+
 static void iwl4965_bg_scan_completed(struct work_struct *work)
 {
        struct iwl4965_priv *priv =
@@ -7244,6 +7316,9 @@ static void iwl4965_bg_scan_completed(struct work_struct *work)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
+       if (test_bit(STATUS_CONF_PENDING, &priv->status))
+               iwl4965_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw));
+
        ieee80211_scan_completed(priv->hw);
 
        /* Since setting the TXPOWER may have been deferred while
@@ -7259,23 +7334,83 @@ static void iwl4965_bg_scan_completed(struct work_struct *work)
  *
  *****************************************************************************/
 
+#define UCODE_READY_TIMEOUT    (2 * HZ)
+
 static int iwl4965_mac_start(struct ieee80211_hw *hw)
 {
        struct iwl4965_priv *priv = hw->priv;
+       int ret;
 
        IWL_DEBUG_MAC80211("enter\n");
 
+       if (pci_enable_device(priv->pci_dev)) {
+               IWL_ERROR("Fail to pci_enable_device\n");
+               return -ENODEV;
+       }
+       pci_restore_state(priv->pci_dev);
+       pci_enable_msi(priv->pci_dev);
+
+       ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED,
+                         DRV_NAME, priv);
+       if (ret) {
+               IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq);
+               goto out_disable_msi;
+       }
+
        /* we should be verifying the device is ready to be opened */
        mutex_lock(&priv->mutex);
 
-       priv->is_open = 1;
+       memset(&priv->staging_rxon, 0, sizeof(struct iwl4965_rxon_cmd));
+       /* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+        * ucode filename and max sizes are card-specific. */
+
+       if (!priv->ucode_code.len) {
+               ret = iwl4965_read_ucode(priv);
+               if (ret) {
+                       IWL_ERROR("Could not read microcode: %d\n", ret);
+                       mutex_unlock(&priv->mutex);
+                       goto out_release_irq;
+               }
+       }
 
-       if (!iwl4965_is_rfkill(priv))
-               ieee80211_start_queues(priv->hw);
+       ret = __iwl4965_up(priv);
 
        mutex_unlock(&priv->mutex);
+
+       if (ret)
+               goto out_release_irq;
+
+       IWL_DEBUG_INFO("Start UP work done.\n");
+
+       if (test_bit(STATUS_IN_SUSPEND, &priv->status))
+               return 0;
+
+       /* Wait for START_ALIVE from ucode. Otherwise callbacks from
+        * mac80211 will not be run successfully. */
+       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+                       test_bit(STATUS_READY, &priv->status),
+                       UCODE_READY_TIMEOUT);
+       if (!ret) {
+               if (!test_bit(STATUS_READY, &priv->status)) {
+                       IWL_ERROR("Wait for START_ALIVE timeout after %dms.\n",
+                                 jiffies_to_msecs(UCODE_READY_TIMEOUT));
+                       ret = -ETIMEDOUT;
+                       goto out_release_irq;
+               }
+       }
+
+       priv->is_open = 1;
        IWL_DEBUG_MAC80211("leave\n");
        return 0;
+
+out_release_irq:
+       free_irq(priv->pci_dev->irq, priv);
+out_disable_msi:
+       pci_disable_msi(priv->pci_dev);
+       pci_disable_device(priv->pci_dev);
+       priv->is_open = 0;
+       IWL_DEBUG_MAC80211("leave - failed\n");
+       return ret;
 }
 
 static void iwl4965_mac_stop(struct ieee80211_hw *hw)
@@ -7284,17 +7419,30 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw)
 
        IWL_DEBUG_MAC80211("enter\n");
 
+       if (!priv->is_open) {
+               IWL_DEBUG_MAC80211("leave - skip\n");
+               return;
+       }
 
-       mutex_lock(&priv->mutex);
-       /* stop mac, cancel any scan request and clear
-        * RXON_FILTER_ASSOC_MSK BIT
-        */
        priv->is_open = 0;
-       iwl4965_scan_cancel_timeout(priv, 100);
-       cancel_delayed_work(&priv->post_associate);
-       priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       iwl4965_commit_rxon(priv);
-       mutex_unlock(&priv->mutex);
+
+       if (iwl4965_is_ready_rf(priv)) {
+               /* stop mac, cancel any scan request and clear
+                * RXON_FILTER_ASSOC_MSK BIT
+                */
+               mutex_lock(&priv->mutex);
+               iwl4965_scan_cancel_timeout(priv, 100);
+               cancel_delayed_work(&priv->post_associate);
+               mutex_unlock(&priv->mutex);
+       }
+
+       iwl4965_down(priv);
+
+       flush_workqueue(priv->workqueue);
+       free_irq(priv->pci_dev->irq, priv);
+       pci_disable_msi(priv->pci_dev);
+       pci_save_state(priv->pci_dev);
+       pci_disable_device(priv->pci_dev);
 
        IWL_DEBUG_MAC80211("leave\n");
 }
@@ -7328,15 +7476,15 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
        unsigned long flags;
        DECLARE_MAC_BUF(mac);
 
-       IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type);
+       IWL_DEBUG_MAC80211("enter: type %d\n", conf->type);
 
-       if (priv->interface_id) {
-               IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
-               return 0;
+       if (priv->vif) {
+               IWL_DEBUG_MAC80211("leave - vif != NULL\n");
+               return -EOPNOTSUPP;
        }
 
        spin_lock_irqsave(&priv->lock, flags);
-       priv->interface_id = conf->if_id;
+       priv->vif = conf->vif;
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -7346,11 +7494,13 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
                IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr));
                memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
        }
-       iwl4965_set_mode(priv, conf->type);
 
-       IWL_DEBUG_MAC80211("leave\n");
+       if (iwl4965_is_ready(priv))
+               iwl4965_set_mode(priv, conf->type);
+
        mutex_unlock(&priv->mutex);
 
+       IWL_DEBUG_MAC80211("leave\n");
        return 0;
 }
 
@@ -7366,21 +7516,23 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
        struct iwl4965_priv *priv = hw->priv;
        const struct iwl4965_channel_info *ch_info;
        unsigned long flags;
+       int ret = 0;
 
        mutex_lock(&priv->mutex);
        IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
 
+       priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
+
        if (!iwl4965_is_ready(priv)) {
                IWL_DEBUG_MAC80211("leave - not ready\n");
-               mutex_unlock(&priv->mutex);
-               return -EIO;
+               ret = -EIO;
+               goto out;
        }
 
-       /* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only
-        * what is exposed through include/ declarations */
        if (unlikely(!iwl4965_param_disable_hw_scan &&
                     test_bit(STATUS_SCANNING, &priv->status))) {
                IWL_DEBUG_MAC80211("leave - scanning\n");
+               set_bit(STATUS_CONF_PENDING, &priv->status);
                mutex_unlock(&priv->mutex);
                return 0;
        }
@@ -7393,8 +7545,8 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
                               conf->channel, conf->phymode);
                IWL_DEBUG_MAC80211("leave - invalid channel\n");
                spin_unlock_irqrestore(&priv->lock, flags);
-               mutex_unlock(&priv->mutex);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
 #ifdef CONFIG_IWL4965_HT
@@ -7423,8 +7575,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
 #ifdef IEEE80211_CONF_CHANNEL_SWITCH
        if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
                iwl4965_hw_channel_switch(priv, conf->channel);
-               mutex_unlock(&priv->mutex);
-               return 0;
+               goto out;
        }
 #endif
 
@@ -7432,14 +7583,13 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
 
        if (!conf->radio_enabled) {
                IWL_DEBUG_MAC80211("leave - radio disabled\n");
-               mutex_unlock(&priv->mutex);
-               return 0;
+               goto out;
        }
 
        if (iwl4965_is_rfkill(priv)) {
                IWL_DEBUG_MAC80211("leave - RF kill\n");
-               mutex_unlock(&priv->mutex);
-               return -EIO;
+               ret = -EIO;
+               goto out;
        }
 
        iwl4965_set_rate(priv);
@@ -7452,16 +7602,17 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
 
        IWL_DEBUG_MAC80211("leave\n");
 
+out:
+       clear_bit(STATUS_CONF_PENDING, &priv->status);
        mutex_unlock(&priv->mutex);
-
-       return 0;
+       return ret;
 }
 
 static void iwl4965_config_ap(struct iwl4965_priv *priv)
 {
        int rc = 0;
 
-       if (priv->status & STATUS_EXIT_PENDING)
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        /* The following should be done only at AP bring up */
@@ -7519,7 +7670,8 @@ static void iwl4965_config_ap(struct iwl4965_priv *priv)
         * clear sta table, add BCAST sta... */
 }
 
-static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif,
                                    struct ieee80211_if_conf *conf)
 {
        struct iwl4965_priv *priv = hw->priv;
@@ -7537,9 +7689,11 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, int if_id,
                return 0;
        }
 
+       if (!iwl4965_is_alive(priv))
+               return -EAGAIN;
+
        mutex_lock(&priv->mutex);
 
-       IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id);
        if (conf->bssid)
                IWL_DEBUG_MAC80211("bssid: %s\n",
                                   print_mac(mac, conf->bssid));
@@ -7556,8 +7710,8 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, int if_id,
                return 0;
        }
 
-       if (priv->interface_id != if_id) {
-               IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
+       if (priv->vif != vif) {
+               IWL_DEBUG_MAC80211("leave - priv->vif != vif\n");
                mutex_unlock(&priv->mutex);
                return 0;
        }
@@ -7575,6 +7729,9 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, int if_id,
                priv->ibss_beacon = conf->beacon;
        }
 
+       if (iwl4965_is_rfkill(priv))
+               goto done;
+
        if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
            !is_multicast_ether_addr(conf->bssid)) {
                /* If there is currently a HW scan going on in the background
@@ -7609,6 +7766,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, int if_id,
                iwl4965_commit_rxon(priv);
        }
 
+ done:
        spin_lock_irqsave(&priv->lock, flags);
        if (!conf->ssid_len)
                memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
@@ -7645,13 +7803,14 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mutex);
 
-       iwl4965_scan_cancel_timeout(priv, 100);
-       cancel_delayed_work(&priv->post_associate);
-       priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       iwl4965_commit_rxon(priv);
-
-       if (priv->interface_id == conf->if_id) {
-               priv->interface_id = 0;
+       if (iwl4965_is_ready_rf(priv)) {
+               iwl4965_scan_cancel_timeout(priv, 100);
+               cancel_delayed_work(&priv->post_associate);
+               priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+               iwl4965_commit_rxon(priv);
+       }
+       if (priv->vif == conf->vif) {
+               priv->vif = NULL;
                memset(priv->bssid, 0, ETH_ALEN);
                memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
                priv->essid_len = 0;
@@ -7661,30 +7820,39 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
        IWL_DEBUG_MAC80211("leave\n");
 
 }
-static void iwl4965_mac_erp_ie_changed(struct ieee80211_hw *hw,
-               u8 changes, int cts_protection, int preamble)
+
+static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif,
+                                    struct ieee80211_bss_conf *bss_conf,
+                                    u32 changes)
 {
        struct iwl4965_priv *priv = hw->priv;
 
-       if (changes & IEEE80211_ERP_CHANGE_PREAMBLE) {
-               if (preamble == WLAN_ERP_PREAMBLE_SHORT)
+       if (changes & BSS_CHANGED_ERP_PREAMBLE) {
+               if (bss_conf->use_short_preamble)
                        priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
                else
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
        }
 
-       if (changes & IEEE80211_ERP_CHANGE_PROTECTION) {
-               if (cts_protection && (priv->phymode != MODE_IEEE80211A))
+       if (changes & BSS_CHANGED_ERP_CTS_PROT) {
+               if (bss_conf->use_cts_prot && (priv->phymode != MODE_IEEE80211A))
                        priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
                else
                        priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
        }
 
+       if (changes & BSS_CHANGED_ASSOC) {
+               /*
+                * TODO:
+                * do stuff instead of sniffing assoc resp
+                */
+       }
+
        if (iwl4965_is_associated(priv))
                iwl4965_send_rxon_assoc(priv);
 }
 
-#define IWL_DELAY_NEXT_SCAN (HZ*2)
 static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
 {
        int rc = 0;
@@ -7708,16 +7876,20 @@ static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
                goto out_unlock;
        }
 
+       /* we don't schedule scan within next_scan_jiffies period */
+       if (priv->next_scan_jiffies &&
+                       time_after(priv->next_scan_jiffies, jiffies)) {
+               rc = -EAGAIN;
+               goto out_unlock;
+       }
        /* if we just finished scan ask for delay */
-       if (priv->last_scan_jiffies &&
-           time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
-                      jiffies)) {
+       if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies +
+                               IWL_DELAY_NEXT_SCAN, jiffies)) {
                rc = -EAGAIN;
                goto out_unlock;
        }
        if (len) {
-               IWL_DEBUG_SCAN("direct scan for  "
-                              "%s [%d]\n ",
+               IWL_DEBUG_SCAN("direct scan for %s [%d]\n ",
                               iwl4965_escape_essid(ssid, len), (int)len);
 
                priv->one_direct_scan = 1;
@@ -7805,7 +7977,7 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue,
 #ifdef CONFIG_IWL4965_QOS
        unsigned long flags;
        int q;
-#endif /* CONFIG_IWL_QOS */
+#endif /* CONFIG_IWL4965_QOS */
 
        IWL_DEBUG_MAC80211("enter\n");
 
@@ -7917,7 +8089,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
        priv->lq_mngr.lq_ready = 0;
 #ifdef CONFIG_IWL4965_HT
        spin_lock_irqsave(&priv->lock, flags);
-       memset(&priv->current_assoc_ht, 0, sizeof(struct sta_ht_info));
+       memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info));
        spin_unlock_irqrestore(&priv->lock, flags);
 #ifdef CONFIG_IWL4965_HT_AGG
 /*     if (priv->lq_mngr.agg_ctrl.granted_ba)
@@ -7959,6 +8131,12 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
+       if (!iwl4965_is_ready_rf(priv)) {
+               IWL_DEBUG_MAC80211("leave - not ready\n");
+               mutex_unlock(&priv->mutex);
+               return;
+       }
+
        /* we are restarting association process
         * clear RXON_FILTER_ASSOC_MSK bit
         */
@@ -7976,12 +8154,6 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
                return;
        }
 
-       if (!iwl4965_is_ready_rf(priv)) {
-               IWL_DEBUG_MAC80211("leave - not ready\n");
-               mutex_unlock(&priv->mutex);
-               return;
-       }
-
        priv->only_active_channel = 0;
 
        iwl4965_set_rate(priv);
@@ -7989,7 +8161,6 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
        mutex_unlock(&priv->mutex);
 
        IWL_DEBUG_MAC80211("leave\n");
-
 }
 
 static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
@@ -8037,132 +8208,61 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
 }
 
 #ifdef CONFIG_IWL4965_HT
-union ht_cap_info {
-       struct {
-               u16 advanced_coding_cap         :1;
-               u16 supported_chan_width_set    :1;
-               u16 mimo_power_save_mode        :2;
-               u16 green_field                 :1;
-               u16 short_GI20                  :1;
-               u16 short_GI40                  :1;
-               u16 tx_stbc                     :1;
-               u16 rx_stbc                     :1;
-               u16 beam_forming                :1;
-               u16 delayed_ba                  :1;
-               u16 maximal_amsdu_size          :1;
-               u16 cck_mode_at_40MHz           :1;
-               u16 psmp_support                :1;
-               u16 stbc_ctrl_frame_support     :1;
-               u16 sig_txop_protection_support :1;
-       };
-       u16 val;
-} __attribute__ ((packed));
-
-union ht_param_info{
-       struct {
-               u8 max_rx_ampdu_factor  :2;
-               u8 mpdu_density         :3;
-               u8 reserved             :3;
-       };
-       u8 val;
-} __attribute__ ((packed));
-
-union ht_exra_param_info {
-       struct {
-               u8 ext_chan_offset              :2;
-               u8 tx_chan_width                :1;
-               u8 rifs_mode                    :1;
-               u8 controlled_access_only       :1;
-               u8 service_interval_granularity :3;
-       };
-       u8 val;
-} __attribute__ ((packed));
-
-union ht_operation_mode{
-       struct {
-               u16 op_mode     :2;
-               u16 non_GF      :1;
-               u16 reserved    :13;
-       };
-       u16 val;
-} __attribute__ ((packed));
-
 
-static int sta_ht_info_init(struct ieee80211_ht_capability *ht_cap,
-                           struct ieee80211_ht_additional_info *ht_extra,
-                           struct sta_ht_info *ht_info_ap,
-                           struct sta_ht_info *ht_info)
+static void iwl4965_ht_info_fill(struct ieee80211_conf *conf,
+                                struct iwl4965_priv *priv)
 {
-       union ht_cap_info cap;
-       union ht_operation_mode op_mode;
-       union ht_param_info param_info;
-       union ht_exra_param_info extra_param_info;
+       struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
+       struct ieee80211_ht_info *ht_conf = &conf->ht_conf;
+       struct ieee80211_ht_bss_info *ht_bss_conf = &conf->ht_bss_conf;
 
        IWL_DEBUG_MAC80211("enter: \n");
 
-       if (!ht_info) {
-               IWL_DEBUG_MAC80211("leave: ht_info is NULL\n");
-               return -1;
+       if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) {
+               iwl_conf->is_ht = 0;
+               return;
        }
 
-       if (ht_cap) {
-               cap.val = (u16) le16_to_cpu(ht_cap->capabilities_info);
-               param_info.val = ht_cap->mac_ht_params_info;
-               ht_info->is_ht = 1;
-               if (cap.short_GI20)
-                       ht_info->sgf |= 0x1;
-               if (cap.short_GI40)
-                       ht_info->sgf |= 0x2;
-               ht_info->is_green_field = cap.green_field;
-               ht_info->max_amsdu_size = cap.maximal_amsdu_size;
-               ht_info->supported_chan_width = cap.supported_chan_width_set;
-               ht_info->tx_mimo_ps_mode = cap.mimo_power_save_mode;
-               memcpy(ht_info->supp_rates, ht_cap->supported_mcs_set, 16);
-
-               ht_info->ampdu_factor = param_info.max_rx_ampdu_factor;
-               ht_info->mpdu_density = param_info.mpdu_density;
-
-               IWL_DEBUG_MAC80211("SISO mask 0x%X MIMO mask 0x%X \n",
-                                   ht_cap->supported_mcs_set[0],
-                                   ht_cap->supported_mcs_set[1]);
-
-               if (ht_info_ap) {
-                       ht_info->control_channel = ht_info_ap->control_channel;
-                       ht_info->extension_chan_offset =
-                               ht_info_ap->extension_chan_offset;
-                       ht_info->tx_chan_width = ht_info_ap->tx_chan_width;
-                       ht_info->operating_mode = ht_info_ap->operating_mode;
-               }
-
-               if (ht_extra) {
-                       extra_param_info.val = ht_extra->ht_param;
-                       ht_info->control_channel = ht_extra->control_chan;
-                       ht_info->extension_chan_offset =
-                           extra_param_info.ext_chan_offset;
-                       ht_info->tx_chan_width = extra_param_info.tx_chan_width;
-                       op_mode.val = (u16)
-                           le16_to_cpu(ht_extra->operation_mode);
-                       ht_info->operating_mode = op_mode.op_mode;
-                       IWL_DEBUG_MAC80211("control channel %d\n",
-                                           ht_extra->control_chan);
-               }
-       } else
-               ht_info->is_ht = 0;
-
+       iwl_conf->is_ht = 1;
+       priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
+
+       if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
+               iwl_conf->sgf |= 0x1;
+       if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
+               iwl_conf->sgf |= 0x2;
+
+       iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
+       iwl_conf->max_amsdu_size =
+               !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
+       iwl_conf->supported_chan_width =
+               !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH);
+       iwl_conf->tx_mimo_ps_mode =
+               (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
+       memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
+
+       iwl_conf->control_channel = ht_bss_conf->primary_channel;
+       iwl_conf->extension_chan_offset =
+               ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
+       iwl_conf->tx_chan_width =
+               !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH);
+       iwl_conf->ht_protection =
+               ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION;
+       iwl_conf->non_GF_STA_present =
+               !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT);
+
+       IWL_DEBUG_MAC80211("control channel %d\n",
+               iwl_conf->control_channel);
        IWL_DEBUG_MAC80211("leave\n");
-       return 0;
 }
 
 static int iwl4965_mac_conf_ht(struct ieee80211_hw *hw,
-                          struct ieee80211_ht_capability *ht_cap,
-                          struct ieee80211_ht_additional_info *ht_extra)
+                              struct ieee80211_conf *conf)
 {
        struct iwl4965_priv *priv = hw->priv;
-       int rs;
 
        IWL_DEBUG_MAC80211("enter: \n");
 
-       rs = sta_ht_info_init(ht_cap, ht_extra, NULL, &priv->current_assoc_ht);
+       iwl4965_ht_info_fill(conf, priv);
        iwl4965_set_rxon_chain(priv);
 
        if (priv && priv->assoc_id &&
@@ -8177,57 +8277,32 @@ static int iwl4965_mac_conf_ht(struct ieee80211_hw *hw,
                spin_unlock_irqrestore(&priv->lock, flags);
        }
 
-       IWL_DEBUG_MAC80211("leave: control channel %d\n",
-                       ht_extra->control_chan);
-       return rs;
-
+       IWL_DEBUG_MAC80211("leave:\n");
+       return 0;
 }
 
 static void iwl4965_set_ht_capab(struct ieee80211_hw *hw,
-                            struct ieee80211_ht_capability *ht_cap,
-                            u8 use_wide_chan)
+                       struct ieee80211_ht_cap *ht_cap,
+                       u8 use_current_config)
 {
-       union ht_cap_info cap;
-       union ht_param_info param_info;
+       struct ieee80211_conf *conf = &hw->conf;
+       struct ieee80211_hw_mode *mode = conf->mode;
 
-       memset(&cap, 0, sizeof(union ht_cap_info));
-       memset(&param_info, 0, sizeof(union ht_param_info));
-
-       cap.maximal_amsdu_size = HT_IE_MAX_AMSDU_SIZE_4K;
-       cap.green_field = 1;
-       cap.short_GI20 = 1;
-       cap.short_GI40 = 1;
-       cap.supported_chan_width_set = use_wide_chan;
-       cap.mimo_power_save_mode = 0x3;
-
-       param_info.max_rx_ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
-       param_info.mpdu_density = CFG_HT_MPDU_DENSITY_DEF;
-       ht_cap->capabilities_info = (__le16) cpu_to_le16(cap.val);
-       ht_cap->mac_ht_params_info = (u8) param_info.val;
-
-       ht_cap->supported_mcs_set[0] = 0xff;
-       ht_cap->supported_mcs_set[1] = 0xff;
-       ht_cap->supported_mcs_set[4] =
-           (cap.supported_chan_width_set) ? 0x1: 0x0;
+       if (use_current_config) {
+               ht_cap->cap_info = cpu_to_le16(conf->ht_conf.cap);
+               memcpy(ht_cap->supp_mcs_set,
+                               conf->ht_conf.supp_mcs_set, 16);
+       } else {
+               ht_cap->cap_info = cpu_to_le16(mode->ht_info.cap);
+               memcpy(ht_cap->supp_mcs_set,
+                               mode->ht_info.supp_mcs_set, 16);
+       }
+       ht_cap->ampdu_params_info =
+               (mode->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) |
+               ((mode->ht_info.ampdu_density << 2) &
+                                       IEEE80211_HT_CAP_AMPDU_DENSITY);
 }
 
-static void iwl4965_mac_get_ht_capab(struct ieee80211_hw *hw,
-                                struct ieee80211_ht_capability *ht_cap)
-{
-       u8 use_wide_channel = 1;
-       struct iwl4965_priv *priv = hw->priv;
-
-       IWL_DEBUG_MAC80211("enter: \n");
-       if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
-               use_wide_channel = 0;
-
-       /* no fat tx allowed on 2.4GHZ */
-       if (priv->phymode != MODE_IEEE80211A)
-               use_wide_channel = 0;
-
-       iwl4965_set_ht_capab(hw, ht_cap, use_wide_channel);
-       IWL_DEBUG_MAC80211("leave: \n");
-}
 #endif /*CONFIG_IWL4965_HT*/
 
 /*****************************************************************************
@@ -8942,15 +9017,13 @@ static struct ieee80211_ops iwl4965_hw_ops = {
        .get_tsf = iwl4965_mac_get_tsf,
        .reset_tsf = iwl4965_mac_reset_tsf,
        .beacon_update = iwl4965_mac_beacon_update,
-       .erp_ie_changed = iwl4965_mac_erp_ie_changed,
+       .bss_info_changed = iwl4965_bss_info_changed,
 #ifdef CONFIG_IWL4965_HT
        .conf_ht = iwl4965_mac_conf_ht,
-       .get_ht_capab = iwl4965_mac_get_ht_capab,
+       .ampdu_action = iwl4965_mac_ampdu_action,
 #ifdef CONFIG_IWL4965_HT_AGG
        .ht_tx_agg_start = iwl4965_mac_ht_tx_agg_start,
        .ht_tx_agg_stop = iwl4965_mac_ht_tx_agg_stop,
-       .ht_rx_agg_start = iwl4965_mac_ht_rx_agg_start,
-       .ht_rx_agg_stop = iwl4965_mac_ht_rx_agg_stop,
 #endif  /* CONFIG_IWL4965_HT_AGG */
 #endif  /* CONFIG_IWL4965_HT */
        .hw_scan = iwl4965_mac_hw_scan
@@ -8962,7 +9035,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        struct iwl4965_priv *priv;
        struct ieee80211_hw *hw;
        int i;
+       DECLARE_MAC_BUF(mac);
 
+       /* Disabling hardware scan means that mac80211 will perform scans
+        * "the hard way", rather than using device's scan. */
        if (iwl4965_param_disable_hw_scan) {
                IWL_DEBUG_INFO("Disabling hw_scan\n");
                iwl4965_hw_ops.hw_scan = NULL;
@@ -9014,9 +9090,11 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        /* Tell mac80211 our Tx characteristics */
        hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
 
+       /* Default value; 4 EDCA QOS priorities */
        hw->queues = 4;
 #ifdef CONFIG_IWL4965_HT
 #ifdef CONFIG_IWL4965_HT_AGG
+       /* Enhanced value; more queues, to support 11n aggregation */
        hw->queues = 16;
 #endif /* CONFIG_IWL4965_HT_AGG */
 #endif /* CONFIG_IWL4965_HT */
@@ -9040,6 +9118,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        pci_set_master(pdev);
 
+       /* Clear the driver's (not device's) station table */
        iwl4965_clear_stations_table(priv);
 
        priv->data_retry_limit = -1;
@@ -9059,9 +9138,11 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        err = pci_request_regions(pdev, DRV_NAME);
        if (err)
                goto out_pci_disable_device;
+
        /* We disable the RETRY_TIMEOUT register (0x41) to keep
         * PCI Tx retries from interfering with C3 CPU state */
        pci_write_config_byte(pdev, 0x41, 0x00);
+
        priv->hw_base = pci_iomap(pdev, 0, 0);
        if (!priv->hw_base) {
                err = -ENODEV;
@@ -9074,6 +9155,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        /* Initialize module parameter values here */
 
+       /* Disable radio (SW RF KILL) via parameter when loading driver */
        if (iwl4965_param_disable) {
                set_bit(STATUS_RF_KILL_SW, &priv->status);
                IWL_DEBUG_INFO("Radio disabled.\n");
@@ -9083,11 +9165,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        priv->ps_mode = 0;
        priv->use_ant_b_for_management_frame = 1; /* start with ant B */
-       priv->is_ht_enabled = 1;
-       priv->channel_width = IWL_CHANNEL_WIDTH_40MHZ;
        priv->valid_antenna = 0x7;      /* assume all 3 connected */
        priv->ps_mode = IWL_MIMO_PS_NONE;
 
+       /* Choose which receivers/antennas to use */
        iwl4965_set_rxon_chain(priv);
 
        printk(KERN_INFO DRV_NAME
@@ -9096,7 +9177,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        /* Device-specific setup */
        if (iwl4965_hw_set_hw_setting(priv)) {
                IWL_ERROR("failed to set hw settings\n");
-               mutex_unlock(&priv->mutex);
                goto out_iounmap;
        }
 
@@ -9121,50 +9201,70 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        iwl4965_disable_interrupts(priv);
 
-       pci_enable_msi(pdev);
-
-       err = request_irq(pdev->irq, iwl4965_isr, IRQF_SHARED, DRV_NAME, priv);
-       if (err) {
-               IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
-               goto out_disable_msi;
-       }
-
-       mutex_lock(&priv->mutex);
-
        err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
        if (err) {
                IWL_ERROR("failed to create sysfs device attributes\n");
-               mutex_unlock(&priv->mutex);
                goto out_release_irq;
        }
 
-       /* fetch ucode file from disk, alloc and copy to bus-master buffers ...
-        * ucode filename and max sizes are card-specific. */
-       err = iwl4965_read_ucode(priv);
+       /* nic init */
+       iwl4965_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+                    CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+
+        iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+        err = iwl4965_poll_bit(priv, CSR_GP_CNTRL,
+                          CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+                          CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+        if (err < 0) {
+                IWL_DEBUG_INFO("Failed to init the card\n");
+               goto out_remove_sysfs;
+        }
+       /* Read the EEPROM */
+       err = iwl4965_eeprom_init(priv);
        if (err) {
-               IWL_ERROR("Could not read microcode: %d\n", err);
-               mutex_unlock(&priv->mutex);
-               goto out_pci_alloc;
+               IWL_ERROR("Unable to init EEPROM\n");
+               goto out_remove_sysfs;
        }
+       /* MAC Address location in EEPROM same for 3945/4965 */
+       get_eeprom_mac(priv, priv->mac_addr);
+       IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
+       SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
 
-       mutex_unlock(&priv->mutex);
+       err = iwl4965_init_channel_map(priv);
+       if (err) {
+               IWL_ERROR("initializing regulatory failed: %d\n", err);
+               goto out_remove_sysfs;
+       }
 
-       IWL_DEBUG_INFO("Queueing UP work.\n");
+       err = iwl4965_init_geos(priv);
+       if (err) {
+               IWL_ERROR("initializing geos failed: %d\n", err);
+               goto out_free_channel_map;
+       }
+       iwl4965_reset_channel_flag(priv);
 
-       queue_work(priv->workqueue, &priv->up);
+       iwl4965_rate_control_register(priv->hw);
+       err = ieee80211_register_hw(priv->hw);
+       if (err) {
+               IWL_ERROR("Failed to register network device (error %d)\n", err);
+               goto out_free_geos;
+       }
 
-       return 0;
+       priv->hw->conf.beacon_int = 100;
+       priv->mac80211_registered = 1;
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
 
- out_pci_alloc:
-       iwl4965_dealloc_ucode_pci(priv);
+       return 0;
 
+ out_free_geos:
+       iwl4965_free_geos(priv);
+ out_free_channel_map:
+       iwl4965_free_channel_map(priv);
+ out_remove_sysfs:
        sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
 
  out_release_irq:
-       free_irq(pdev->irq, priv);
-
- out_disable_msi:
-       pci_disable_msi(pdev);
        destroy_workqueue(priv->workqueue);
        priv->workqueue = NULL;
        iwl4965_unset_hw_setting(priv);
@@ -9230,17 +9330,13 @@ static void iwl4965_pci_remove(struct pci_dev *pdev)
        destroy_workqueue(priv->workqueue);
        priv->workqueue = NULL;
 
-       free_irq(pdev->irq, priv);
-       pci_disable_msi(pdev);
        pci_iounmap(pdev, priv->hw_base);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
 
-       kfree(priv->channel_info);
-
-       kfree(priv->ieee_channels);
-       kfree(priv->ieee_rates);
+       iwl4965_free_channel_map(priv);
+       iwl4965_free_geos(priv);
 
        if (priv->ibss_beacon)
                dev_kfree_skb(priv->ibss_beacon);
@@ -9254,89 +9350,27 @@ static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct iwl4965_priv *priv = pci_get_drvdata(pdev);
 
-       set_bit(STATUS_IN_SUSPEND, &priv->status);
-
-       /* Take down the device; powers it off, etc. */
-       iwl4965_down(priv);
-
-       if (priv->mac80211_registered)
-               ieee80211_stop_queues(priv->hw);
+       if (priv->is_open) {
+               set_bit(STATUS_IN_SUSPEND, &priv->status);
+               iwl4965_mac_stop(priv->hw);
+               priv->is_open = 1;
+       }
 
-       pci_save_state(pdev);
-       pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
 
        return 0;
 }
 
-static void iwl4965_resume(struct iwl4965_priv *priv)
-{
-       unsigned long flags;
-
-       /* The following it a temporary work around due to the
-        * suspend / resume not fully initializing the NIC correctly.
-        * Without all of the following, resume will not attempt to take
-        * down the NIC (it shouldn't really need to) and will just try
-        * and bring the NIC back up.  However that fails during the
-        * ucode verification process.  This then causes iwl4965_down to be
-        * called *after* iwl4965_hw_nic_init() has succeeded -- which
-        * then lets the next init sequence succeed.  So, we've
-        * replicated all of that NIC init code here... */
-
-       iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF);
-
-       iwl4965_hw_nic_init(priv);
-
-       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR,
-                   CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-       iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF);
-       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-       /* tell the device to stop sending interrupts */
-       iwl4965_disable_interrupts(priv);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl4965_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
-       if (!iwl4965_grab_nic_access(priv)) {
-               iwl4965_write_prph(priv, APMG_CLK_DIS_REG,
-                               APMG_CLK_VAL_DMA_CLK_RQT);
-               iwl4965_release_nic_access(priv);
-       }
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       udelay(5);
-
-       iwl4965_hw_nic_reset(priv);
-
-       /* Bring the device back up */
-       clear_bit(STATUS_IN_SUSPEND, &priv->status);
-       queue_work(priv->workqueue, &priv->up);
-}
-
 static int iwl4965_pci_resume(struct pci_dev *pdev)
 {
        struct iwl4965_priv *priv = pci_get_drvdata(pdev);
-       int err;
-
-       printk(KERN_INFO "Coming out of suspend...\n");
 
        pci_set_power_state(pdev, PCI_D0);
-       err = pci_enable_device(pdev);
-       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_restore_state won't help
-        * here since it only restores the first 64 bytes pci config header.
-        */
-       pci_write_config_byte(pdev, 0x41, 0x00);
-
-       iwl4965_resume(priv);
+       if (priv->is_open)
+               iwl4965_mac_start(priv->hw);
 
+       clear_bit(STATUS_IN_SUSPEND, &priv->status);
        return 0;
 }
 
@@ -9408,6 +9442,8 @@ MODULE_PARM_DESC(queues_num, "number of hw queues.");
 /* QoS */
 module_param_named(qos_enable, iwl4965_param_qos_enable, int, 0444);
 MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
+module_param_named(amsdu_size_8K, iwl4965_param_amsdu_size_8K, int, 0444);
+MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
 
 module_exit(iwl4965_exit);
 module_init(iwl4965_init);