Merge branch 'for-3.5-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj...
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / iwlwifi / iwl-agn.c
index f1226dbf789d796c7c366fe102f410eb32537f7f..ec36e2b020b6e9227935ca85fff855c58f5fd894 100644 (file)
@@ -26,6 +26,9 @@
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
 
 #include "iwl-eeprom.h"
 #include "iwl-dev.h"
-#include "iwl-core.h"
 #include "iwl-io.h"
 #include "iwl-agn-calib.h"
 #include "iwl-agn.h"
-#include "iwl-shared.h"
 #include "iwl-trans.h"
 #include "iwl-op-mode.h"
+#include "iwl-drv.h"
+#include "iwl-modparams.h"
 
 /******************************************************************************
  *
@@ -177,7 +180,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
                rate = info->control.rates[0].idx;
 
        priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
-                                             hw_params(priv).valid_tx_ant);
+                                             priv->hw_params.valid_tx_ant);
        rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
 
        /* In mac80211, rates for 5 GHz start at 0 */
@@ -286,6 +289,25 @@ out:
        mutex_unlock(&priv->mutex);
 }
 
+int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
+{
+       struct iwl_statistics_cmd statistics_cmd = {
+               .configuration_flags =
+                       clear ? IWL_STATS_CONF_CLEAR_STATS : 0,
+       };
+
+       if (flags & CMD_ASYNC)
+               return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
+                                       CMD_ASYNC,
+                                       sizeof(struct iwl_statistics_cmd),
+                                       &statistics_cmd);
+       else
+               return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
+                                       CMD_SYNC,
+                                       sizeof(struct iwl_statistics_cmd),
+                                       &statistics_cmd);
+}
+
 /**
  * iwl_bg_statistics_periodic - Timer callback to queue statistics
  *
@@ -326,14 +348,14 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
                ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
 
        /* Make sure device is powered up for SRAM reads */
-       spin_lock_irqsave(&trans(priv)->reg_lock, reg_flags);
-       if (unlikely(!iwl_grab_nic_access(trans(priv)))) {
-               spin_unlock_irqrestore(&trans(priv)->reg_lock, reg_flags);
+       spin_lock_irqsave(&priv->trans->reg_lock, reg_flags);
+       if (unlikely(!iwl_grab_nic_access(priv->trans))) {
+               spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
                return;
        }
 
        /* Set starting address; reads will auto-increment */
-       iwl_write32(trans(priv), HBUS_TARG_MEM_RADDR, ptr);
+       iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr);
 
        /*
         * Refuse to read more than would have fit into the log from
@@ -349,20 +371,20 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
         * place event id # at far right for easier visual parsing.
         */
        for (i = 0; i < num_events; i++) {
-               ev = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
-               time = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
+               ev = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
+               time = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
                if (mode == 0) {
                        trace_iwlwifi_dev_ucode_cont_event(
-                                       trans(priv)->dev, 0, time, ev);
+                                       priv->trans->dev, 0, time, ev);
                } else {
-                       data = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
+                       data = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
                        trace_iwlwifi_dev_ucode_cont_event(
-                                       trans(priv)->dev, time, data, ev);
+                                       priv->trans->dev, time, data, ev);
                }
        }
        /* Allow device to power down */
-       iwl_release_nic_access(trans(priv));
-       spin_unlock_irqrestore(&trans(priv)->reg_lock, reg_flags);
+       iwl_release_nic_access(priv->trans);
+       spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
 }
 
 static void iwl_continuous_event_trace(struct iwl_priv *priv)
@@ -379,10 +401,9 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv)
        u32 num_wraps;  /* # times uCode wrapped to top of log */
        u32 next_entry; /* index of next entry to be written by uCode */
 
-       base = priv->shrd->device_pointers.log_event_table;
+       base = priv->device_pointers.log_event_table;
        if (iwlagn_hw_valid_rtc_data_addr(base)) {
-               iwl_read_targ_mem_words(trans(priv), base, &read, sizeof(read));
-
+               iwl_read_targ_mem_words(priv->trans, base, &read, sizeof(read));
                capacity = read.capacity;
                mode = read.mode;
                num_wraps = read.wrap_counter;
@@ -422,7 +443,7 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv)
                else
                        priv->event_log.wraps_once_count++;
 
-               trace_iwlwifi_dev_ucode_wrap_event(trans(priv)->dev,
+               trace_iwlwifi_dev_ucode_wrap_event(priv->trans->dev,
                                num_wraps - priv->event_log.num_wraps,
                                next_entry, priv->event_log.next_entry);
 
@@ -488,7 +509,76 @@ static void iwl_bg_tx_flush(struct work_struct *work)
        iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
 }
 
-static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
+/*
+ * queue/FIFO/AC mapping definitions
+ */
+
+#define IWL_TX_FIFO_BK         0       /* shared */
+#define IWL_TX_FIFO_BE         1
+#define IWL_TX_FIFO_VI         2       /* shared */
+#define IWL_TX_FIFO_VO         3
+#define IWL_TX_FIFO_BK_IPAN    IWL_TX_FIFO_BK
+#define IWL_TX_FIFO_BE_IPAN    4
+#define IWL_TX_FIFO_VI_IPAN    IWL_TX_FIFO_VI
+#define IWL_TX_FIFO_VO_IPAN    5
+/* re-uses the VO FIFO, uCode will properly flush/schedule */
+#define IWL_TX_FIFO_AUX                5
+#define IWL_TX_FIFO_UNUSED     -1
+
+#define IWLAGN_CMD_FIFO_NUM    7
+
+/*
+ * This queue number is required for proper operation
+ * because the ucode will stop/start the scheduler as
+ * required.
+ */
+#define IWL_IPAN_MCAST_QUEUE   8
+
+static const u8 iwlagn_default_queue_to_tx_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+       IWLAGN_CMD_FIFO_NUM,
+};
+
+static const u8 iwlagn_ipan_queue_to_tx_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+       IWL_TX_FIFO_BK_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWL_TX_FIFO_VI_IPAN,
+       IWL_TX_FIFO_VO_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWLAGN_CMD_FIFO_NUM,
+       IWL_TX_FIFO_AUX,
+};
+
+static const u8 iwlagn_bss_ac_to_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+};
+
+static const u8 iwlagn_bss_ac_to_queue[] = {
+       0, 1, 2, 3,
+};
+
+static const u8 iwlagn_pan_ac_to_fifo[] = {
+       IWL_TX_FIFO_VO_IPAN,
+       IWL_TX_FIFO_VI_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWL_TX_FIFO_BK_IPAN,
+};
+
+static const u8 iwlagn_pan_ac_to_queue[] = {
+       7, 6, 5, 4,
+};
+
+void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
 {
        int i;
 
@@ -496,9 +586,9 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
         * The default context is always valid,
         * the PAN context depends on uCode.
         */
-       priv->shrd->valid_contexts = BIT(IWL_RXON_CTX_BSS);
+       priv->valid_contexts = BIT(IWL_RXON_CTX_BSS);
        if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN)
-               priv->shrd->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
+               priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
 
        for (i = 0; i < NUM_IWL_RXON_CTX; i++)
                priv->contexts[i].ctxid = i;
@@ -513,13 +603,17 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
        priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
        priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
        priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
-               BIT(NL80211_IFTYPE_ADHOC);
+               BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MONITOR);
        priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
                BIT(NL80211_IFTYPE_STATION);
        priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP;
        priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
        priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
        priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
+       memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue,
+              iwlagn_bss_ac_to_queue, sizeof(iwlagn_bss_ac_to_queue));
+       memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo,
+              iwlagn_bss_ac_to_fifo, sizeof(iwlagn_bss_ac_to_fifo));
 
        priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON;
        priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd =
@@ -542,26 +636,31 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
        priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
        priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
        priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
+       memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue,
+              iwlagn_pan_ac_to_queue, sizeof(iwlagn_pan_ac_to_queue));
+       memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo,
+              iwlagn_pan_ac_to_fifo, sizeof(iwlagn_pan_ac_to_fifo));
+       priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
 
        BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
 }
 
-static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
+void iwl_rf_kill_ct_config(struct iwl_priv *priv)
 {
        struct iwl_ct_kill_config cmd;
        struct iwl_ct_kill_throttling_config adv_cmd;
        int ret = 0;
 
-       iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_CLR,
+       iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
                    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
 
        priv->thermal_throttle.ct_kill_toggle = false;
 
-       if (cfg(priv)->base_params->support_ct_kill_exit) {
+       if (priv->cfg->base_params->support_ct_kill_exit) {
                adv_cmd.critical_temperature_enter =
-                       cpu_to_le32(hw_params(priv).ct_kill_threshold);
+                       cpu_to_le32(priv->hw_params.ct_kill_threshold);
                adv_cmd.critical_temperature_exit =
-                       cpu_to_le32(hw_params(priv).ct_kill_exit_threshold);
+                       cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
 
                ret = iwl_dvm_send_cmd_pdu(priv,
                                       REPLY_CT_KILL_CONFIG_CMD,
@@ -572,11 +671,11 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
                        IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
                                "succeeded, critical temperature enter is %d,"
                                "exit is %d\n",
-                               hw_params(priv).ct_kill_threshold,
-                               hw_params(priv).ct_kill_exit_threshold);
+                               priv->hw_params.ct_kill_threshold,
+                               priv->hw_params.ct_kill_exit_threshold);
        } else {
                cmd.critical_temperature_R =
-                       cpu_to_le32(hw_params(priv).ct_kill_threshold);
+                       cpu_to_le32(priv->hw_params.ct_kill_threshold);
 
                ret = iwl_dvm_send_cmd_pdu(priv,
                                       REPLY_CT_KILL_CONFIG_CMD,
@@ -587,7 +686,7 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
                        IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
                                "succeeded, "
                                "critical temperature is %d\n",
-                               hw_params(priv).ct_kill_threshold);
+                               priv->hw_params.ct_kill_threshold);
        }
 }
 
@@ -627,6 +726,29 @@ static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
        }
 }
 
+void iwl_send_bt_config(struct iwl_priv *priv)
+{
+       struct iwl_bt_cmd bt_cmd = {
+               .lead_time = BT_LEAD_TIME_DEF,
+               .max_kill = BT_MAX_KILL_DEF,
+               .kill_ack_mask = 0,
+               .kill_cts_mask = 0,
+       };
+
+       if (!iwlwifi_mod_params.bt_coex_active)
+               bt_cmd.flags = BT_COEX_DISABLE;
+       else
+               bt_cmd.flags = BT_COEX_ENABLE;
+
+       priv->bt_enable_flag = bt_cmd.flags;
+       IWL_DEBUG_INFO(priv, "BT coex %s\n",
+               (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
+
+       if (iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+                            CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd))
+               IWL_ERR(priv, "failed to send BT Coex Config\n");
+}
+
 /**
  * iwl_alive_start - called after REPLY_ALIVE notification received
  *                   from protocol/runtime uCode (initialization uCode's
@@ -642,9 +764,6 @@ int iwl_alive_start(struct iwl_priv *priv)
        /* After the ALIVE response, we can send host commands to the uCode */
        set_bit(STATUS_ALIVE, &priv->status);
 
-       /* Enable watchdog to monitor the driver tx queues */
-       iwl_setup_watchdog(priv);
-
        if (iwl_is_rfkill(priv))
                return -ERFKILL;
 
@@ -654,10 +773,10 @@ int iwl_alive_start(struct iwl_priv *priv)
        }
 
        /* download priority table before any calibration request */
-       if (cfg(priv)->bt_params &&
-           cfg(priv)->bt_params->advanced_bt_coexist) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
                /* Configure Bluetooth device coexistence support */
-               if (cfg(priv)->bt_params->bt_sco_disable)
+               if (priv->cfg->bt_params->bt_sco_disable)
                        priv->bt_enable_pspoll = false;
                else
                        priv->bt_enable_pspoll = true;
@@ -694,10 +813,8 @@ int iwl_alive_start(struct iwl_priv *priv)
 
        ieee80211_wake_queues(priv->hw);
 
-       priv->active_rate = IWL_RATES_MASK;
-
        /* Configure Tx antenna selection based on H/W config */
-       iwlagn_send_tx_ant_config(priv, hw_params(priv).valid_tx_ant);
+       iwlagn_send_tx_ant_config(priv, priv->hw_params.valid_tx_ant);
 
        if (iwl_is_associated_ctx(ctx) && !priv->wowlan) {
                struct iwl_rxon_cmd *active_rxon =
@@ -788,10 +905,6 @@ void iwl_down(struct iwl_priv *priv)
        exit_pending =
                test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
 
-       /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
-        * to prevent rearm timer */
-       del_timer_sync(&priv->watchdog);
-
        iwl_clear_ucode_stations(priv, NULL);
        iwl_dealloc_bcast_stations(priv);
        iwl_clear_driver_stations(priv);
@@ -800,9 +913,9 @@ void iwl_down(struct iwl_priv *priv)
        priv->bt_status = 0;
        priv->cur_rssi_ctx = NULL;
        priv->bt_is_sco = 0;
-       if (cfg(priv)->bt_params)
+       if (priv->cfg->bt_params)
                priv->bt_traffic_load =
-                        cfg(priv)->bt_params->bt_init_traffic_load;
+                        priv->cfg->bt_params->bt_init_traffic_load;
        else
                priv->bt_traffic_load = 0;
        priv->bt_full_concurrent = false;
@@ -817,18 +930,17 @@ void iwl_down(struct iwl_priv *priv)
                ieee80211_stop_queues(priv->hw);
 
        priv->ucode_loaded = false;
-       iwl_trans_stop_device(trans(priv));
+       iwl_trans_stop_device(priv->trans);
 
        /* Clear out all status bits but a few that are stable across reset */
        priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
                                STATUS_RF_KILL_HW |
                        test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
                                STATUS_GEO_CONFIGURED |
+                       test_bit(STATUS_FW_ERROR, &priv->status) <<
+                               STATUS_FW_ERROR |
                        test_bit(STATUS_EXIT_PENDING, &priv->status) <<
                                STATUS_EXIT_PENDING;
-       priv->shrd->status &=
-                       test_bit(STATUS_FW_ERROR, &priv->shrd->status) <<
-                               STATUS_FW_ERROR;
 
        dev_kfree_skb(priv->beacon_skb);
        priv->beacon_skb = NULL;
@@ -863,17 +975,15 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
 
 void iwlagn_prepare_restart(struct iwl_priv *priv)
 {
-       struct iwl_rxon_context *ctx;
        bool bt_full_concurrent;
        u8 bt_ci_compliance;
        u8 bt_load;
        u8 bt_status;
        bool bt_is_sco;
+       int i;
 
        lockdep_assert_held(&priv->mutex);
 
-       for_each_context(priv, ctx)
-               ctx->vif = NULL;
        priv->is_open = 0;
 
        /*
@@ -898,6 +1008,15 @@ void iwlagn_prepare_restart(struct iwl_priv *priv)
        priv->bt_traffic_load = bt_load;
        priv->bt_status = bt_status;
        priv->bt_is_sco = bt_is_sco;
+
+       /* reset aggregation queues */
+       for (i = IWLAGN_FIRST_AMPDU_QUEUE; i < IWL_MAX_HW_QUEUES; i++)
+               priv->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
+       /* and stop counts */
+       for (i = 0; i < IWL_MAX_HW_QUEUES; i++)
+               atomic_set(&priv->queue_stop_count[i], 0);
+
+       memset(priv->agg_q_alloc, 0, sizeof(priv->agg_q_alloc));
 }
 
 static void iwl_bg_restart(struct work_struct *data)
@@ -907,7 +1026,7 @@ static void iwl_bg_restart(struct work_struct *data)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (test_and_clear_bit(STATUS_FW_ERROR, &priv->shrd->status)) {
+       if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
                mutex_lock(&priv->mutex);
                iwlagn_prepare_restart(priv);
                mutex_unlock(&priv->mutex);
@@ -959,7 +1078,7 @@ static void iwlagn_disable_roc_work(struct work_struct *work)
  *
  *****************************************************************************/
 
-static void iwl_setup_deferred_work(struct iwl_priv *priv)
+void iwl_setup_deferred_work(struct iwl_priv *priv)
 {
        priv->workqueue = create_singlethread_workqueue(DRV_NAME);
 
@@ -974,7 +1093,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
 
        iwl_setup_scan_deferred_work(priv);
 
-       if (cfg(priv)->bt_params)
+       if (priv->cfg->bt_params)
                iwlagn_bt_setup_deferred_work(priv);
 
        init_timer(&priv->statistics_periodic);
@@ -984,15 +1103,11 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
        init_timer(&priv->ucode_trace);
        priv->ucode_trace.data = (unsigned long)priv;
        priv->ucode_trace.function = iwl_bg_ucode_trace;
-
-       init_timer(&priv->watchdog);
-       priv->watchdog.data = (unsigned long)priv;
-       priv->watchdog.function = iwl_bg_watchdog;
 }
 
 void iwl_cancel_deferred_work(struct iwl_priv *priv)
 {
-       if (cfg(priv)->bt_params)
+       if (priv->cfg->bt_params)
                iwlagn_bt_cancel_deferred_work(priv);
 
        cancel_work_sync(&priv->run_time_calib_work);
@@ -1028,7 +1143,193 @@ static void iwl_init_hw_rates(struct ieee80211_rate *rates)
        }
 }
 
-static int iwl_init_drv(struct iwl_priv *priv)
+#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
+#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
+static void iwl_init_ht_hw_capab(const struct iwl_priv *priv,
+                             struct ieee80211_sta_ht_cap *ht_info,
+                             enum ieee80211_band band)
+{
+       u16 max_bit_rate = 0;
+       u8 rx_chains_num = priv->hw_params.rx_chains_num;
+       u8 tx_chains_num = priv->hw_params.tx_chains_num;
+
+       ht_info->cap = 0;
+       memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+
+       ht_info->ht_supported = true;
+
+       if (priv->cfg->ht_params &&
+           priv->cfg->ht_params->ht_greenfield_support)
+               ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
+       ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+       max_bit_rate = MAX_BIT_RATE_20_MHZ;
+       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;
+               max_bit_rate = MAX_BIT_RATE_40_MHZ;
+       }
+
+       if (iwlwifi_mod_params.amsdu_size_8K)
+               ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+
+       ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
+       ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
+
+       ht_info->mcs.rx_mask[0] = 0xFF;
+       if (rx_chains_num >= 2)
+               ht_info->mcs.rx_mask[1] = 0xFF;
+       if (rx_chains_num >= 3)
+               ht_info->mcs.rx_mask[2] = 0xFF;
+
+       /* Highest supported Rx data rate */
+       max_bit_rate *= rx_chains_num;
+       WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK);
+       ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate);
+
+       /* Tx MCS capabilities */
+       ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+       if (tx_chains_num != rx_chains_num) {
+               ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+               ht_info->mcs.tx_params |= ((tx_chains_num - 1) <<
+                               IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
+       }
+}
+
+/**
+ * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
+ */
+static int iwl_init_geos(struct iwl_priv *priv)
+{
+       struct iwl_channel_info *ch;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *channels;
+       struct ieee80211_channel *geo_ch;
+       struct ieee80211_rate *rates;
+       int i = 0;
+       s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN;
+
+       if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
+           priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
+               IWL_DEBUG_INFO(priv, "Geography modes already initialized.\n");
+               set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+               return 0;
+       }
+
+       channels = kcalloc(priv->channel_count,
+                          sizeof(struct ieee80211_channel), GFP_KERNEL);
+       if (!channels)
+               return -ENOMEM;
+
+       rates = kcalloc(IWL_RATE_COUNT_LEGACY, sizeof(struct ieee80211_rate),
+                       GFP_KERNEL);
+       if (!rates) {
+               kfree(channels);
+               return -ENOMEM;
+       }
+
+       /* 5.2GHz channels start after the 2.4GHz channels */
+       sband = &priv->bands[IEEE80211_BAND_5GHZ];
+       sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
+       /* just OFDM */
+       sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
+       sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE;
+
+       if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
+               iwl_init_ht_hw_capab(priv, &sband->ht_cap,
+                                        IEEE80211_BAND_5GHZ);
+
+       sband = &priv->bands[IEEE80211_BAND_2GHZ];
+       sband->channels = channels;
+       /* OFDM & CCK */
+       sband->bitrates = rates;
+       sband->n_bitrates = IWL_RATE_COUNT_LEGACY;
+
+       if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
+               iwl_init_ht_hw_capab(priv, &sband->ht_cap,
+                                        IEEE80211_BAND_2GHZ);
+
+       priv->ieee_channels = channels;
+       priv->ieee_rates = rates;
+
+       for (i = 0;  i < priv->channel_count; i++) {
+               ch = &priv->channel_info[i];
+
+               /* FIXME: might be removed if scan is OK */
+               if (!is_channel_valid(ch))
+                       continue;
+
+               sband =  &priv->bands[ch->band];
+
+               geo_ch = &sband->channels[sband->n_channels++];
+
+               geo_ch->center_freq =
+                       ieee80211_channel_to_frequency(ch->channel, ch->band);
+               geo_ch->max_power = ch->max_power_avg;
+               geo_ch->max_antenna_gain = 0xff;
+               geo_ch->hw_value = ch->channel;
+
+               if (is_channel_valid(ch)) {
+                       if (!(ch->flags & EEPROM_CHANNEL_IBSS))
+                               geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
+
+                       if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
+                               geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+
+                       if (ch->flags & EEPROM_CHANNEL_RADAR)
+                               geo_ch->flags |= IEEE80211_CHAN_RADAR;
+
+                       geo_ch->flags |= ch->ht40_extension_channel;
+
+                       if (ch->max_power_avg > max_tx_power)
+                               max_tx_power = ch->max_power_avg;
+               } else {
+                       geo_ch->flags |= IEEE80211_CHAN_DISABLED;
+               }
+
+               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",
+                               geo_ch->flags & IEEE80211_CHAN_DISABLED ?
+                               "restricted" : "valid",
+                                geo_ch->flags);
+       }
+
+       priv->tx_power_device_lmt = max_tx_power;
+       priv->tx_power_user_lmt = max_tx_power;
+       priv->tx_power_next = max_tx_power;
+
+       if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
+            priv->hw_params.sku & EEPROM_SKU_CAP_BAND_52GHZ) {
+               IWL_INFO(priv, "Incorrectly detected BG card as ABG. "
+                       "Please send your %s to maintainer.\n",
+                       priv->trans->hw_id_str);
+               priv->hw_params.sku &= ~EEPROM_SKU_CAP_BAND_52GHZ;
+       }
+
+       if (iwlwifi_mod_params.disable_5ghz)
+               priv->bands[IEEE80211_BAND_5GHZ].n_channels = 0;
+
+       IWL_INFO(priv, "Tunable channels: %d 802.11bg, %d 802.11a channels\n",
+                  priv->bands[IEEE80211_BAND_2GHZ].n_channels,
+                  priv->bands[IEEE80211_BAND_5GHZ].n_channels);
+
+       set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+
+       return 0;
+}
+
+/*
+ * iwl_free_geos - undo allocations in iwl_init_geos
+ */
+static void iwl_free_geos(struct iwl_priv *priv)
+{
+       kfree(priv->ieee_channels);
+       kfree(priv->ieee_rates);
+       clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
+}
+
+int iwl_init_drv(struct iwl_priv *priv)
 {
        int ret;
 
@@ -1043,7 +1344,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
        priv->band = IEEE80211_BAND_2GHZ;
 
        priv->plcp_delta_threshold =
-               cfg(priv)->base_params->plcp_delta_threshold;
+               priv->cfg->base_params->plcp_delta_threshold;
 
        priv->iw_mode = NL80211_IFTYPE_STATION;
        priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
@@ -1052,12 +1353,6 @@ static int iwl_init_drv(struct iwl_priv *priv)
 
        priv->ucode_owner = IWL_OWNERSHIP_DRIVER;
 
-       /* initialize force reset */
-       priv->force_reset[IWL_RF_RESET].reset_duration =
-               IWL_DELAY_NEXT_FORCE_RF_RESET;
-       priv->force_reset[IWL_FW_RESET].reset_duration =
-               IWL_DELAY_NEXT_FORCE_FW_RELOAD;
-
        priv->rx_statistics_jiffies = jiffies;
 
        /* Choose which receivers/antennas to use */
@@ -1066,8 +1361,8 @@ static int iwl_init_drv(struct iwl_priv *priv)
        iwl_init_scan_params(priv);
 
        /* init bt coex */
-       if (cfg(priv)->bt_params &&
-           cfg(priv)->bt_params->advanced_bt_coexist) {
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
                priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
                priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
                priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
@@ -1097,7 +1392,7 @@ err:
        return ret;
 }
 
-static void iwl_uninit_drv(struct iwl_priv *priv)
+void iwl_uninit_drv(struct iwl_priv *priv)
 {
        iwl_free_geos(priv);
        iwl_free_channel_map(priv);
@@ -1110,75 +1405,59 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
 #endif
 }
 
-/* Size of one Rx buffer in host DRAM */
-#define IWL_RX_BUF_SIZE_4K (4 * 1024)
-#define IWL_RX_BUF_SIZE_8K (8 * 1024)
-
-static void iwl_set_hw_params(struct iwl_priv *priv)
+void iwl_set_hw_params(struct iwl_priv *priv)
 {
-       if (cfg(priv)->ht_params)
-               hw_params(priv).use_rts_for_aggregation =
-                       cfg(priv)->ht_params->use_rts_for_aggregation;
-
-       if (iwlagn_mod_params.amsdu_size_8K)
-               hw_params(priv).rx_page_order =
-                       get_order(IWL_RX_BUF_SIZE_8K);
-       else
-               hw_params(priv).rx_page_order =
-                       get_order(IWL_RX_BUF_SIZE_4K);
+       if (priv->cfg->ht_params)
+               priv->hw_params.use_rts_for_aggregation =
+                       priv->cfg->ht_params->use_rts_for_aggregation;
 
-       if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
-               hw_params(priv).sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
-
-       hw_params(priv).num_ampdu_queues =
-               cfg(priv)->base_params->num_of_ampdu_queues;
-       hw_params(priv).wd_timeout = cfg(priv)->base_params->wd_timeout;
+       if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
+               priv->hw_params.sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
 
        /* Device-specific setup */
-       cfg(priv)->lib->set_hw_params(priv);
+       priv->lib->set_hw_params(priv);
 }
 
 
 
-static void iwl_debug_config(struct iwl_priv *priv)
+/* show what optional capabilities we have */
+void iwl_option_config(struct iwl_priv *priv)
 {
-       dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEBUG "
 #ifdef CONFIG_IWLWIFI_DEBUG
-               "enabled\n");
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG enabled\n");
 #else
-               "disabled\n");
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG disabled\n");
 #endif
-       dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEBUGFS "
+
 #ifdef CONFIG_IWLWIFI_DEBUGFS
-               "enabled\n");
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS enabled\n");
 #else
-               "disabled\n");
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS disabled\n");
 #endif
-       dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TRACING "
+
 #ifdef CONFIG_IWLWIFI_DEVICE_TRACING
-               "enabled\n");
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING enabled\n");
 #else
-               "disabled\n");
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING disabled\n");
 #endif
 
-       dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TESTMODE "
 #ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-               "enabled\n");
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TESTMODE enabled\n");
 #else
-               "disabled\n");
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TESTMODE disabled\n");
 #endif
-       dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_P2P "
+
 #ifdef CONFIG_IWLWIFI_P2P
-               "enabled\n");
+       IWL_INFO(priv, "CONFIG_IWLWIFI_P2P enabled\n");
 #else
-               "disabled\n");
+       IWL_INFO(priv, "CONFIG_IWLWIFI_P2P disabled\n");
 #endif
 }
 
 static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
+                                                const struct iwl_cfg *cfg,
                                                 const struct iwl_fw *fw)
 {
-       int err = 0;
        struct iwl_priv *priv;
        struct ieee80211_hw *hw;
        struct iwl_op_mode *op_mode;
@@ -1193,25 +1472,60 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
                STATISTICS_NOTIFICATION,
                REPLY_TX,
        };
+       int i;
 
        /************************
         * 1. Allocating HW data
         ************************/
        hw = iwl_alloc_all();
        if (!hw) {
-               pr_err("%s: Cannot allocate network device\n",
-                               cfg(trans)->name);
-               err = -ENOMEM;
+               pr_err("%s: Cannot allocate network device\n", cfg->name);
                goto out;
        }
 
        op_mode = hw->priv;
        op_mode->ops = &iwl_dvm_ops;
        priv = IWL_OP_MODE_GET_DVM(op_mode);
-       priv->shrd = trans->shrd;
+       priv->trans = trans;
+       priv->dev = trans->dev;
+       priv->cfg = cfg;
        priv->fw = fw;
-       /* TODO: remove fw from shared data later */
-       priv->shrd->fw = fw;
+
+       switch (priv->cfg->device_family) {
+       case IWL_DEVICE_FAMILY_1000:
+       case IWL_DEVICE_FAMILY_100:
+               priv->lib = &iwl1000_lib;
+               break;
+       case IWL_DEVICE_FAMILY_2000:
+       case IWL_DEVICE_FAMILY_105:
+               priv->lib = &iwl2000_lib;
+               break;
+       case IWL_DEVICE_FAMILY_2030:
+       case IWL_DEVICE_FAMILY_135:
+               priv->lib = &iwl2030_lib;
+               break;
+       case IWL_DEVICE_FAMILY_5000:
+               priv->lib = &iwl5000_lib;
+               break;
+       case IWL_DEVICE_FAMILY_5150:
+               priv->lib = &iwl5150_lib;
+               break;
+       case IWL_DEVICE_FAMILY_6000:
+       case IWL_DEVICE_FAMILY_6005:
+       case IWL_DEVICE_FAMILY_6000i:
+       case IWL_DEVICE_FAMILY_6050:
+       case IWL_DEVICE_FAMILY_6150:
+               priv->lib = &iwl6000_lib;
+               break;
+       case IWL_DEVICE_FAMILY_6030:
+               priv->lib = &iwl6030_lib;
+               break;
+       default:
+               break;
+       }
+
+       if (WARN_ON(!priv->lib))
+               goto out_free_hw;
 
        /*
         * Populate the state variables that the transport layer needs
@@ -1220,87 +1534,90 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
        trans_cfg.op_mode = op_mode;
        trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
        trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
+       trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K;
+       if (!iwlwifi_mod_params.wd_disable)
+               trans_cfg.queue_watchdog_timeout =
+                       priv->cfg->base_params->wd_timeout;
+       else
+               trans_cfg.queue_watchdog_timeout = IWL_WATCHHDOG_DISABLED;
+       trans_cfg.command_names = iwl_dvm_cmd_strings;
 
        ucode_flags = fw->ucode_capa.flags;
 
 #ifndef CONFIG_IWLWIFI_P2P
-       ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
+       ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
 #endif
 
        if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) {
                priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
                trans_cfg.cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
+               trans_cfg.queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
+               trans_cfg.n_queue_to_fifo =
+                       ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo);
        } else {
                priv->sta_key_max_num = STA_KEY_MAX_NUM;
                trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+               trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
+               trans_cfg.n_queue_to_fifo =
+                       ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo);
        }
 
        /* Configure transport layer */
-       iwl_trans_configure(trans(priv), &trans_cfg);
+       iwl_trans_configure(priv->trans, &trans_cfg);
 
        /* At this point both hw and priv are allocated. */
 
-       SET_IEEE80211_DEV(priv->hw, trans(priv)->dev);
+       SET_IEEE80211_DEV(priv->hw, priv->trans->dev);
 
-       /* show what debugging capabilities we have */
-       iwl_debug_config(priv);
+       iwl_option_config(priv);
 
        IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
 
        /* is antenna coupling more than 35dB ? */
        priv->bt_ant_couple_ok =
-               (iwlagn_mod_params.ant_coupling >
+               (iwlwifi_mod_params.ant_coupling >
                        IWL_BT_ANTENNA_COUPLING_THRESHOLD) ?
                        true : false;
 
        /* enable/disable bt channel inhibition */
-       priv->bt_ch_announce = iwlagn_mod_params.bt_ch_announce;
+       priv->bt_ch_announce = iwlwifi_mod_params.bt_ch_announce;
        IWL_DEBUG_INFO(priv, "BT channel inhibition is %s\n",
                       (priv->bt_ch_announce) ? "On" : "Off");
 
-       if (iwl_alloc_traffic_mem(priv))
-               IWL_ERR(priv, "Not enough memory to generate traffic log\n");
-
        /* these spin locks will be used in apm_ops.init and EEPROM access
         * we should init now
         */
-       spin_lock_init(&trans(priv)->reg_lock);
        spin_lock_init(&priv->statistics.lock);
 
        /***********************
         * 2. Read REV register
         ***********************/
        IWL_INFO(priv, "Detected %s, REV=0x%X\n",
-               cfg(priv)->name, trans(priv)->hw_rev);
+               priv->cfg->name, priv->trans->hw_rev);
 
-       err = iwl_trans_start_hw(trans(priv));
-       if (err)
-               goto out_free_traffic_mem;
+       if (iwl_trans_start_hw(priv->trans))
+               goto out_free_hw;
 
-       /*****************
-        * 3. Read EEPROM
-        *****************/
-       err = iwl_eeprom_init(trans(priv), trans(priv)->hw_rev);
-       /* Reset chip to save power until we load uCode during "up". */
-       iwl_trans_stop_hw(trans(priv));
-       if (err) {
+       /* Read the EEPROM */
+       if (iwl_eeprom_init(priv, priv->trans->hw_rev)) {
                IWL_ERR(priv, "Unable to init EEPROM\n");
-               goto out_free_traffic_mem;
+               goto out_free_hw;
        }
-       err = iwl_eeprom_check_version(priv);
-       if (err)
+       /* Reset chip to save power until we load uCode during "up". */
+       iwl_trans_stop_hw(priv->trans, false);
+
+       if (iwl_eeprom_check_version(priv))
                goto out_free_eeprom;
 
-       err = iwl_eeprom_init_hw_params(priv);
-       if (err)
+       if (iwl_eeprom_init_hw_params(priv))
                goto out_free_eeprom;
 
        /* extract MAC Address */
-       iwl_eeprom_get_mac(priv->shrd, priv->addresses[0].addr);
+       iwl_eeprom_get_mac(priv, priv->addresses[0].addr);
        IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->addresses[0].addr);
        priv->hw->wiphy->addresses = priv->addresses;
        priv->hw->wiphy->n_addresses = 1;
-       num_mac = iwl_eeprom_query16(priv->shrd, EEPROM_NUM_MAC_ADDRESS);
+       num_mac = iwl_eeprom_query16(priv, EEPROM_NUM_MAC_ADDRESS);
        if (num_mac > 1) {
                memcpy(priv->addresses[1].addr, priv->addresses[0].addr,
                       ETH_ALEN);
@@ -1313,7 +1630,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
         ************************/
        iwl_set_hw_params(priv);
 
-       if (!(hw_params(priv).sku & EEPROM_SKU_CAP_IPAN_ENABLE)) {
+       if (!(priv->hw_params.sku & EEPROM_SKU_CAP_IPAN_ENABLE)) {
                IWL_DEBUG_INFO(priv, "Your EEPROM disabled PAN");
                ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
                /*
@@ -1323,18 +1640,32 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
                ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
                priv->sta_key_max_num = STA_KEY_MAX_NUM;
                trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+               trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
+               trans_cfg.n_queue_to_fifo =
+                       ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo);
 
                /* Configure transport layer again*/
-               iwl_trans_configure(trans(priv), &trans_cfg);
+               iwl_trans_configure(priv->trans, &trans_cfg);
        }
 
        /*******************
         * 5. Setup priv
         *******************/
+       for (i = 0; i < IWL_MAX_HW_QUEUES; i++) {
+               priv->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
+               if (i < IWLAGN_FIRST_AMPDU_QUEUE &&
+                   i != IWL_DEFAULT_CMD_QUEUE_NUM &&
+                   i != IWL_IPAN_CMD_QUEUE_NUM)
+                       priv->queue_to_mac80211[i] = i;
+               atomic_set(&priv->queue_stop_count[i], 0);
+       }
 
-       err = iwl_init_drv(priv);
-       if (err)
+       WARN_ON(trans_cfg.queue_to_fifo[trans_cfg.cmd_queue] !=
+                                               IWLAGN_CMD_FIFO_NUM);
+
+       if (iwl_init_drv(priv))
                goto out_free_eeprom;
+
        /* At this point both hw and priv are initialized. */
 
        /********************
@@ -1367,15 +1698,12 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
         *
         * 7. Setup and register with mac80211 and debugfs
         **************************************************/
-       err = iwlagn_mac_setup_register(priv, &fw->ucode_capa);
-       if (err)
+       if (iwlagn_mac_setup_register(priv, &fw->ucode_capa))
                goto out_destroy_workqueue;
 
-       err = iwl_dbgfs_register(priv, DRV_NAME);
-       if (err)
+       if (iwl_dbgfs_register(priv, DRV_NAME))
                IWL_ERR(priv,
-                       "failed to create debugfs files. Ignoring error: %d\n",
-                       err);
+                       "failed to create debugfs files. Ignoring error\n");
 
        return op_mode;
 
@@ -1384,16 +1712,15 @@ out_destroy_workqueue:
        priv->workqueue = NULL;
        iwl_uninit_drv(priv);
 out_free_eeprom:
-       iwl_eeprom_free(priv->shrd);
-out_free_traffic_mem:
-       iwl_free_traffic_mem(priv);
+       iwl_eeprom_free(priv);
+out_free_hw:
        ieee80211_free_hw(priv->hw);
 out:
        op_mode = NULL;
        return op_mode;
 }
 
-static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
+void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
 {
        struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
 
@@ -1408,9 +1735,9 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
 
        /*This will stop the queues, move the device to low power state */
        priv->ucode_loaded = false;
-       iwl_trans_stop_device(trans(priv));
+       iwl_trans_stop_device(priv->trans);
 
-       iwl_eeprom_free(priv->shrd);
+       iwl_eeprom_free(priv);
 
        /*netif_stop_queue(dev); */
        flush_workqueue(priv->workqueue);
@@ -1420,69 +1747,562 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
         * until now... */
        destroy_workqueue(priv->workqueue);
        priv->workqueue = NULL;
-       iwl_free_traffic_mem(priv);
 
        iwl_uninit_drv(priv);
 
        dev_kfree_skb(priv->beacon_skb);
 
+       iwl_trans_stop_hw(priv->trans, true);
        ieee80211_free_hw(priv->hw);
 }
 
-static void iwl_cmd_queue_full(struct iwl_op_mode *op_mode)
+static const char * const 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",
+};
+
+static struct { char *name; u8 num; } advanced_lookup[] = {
+       { "NMI_INTERRUPT_WDG", 0x34 },
+       { "SYSASSERT", 0x35 },
+       { "UCODE_VERSION_MISMATCH", 0x37 },
+       { "BAD_COMMAND", 0x38 },
+       { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
+       { "FATAL_ERROR", 0x3D },
+       { "NMI_TRM_HW_ERR", 0x46 },
+       { "NMI_INTERRUPT_TRM", 0x4C },
+       { "NMI_INTERRUPT_BREAK_POINT", 0x54 },
+       { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C },
+       { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 },
+       { "NMI_INTERRUPT_HOST", 0x66 },
+       { "NMI_INTERRUPT_ACTION_PT", 0x7C },
+       { "NMI_INTERRUPT_UNKNOWN", 0x84 },
+       { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 },
+       { "ADVANCED_SYSASSERT", 0 },
+};
+
+static const char *desc_lookup(u32 num)
+{
+       int i;
+       int max = ARRAY_SIZE(desc_lookup_text);
+
+       if (num < max)
+               return desc_lookup_text[num];
+
+       max = ARRAY_SIZE(advanced_lookup) - 1;
+       for (i = 0; i < max; i++) {
+               if (advanced_lookup[i].num == num)
+                       break;
+       }
+       return advanced_lookup[i].name;
+}
+
+#define ERROR_START_OFFSET  (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
+
+static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+       struct iwl_trans *trans = priv->trans;
+       u32 base;
+       struct iwl_error_event_table table;
+
+       base = priv->device_pointers.error_event_table;
+       if (priv->cur_ucode == IWL_UCODE_INIT) {
+               if (!base)
+                       base = priv->fw->init_errlog_ptr;
+       } else {
+               if (!base)
+                       base = priv->fw->inst_errlog_ptr;
+       }
+
+       if (!iwlagn_hw_valid_rtc_data_addr(base)) {
+               IWL_ERR(priv,
+                       "Not valid error log pointer 0x%08X for %s uCode\n",
+                       base,
+                       (priv->cur_ucode == IWL_UCODE_INIT)
+                                       ? "Init" : "RT");
+               return;
+       }
+
+       /*TODO: Update dbgfs with ISR error stats obtained below */
+       iwl_read_targ_mem_words(trans, base, &table, sizeof(table));
+
+       if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
+               IWL_ERR(trans, "Start IWL Error Log Dump:\n");
+               IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
+                       priv->status, table.valid);
+       }
+
+       trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low,
+                                     table.data1, table.data2, table.line,
+                                     table.blink1, table.blink2, table.ilink1,
+                                     table.ilink2, table.bcon_time, table.gp1,
+                                     table.gp2, table.gp3, table.ucode_ver,
+                                     table.hw_ver, table.brd_ver);
+       IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id,
+               desc_lookup(table.error_id));
+       IWL_ERR(priv, "0x%08X | uPc\n", table.pc);
+       IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1);
+       IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2);
+       IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1);
+       IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2);
+       IWL_ERR(priv, "0x%08X | data1\n", table.data1);
+       IWL_ERR(priv, "0x%08X | data2\n", table.data2);
+       IWL_ERR(priv, "0x%08X | line\n", table.line);
+       IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time);
+       IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low);
+       IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi);
+       IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1);
+       IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2);
+       IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3);
+       IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver);
+       IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver);
+       IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver);
+       IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd);
+       IWL_ERR(priv, "0x%08X | isr0\n", table.isr0);
+       IWL_ERR(priv, "0x%08X | isr1\n", table.isr1);
+       IWL_ERR(priv, "0x%08X | isr2\n", table.isr2);
+       IWL_ERR(priv, "0x%08X | isr3\n", table.isr3);
+       IWL_ERR(priv, "0x%08X | isr4\n", table.isr4);
+       IWL_ERR(priv, "0x%08X | isr_pref\n", table.isr_pref);
+       IWL_ERR(priv, "0x%08X | wait_event\n", table.wait_event);
+       IWL_ERR(priv, "0x%08X | l2p_control\n", table.l2p_control);
+       IWL_ERR(priv, "0x%08X | l2p_duration\n", table.l2p_duration);
+       IWL_ERR(priv, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid);
+       IWL_ERR(priv, "0x%08X | l2p_addr_match\n", table.l2p_addr_match);
+       IWL_ERR(priv, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
+       IWL_ERR(priv, "0x%08X | timestamp\n", table.u_timestamp);
+       IWL_ERR(priv, "0x%08X | flow_handler\n", table.flow_handler);
+}
+
+#define EVENT_START_OFFSET  (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ */
+static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+                              u32 num_events, u32 mode,
+                              int pos, char **buf, size_t bufsz)
+{
+       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 */
+       unsigned long reg_flags;
+
+       struct iwl_trans *trans = priv->trans;
+
+       if (num_events == 0)
+               return pos;
+
+       base = priv->device_pointers.log_event_table;
+       if (priv->cur_ucode == IWL_UCODE_INIT) {
+               if (!base)
+                       base = priv->fw->init_evtlog_ptr;
+       } else {
+               if (!base)
+                       base = priv->fw->inst_evtlog_ptr;
+       }
+
+       if (mode == 0)
+               event_size = 2 * sizeof(u32);
+       else
+               event_size = 3 * sizeof(u32);
+
+       ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+       /* Make sure device is powered up for SRAM reads */
+       spin_lock_irqsave(&trans->reg_lock, reg_flags);
+       if (unlikely(!iwl_grab_nic_access(trans)))
+               goto out_unlock;
+
+       /* Set starting address; reads will auto-increment */
+       iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr);
+
+       /* "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_read32(trans, HBUS_TARG_MEM_RDAT);
+               time = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
+               if (mode == 0) {
+                       /* data, ev */
+                       if (bufsz) {
+                               pos += scnprintf(*buf + pos, bufsz - pos,
+                                               "EVT_LOG:0x%08x:%04u\n",
+                                               time, ev);
+                       } else {
+                               trace_iwlwifi_dev_ucode_event(trans->dev, 0,
+                                       time, ev);
+                               IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n",
+                                       time, ev);
+                       }
+               } else {
+                       data = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
+                       if (bufsz) {
+                               pos += scnprintf(*buf + pos, bufsz - pos,
+                                               "EVT_LOGT:%010u:0x%08x:%04u\n",
+                                                time, data, ev);
+                       } else {
+                               IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
+                                       time, data, ev);
+                               trace_iwlwifi_dev_ucode_event(trans->dev, time,
+                                       data, ev);
+                       }
+               }
+       }
+
+       /* Allow device to power down */
+       iwl_release_nic_access(trans);
+out_unlock:
+       spin_unlock_irqrestore(&trans->reg_lock, reg_flags);
+       return pos;
+}
+
+/**
+ * iwl_print_last_event_logs - Dump the newest # of event log to syslog
+ */
+static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
+                                   u32 num_wraps, u32 next_entry,
+                                   u32 size, u32 mode,
+                                   int pos, char **buf, size_t bufsz)
+{
+       /*
+        * display the newest DEFAULT_LOG_ENTRIES entries
+        * i.e the entries just before the next ont that uCode would fill.
+        */
+       if (num_wraps) {
+               if (next_entry < size) {
+                       pos = iwl_print_event_log(priv,
+                                               capacity - (size - next_entry),
+                                               size - next_entry, mode,
+                                               pos, buf, bufsz);
+                       pos = iwl_print_event_log(priv, 0,
+                                                 next_entry, mode,
+                                                 pos, buf, bufsz);
+               } else
+                       pos = iwl_print_event_log(priv, next_entry - size,
+                                                 size, mode, pos, buf, bufsz);
+       } else {
+               if (next_entry < size) {
+                       pos = iwl_print_event_log(priv, 0, next_entry,
+                                                 mode, pos, buf, bufsz);
+               } else {
+                       pos = iwl_print_event_log(priv, next_entry - size,
+                                                 size, mode, pos, buf, bufsz);
+               }
+       }
+       return pos;
+}
+
+#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
+
+int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+                           char **buf, bool display)
+{
+       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 */
+       u32 logsize;
+       int pos = 0;
+       size_t bufsz = 0;
+       struct iwl_trans *trans = priv->trans;
+
+       base = priv->device_pointers.log_event_table;
+       if (priv->cur_ucode == IWL_UCODE_INIT) {
+               logsize = priv->fw->init_evtlog_size;
+               if (!base)
+                       base = priv->fw->init_evtlog_ptr;
+       } else {
+               logsize = priv->fw->inst_evtlog_size;
+               if (!base)
+                       base = priv->fw->inst_evtlog_ptr;
+       }
+
+       if (!iwlagn_hw_valid_rtc_data_addr(base)) {
+               IWL_ERR(priv,
+                       "Invalid event log pointer 0x%08X for %s uCode\n",
+                       base,
+                       (priv->cur_ucode == IWL_UCODE_INIT)
+                                       ? "Init" : "RT");
+               return -EINVAL;
+       }
+
+       /* event log header */
+       capacity = iwl_read_targ_mem(trans, base);
+       mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32)));
+       num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32)));
+       next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32)));
+
+       if (capacity > logsize) {
+               IWL_ERR(priv, "Log capacity %d is bogus, limit to %d "
+                       "entries\n", capacity, logsize);
+               capacity = logsize;
+       }
+
+       if (next_entry > logsize) {
+               IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
+                       next_entry, logsize);
+               next_entry = logsize;
+       }
+
+       size = num_wraps ? capacity : next_entry;
+
+       /* bail out if nothing in log */
+       if (size == 0) {
+               IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n");
+               return pos;
+       }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (!(iwl_have_debug_level(IWL_DL_FW_ERRORS)) && !full_log)
+               size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
+                       ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
+#else
+       size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
+               ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
+#endif
+       IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n",
+               size);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (display) {
+               if (full_log)
+                       bufsz = capacity * 48;
+               else
+                       bufsz = size * 48;
+               *buf = kmalloc(bufsz, GFP_KERNEL);
+               if (!*buf)
+                       return -ENOMEM;
+       }
+       if (iwl_have_debug_level(IWL_DL_FW_ERRORS) || full_log) {
+               /*
+                * 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)
+                       pos = iwl_print_event_log(priv, next_entry,
+                                               capacity - next_entry, mode,
+                                               pos, buf, bufsz);
+               /* (then/else) start at top of log */
+               pos = iwl_print_event_log(priv, 0,
+                                         next_entry, mode, pos, buf, bufsz);
+       } else
+               pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
+                                               next_entry, size, mode,
+                                               pos, buf, bufsz);
+#else
+       pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
+                                       next_entry, size, mode,
+                                       pos, buf, bufsz);
+#endif
+       return pos;
+}
+
+static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
+{
+       unsigned int reload_msec;
+       unsigned long reload_jiffies;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (iwl_have_debug_level(IWL_DL_FW_ERRORS))
+               iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS);
+#endif
+
+       /* uCode is no longer loaded. */
+       priv->ucode_loaded = false;
+
+       /* Set the FW error flag -- cleared on iwl_down */
+       set_bit(STATUS_FW_ERROR, &priv->status);
+
+       iwl_abort_notification_waits(&priv->notif_wait);
+
+       /* Keep the restart process from trying to send host
+        * commands by clearing the ready bit */
+       clear_bit(STATUS_READY, &priv->status);
+
+       wake_up(&priv->trans->wait_command_queue);
+
+       if (!ondemand) {
+               /*
+                * If firmware keep reloading, then it indicate something
+                * serious wrong and firmware having problem to recover
+                * from it. Instead of keep trying which will fill the syslog
+                * and hang the system, let's just stop it
+                */
+               reload_jiffies = jiffies;
+               reload_msec = jiffies_to_msecs((long) reload_jiffies -
+                                       (long) priv->reload_jiffies);
+               priv->reload_jiffies = reload_jiffies;
+               if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
+                       priv->reload_count++;
+                       if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
+                               IWL_ERR(priv, "BUG_ON, Stop restarting\n");
+                               return;
+                       }
+               } else
+                       priv->reload_count = 0;
+       }
+
+       if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+               if (iwlwifi_mod_params.restart_fw) {
+                       IWL_DEBUG_FW_ERRORS(priv,
+                                 "Restarting adapter due to uCode error.\n");
+                       queue_work(priv->workqueue, &priv->restart);
+               } else
+                       IWL_DEBUG_FW_ERRORS(priv,
+                                 "Detected FW error, but not restarting\n");
+       }
+}
+
+void iwl_nic_error(struct iwl_op_mode *op_mode)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+       IWL_ERR(priv, "Loaded firmware version: %s\n",
+               priv->fw->fw_version);
+
+       iwl_dump_nic_error_log(priv);
+       iwl_dump_nic_event_log(priv, false, NULL, false);
+
+       iwlagn_fw_error(priv, false);
+}
+
+void iwl_cmd_queue_full(struct iwl_op_mode *op_mode)
 {
        struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
 
        if (!iwl_check_for_ct_kill(priv)) {
                IWL_ERR(priv, "Restarting adapter queue is full\n");
-               iwl_nic_error(op_mode);
+               iwlagn_fw_error(priv, false);
        }
 }
 
-static void iwl_nic_config(struct iwl_op_mode *op_mode)
+void iwl_nic_config(struct iwl_op_mode *op_mode)
 {
        struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
 
-       cfg(priv)->lib->nic_config(priv);
+       priv->lib->nic_config(priv);
 }
 
-static void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac)
+static void iwl_wimax_active(struct iwl_op_mode *op_mode)
 {
        struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
 
-       set_bit(ac, &priv->transport_queue_stop);
-       ieee80211_stop_queue(priv->hw, ac);
+       clear_bit(STATUS_READY, &priv->status);
+       IWL_ERR(priv, "RF is used by WiMAX\n");
+}
+
+void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       int mq = priv->queue_to_mac80211[queue];
+
+       if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
+               return;
+
+       if (atomic_inc_return(&priv->queue_stop_count[mq]) > 1) {
+               IWL_DEBUG_TX_QUEUES(priv,
+                       "queue %d (mac80211 %d) already stopped\n",
+                       queue, mq);
+               return;
+       }
+
+       set_bit(mq, &priv->transport_queue_stop);
+       ieee80211_stop_queue(priv->hw, mq);
 }
 
-static void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, u8 ac)
+void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
 {
        struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       int mq = priv->queue_to_mac80211[queue];
 
-       clear_bit(ac, &priv->transport_queue_stop);
+       if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
+               return;
+
+       if (atomic_dec_return(&priv->queue_stop_count[mq]) > 0) {
+               IWL_DEBUG_TX_QUEUES(priv,
+                       "queue %d (mac80211 %d) already awake\n",
+                       queue, mq);
+               return;
+       }
+
+       clear_bit(mq, &priv->transport_queue_stop);
 
        if (!priv->passive_no_rx)
-               ieee80211_wake_queue(priv->hw, ac);
+               ieee80211_wake_queue(priv->hw, mq);
 }
 
 void iwlagn_lift_passive_no_rx(struct iwl_priv *priv)
 {
-       int ac;
+       int mq;
 
        if (!priv->passive_no_rx)
                return;
 
-       for (ac = IEEE80211_AC_VO; ac < IEEE80211_NUM_ACS; ac++) {
-               if (!test_bit(ac, &priv->transport_queue_stop)) {
-                       IWL_DEBUG_TX_QUEUES(priv, "Wake queue %d");
-                       ieee80211_wake_queue(priv->hw, ac);
+       for (mq = 0; mq < IWLAGN_FIRST_AMPDU_QUEUE; mq++) {
+               if (!test_bit(mq, &priv->transport_queue_stop)) {
+                       IWL_DEBUG_TX_QUEUES(priv, "Wake queue %d", mq);
+                       ieee80211_wake_queue(priv->hw, mq);
                } else {
-                       IWL_DEBUG_TX_QUEUES(priv, "Don't wake queue %d");
+                       IWL_DEBUG_TX_QUEUES(priv, "Don't wake queue %d", mq);
                }
        }
 
        priv->passive_no_rx = false;
 }
 
+void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
+{
+       struct ieee80211_tx_info *info;
+
+       info = IEEE80211_SKB_CB(skb);
+       kmem_cache_free(iwl_tx_cmd_pool, (info->driver_data[1]));
+       dev_kfree_skb_any(skb);
+}
+
+void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+       if (state)
+               set_bit(STATUS_RF_KILL_HW, &priv->status);
+       else
+               clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+       wiphy_rfkill_set_hw_state(priv->hw->wiphy, state);
+}
+
 const struct iwl_op_mode_ops iwl_dvm_ops = {
        .start = iwl_op_mode_dvm_start,
        .stop = iwl_op_mode_dvm_stop,
@@ -1494,6 +2314,7 @@ const struct iwl_op_mode_ops iwl_dvm_ops = {
        .nic_error = iwl_nic_error,
        .cmd_queue_full = iwl_cmd_queue_full,
        .nic_config = iwl_nic_config,
+       .wimax_active = iwl_wimax_active,
 };
 
 /*****************************************************************************
@@ -1544,96 +2365,3 @@ static void __exit iwl_exit(void)
 
 module_exit(iwl_exit);
 module_init(iwl_init);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-module_param_named(debug, iwlagn_mod_params.debug_level, uint,
-                  S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "debug output mask");
-#endif
-
-module_param_named(swcrypto, iwlagn_mod_params.sw_crypto, int, S_IRUGO);
-MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(11n_disable, iwlagn_mod_params.disable_11n, uint, S_IRUGO);
-MODULE_PARM_DESC(11n_disable,
-       "disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX");
-module_param_named(amsdu_size_8K, iwlagn_mod_params.amsdu_size_8K,
-                  int, S_IRUGO);
-MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
-module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO);
-MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
-
-module_param_named(ucode_alternative,
-                  iwlagn_mod_params.wanted_ucode_alternative,
-                  int, S_IRUGO);
-MODULE_PARM_DESC(ucode_alternative,
-                "specify ucode alternative to use from ucode file");
-
-module_param_named(antenna_coupling, iwlagn_mod_params.ant_coupling,
-                  int, S_IRUGO);
-MODULE_PARM_DESC(antenna_coupling,
-                "specify antenna coupling in dB (defualt: 0 dB)");
-
-module_param_named(bt_ch_inhibition, iwlagn_mod_params.bt_ch_announce,
-                  bool, S_IRUGO);
-MODULE_PARM_DESC(bt_ch_inhibition,
-                "Enable BT channel inhibition (default: enable)");
-
-module_param_named(plcp_check, iwlagn_mod_params.plcp_check, bool, S_IRUGO);
-MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])");
-
-module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO);
-MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])");
-
-module_param_named(wd_disable, iwlagn_mod_params.wd_disable, int, S_IRUGO);
-MODULE_PARM_DESC(wd_disable,
-               "Disable stuck queue watchdog timer 0=system default, "
-               "1=disable, 2=enable (default: 0)");
-
-/*
- * set bt_coex_active to true, uCode will do kill/defer
- * every time the priority line is asserted (BT is sending signals on the
- * priority line in the PCIx).
- * set bt_coex_active to false, uCode will ignore the BT activity and
- * perform the normal operation
- *
- * User might experience transmit issue on some platform due to WiFi/BT
- * co-exist problem. The possible behaviors are:
- *   Able to scan and finding all the available AP
- *   Not able to associate with any AP
- * On those platforms, WiFi communication can be restored by set
- * "bt_coex_active" module parameter to "false"
- *
- * default: bt_coex_active = true (BT_COEX_ENABLE)
- */
-module_param_named(bt_coex_active, iwlagn_mod_params.bt_coex_active,
-               bool, S_IRUGO);
-MODULE_PARM_DESC(bt_coex_active, "enable wifi/bt co-exist (default: enable)");
-
-module_param_named(led_mode, iwlagn_mod_params.led_mode, int, S_IRUGO);
-MODULE_PARM_DESC(led_mode, "0=system default, "
-               "1=On(RF On)/Off(RF Off), 2=blinking, 3=Off (default: 0)");
-
-module_param_named(power_save, iwlagn_mod_params.power_save,
-               bool, S_IRUGO);
-MODULE_PARM_DESC(power_save,
-                "enable WiFi power management (default: disable)");
-
-module_param_named(power_level, iwlagn_mod_params.power_level,
-               int, S_IRUGO);
-MODULE_PARM_DESC(power_level,
-                "default power save level (range from 1 - 5, default: 1)");
-
-module_param_named(auto_agg, iwlagn_mod_params.auto_agg,
-               bool, S_IRUGO);
-MODULE_PARM_DESC(auto_agg,
-                "enable agg w/o check traffic load (default: enable)");
-
-/*
- * For now, keep using power level 1 instead of automatically
- * adjusting ...
- */
-module_param_named(no_sleep_autoadjust, iwlagn_mod_params.no_sleep_autoadjust,
-               bool, S_IRUGO);
-MODULE_PARM_DESC(no_sleep_autoadjust,
-                "don't automatically adjust sleep level "
-                "according to maximum network latency (default: true)");