headers: remove sched.h from interrupt.h
[safe/jmp/linux-2.6] / drivers / net / wireless / iwlwifi / iwl-core.c
index 61b9902..2dc9287 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/etherdevice.h>
+#include <linux/sched.h>
 #include <net/mac80211.h>
 
 #include "iwl-eeprom.h"
@@ -36,9 +37,9 @@
 #include "iwl-debug.h"
 #include "iwl-core.h"
 #include "iwl-io.h"
-#include "iwl-rfkill.h"
 #include "iwl-power.h"
 #include "iwl-sta.h"
+#include "iwl-helpers.h"
 
 
 MODULE_DESCRIPTION("iwl core");
@@ -59,6 +60,11 @@ MODULE_LICENSE("GPL");
                                    IWL_RATE_##pp##M_INDEX,    \
                                    IWL_RATE_##np##M_INDEX }
 
+u32 iwl_debug_level;
+EXPORT_SYMBOL(iwl_debug_level);
+
+static irqreturn_t iwl_isr(int irq, void *data);
+
 /*
  * Parameter order:
  *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
@@ -91,7 +97,6 @@ EXPORT_SYMBOL(iwl_rates);
 void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
                                  struct ieee80211_tx_info *info)
 {
-       int rate_index;
        struct ieee80211_tx_rate *r = &info->control.rates[0];
 
        info->antenna_sel_tx =
@@ -100,16 +105,13 @@ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
                r->flags |= IEEE80211_TX_RC_MCS;
        if (rate_n_flags & RATE_MCS_GF_MSK)
                r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
-       if (rate_n_flags & RATE_MCS_FAT_MSK)
+       if (rate_n_flags & RATE_MCS_HT40_MSK)
                r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
        if (rate_n_flags & RATE_MCS_DUP_MSK)
                r->flags |= IEEE80211_TX_RC_DUP_DATA;
        if (rate_n_flags & RATE_MCS_SGI_MSK)
                r->flags |= IEEE80211_TX_RC_SHORT_GI;
-       rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags);
-       if (info->band == IEEE80211_BAND_5GHZ)
-               rate_index -= IWL_FIRST_OFDM_RATE;
-       r->idx = rate_index;
+       r->idx = iwl_hwrate_to_mac80211_idx(rate_n_flags, info->band);
 }
 EXPORT_SYMBOL(iwl_hwrate_to_tx_control);
 
@@ -144,6 +146,27 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
 }
 EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx);
 
+int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band)
+{
+       int idx = 0;
+       int band_offset = 0;
+
+       /* HT rate format: mac80211 wants an MCS number, which is just LSB */
+       if (rate_n_flags & RATE_MCS_HT_MSK) {
+               idx = (rate_n_flags & 0xff);
+               return idx;
+       /* Legacy rate format, search for match in table */
+       } else {
+               if (band == IEEE80211_BAND_5GHZ)
+                       band_offset = IWL_FIRST_OFDM_RATE;
+               for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
+                       if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
+                               return idx - band_offset;
+       }
+
+       return -1;
+}
+
 u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant)
 {
        int i;
@@ -240,6 +263,47 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_hw_nic_init);
 
+/*
+ * QoS  support
+*/
+void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+{
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       priv->qos_data.def_qos_parm.qos_flags = 0;
+
+       if (priv->qos_data.qos_cap.q_AP.queue_request &&
+           !priv->qos_data.qos_cap.q_AP.txop_request)
+               priv->qos_data.def_qos_parm.qos_flags |=
+                       QOS_PARAM_FLG_TXOP_TYPE_MSK;
+       if (priv->qos_data.qos_active)
+               priv->qos_data.def_qos_parm.qos_flags |=
+                       QOS_PARAM_FLG_UPDATE_EDCA_MSK;
+
+       if (priv->current_ht_config.is_ht)
+               priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
+
+       if (force || iwl_is_associated(priv)) {
+               IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
+                               priv->qos_data.qos_active,
+                               priv->qos_data.def_qos_parm.qos_flags);
+
+               iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
+                                      sizeof(struct iwl_qosparam_cmd),
+                                      &priv->qos_data.def_qos_parm, NULL);
+       }
+}
+EXPORT_SYMBOL(iwl_activate_qos);
+
+/*
+ * AC        CWmin         CW max      AIFSN      TXOP Limit    TXOP Limit
+ *                                              (802.11b)      (802.11a/g)
+ * AC_BK      15            1023        7           0               0
+ * AC_BE      15            1023        3           0               0
+ * AC_VI       7              15        2          6.016ms       3.008ms
+ * AC_VO       3               7        2          3.264ms       1.504ms
+ */
 void iwl_reset_qos(struct iwl_priv *priv)
 {
        u16 cw_min = 15;
@@ -271,6 +335,7 @@ void iwl_reset_qos(struct iwl_priv *priv)
        if (priv->qos_data.qos_active)
                aifs = 3;
 
+       /* AC_BE */
        priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min);
        priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max);
        priv->qos_data.def_qos_parm.ac[0].aifsn = aifs;
@@ -278,6 +343,7 @@ void iwl_reset_qos(struct iwl_priv *priv)
        priv->qos_data.def_qos_parm.ac[0].reserved1 = 0;
 
        if (priv->qos_data.qos_active) {
+               /* AC_BK */
                i = 1;
                priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min);
                priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max);
@@ -285,11 +351,12 @@ void iwl_reset_qos(struct iwl_priv *priv)
                priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
                priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
 
+               /* AC_VI */
                i = 2;
                priv->qos_data.def_qos_parm.ac[i].cw_min =
                        cpu_to_le16((cw_min + 1) / 2 - 1);
                priv->qos_data.def_qos_parm.ac[i].cw_max =
-                       cpu_to_le16(cw_max);
+                       cpu_to_le16(cw_min);
                priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
                if (is_legacy)
                        priv->qos_data.def_qos_parm.ac[i].edca_txop =
@@ -299,11 +366,12 @@ void iwl_reset_qos(struct iwl_priv *priv)
                                cpu_to_le16(3008);
                priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
 
+               /* AC_VO */
                i = 3;
                priv->qos_data.def_qos_parm.ac[i].cw_min =
                        cpu_to_le16((cw_min + 1) / 4 - 1);
                priv->qos_data.def_qos_parm.ac[i].cw_max =
-                       cpu_to_le16((cw_max + 1) / 2 - 1);
+                       cpu_to_le16((cw_min + 1) / 2 - 1);
                priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
                priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
                if (is_legacy)
@@ -344,13 +412,14 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
 
        ht_info->ht_supported = true;
 
-       ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
+       if (priv->cfg->ht_greenfield_support)
+               ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
        ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
        ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
                             (WLAN_HT_CAP_SM_PS_DISABLED << 2));
 
        max_bit_rate = MAX_BIT_RATE_20_MHZ;
-       if (priv->hw_params.fat_channel & BIT(band)) {
+       if (priv->hw_params.ht40_channel & BIT(band)) {
                ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
                ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
                ht_info->mcs.rx_mask[4] = 0x01;
@@ -388,12 +457,12 @@ static void iwlcore_init_hw_rates(struct iwl_priv *priv,
 {
        int i;
 
-       for (i = 0; i < IWL_RATE_COUNT; i++) {
+       for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {
                rates[i].bitrate = iwl_rates[i].ieee * 5;
                rates[i].hw_value = i; /* Rate scaling will work on indexes */
                rates[i].hw_value_short = i;
                rates[i].flags = 0;
-               if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) {
+               if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) {
                        /*
                         * If CCK != 1M then set short preamble rate flag.
                         */
@@ -429,7 +498,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
        if (!channels)
                return -ENOMEM;
 
-       rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)),
+       rates = kzalloc((sizeof(struct ieee80211_rate) * IWL_RATE_COUNT_LEGACY),
                        GFP_KERNEL);
        if (!rates) {
                kfree(channels);
@@ -441,7 +510,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
        sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
        /* just OFDM */
        sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
-       sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE;
+       sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE;
 
        if (priv->cfg->sku & IWL_SKU_N)
                iwlcore_init_ht_hw_capab(priv, &sband->ht_cap,
@@ -451,7 +520,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
        sband->channels = channels;
        /* OFDM & CCK */
        sband->bitrates = rates;
-       sband->n_bitrates = IWL_RATE_COUNT;
+       sband->n_bitrates = IWL_RATE_COUNT_LEGACY;
 
        if (priv->cfg->sku & IWL_SKU_N)
                iwlcore_init_ht_hw_capab(priv, &sband->ht_cap,
@@ -490,17 +559,14 @@ int iwlcore_init_geos(struct iwl_priv *priv)
                        if (ch->flags & EEPROM_CHANNEL_RADAR)
                                geo_ch->flags |= IEEE80211_CHAN_RADAR;
 
-                       geo_ch->flags |= ch->fat_extension_channel;
+                       geo_ch->flags |= ch->ht40_extension_channel;
 
-                       if (ch->max_power_avg > priv->tx_power_channel_lmt)
-                               priv->tx_power_channel_lmt = ch->max_power_avg;
+                       if (ch->max_power_avg > priv->tx_power_device_lmt)
+                               priv->tx_power_device_lmt = ch->max_power_avg;
                } else {
                        geo_ch->flags |= IEEE80211_CHAN_DISABLED;
                }
 
-               /* Save flags for reg domain usage */
-               geo_ch->orig_flags = geo_ch->flags;
-
                IWL_DEBUG_INFO(priv, "Channel %d Freq=%d[%sGHz] %s flag=0x%X\n",
                                ch->channel, geo_ch->center_freq,
                                is_channel_a_band(ch) ?  "5.2" : "2.4",
@@ -557,36 +623,97 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv,
                return 0;
 
        if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
-               return !(ch_info->fat_extension_channel &
-                                       IEEE80211_CHAN_NO_FAT_ABOVE);
+               return !(ch_info->ht40_extension_channel &
+                                       IEEE80211_CHAN_NO_HT40PLUS);
        else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
-               return !(ch_info->fat_extension_channel &
-                                       IEEE80211_CHAN_NO_FAT_BELOW);
+               return !(ch_info->ht40_extension_channel &
+                                       IEEE80211_CHAN_NO_HT40MINUS);
 
        return 0;
 }
 
-u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
+u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
                         struct ieee80211_sta_ht_cap *sta_ht_inf)
 {
        struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
 
        if ((!iwl_ht_conf->is_ht) ||
-          (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) ||
-          (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE))
+           (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ))
                return 0;
 
+       /* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
+        * the bit will not set if it is pure 40MHz case
+        */
        if (sta_ht_inf) {
-               if ((!sta_ht_inf->ht_supported) ||
-                  (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)))
+               if (!sta_ht_inf->ht_supported)
                        return 0;
        }
-
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (priv->disable_ht40)
+               return 0;
+#endif
        return iwl_is_channel_extension(priv, priv->band,
-                                       le16_to_cpu(priv->staging_rxon.channel),
-                                       iwl_ht_conf->extension_chan_offset);
+                       le16_to_cpu(priv->staging_rxon.channel),
+                       iwl_ht_conf->extension_chan_offset);
+}
+EXPORT_SYMBOL(iwl_is_ht40_tx_allowed);
+
+static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
+{
+       u16 new_val = 0;
+       u16 beacon_factor = 0;
+
+       beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val;
+       new_val = beacon_val / beacon_factor;
+
+       if (!new_val)
+               new_val = max_beacon_val;
+
+       return new_val;
+}
+
+void iwl_setup_rxon_timing(struct iwl_priv *priv)
+{
+       u64 tsf;
+       s32 interval_tm, rem;
+       unsigned long flags;
+       struct ieee80211_conf *conf = NULL;
+       u16 beacon_int;
+
+       conf = ieee80211_get_hw_conf(priv->hw);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
+       priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
+
+       if (priv->iw_mode == NL80211_IFTYPE_STATION) {
+               beacon_int = priv->beacon_int;
+               priv->rxon_timing.atim_window = 0;
+       } else {
+               beacon_int = priv->vif->bss_conf.beacon_int;
+
+               /* TODO: we need to get atim_window from upper stack
+                * for now we set to 0 */
+               priv->rxon_timing.atim_window = 0;
+       }
+
+       beacon_int = iwl_adjust_beacon_interval(beacon_int,
+                               priv->hw_params.max_beacon_itrvl * 1024);
+       priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
+
+       tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
+       interval_tm = beacon_int * 1024;
+       rem = do_div(tsf, interval_tm);
+       priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+       IWL_DEBUG_ASSOC(priv,
+                       "beacon interval %d beacon timer %d beacon tim %d\n",
+                       le16_to_cpu(priv->rxon_timing.beacon_interval),
+                       le32_to_cpu(priv->rxon_timing.beacon_init_val),
+                       le16_to_cpu(priv->rxon_timing.atim_window));
 }
-EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
+EXPORT_SYMBOL(iwl_setup_rxon_timing);
 
 void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
 {
@@ -702,6 +829,8 @@ int iwl_full_rxon_required(struct iwl_priv *priv)
             priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
            (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
             priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
+           (priv->staging_rxon.ofdm_ht_triple_stream_basic_rates !=
+            priv->active_rxon.ofdm_ht_triple_stream_basic_rates) ||
            (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
                return 1;
 
@@ -752,43 +881,62 @@ EXPORT_SYMBOL(iwl_rate_get_lowest_plcp);
 void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
 {
        struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
-       u32 val;
 
        if (!ht_info->is_ht) {
-               rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
-                       RXON_FLG_CHANNEL_MODE_PURE_40_MSK |
+               rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
                        RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
-                       RXON_FLG_FAT_PROT_MSK |
+                       RXON_FLG_HT40_PROT_MSK |
                        RXON_FLG_HT_PROT_MSK);
                return;
        }
 
-       /* Set up channel bandwidth:  20 MHz only, or 20/40 mixed if fat ok */
-       if (iwl_is_fat_tx_allowed(priv, NULL))
-               rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK;
-       else
-               rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
-                                RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
-
-       /* Note: control channel is opposite of extension channel */
-       switch (ht_info->extension_chan_offset) {
-       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-               rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
-               break;
-       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-               rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
-               break;
-       case IEEE80211_HT_PARAM_CHA_SEC_NONE:
-       default:
-               rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
-               break;
+       /* FIXME: if the definition of ht_protection changed, the "translation"
+        * will be needed for rxon->flags
+        */
+       rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS);
+
+       /* Set up channel bandwidth:
+        * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
+       /* clear the HT channel mode before set the mode */
+       rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
+                        RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
+       if (iwl_is_ht40_tx_allowed(priv, NULL)) {
+               /* pure ht40 */
+               if (ht_info->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
+                       rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
+                       /* Note: control channel is opposite of extension channel */
+                       switch (ht_info->extension_chan_offset) {
+                       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+                               rxon->flags &= ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+                               break;
+                       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+                               rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+                               break;
+                       }
+               } else {
+                       /* Note: control channel is opposite of extension channel */
+                       switch (ht_info->extension_chan_offset) {
+                       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+                               rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
+                               rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
+                               break;
+                       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+                               rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+                               rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
+                               break;
+                       case IEEE80211_HT_PARAM_CHA_SEC_NONE:
+                       default:
+                               /* channel location only valid if in Mixed mode */
+                               IWL_ERR(priv, "invalid extension channel offset\n");
+                               break;
+                       }
+               }
+       } else {
+               rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
        }
 
-       val = ht_info->ht_protection;
-
-       rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
-
-       iwl_set_rxon_chain(priv);
+       if (priv->cfg->ops->hcmd->set_rxon_chain)
+               priv->cfg->ops->hcmd->set_rxon_chain(priv);
 
        IWL_DEBUG_ASSOC(priv, "supported HT rate 0x%X 0x%X 0x%X "
                        "rxon flags 0x%X operation mode :0x%X "
@@ -868,10 +1016,11 @@ static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
  * never called for monitor mode. The only way mac80211 informs us about
  * monitor mode is through configuring filters (call to configure_filter).
  */
-static bool iwl_is_monitor_mode(struct iwl_priv *priv)
+bool iwl_is_monitor_mode(struct iwl_priv *priv)
 {
        return !!(priv->staging_rxon.filter_flags & RXON_FILTER_PROMISC_MSK);
 }
+EXPORT_SYMBOL(iwl_is_monitor_mode);
 
 /**
  * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
@@ -923,10 +1072,10 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
        if (iwl_is_monitor_mode(priv) &&
            !(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) &&
            ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)) {
-               rx_chain = 0x07 << RXON_RX_CHAIN_VALID_POS;
-               rx_chain |= 0x06 << RXON_RX_CHAIN_FORCE_SEL_POS;
-               rx_chain |= 0x07 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
-               rx_chain |= 0x01 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
+               rx_chain = ANT_ABC << RXON_RX_CHAIN_VALID_POS;
+               rx_chain |= ANT_BC << RXON_RX_CHAIN_FORCE_SEL_POS;
+               rx_chain |= ANT_ABC << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
+               rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
        }
 
        priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain);
@@ -1007,7 +1156,6 @@ void iwl_set_flags_for_band(struct iwl_priv *priv,
                priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
        }
 }
-EXPORT_SYMBOL(iwl_set_flags_for_band);
 
 /*
  * initialize rxon structure with default values from eeprom
@@ -1035,11 +1183,6 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
                                                  RXON_FILTER_ACCEPT_GRP_MSK;
                break;
 
-       case NL80211_IFTYPE_MONITOR:
-               priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
-               priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
-                   RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
-               break;
        default:
                IWL_ERR(priv, "Unsupported interface type %d\n", mode);
                break;
@@ -1078,16 +1221,18 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
        priv->staging_rxon.cck_basic_rates =
            (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
 
-       priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
-                                       RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
+       /* clear both MIX and PURE40 mode flag */
+       priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
+                                       RXON_FLG_CHANNEL_MODE_PURE_40);
        memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
        memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
        priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
        priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
+       priv->staging_rxon.ofdm_ht_triple_stream_basic_rates = 0xff;
 }
 EXPORT_SYMBOL(iwl_connection_init_rx_config);
 
-void iwl_set_rate(struct iwl_priv *priv)
+static void iwl_set_rate(struct iwl_priv *priv)
 {
        const struct ieee80211_supported_band *hw = NULL;
        struct ieee80211_rate *rate;
@@ -1104,7 +1249,7 @@ void iwl_set_rate(struct iwl_priv *priv)
 
        for (i = 0; i < hw->n_bitrates; i++) {
                rate = &(hw->bitrates[i]);
-               if (rate->hw_value < IWL_RATE_COUNT)
+               if (rate->hw_value < IWL_RATE_COUNT_LEGACY)
                        priv->active_rate |= (1 << rate->hw_value);
        }
 
@@ -1133,7 +1278,6 @@ void iwl_set_rate(struct iwl_priv *priv)
                priv->staging_rxon.ofdm_basic_rates =
                   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
 }
-EXPORT_SYMBOL(iwl_set_rate);
 
 void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 {
@@ -1167,7 +1311,6 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
        IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
 }
 #endif
-
 /**
  * iwl_irq_handle_error - called for HW or SW error interrupt from card
  */
@@ -1180,9 +1323,9 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (priv->debug_level & IWL_DL_FW_ERRORS) {
-               iwl_dump_nic_error_log(priv);
-               iwl_dump_nic_event_log(priv);
+       if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) {
+               priv->cfg->ops->lib->dump_nic_error_log(priv);
+               priv->cfg->ops->lib->dump_nic_event_log(priv);
                iwl_print_rx_config_cmd(priv);
        }
 #endif
@@ -1197,11 +1340,6 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
                IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
                          "Restarting adapter due to uCode error.\n");
 
-               if (iwl_is_associated(priv)) {
-                       memcpy(&priv->recovery_rxon, &priv->active_rxon,
-                              sizeof(priv->recovery_rxon));
-                       priv->error_recovering = 1;
-               }
                if (priv->cfg->mod_params->restart_fw)
                        queue_work(priv->workqueue, &priv->restart);
        }
@@ -1211,7 +1349,7 @@ EXPORT_SYMBOL(iwl_irq_handle_error);
 void iwl_configure_filter(struct ieee80211_hw *hw,
                          unsigned int changed_flags,
                          unsigned int *total_flags,
-                         int mc_count, struct dev_addr_list *mc_list)
+                         u64 multicast)
 {
        struct iwl_priv *priv = hw->priv;
        __le32 *filter_flags = &priv->staging_rxon.filter_flags;
@@ -1265,21 +1403,34 @@ int iwl_setup_mac(struct iwl_priv *priv)
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_NOISE_DBM |
                    IEEE80211_HW_AMPDU_AGGREGATION |
-                   IEEE80211_HW_SUPPORTS_PS;
+                   IEEE80211_HW_SPECTRUM_MGMT;
+
+       if (!priv->cfg->broken_powersave)
+               hw->flags |= IEEE80211_HW_SUPPORTS_PS |
+                            IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_ADHOC);
 
        hw->wiphy->custom_regulatory = true;
-       hw->wiphy->max_scan_ssids = 1;
+
+       /* Firmware does not support this */
+       hw->wiphy->disable_beacon_hints = true;
+
+       /*
+        * For now, disable PS by default because it affects
+        * RX performance significantly.
+        */
+       hw->wiphy->ps_default = false;
+
+       hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
+       /* we create the 802.11 header and a zero-length SSID element */
+       hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
 
        /* Default value; 4 EDCA QOS priorities */
        hw->queues = 4;
-       /* queues to support 11n aggregation */
-       if (priv->cfg->sku & IWL_SKU_N)
-               hw->ampdu_queues = priv->cfg->mod_params->num_of_ampdu_queues;
 
-       hw->conf.beacon_int = 100;
        hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
 
        if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
@@ -1302,7 +1453,6 @@ EXPORT_SYMBOL(iwl_setup_mac);
 
 int iwl_set_hw_params(struct iwl_priv *priv)
 {
-       priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto;
        priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
        priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
        if (priv->cfg->mod_params->amsdu_size_8K)
@@ -1311,6 +1461,8 @@ int iwl_set_hw_params(struct iwl_priv *priv)
                priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K;
        priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256;
 
+       priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
+
        if (priv->cfg->mod_params->disable_11n)
                priv->cfg->sku &= ~IWL_SKU_N;
 
@@ -1326,7 +1478,6 @@ int iwl_init_drv(struct iwl_priv *priv)
        priv->ibss_beacon = NULL;
 
        spin_lock_init(&priv->lock);
-       spin_lock_init(&priv->power_data.lock);
        spin_lock_init(&priv->sta_lock);
        spin_lock_init(&priv->hcmd_lock);
 
@@ -1347,7 +1498,9 @@ int iwl_init_drv(struct iwl_priv *priv)
        priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED;
 
        /* Choose which receivers/antennas to use */
-       iwl_set_rxon_chain(priv);
+       if (priv->cfg->ops->hcmd->set_rxon_chain)
+               priv->cfg->ops->hcmd->set_rxon_chain(priv);
+
        iwl_init_scan_params(priv);
 
        iwl_reset_qos(priv);
@@ -1356,9 +1509,10 @@ int iwl_init_drv(struct iwl_priv *priv)
        priv->qos_data.qos_cap.val = 0;
 
        priv->rates_mask = IWL_RATES_MASK;
-       /* If power management is turned on, default to CAM mode */
-       priv->power_mode = IWL_POWER_MODE_CAM;
-       priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX;
+       /* Set the tx_power_user_lmt to the lowest power level
+        * this value will get overwritten by channel max power avg
+        * from eeprom */
+       priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MIN;
 
        ret = iwl_init_channel_map(priv);
        if (ret) {
@@ -1385,6 +1539,8 @@ EXPORT_SYMBOL(iwl_init_drv);
 int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
 {
        int ret = 0;
+       s8 prev_tx_power = priv->tx_power_user_lmt;
+
        if (tx_power < IWL_TX_POWER_TARGET_POWER_MIN) {
                IWL_WARN(priv, "Requested user TXPOWER %d below lower limit %d.\n",
                         tx_power,
@@ -1392,21 +1548,37 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
                return -EINVAL;
        }
 
-       if (tx_power > IWL_TX_POWER_TARGET_POWER_MAX) {
-               IWL_WARN(priv, "Requested user TXPOWER %d above upper limit %d.\n",
-                        tx_power,
-                        IWL_TX_POWER_TARGET_POWER_MAX);
+       if (tx_power > priv->tx_power_device_lmt) {
+               IWL_WARN(priv,
+                       "Requested user TXPOWER %d above upper limit %d.\n",
+                        tx_power, priv->tx_power_device_lmt);
                return -EINVAL;
        }
 
        if (priv->tx_power_user_lmt != tx_power)
                force = true;
 
-       priv->tx_power_user_lmt = tx_power;
-
-       if (force && priv->cfg->ops->lib->send_tx_power)
-               ret = priv->cfg->ops->lib->send_tx_power(priv);
+       /* if nic is not up don't send command */
+       if (iwl_is_ready_rf(priv)) {
+               priv->tx_power_user_lmt = tx_power;
+               if (force && priv->cfg->ops->lib->send_tx_power)
+                       ret = priv->cfg->ops->lib->send_tx_power(priv);
+               else if (!priv->cfg->ops->lib->send_tx_power)
+                       ret = -EOPNOTSUPP;
+               /*
+                * if fail to set tx_power, restore the orig. tx power
+                */
+               if (ret)
+                       priv->tx_power_user_lmt = prev_tx_power;
+       }
 
+       /*
+        * Even this is an async host command, the command
+        * will always report success from uCode
+        * So once driver can placing the command into the queue
+        * successfully, driver can use priv->tx_power_user_lmt
+        * to reflect the current tx power
+        */
        return ret;
 }
 EXPORT_SYMBOL(iwl_set_tx_power);
@@ -1420,29 +1592,325 @@ void iwl_uninit_drv(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_uninit_drv);
 
+#define ICT_COUNT (PAGE_SIZE/sizeof(u32))
+
+/* Free dram table */
+void iwl_free_isr_ict(struct iwl_priv *priv)
+{
+       if (priv->ict_tbl_vir) {
+               pci_free_consistent(priv->pci_dev, (sizeof(u32) * ICT_COUNT) +
+                                       PAGE_SIZE, priv->ict_tbl_vir,
+                                       priv->ict_tbl_dma);
+               priv->ict_tbl_vir = NULL;
+       }
+}
+EXPORT_SYMBOL(iwl_free_isr_ict);
+
+
+/* allocate dram shared table it is a PAGE_SIZE aligned
+ * also reset all data related to ICT table interrupt.
+ */
+int iwl_alloc_isr_ict(struct iwl_priv *priv)
+{
+
+       if (priv->cfg->use_isr_legacy)
+               return 0;
+       /* allocate shrared data table */
+       priv->ict_tbl_vir = pci_alloc_consistent(priv->pci_dev, (sizeof(u32) *
+                                                 ICT_COUNT) + PAGE_SIZE,
+                                                 &priv->ict_tbl_dma);
+       if (!priv->ict_tbl_vir)
+               return -ENOMEM;
+
+       /* align table to PAGE_SIZE boundry */
+       priv->aligned_ict_tbl_dma = ALIGN(priv->ict_tbl_dma, PAGE_SIZE);
+
+       IWL_DEBUG_ISR(priv, "ict dma addr %Lx dma aligned %Lx diff %d\n",
+                            (unsigned long long)priv->ict_tbl_dma,
+                            (unsigned long long)priv->aligned_ict_tbl_dma,
+                       (int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma));
+
+       priv->ict_tbl =  priv->ict_tbl_vir +
+                         (priv->aligned_ict_tbl_dma - priv->ict_tbl_dma);
+
+       IWL_DEBUG_ISR(priv, "ict vir addr %p vir aligned %p diff %d\n",
+                            priv->ict_tbl, priv->ict_tbl_vir,
+                       (int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma));
+
+       /* reset table and index to all 0 */
+       memset(priv->ict_tbl_vir,0, (sizeof(u32) * ICT_COUNT) + PAGE_SIZE);
+       priv->ict_index = 0;
+
+       /* add periodic RX interrupt */
+       priv->inta_mask |= CSR_INT_BIT_RX_PERIODIC;
+       return 0;
+}
+EXPORT_SYMBOL(iwl_alloc_isr_ict);
+
+/* Device is going up inform it about using ICT interrupt table,
+ * also we need to tell the driver to start using ICT interrupt.
+ */
+int iwl_reset_ict(struct iwl_priv *priv)
+{
+       u32 val;
+       unsigned long flags;
+
+       if (!priv->ict_tbl_vir)
+               return 0;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       iwl_disable_interrupts(priv);
+
+       memset(&priv->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT);
+
+       val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT;
+
+       val |= CSR_DRAM_INT_TBL_ENABLE;
+       val |= CSR_DRAM_INIT_TBL_WRAP_CHECK;
+
+       IWL_DEBUG_ISR(priv, "CSR_DRAM_INT_TBL_REG =0x%X "
+                       "aligned dma address %Lx\n",
+                       val, (unsigned long long)priv->aligned_ict_tbl_dma);
+
+       iwl_write32(priv, CSR_DRAM_INT_TBL_REG, val);
+       priv->use_ict = true;
+       priv->ict_index = 0;
+       iwl_write32(priv, CSR_INT, priv->inta_mask);
+       iwl_enable_interrupts(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(iwl_reset_ict);
+
+/* Device is going down disable ict interrupt usage */
+void iwl_disable_ict(struct iwl_priv *priv)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->use_ict = false;
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL(iwl_disable_ict);
+
+/* interrupt handler using ict table, with this interrupt driver will
+ * stop using INTA register to get device's interrupt, reading this register
+ * is expensive, device will write interrupts in ICT dram table, increment
+ * index then will fire interrupt to driver, driver will OR all ICT table
+ * entries from current index up to table entry with 0 value. the result is
+ * the interrupt we need to service, driver will set the entries back to 0 and
+ * set index.
+ */
+irqreturn_t iwl_isr_ict(int irq, void *data)
+{
+       struct iwl_priv *priv = data;
+       u32 inta, inta_mask;
+       u32 val = 0;
+
+       if (!priv)
+               return IRQ_NONE;
+
+       /* dram interrupt table not set yet,
+        * use legacy interrupt.
+        */
+       if (!priv->use_ict)
+               return iwl_isr(irq, data);
+
+       spin_lock(&priv->lock);
+
+       /* Disable (but don't clear!) interrupts here to avoid
+        * back-to-back ISRs and sporadic interrupts from our NIC.
+        * If we have something to service, the tasklet will re-enable ints.
+        * If we *don't* have something, we'll re-enable before leaving here.
+        */
+       inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
+       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+
+       /* Ignore interrupt if there's nothing in NIC to service.
+        * This may be due to IRQ shared with another device,
+        * or due to sporadic interrupts thrown from our NIC. */
+       if (!priv->ict_tbl[priv->ict_index]) {
+               IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n");
+               goto none;
+       }
+
+       /* read all entries that not 0 start with ict_index */
+       while (priv->ict_tbl[priv->ict_index]) {
+
+               val |= le32_to_cpu(priv->ict_tbl[priv->ict_index]);
+               IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n",
+                               priv->ict_index,
+                               le32_to_cpu(priv->ict_tbl[priv->ict_index]));
+               priv->ict_tbl[priv->ict_index] = 0;
+               priv->ict_index = iwl_queue_inc_wrap(priv->ict_index,
+                                                    ICT_COUNT);
+
+       }
+
+       /* We should not get this value, just ignore it. */
+       if (val == 0xffffffff)
+               val = 0;
+
+       inta = (0xff & val) | ((0xff00 & val) << 16);
+       IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
+                       inta, inta_mask, val);
+
+       inta &= priv->inta_mask;
+       priv->inta |= inta;
+
+       /* iwl_irq_tasklet() will service interrupts and re-enable them */
+       if (likely(inta))
+               tasklet_schedule(&priv->irq_tasklet);
+       else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) {
+               /* Allow interrupt if was disabled by this handler and
+                * no tasklet was schedules, We should not enable interrupt,
+                * tasklet will enable it.
+                */
+               iwl_enable_interrupts(priv);
+       }
+
+       spin_unlock(&priv->lock);
+       return IRQ_HANDLED;
+
+ none:
+       /* re-enable interrupts here since we don't have anything to service.
+        * only Re-enable if disabled by irq.
+        */
+       if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta)
+               iwl_enable_interrupts(priv);
+
+       spin_unlock(&priv->lock);
+       return IRQ_NONE;
+}
+EXPORT_SYMBOL(iwl_isr_ict);
+
 
-void iwl_disable_interrupts(struct iwl_priv *priv)
+static irqreturn_t iwl_isr(int irq, void *data)
 {
-       clear_bit(STATUS_INT_ENABLED, &priv->status);
+       struct iwl_priv *priv = data;
+       u32 inta, inta_mask;
+#ifdef CONFIG_IWLWIFI_DEBUG
+       u32 inta_fh;
+#endif
+       if (!priv)
+               return IRQ_NONE;
 
-       /* disable interrupts from uCode/NIC to host */
+       spin_lock(&priv->lock);
+
+       /* Disable (but don't clear!) interrupts here to avoid
+        *    back-to-back ISRs and sporadic interrupts from our NIC.
+        * If we have something to service, the tasklet will re-enable ints.
+        * If we *don't* have something, we'll re-enable before leaving here. */
+       inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
        iwl_write32(priv, CSR_INT_MASK, 0x00000000);
 
-       /* acknowledge/clear/reset any interrupts still pending
-        * from uCode or flow handler (Rx/Tx DMA) */
-       iwl_write32(priv, CSR_INT, 0xffffffff);
-       iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
-       IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
+       /* Discover which interrupts are active/pending */
+       inta = iwl_read32(priv, CSR_INT);
+
+       /* Ignore interrupt if there's nothing in NIC to service.
+        * This may be due to IRQ shared with another device,
+        * or due to sporadic interrupts thrown from our NIC. */
+       if (!inta) {
+               IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n");
+               goto none;
+       }
+
+       if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+               /* Hardware disappeared. It might have already raised
+                * an interrupt */
+               IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
+               goto unplugged;
+       }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
+               inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+               IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, "
+                             "fh 0x%08x\n", inta, inta_mask, inta_fh);
+       }
+#endif
+
+       priv->inta |= inta;
+       /* iwl_irq_tasklet() will service interrupts and re-enable them */
+       if (likely(inta))
+               tasklet_schedule(&priv->irq_tasklet);
+       else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta)
+               iwl_enable_interrupts(priv);
+
+ unplugged:
+       spin_unlock(&priv->lock);
+       return IRQ_HANDLED;
+
+ none:
+       /* re-enable interrupts here since we don't have anything to service. */
+       /* only Re-enable if diabled by irq  and no schedules tasklet. */
+       if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta)
+               iwl_enable_interrupts(priv);
+
+       spin_unlock(&priv->lock);
+       return IRQ_NONE;
 }
-EXPORT_SYMBOL(iwl_disable_interrupts);
 
-void iwl_enable_interrupts(struct iwl_priv *priv)
+irqreturn_t iwl_isr_legacy(int irq, void *data)
 {
-       IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
-       set_bit(STATUS_INT_ENABLED, &priv->status);
-       iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+       struct iwl_priv *priv = data;
+       u32 inta, inta_mask;
+       u32 inta_fh;
+       if (!priv)
+               return IRQ_NONE;
+
+       spin_lock(&priv->lock);
+
+       /* Disable (but don't clear!) interrupts here to avoid
+        *    back-to-back ISRs and sporadic interrupts from our NIC.
+        * If we have something to service, the tasklet will re-enable ints.
+        * If we *don't* have something, we'll re-enable before leaving here. */
+       inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
+       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+       /* Discover which interrupts are active/pending */
+       inta = iwl_read32(priv, CSR_INT);
+       inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+
+       /* Ignore interrupt if there's nothing in NIC to service.
+        * This may be due to IRQ shared with another device,
+        * or due to sporadic interrupts thrown from our NIC. */
+       if (!inta && !inta_fh) {
+               IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0, inta_fh == 0\n");
+               goto none;
+       }
+
+       if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+               /* Hardware disappeared. It might have already raised
+                * an interrupt */
+               IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
+               goto unplugged;
+       }
+
+       IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+                     inta, inta_mask, inta_fh);
+
+       inta &= ~CSR_INT_BIT_SCD;
+
+       /* iwl_irq_tasklet() will service interrupts and re-enable them */
+       if (likely(inta || inta_fh))
+               tasklet_schedule(&priv->irq_tasklet);
+
+ unplugged:
+       spin_unlock(&priv->lock);
+       return IRQ_HANDLED;
+
+ none:
+       /* re-enable interrupts here since we don't have anything to service. */
+       /* only Re-enable if diabled by irq */
+       if (test_bit(STATUS_INT_ENABLED, &priv->status))
+               iwl_enable_interrupts(priv);
+       spin_unlock(&priv->lock);
+       return IRQ_NONE;
 }
-EXPORT_SYMBOL(iwl_enable_interrupts);
+EXPORT_SYMBOL(iwl_isr_legacy);
 
 int iwl_send_bt_config(struct iwl_priv *priv)
 {
@@ -1464,7 +1932,7 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags)
        u32 stat_flags = 0;
        struct iwl_host_cmd cmd = {
                .id = REPLY_STATISTICS_CMD,
-               .meta.flags = flags,
+               .flags = flags,
                .len = sizeof(stat_flags),
                .data = (u8 *) &stat_flags,
        };
@@ -1486,10 +1954,6 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32
 
        IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
 
-       ret = iwl_grab_nic_access(priv);
-       if (ret)
-               return ret;
-
        for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
                /* read data comes through single port, auto-incr addr */
                /* NOTE: Use the debugless read so we don't flood kernel log
@@ -1505,8 +1969,6 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32
                }
        }
 
-       iwl_release_nic_access(priv);
-
        return ret;
 }
 
@@ -1524,10 +1986,6 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image,
 
        IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
 
-       ret = iwl_grab_nic_access(priv);
-       if (ret)
-               return ret;
-
        iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
                           IWL49_RTC_INST_LOWER_BOUND);
 
@@ -1548,8 +2006,6 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image,
                }
        }
 
-       iwl_release_nic_access(priv);
-
        if (!errcnt)
                IWL_DEBUG_INFO(priv,
                    "ucode image in INSTRUCTION memory is good\n");
@@ -1608,413 +2064,1013 @@ int iwl_verify_ucode(struct iwl_priv *priv)
 EXPORT_SYMBOL(iwl_verify_ucode);
 
 
-static const char *desc_lookup_text[] = {
-       "OK",
-       "FAIL",
-       "BAD_PARAM",
-       "BAD_CHECKSUM",
-       "NMI_INTERRUPT_WDG",
-       "SYSASSERT",
-       "FATAL_ERROR",
-       "BAD_COMMAND",
-       "HW_ERROR_TUNE_LOCK",
-       "HW_ERROR_TEMPERATURE",
-       "ILLEGAL_CHAN_FREQ",
-       "VCC_NOT_STABLE",
-       "FH_ERROR",
-       "NMI_INTERRUPT_HOST",
-       "NMI_INTERRUPT_ACTION_PT",
-       "NMI_INTERRUPT_UNKNOWN",
-       "UCODE_VERSION_MISMATCH",
-       "HW_ERROR_ABS_LOCK",
-       "HW_ERROR_CAL_LOCK_FAIL",
-       "NMI_INTERRUPT_INST_ACTION_PT",
-       "NMI_INTERRUPT_DATA_ACTION_PT",
-       "NMI_TRM_HW_ER",
-       "NMI_INTERRUPT_TRM",
-       "NMI_INTERRUPT_BREAK_POINT"
-       "DEBUG_0",
-       "DEBUG_1",
-       "DEBUG_2",
-       "DEBUG_3",
-       "UNKNOWN"
-};
-
-static const char *desc_lookup(int i)
-{
-       int max = ARRAY_SIZE(desc_lookup_text) - 1;
-
-       if (i < 0 || i > max)
-               i = max;
-
-       return desc_lookup_text[i];
-}
-
-#define ERROR_START_OFFSET  (1 * sizeof(u32))
-#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
-
-void iwl_dump_nic_error_log(struct iwl_priv *priv)
+void iwl_rf_kill_ct_config(struct iwl_priv *priv)
 {
-       u32 data2, line;
-       u32 desc, time, count, base, data1;
-       u32 blink1, blink2, ilink1, ilink2;
-       int ret;
-
-       if (priv->ucode_type == UCODE_INIT)
-               base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
-       else
-               base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
-
-       if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
-               IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
-               return;
-       }
-
-       ret = iwl_grab_nic_access(priv);
-       if (ret) {
-               IWL_WARN(priv, "Can not read from adapter at this time.\n");
-               return;
-       }
+       struct iwl_ct_kill_config cmd;
+       struct iwl_ct_kill_throttling_config adv_cmd;
+       unsigned long flags;
+       int ret = 0;
 
-       count = iwl_read_targ_mem(priv, base);
+       spin_lock_irqsave(&priv->lock, flags);
+       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->thermal_throttle.ct_kill_toggle = false;
+
+       switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+       case CSR_HW_REV_TYPE_1000:
+       case CSR_HW_REV_TYPE_6x00:
+       case CSR_HW_REV_TYPE_6x50:
+               adv_cmd.critical_temperature_enter =
+                       cpu_to_le32(priv->hw_params.ct_kill_threshold);
+               adv_cmd.critical_temperature_exit =
+                       cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
+
+               ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
+                                      sizeof(adv_cmd), &adv_cmd);
+               if (ret)
+                       IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
+               else
+                       IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
+                                       "succeeded, "
+                                       "critical temperature enter is %d,"
+                                       "exit is %d\n",
+                                      priv->hw_params.ct_kill_threshold,
+                                      priv->hw_params.ct_kill_exit_threshold);
+               break;
+       default:
+               cmd.critical_temperature_R =
+                       cpu_to_le32(priv->hw_params.ct_kill_threshold);
 
-       if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
-               IWL_ERR(priv, "Start IWL Error Log Dump:\n");
-               IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
-                       priv->status, count);
+               ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
+                                      sizeof(cmd), &cmd);
+               if (ret)
+                       IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
+               else
+                       IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
+                                       "succeeded, "
+                                       "critical temperature is %d\n",
+                                       priv->hw_params.ct_kill_threshold);
+               break;
        }
-
-       desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
-       blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
-       blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
-       ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
-       ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
-       data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
-       data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
-       line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
-       time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
-
-       IWL_ERR(priv, "Desc                               Time       "
-               "data1      data2      line\n");
-       IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
-               desc_lookup(desc), desc, time, data1, data2, line);
-       IWL_ERR(priv, "blink1  blink2  ilink1  ilink2\n");
-       IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
-               ilink1, ilink2);
-
-       iwl_release_nic_access(priv);
 }
-EXPORT_SYMBOL(iwl_dump_nic_error_log);
+EXPORT_SYMBOL(iwl_rf_kill_ct_config);
 
-#define EVENT_START_OFFSET  (4 * sizeof(u32))
 
-/**
- * iwl_print_event_log - Dump error event log to syslog
+/*
+ * CARD_STATE_CMD
+ *
+ * Use: Sets the device's internal card state to enable, disable, or halt
  *
- * NOTE: Must be called with iwl_grab_nic_access() already obtained!
+ * When in the 'enable' state the card operates as normal.
+ * When in the 'disable' state, the card enters into a low power mode.
+ * When in the 'halt' state, the card is shut down and must be fully
+ * restarted to come back on.
  */
-static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
-                               u32 num_events, u32 mode)
+int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
 {
-       u32 i;
-       u32 base;       /* SRAM byte address of event log header */
-       u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
-       u32 ptr;        /* SRAM byte address of log data */
-       u32 ev, time, data; /* event log data */
-
-       if (num_events == 0)
-               return;
-       if (priv->ucode_type == UCODE_INIT)
-               base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
-       else
-               base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_CARD_STATE_CMD,
+               .len = sizeof(u32),
+               .data = &flags,
+               .flags = meta_flag,
+       };
 
-       if (mode == 0)
-               event_size = 2 * sizeof(u32);
-       else
-               event_size = 3 * sizeof(u32);
-
-       ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
-
-       /* "time" is actually "data" for mode 0 (no timestamp).
-       * place event id # at far right for easier visual parsing. */
-       for (i = 0; i < num_events; i++) {
-               ev = iwl_read_targ_mem(priv, ptr);
-               ptr += sizeof(u32);
-               time = iwl_read_targ_mem(priv, ptr);
-               ptr += sizeof(u32);
-               if (mode == 0) {
-                       /* data, ev */
-                       IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
-               } else {
-                       data = iwl_read_targ_mem(priv, ptr);
-                       ptr += sizeof(u32);
-                       IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
-                                       time, data, ev);
-               }
-       }
+       return iwl_send_cmd(priv, &cmd);
 }
 
-void iwl_dump_nic_event_log(struct iwl_priv *priv)
+void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
+                          struct iwl_rx_mem_buffer *rxb)
 {
-       int ret;
-       u32 base;       /* SRAM byte address of event log header */
-       u32 capacity;   /* event log capacity in # entries */
-       u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
-       u32 num_wraps;  /* # times uCode wrapped to top of log */
-       u32 next_entry; /* index of next entry to be written by uCode */
-       u32 size;       /* # entries that we'll print */
-
-       if (priv->ucode_type == UCODE_INIT)
-               base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
-       else
-               base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+#ifdef CONFIG_IWLWIFI_DEBUG
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
+       IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
+                    sleep->pm_sleep_mode, sleep->pm_wakeup_src);
+#endif
+}
+EXPORT_SYMBOL(iwl_rx_pm_sleep_notif);
 
-       if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
-               IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
-               return;
+void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+                                     struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+       IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
+                       "notification for %s:\n", len,
+                       get_cmd_string(pkt->hdr.cmd));
+       iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len);
+}
+EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);
+
+void iwl_rx_reply_error(struct iwl_priv *priv,
+                       struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+
+       IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) "
+               "seq 0x%04X ser 0x%08X\n",
+               le32_to_cpu(pkt->u.err_resp.error_type),
+               get_cmd_string(pkt->u.err_resp.cmd_id),
+               pkt->u.err_resp.cmd_id,
+               le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
+               le32_to_cpu(pkt->u.err_resp.error_info));
+}
+EXPORT_SYMBOL(iwl_rx_reply_error);
+
+void iwl_clear_isr_stats(struct iwl_priv *priv)
+{
+       memset(&priv->isr_stats, 0, sizeof(priv->isr_stats));
+}
+
+int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
+                          const struct ieee80211_tx_queue_params *params)
+{
+       struct iwl_priv *priv = hw->priv;
+       unsigned long flags;
+       int q;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (!iwl_is_ready_rf(priv)) {
+               IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+               return -EIO;
        }
 
-       ret = iwl_grab_nic_access(priv);
-       if (ret) {
-               IWL_WARN(priv, "Can not read from adapter at this time.\n");
+       if (queue >= AC_NUM) {
+               IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
+               return 0;
+       }
+
+       q = AC_NUM - 1 - queue;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
+       priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
+       priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+       priv->qos_data.def_qos_parm.ac[q].edca_txop =
+                       cpu_to_le16((params->txop * 32));
+
+       priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+       priv->qos_data.qos_active = 1;
+
+       if (priv->iw_mode == NL80211_IFTYPE_AP)
+               iwl_activate_qos(priv, 1);
+       else if (priv->assoc_id && iwl_is_associated(priv))
+               iwl_activate_qos(priv, 0);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return 0;
+}
+EXPORT_SYMBOL(iwl_mac_conf_tx);
+
+static void iwl_ht_conf(struct iwl_priv *priv,
+                           struct ieee80211_bss_conf *bss_conf)
+{
+       struct ieee80211_sta_ht_cap *ht_conf;
+       struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
+       struct ieee80211_sta *sta;
+
+       IWL_DEBUG_MAC80211(priv, "enter: \n");
+
+       if (!iwl_conf->is_ht)
+               return;
+
+
+       /*
+        * It is totally wrong to base global information on something
+        * that is valid only when associated, alas, this driver works
+        * that way and I don't know how to fix it.
+        */
+
+       rcu_read_lock();
+       sta = ieee80211_find_sta(priv->hw, priv->bssid);
+       if (!sta) {
+               rcu_read_unlock();
                return;
        }
+       ht_conf = &sta->ht_cap;
+
+       iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
+
+       memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
+
+       iwl_conf->ht_protection =
+               bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
+       iwl_conf->non_GF_STA_present =
+               !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+
+       rcu_read_unlock();
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
 
-       /* event log header */
-       capacity = iwl_read_targ_mem(priv, base);
-       mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
-       num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
-       next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
+void iwl_bss_info_changed(struct ieee80211_hw *hw,
+                         struct ieee80211_vif *vif,
+                         struct ieee80211_bss_conf *bss_conf,
+                         u32 changes)
+{
+       struct iwl_priv *priv = hw->priv;
+       int ret;
 
-       size = num_wraps ? capacity : next_entry;
+       IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes);
 
-       /* bail out if nothing in log */
-       if (size == 0) {
-               IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
-               iwl_release_nic_access(priv);
+       if (!iwl_is_alive(priv))
                return;
+
+       mutex_lock(&priv->mutex);
+
+       if (changes & BSS_CHANGED_BEACON &&
+           priv->iw_mode == NL80211_IFTYPE_AP) {
+               dev_kfree_skb(priv->ibss_beacon);
+               priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
+       }
+
+       if (changes & BSS_CHANGED_BEACON_INT) {
+               priv->beacon_int = bss_conf->beacon_int;
+               /* TODO: in AP mode, do something to make this take effect */
+       }
+
+       if (changes & BSS_CHANGED_BSSID) {
+               IWL_DEBUG_MAC80211(priv, "BSSID %pM\n", bss_conf->bssid);
+
+               /*
+                * If there is currently a HW scan going on in the
+                * background then we need to cancel it else the RXON
+                * below/in post_associate will fail.
+                */
+               if (iwl_scan_cancel_timeout(priv, 100)) {
+                       IWL_WARN(priv, "Aborted scan still in progress after 100ms\n");
+                       IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
+                       mutex_unlock(&priv->mutex);
+                       return;
+               }
+
+               /* mac80211 only sets assoc when in STATION mode */
+               if (priv->iw_mode == NL80211_IFTYPE_ADHOC ||
+                   bss_conf->assoc) {
+                       memcpy(priv->staging_rxon.bssid_addr,
+                              bss_conf->bssid, ETH_ALEN);
+
+                       /* currently needed in a few places */
+                       memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
+               } else {
+                       priv->staging_rxon.filter_flags &=
+                               ~RXON_FILTER_ASSOC_MSK;
+               }
+
+       }
+
+       /*
+        * This needs to be after setting the BSSID in case
+        * mac80211 decides to do both changes at once because
+        * it will invoke post_associate.
+        */
+       if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
+           changes & BSS_CHANGED_BEACON) {
+               struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+
+               if (beacon)
+                       iwl_mac_beacon_update(hw, beacon);
+       }
+
+       if (changes & BSS_CHANGED_ERP_PREAMBLE) {
+               IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n",
+                                  bss_conf->use_short_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 & BSS_CHANGED_ERP_CTS_PROT) {
+               IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot);
+               if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
+                       priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
+               else
+                       priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+       }
+
+       if (changes & BSS_CHANGED_BASIC_RATES) {
+               /* XXX use this information
+                *
+                * To do that, remove code from iwl_set_rate() and put something
+                * like this here:
+                *
+               if (A-band)
+                       priv->staging_rxon.ofdm_basic_rates =
+                               bss_conf->basic_rates;
+               else
+                       priv->staging_rxon.ofdm_basic_rates =
+                               bss_conf->basic_rates >> 4;
+                       priv->staging_rxon.cck_basic_rates =
+                               bss_conf->basic_rates & 0xF;
+                */
        }
 
-       IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
-                       size, num_wraps);
+       if (changes & BSS_CHANGED_HT) {
+               iwl_ht_conf(priv, bss_conf);
+
+               if (priv->cfg->ops->hcmd->set_rxon_chain)
+                       priv->cfg->ops->hcmd->set_rxon_chain(priv);
+       }
 
-       /* if uCode has wrapped back to top of log, start at the oldest entry,
-        * i.e the next one that uCode would fill. */
-       if (num_wraps)
-               iwl_print_event_log(priv, next_entry,
-                                       capacity - next_entry, mode);
-       /* (then/else) start at top of log */
-       iwl_print_event_log(priv, 0, next_entry, mode);
+       if (changes & BSS_CHANGED_ASSOC) {
+               IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc);
+               if (bss_conf->assoc) {
+                       priv->assoc_id = bss_conf->aid;
+                       priv->beacon_int = bss_conf->beacon_int;
+                       priv->timestamp = bss_conf->timestamp;
+                       priv->assoc_capability = bss_conf->assoc_capability;
 
-       iwl_release_nic_access(priv);
+                       /*
+                        * We have just associated, don't start scan too early
+                        * leave time for EAPOL exchange to complete.
+                        *
+                        * XXX: do this in mac80211
+                        */
+                       priv->next_scan_jiffies = jiffies +
+                                       IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
+                       if (!iwl_is_rfkill(priv))
+                               priv->cfg->ops->lib->post_associate(priv);
+               } else
+                       priv->assoc_id = 0;
+
+       }
+
+       if (changes && iwl_is_associated(priv) && priv->assoc_id) {
+               IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n",
+                                  changes);
+               ret = iwl_send_rxon_assoc(priv);
+               if (!ret) {
+                       /* Sync active_rxon with latest change. */
+                       memcpy((void *)&priv->active_rxon,
+                               &priv->staging_rxon,
+                               sizeof(struct iwl_rxon_cmd));
+               }
+       }
+
+       mutex_unlock(&priv->mutex);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
 }
-EXPORT_SYMBOL(iwl_dump_nic_event_log);
+EXPORT_SYMBOL(iwl_bss_info_changed);
 
-void iwl_rf_kill_ct_config(struct iwl_priv *priv)
+int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
-       struct iwl_ct_kill_config cmd;
+       struct iwl_priv *priv = hw->priv;
        unsigned long flags;
-       int ret = 0;
+       __le64 timestamp;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (!iwl_is_ready_rf(priv)) {
+               IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+               return -EIO;
+       }
+
+       if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
+               IWL_DEBUG_MAC80211(priv, "leave - not IBSS\n");
+               return -EIO;
+       }
 
        spin_lock_irqsave(&priv->lock, flags);
-       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
-                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+
+       if (priv->ibss_beacon)
+               dev_kfree_skb(priv->ibss_beacon);
+
+       priv->ibss_beacon = skb;
+
+       priv->assoc_id = 0;
+       timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
+       priv->timestamp = le64_to_cpu(timestamp);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       cmd.critical_temperature_R =
-               cpu_to_le32(priv->hw_params.ct_kill_threshold);
+       iwl_reset_qos(priv);
 
-       ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
-                              sizeof(cmd), &cmd);
-       if (ret)
-               IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
-       else
-               IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD succeeded, "
-                       "critical temperature is %d\n",
-                       cmd.critical_temperature_R);
-}
-EXPORT_SYMBOL(iwl_rf_kill_ct_config);
+       priv->cfg->ops->lib->post_associate(priv);
 
 
-/*
- * CARD_STATE_CMD
- *
- * 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.
- * When in the 'halt' state, the card is shut down and must be fully
- * restarted to come back on.
- */
-int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
+       return 0;
+}
+EXPORT_SYMBOL(iwl_mac_beacon_update);
+
+int iwl_set_mode(struct iwl_priv *priv, int mode)
 {
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_CARD_STATE_CMD,
-               .len = sizeof(u32),
-               .data = &flags,
-               .meta.flags = meta_flag,
-       };
+       if (mode == NL80211_IFTYPE_ADHOC) {
+               const struct iwl_channel_info *ch_info;
 
-       return iwl_send_cmd(priv, &cmd);
+               ch_info = iwl_get_channel_info(priv,
+                       priv->band,
+                       le16_to_cpu(priv->staging_rxon.channel));
+
+               if (!ch_info || !is_channel_ibss(ch_info)) {
+                       IWL_ERR(priv, "channel %d not IBSS channel\n",
+                                 le16_to_cpu(priv->staging_rxon.channel));
+                       return -EINVAL;
+               }
+       }
+
+       iwl_connection_init_rx_config(priv, mode);
+
+       if (priv->cfg->ops->hcmd->set_rxon_chain)
+               priv->cfg->ops->hcmd->set_rxon_chain(priv);
+
+       memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+
+       iwl_clear_stations_table(priv);
+
+       /* dont commit rxon if rf-kill is on*/
+       if (!iwl_is_ready_rf(priv))
+               return -EAGAIN;
+
+       iwlcore_commit_rxon(priv);
+
+       return 0;
 }
-EXPORT_SYMBOL(iwl_send_card_state);
+EXPORT_SYMBOL(iwl_set_mode);
 
-void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv)
+int iwl_mac_add_interface(struct ieee80211_hw *hw,
+                                struct ieee80211_if_init_conf *conf)
 {
+       struct iwl_priv *priv = hw->priv;
        unsigned long flags;
 
-       if (test_bit(STATUS_RF_KILL_SW, &priv->status))
-               return;
+       IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type);
 
-       IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO OFF\n");
+       if (priv->vif) {
+               IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
+               return -EOPNOTSUPP;
+       }
+
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->vif = conf->vif;
+       priv->iw_mode = conf->type;
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       mutex_lock(&priv->mutex);
+
+       if (conf->mac_addr) {
+               IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr);
+               memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+       }
+
+       if (iwl_set_mode(priv, conf->type) == -EAGAIN)
+               /* we are not ready, will run again when ready */
+               set_bit(STATUS_MODE_PENDING, &priv->status);
+
+       mutex_unlock(&priv->mutex);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return 0;
+}
+EXPORT_SYMBOL(iwl_mac_add_interface);
+
+void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+                                    struct ieee80211_if_init_conf *conf)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       mutex_lock(&priv->mutex);
+
+       if (iwl_is_ready_rf(priv)) {
+               iwl_scan_cancel_timeout(priv, 100);
+               priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+               iwlcore_commit_rxon(priv);
+       }
+       if (priv->vif == conf->vif) {
+               priv->vif = NULL;
+               memset(priv->bssid, 0, ETH_ALEN);
+       }
+       mutex_unlock(&priv->mutex);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+}
+EXPORT_SYMBOL(iwl_mac_remove_interface);
+
+/**
+ * iwl_mac_config - mac80211 config callback
+ *
+ * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
+ * be set inappropriately and the driver currently sets the hardware up to
+ * use it whenever needed.
+ */
+int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
+{
+       struct iwl_priv *priv = hw->priv;
+       const struct iwl_channel_info *ch_info;
+       struct ieee80211_conf *conf = &hw->conf;
+       struct iwl_ht_info *ht_conf = &priv->current_ht_config;
+       unsigned long flags = 0;
+       int ret = 0;
+       u16 ch;
+       int scan_active = 0;
+
+       mutex_lock(&priv->mutex);
+
+       IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
+                                       conf->channel->hw_value, changed);
+
+       if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
+                       test_bit(STATUS_SCANNING, &priv->status))) {
+               scan_active = 1;
+               IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
+       }
+
+
+       /* during scanning mac80211 will delay channel setting until
+        * scan finish with changed = 0
+        */
+       if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
+               if (scan_active)
+                       goto set_ch_out;
+
+               ch = ieee80211_frequency_to_channel(conf->channel->center_freq);
+               ch_info = iwl_get_channel_info(priv, conf->channel->band, ch);
+               if (!is_channel_valid(ch_info)) {
+                       IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
+                       ret = -EINVAL;
+                       goto set_ch_out;
+               }
+
+               if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
+                       !is_channel_ibss(ch_info)) {
+                       IWL_ERR(priv, "channel %d in band %d not "
+                               "IBSS channel\n",
+                               conf->channel->hw_value, conf->channel->band);
+                       ret = -EINVAL;
+                       goto set_ch_out;
+               }
 
-       iwl_scan_cancel(priv);
-       /* FIXME: This is a workaround for AP */
-       if (priv->iw_mode != NL80211_IFTYPE_AP) {
                spin_lock_irqsave(&priv->lock, flags);
-               iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
-                           CSR_UCODE_SW_BIT_RFKILL);
+
+               /* Configure HT40 channels */
+               ht_conf->is_ht = conf_is_ht(conf);
+               if (ht_conf->is_ht) {
+                       if (conf_is_ht40_minus(conf)) {
+                               ht_conf->extension_chan_offset =
+                                       IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+                               ht_conf->supported_chan_width =
+                                       IWL_CHANNEL_WIDTH_40MHZ;
+                       } else if (conf_is_ht40_plus(conf)) {
+                               ht_conf->extension_chan_offset =
+                                       IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+                               ht_conf->supported_chan_width =
+                                       IWL_CHANNEL_WIDTH_40MHZ;
+                       } else {
+                               ht_conf->extension_chan_offset =
+                                       IEEE80211_HT_PARAM_CHA_SEC_NONE;
+                               ht_conf->supported_chan_width =
+                                       IWL_CHANNEL_WIDTH_20MHZ;
+                       }
+               } else
+                       ht_conf->supported_chan_width = IWL_CHANNEL_WIDTH_20MHZ;
+               /* Default to no protection. Protection mode will later be set
+                * from BSS config in iwl_ht_conf */
+               ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
+
+               /* if we are switching from ht to 2.4 clear flags
+                * from any ht related info since 2.4 does not
+                * support ht */
+               if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
+                       priv->staging_rxon.flags = 0;
+
+               iwl_set_rxon_channel(priv, conf->channel);
+
+               iwl_set_flags_for_band(priv, conf->channel->band);
                spin_unlock_irqrestore(&priv->lock, flags);
-               /* call the host command only if no hw rf-kill set */
-               if (!test_bit(STATUS_RF_KILL_HW, &priv->status) &&
-                   iwl_is_ready(priv))
-                       iwl_send_card_state(priv,
-                               CARD_STATE_CMD_DISABLE, 0);
-               set_bit(STATUS_RF_KILL_SW, &priv->status);
-                       /* make sure mac80211 stop sending Tx frame */
-               if (priv->mac80211_registered)
-                       ieee80211_stop_queues(priv->hw);
+ set_ch_out:
+               /* The list of supported rates and rate mask can be different
+                * for each band; since the band may have changed, reset
+                * the rate mask to what mac80211 lists */
+               iwl_set_rate(priv);
        }
+
+       if (changed & IEEE80211_CONF_CHANGE_PS) {
+               ret = iwl_power_update_mode(priv, false);
+               if (ret)
+                       IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
+       }
+
+       if (changed & IEEE80211_CONF_CHANGE_POWER) {
+               IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n",
+                       priv->tx_power_user_lmt, conf->power_level);
+
+               iwl_set_tx_power(priv, conf->power_level, false);
+       }
+
+       /* call to ensure that 4965 rx_chain is set properly in monitor mode */
+       if (priv->cfg->ops->hcmd->set_rxon_chain)
+               priv->cfg->ops->hcmd->set_rxon_chain(priv);
+
+       if (!iwl_is_ready(priv)) {
+               IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
+               goto out;
+       }
+
+       if (scan_active)
+               goto out;
+
+       if (memcmp(&priv->active_rxon,
+                  &priv->staging_rxon, sizeof(priv->staging_rxon)))
+               iwlcore_commit_rxon(priv);
+       else
+               IWL_DEBUG_INFO(priv, "Not re-sending same RXON configuration.\n");
+
+
+out:
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       mutex_unlock(&priv->mutex);
+       return ret;
 }
-EXPORT_SYMBOL(iwl_radio_kill_sw_disable_radio);
+EXPORT_SYMBOL(iwl_mac_config);
 
-int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv)
+int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+                        struct ieee80211_tx_queue_stats *stats)
 {
+       struct iwl_priv *priv = hw->priv;
+       int i, avail;
+       struct iwl_tx_queue *txq;
+       struct iwl_queue *q;
        unsigned long flags;
 
-       if (!test_bit(STATUS_RF_KILL_SW, &priv->status))
-               return 0;
+       IWL_DEBUG_MAC80211(priv, "enter\n");
 
-       IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO ON\n");
+       if (!iwl_is_ready_rf(priv)) {
+               IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+               return -EIO;
+       }
 
        spin_lock_irqsave(&priv->lock, flags);
-       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
 
-       /* If the driver is up it will receive CARD_STATE_NOTIFICATION
-        * notification where it will clear SW rfkill status.
-        * Setting it here would break the handler. Only if the
-        * interface is down we can set here since we don't
-        * receive any further notification.
-        */
-       if (!priv->is_open)
-               clear_bit(STATUS_RF_KILL_SW, &priv->status);
+       for (i = 0; i < AC_NUM; i++) {
+               txq = &priv->txq[i];
+               q = &txq->q;
+               avail = iwl_queue_space(q);
+
+               stats[i].len = q->n_window - avail;
+               stats[i].limit = q->n_window - q->high_mark;
+               stats[i].count = q->n_window;
+
+       }
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       /* wake up ucode */
-       msleep(10);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return 0;
+}
+EXPORT_SYMBOL(iwl_mac_get_tx_stats);
+
+void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+       unsigned long flags;
+
+       mutex_lock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "enter\n");
 
        spin_lock_irqsave(&priv->lock, flags);
-       iwl_read32(priv, CSR_UCODE_DRV_GP1);
-       if (!iwl_grab_nic_access(priv))
-               iwl_release_nic_access(priv);
+       memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info));
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
-               IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - "
-                                 "disabled by HW switch\n");
-               return 0;
+       iwl_reset_qos(priv);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->assoc_id = 0;
+       priv->assoc_capability = 0;
+       priv->assoc_station_added = 0;
+
+       /* new association get rid of ibss beacon skb */
+       if (priv->ibss_beacon)
+               dev_kfree_skb(priv->ibss_beacon);
+
+       priv->ibss_beacon = NULL;
+
+       priv->beacon_int = priv->vif->bss_conf.beacon_int;
+       priv->timestamp = 0;
+       if ((priv->iw_mode == NL80211_IFTYPE_STATION))
+               priv->beacon_int = 0;
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       if (!iwl_is_ready_rf(priv)) {
+               IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
+               mutex_unlock(&priv->mutex);
+               return;
        }
 
-       /* when driver is up while rfkill is on, it wont receive
-        * any CARD_STATE_NOTIFICATION notifications so we have to
-        * restart it in here
+       /* we are restarting association process
+        * clear RXON_FILTER_ASSOC_MSK bit
         */
-       if (priv->is_open && !test_bit(STATUS_ALIVE, &priv->status)) {
-               clear_bit(STATUS_RF_KILL_SW, &priv->status);
-               if (!iwl_is_rfkill(priv))
-                       queue_work(priv->workqueue, &priv->up);
+       if (priv->iw_mode != NL80211_IFTYPE_AP) {
+               iwl_scan_cancel_timeout(priv, 100);
+               priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+               iwlcore_commit_rxon(priv);
        }
 
-       /* If the driver is already loaded, it will receive
-        * CARD_STATE_NOTIFICATION notifications and the handler will
-        * call restart to reload the driver.
-        */
-       return 1;
+       if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
+               IWL_DEBUG_MAC80211(priv, "leave - not in IBSS\n");
+               mutex_unlock(&priv->mutex);
+               return;
+       }
+
+       iwl_set_rate(priv);
+
+       mutex_unlock(&priv->mutex);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
 }
-EXPORT_SYMBOL(iwl_radio_kill_sw_enable_radio);
+EXPORT_SYMBOL(iwl_mac_reset_tsf);
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
 
-void iwl_bg_rf_kill(struct work_struct *work)
+#define IWL_TRAFFIC_DUMP_SIZE  (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)
+
+void iwl_reset_traffic_log(struct iwl_priv *priv)
 {
-       struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill);
+       priv->tx_traffic_idx = 0;
+       priv->rx_traffic_idx = 0;
+       if (priv->tx_traffic)
+               memset(priv->tx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
+       if (priv->rx_traffic)
+               memset(priv->rx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
+}
 
-       wake_up_interruptible(&priv->wait_command_queue);
+int iwl_alloc_traffic_mem(struct iwl_priv *priv)
+{
+       u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE;
+
+       if (iwl_debug_level & IWL_DL_TX) {
+               if (!priv->tx_traffic) {
+                       priv->tx_traffic =
+                               kzalloc(traffic_size, GFP_KERNEL);
+                       if (!priv->tx_traffic)
+                               return -ENOMEM;
+               }
+       }
+       if (iwl_debug_level & IWL_DL_RX) {
+               if (!priv->rx_traffic) {
+                       priv->rx_traffic =
+                               kzalloc(traffic_size, GFP_KERNEL);
+                       if (!priv->rx_traffic)
+                               return -ENOMEM;
+               }
+       }
+       iwl_reset_traffic_log(priv);
+       return 0;
+}
+EXPORT_SYMBOL(iwl_alloc_traffic_mem);
 
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+void iwl_free_traffic_mem(struct iwl_priv *priv)
+{
+       kfree(priv->tx_traffic);
+       priv->tx_traffic = NULL;
+
+       kfree(priv->rx_traffic);
+       priv->rx_traffic = NULL;
+}
+EXPORT_SYMBOL(iwl_free_traffic_mem);
+
+void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
+                     u16 length, struct ieee80211_hdr *header)
+{
+       __le16 fc;
+       u16 len;
+
+       if (likely(!(iwl_debug_level & IWL_DL_TX)))
                return;
 
-       mutex_lock(&priv->mutex);
+       if (!priv->tx_traffic)
+               return;
 
-       if (!iwl_is_rfkill(priv)) {
-               IWL_DEBUG_RF_KILL(priv,
-                         "HW and/or SW RF Kill no longer active, restarting "
-                         "device\n");
-               if (!test_bit(STATUS_EXIT_PENDING, &priv->status) &&
-                   test_bit(STATUS_ALIVE, &priv->status))
-                       queue_work(priv->workqueue, &priv->restart);
-       } else {
-               /* make sure mac80211 stop sending Tx frame */
-               if (priv->mac80211_registered)
-                       ieee80211_stop_queues(priv->hw);
+       fc = header->frame_control;
+       if (ieee80211_is_data(fc)) {
+               len = (length > IWL_TRAFFIC_ENTRY_SIZE)
+                      ? IWL_TRAFFIC_ENTRY_SIZE : length;
+               memcpy((priv->tx_traffic +
+                      (priv->tx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)),
+                      header, len);
+               priv->tx_traffic_idx =
+                       (priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
+       }
+}
+EXPORT_SYMBOL(iwl_dbg_log_tx_data_frame);
 
-               if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
-                       IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - "
-                                         "disabled by SW switch\n");
-               else
-                       IWL_WARN(priv, "Radio Frequency Kill Switch is On:\n"
-                                   "Kill switch must be turned off for "
-                                   "wireless networking to work.\n");
+void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
+                     u16 length, struct ieee80211_hdr *header)
+{
+       __le16 fc;
+       u16 len;
+
+       if (likely(!(iwl_debug_level & IWL_DL_RX)))
+               return;
+
+       if (!priv->rx_traffic)
+               return;
+
+       fc = header->frame_control;
+       if (ieee80211_is_data(fc)) {
+               len = (length > IWL_TRAFFIC_ENTRY_SIZE)
+                      ? IWL_TRAFFIC_ENTRY_SIZE : length;
+               memcpy((priv->rx_traffic +
+                      (priv->rx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)),
+                      header, len);
+               priv->rx_traffic_idx =
+                       (priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
        }
-       mutex_unlock(&priv->mutex);
-       iwl_rfkill_set_hw_state(priv);
 }
-EXPORT_SYMBOL(iwl_bg_rf_kill);
+EXPORT_SYMBOL(iwl_dbg_log_rx_data_frame);
 
-void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
-                          struct iwl_rx_mem_buffer *rxb)
+const char *get_mgmt_string(int cmd)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
-       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-       struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
-       IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
-                    sleep->pm_sleep_mode, sleep->pm_wakeup_src);
-#endif
+       switch (cmd) {
+               IWL_CMD(MANAGEMENT_ASSOC_REQ);
+               IWL_CMD(MANAGEMENT_ASSOC_RESP);
+               IWL_CMD(MANAGEMENT_REASSOC_REQ);
+               IWL_CMD(MANAGEMENT_REASSOC_RESP);
+               IWL_CMD(MANAGEMENT_PROBE_REQ);
+               IWL_CMD(MANAGEMENT_PROBE_RESP);
+               IWL_CMD(MANAGEMENT_BEACON);
+               IWL_CMD(MANAGEMENT_ATIM);
+               IWL_CMD(MANAGEMENT_DISASSOC);
+               IWL_CMD(MANAGEMENT_AUTH);
+               IWL_CMD(MANAGEMENT_DEAUTH);
+               IWL_CMD(MANAGEMENT_ACTION);
+       default:
+               return "UNKNOWN";
+
+       }
 }
-EXPORT_SYMBOL(iwl_rx_pm_sleep_notif);
 
-void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
-                                     struct iwl_rx_mem_buffer *rxb)
+const char *get_ctrl_string(int cmd)
 {
-       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-       IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
-                       "notification for %s:\n",
-                       le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
-       iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+       switch (cmd) {
+               IWL_CMD(CONTROL_BACK_REQ);
+               IWL_CMD(CONTROL_BACK);
+               IWL_CMD(CONTROL_PSPOLL);
+               IWL_CMD(CONTROL_RTS);
+               IWL_CMD(CONTROL_CTS);
+               IWL_CMD(CONTROL_ACK);
+               IWL_CMD(CONTROL_CFEND);
+               IWL_CMD(CONTROL_CFENDACK);
+       default:
+               return "UNKNOWN";
+
+       }
 }
-EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);
 
-void iwl_rx_reply_error(struct iwl_priv *priv,
-                       struct iwl_rx_mem_buffer *rxb)
+void iwl_clear_tx_stats(struct iwl_priv *priv)
 {
-       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       memset(&priv->tx_stats, 0, sizeof(struct traffic_stats));
 
-       IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) "
-               "seq 0x%04X ser 0x%08X\n",
-               le32_to_cpu(pkt->u.err_resp.error_type),
-               get_cmd_string(pkt->u.err_resp.cmd_id),
-               pkt->u.err_resp.cmd_id,
-               le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
-               le32_to_cpu(pkt->u.err_resp.error_info));
 }
-EXPORT_SYMBOL(iwl_rx_reply_error);
 
+void iwl_clear_rx_stats(struct iwl_priv *priv)
+{
+       memset(&priv->rx_stats, 0, sizeof(struct traffic_stats));
+}
+
+/*
+ * if CONFIG_IWLWIFI_DEBUGFS defined, iwl_update_stats function will
+ * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass.
+ * Use debugFs to display the rx/rx_statistics
+ * if CONFIG_IWLWIFI_DEBUGFS not being defined, then no MGMT and CTRL
+ * information will be recorded, but DATA pkt still will be recorded
+ * for the reason of iwl_led.c need to control the led blinking based on
+ * number of tx and rx data.
+ *
+ */
+void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
+{
+       struct traffic_stats    *stats;
+
+       if (is_tx)
+               stats = &priv->tx_stats;
+       else
+               stats = &priv->rx_stats;
+
+       if (ieee80211_is_mgmt(fc)) {
+               switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+               case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
+                       stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
+                       stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
+                       stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
+                       stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
+                       stats->mgmt[MANAGEMENT_PROBE_REQ]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
+                       stats->mgmt[MANAGEMENT_PROBE_RESP]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_BEACON):
+                       stats->mgmt[MANAGEMENT_BEACON]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_ATIM):
+                       stats->mgmt[MANAGEMENT_ATIM]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
+                       stats->mgmt[MANAGEMENT_DISASSOC]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_AUTH):
+                       stats->mgmt[MANAGEMENT_AUTH]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+                       stats->mgmt[MANAGEMENT_DEAUTH]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_ACTION):
+                       stats->mgmt[MANAGEMENT_ACTION]++;
+                       break;
+               }
+       } else if (ieee80211_is_ctl(fc)) {
+               switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+               case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
+                       stats->ctrl[CONTROL_BACK_REQ]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_BACK):
+                       stats->ctrl[CONTROL_BACK]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
+                       stats->ctrl[CONTROL_PSPOLL]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_RTS):
+                       stats->ctrl[CONTROL_RTS]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_CTS):
+                       stats->ctrl[CONTROL_CTS]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_ACK):
+                       stats->ctrl[CONTROL_ACK]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_CFEND):
+                       stats->ctrl[CONTROL_CFEND]++;
+                       break;
+               case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
+                       stats->ctrl[CONTROL_CFENDACK]++;
+                       break;
+               }
+       } else {
+               /* data */
+               stats->data_cnt++;
+               stats->data_bytes += len;
+       }
+}
+EXPORT_SYMBOL(iwl_update_stats);
+#endif
+
+#ifdef CONFIG_PM
+
+int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct iwl_priv *priv = pci_get_drvdata(pdev);
+
+       /*
+        * This function is called when system goes into suspend state
+        * mac80211 will call iwl_mac_stop() from the mac80211 suspend function
+        * first but since iwl_mac_stop() has no knowledge of who the caller is,
+        * it will not call apm_ops.stop() to stop the DMA operation.
+        * Calling apm_ops.stop here to make sure we stop the DMA.
+        */
+       priv->cfg->ops->lib->apm_ops.stop(priv);
+
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
+
+       return 0;
+}
+EXPORT_SYMBOL(iwl_pci_suspend);
+
+int iwl_pci_resume(struct pci_dev *pdev)
+{
+       struct iwl_priv *priv = pci_get_drvdata(pdev);
+       int ret;
+
+       pci_set_power_state(pdev, PCI_D0);
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
+       pci_restore_state(pdev);
+       iwl_enable_interrupts(priv);
+
+       return 0;
+}
+EXPORT_SYMBOL(iwl_pci_resume);
+
+#endif /* CONFIG_PM */