Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[safe/jmp/linux-2.6] / drivers / net / wireless / iwlwifi / iwl-5000.c
index 539fc0e..c6120f0 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <linux/sched.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
 #include "iwl-io.h"
 #include "iwl-sta.h"
 #include "iwl-helpers.h"
+#include "iwl-agn-led.h"
 #include "iwl-5000-hw.h"
 #include "iwl-6000-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL5000_UCODE_API_MAX 1
-#define IWL5150_UCODE_API_MAX 1
+#define IWL5000_UCODE_API_MAX 2
+#define IWL5150_UCODE_API_MAX 2
 
 /* Lowest firmware API version supported */
 #define IWL5000_UCODE_API_MIN 1
@@ -71,170 +73,18 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = {
        IWL_TX_FIFO_HCCA_2
 };
 
-/* FIXME: same implementation as 4965 */
-static int iwl5000_apm_stop_master(struct iwl_priv *priv)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       /* set stop master bit */
-       iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
-
-       iwl_poll_direct_bit(priv, CSR_RESET,
-                                 CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-       IWL_DEBUG_INFO(priv, "stop master\n");
-
-       return 0;
-}
-
-
-static int iwl5000_apm_init(struct iwl_priv *priv)
-{
-       int ret = 0;
-
-       iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
-                   CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
-
-       /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
-       iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
-                   CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
-
-       /* Set FH wait threshold to maximum (HW error during stress W/A) */
-       iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
-
-       /* enable HAP INTA to move device L1a -> L0s */
-       iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
-                   CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
-
-       iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
-
-       /* set "initialization complete" bit to move adapter
-        * D0U* --> D0A* state */
-       iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
-       /* wait for clock stabilization */
-       ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
-                       CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
-       if (ret < 0) {
-               IWL_DEBUG_INFO(priv, "Failed to init the card\n");
-               return ret;
-       }
-
-       ret = iwl_grab_nic_access(priv);
-       if (ret)
-               return ret;
-
-       /* enable DMA */
-       iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
-
-       udelay(20);
-
-       /* disable L1-Active */
-       iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
-                         APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-
-       iwl_release_nic_access(priv);
-
-       return ret;
-}
-
-/* FIXME: this is identical to 4965 */
-static void iwl5000_apm_stop(struct iwl_priv *priv)
-{
-       unsigned long flags;
-
-       iwl5000_apm_stop_master(priv);
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-
-       udelay(10);
-
-       /* clear "init complete"  move adapter D0A* --> D0U state */
-       iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-
-static int iwl5000_apm_reset(struct iwl_priv *priv)
-{
-       int ret = 0;
-       unsigned long flags;
-
-       iwl5000_apm_stop_master(priv);
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-
-       udelay(10);
-
-
-       /* FIXME: put here L1A -L0S w/a */
-
-       iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
-
-       /* set "initialization complete" bit to move adapter
-        * D0U* --> D0A* state */
-       iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
-       /* wait for clock stabilization */
-       ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
-                       CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
-       if (ret < 0) {
-               IWL_DEBUG_INFO(priv, "Failed to init the card\n");
-               goto out;
-       }
-
-       ret = iwl_grab_nic_access(priv);
-       if (ret)
-               goto out;
-
-       /* enable DMA */
-       iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
-
-       udelay(20);
-
-       /* disable L1-Active */
-       iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
-                         APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-
-       iwl_release_nic_access(priv);
-
-out:
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return ret;
-}
-
-
-static void iwl5000_nic_config(struct iwl_priv *priv)
+/* NIC configuration for 5000 series */
+void iwl5000_nic_config(struct iwl_priv *priv)
 {
        unsigned long flags;
        u16 radio_cfg;
-       u16 link;
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &link);
-
-       /* L1 is enabled by BIOS */
-       if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
-               /* disable L0S disabled L1A enabled */
-               iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
-       else
-               /* L0S enabled L1A disabled */
-               iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
-
        radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
 
        /* write radio config values to register */
-       if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_5000_RF_CFG_TYPE_MAX)
+       if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_RF_CONFIG_TYPE_MAX)
                iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
                            EEPROM_RF_CFG_TYPE_MSK(radio_cfg) |
                            EEPROM_RF_CFG_STEP_MSK(radio_cfg) |
@@ -249,17 +99,15 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
         * (PCIe power is lost before PERST# is asserted),
         * causing ME FW to lose ownership and not being able to obtain it back.
         */
-       iwl_grab_nic_access(priv);
        iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
                                APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
                                ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
-       iwl_release_nic_access(priv);
+
 
        spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 
-
 /*
  * EEPROM
  */
@@ -299,7 +147,7 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
        return (address & ADDRESS_MSK) + (offset << 1);
 }
 
-static u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
+u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
 {
        struct iwl_eeprom_calib_hdr {
                u8 version;
@@ -316,23 +164,26 @@ static u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
 static void iwl5000_gain_computation(struct iwl_priv *priv,
                u32 average_noise[NUM_RX_CHAINS],
                u16 min_average_noise_antenna_i,
-               u32 min_average_noise)
+               u32 min_average_noise,
+               u8 default_chain)
 {
        int i;
        s32 delta_g;
        struct iwl_chain_noise_data *data = &priv->chain_noise_data;
 
-       /* Find Gain Code for the antennas B and C */
-       for (i = 1; i < NUM_RX_CHAINS; i++) {
+       /*
+        * Find Gain Code for the chains based on "default chain"
+        */
+       for (i = default_chain + 1; i < NUM_RX_CHAINS; i++) {
                if ((data->disconn_array[i])) {
                        data->delta_gain_code[i] = 0;
                        continue;
                }
-               delta_g = (1000 * ((s32)average_noise[0] -
+               delta_g = (1000 * ((s32)average_noise[default_chain] -
                        (s32)average_noise[i])) / 1500;
                /* bound gain by 2 bits value max, 3rd bit is sign */
                data->delta_gain_code[i] =
-                       min(abs(delta_g), CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
+                       min(abs(delta_g), (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
 
                if (delta_g < 0)
                        /* set negative sign */
@@ -392,7 +243,7 @@ static void iwl5000_chain_noise_reset(struct iwl_priv *priv)
        }
 }
 
-static void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
+void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
                        __le32 *tx_flags)
 {
        if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
@@ -404,7 +255,7 @@ static void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
 
 static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
        .min_nrg_cck = 95,
-       .max_nrg_cck = 0,
+       .max_nrg_cck = 0, /* not used, set to 0 */
        .auto_corr_min_ofdm = 90,
        .auto_corr_min_ofdm_mrc = 170,
        .auto_corr_min_ofdm_x1 = 120,
@@ -421,9 +272,39 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
        .auto_corr_max_cck_mrc = 400,
        .nrg_th_cck = 95,
        .nrg_th_ofdm = 95,
+
+       .barker_corr_th_min = 190,
+       .barker_corr_th_min_mrc = 390,
+       .nrg_th_cca = 62,
+};
+
+static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
+       .min_nrg_cck = 95,
+       .max_nrg_cck = 0, /* not used, set to 0 */
+       .auto_corr_min_ofdm = 90,
+       .auto_corr_min_ofdm_mrc = 170,
+       .auto_corr_min_ofdm_x1 = 105,
+       .auto_corr_min_ofdm_mrc_x1 = 220,
+
+       .auto_corr_max_ofdm = 120,
+       .auto_corr_max_ofdm_mrc = 210,
+       /* max = min for performance bug in 5150 DSP */
+       .auto_corr_max_ofdm_x1 = 105,
+       .auto_corr_max_ofdm_mrc_x1 = 220,
+
+       .auto_corr_min_cck = 125,
+       .auto_corr_max_cck = 200,
+       .auto_corr_min_cck_mrc = 170,
+       .auto_corr_max_cck_mrc = 400,
+       .nrg_th_cck = 95,
+       .nrg_th_ofdm = 95,
+
+       .barker_corr_th_min = 190,
+       .barker_corr_th_min_mrc = 390,
+       .nrg_th_cca = 62,
 };
 
-static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
+const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
                                           size_t offset)
 {
        u32 address = eeprom_indirect_address(priv, offset);
@@ -431,15 +312,19 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
        return &priv->eeprom[address];
 }
 
-static s32 iwl5150_get_ct_threshold(struct iwl_priv *priv)
+static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
 {
-       const s32 volt2temp_coef = -5;
-       u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv,
-                                               EEPROM_5000_TEMPERATURE);
-       /* offset =  temperate -  voltage / coef */
-       s32 offset = temp_calib[0] - temp_calib[1] / volt2temp_coef;
-       s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - offset;
-       return threshold * volt2temp_coef;
+       const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
+       s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
+                       iwl_temp_calib_to_offset(priv);
+
+       priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
+}
+
+static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
+{
+       /* want Celsius */
+       priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
 }
 
 /*
@@ -448,14 +333,15 @@ static s32 iwl5150_get_ct_threshold(struct iwl_priv *priv)
 static int iwl5000_set_Xtal_calib(struct iwl_priv *priv)
 {
        struct iwl_calib_xtal_freq_cmd cmd;
-       u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL);
+       __le16 *xtal_calib =
+               (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL);
 
        cmd.hdr.op_code = IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD;
        cmd.hdr.first_group = 0;
        cmd.hdr.groups_num = 1;
        cmd.hdr.data_valid = 1;
-       cmd.cap_pin1 = (u8)xtal_calib[0];
-       cmd.cap_pin2 = (u8)xtal_calib[1];
+       cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]);
+       cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]);
        return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL],
                             (u8 *)&cmd, sizeof(cmd));
 }
@@ -481,9 +367,9 @@ static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
 static void iwl5000_rx_calib_result(struct iwl_priv *priv,
                             struct iwl_rx_mem_buffer *rxb)
 {
-       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
-       int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK;
+       int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
        int index;
 
        /* reduce the size of the length field itself */
@@ -530,19 +416,9 @@ static int iwl5000_load_section(struct iwl_priv *priv,
                                struct fw_desc *image,
                                u32 dst_addr)
 {
-       int ret = 0;
-       unsigned long flags;
-
        dma_addr_t phy_addr = image->p_addr;
        u32 byte_cnt = image->len;
 
-       spin_lock_irqsave(&priv->lock, flags);
-       ret = iwl_grab_nic_access(priv);
-       if (ret) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return ret;
-       }
-
        iwl_write_direct32(priv,
                FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
@@ -571,8 +447,6 @@ static int iwl5000_load_section(struct iwl_priv *priv,
                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE    |
                FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
 
-       iwl_release_nic_access(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
        return 0;
 }
 
@@ -626,7 +500,7 @@ static int iwl5000_load_given_ucode(struct iwl_priv *priv,
        return ret;
 }
 
-static int iwl5000_load_ucode(struct iwl_priv *priv)
+int iwl5000_load_ucode(struct iwl_priv *priv)
 {
        int ret = 0;
 
@@ -653,7 +527,7 @@ static int iwl5000_load_ucode(struct iwl_priv *priv)
        return ret;
 }
 
-static void iwl5000_init_alive_start(struct iwl_priv *priv)
+void iwl5000_init_alive_start(struct iwl_priv *priv)
 {
        int ret = 0;
 
@@ -719,32 +593,15 @@ static void iwl5000_tx_queue_set_status(struct iwl_priv *priv,
                       scd_retry ? "BA" : "AC", txq_id, tx_fifo_id);
 }
 
-static int iwl5000_send_wimax_coex(struct iwl_priv *priv)
-{
-       struct iwl_wimax_coex_cmd coex_cmd;
-
-       memset(&coex_cmd, 0, sizeof(coex_cmd));
-
-       return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD,
-                               sizeof(coex_cmd), &coex_cmd);
-}
-
-static int iwl5000_alive_notify(struct iwl_priv *priv)
+int iwl5000_alive_notify(struct iwl_priv *priv)
 {
        u32 a;
        unsigned long flags;
-       int ret;
        int i, chan;
        u32 reg_val;
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       ret = iwl_grab_nic_access(priv);
-       if (ret) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return ret;
-       }
-
        priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR);
        a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET;
        for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET;
@@ -753,7 +610,8 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
        for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET;
                a += 4)
                iwl_write_targ_mem(priv, a, 0);
-       for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4)
+       for (; a < priv->scd_base_addr +
+              IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4)
                iwl_write_targ_mem(priv, a, 0);
 
        iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR,
@@ -805,18 +663,21 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
                iwl_txq_ctx_activate(priv, i);
                iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
        }
-       /* TODO - need to initialize those FIFOs inside the loop above,
-        * not only mark them as active */
-       iwl_txq_ctx_activate(priv, 4);
+
+       /*
+        * TODO - need to initialize these queues and map them to FIFOs
+        * in the loop above, not only mark them as active. We do this
+        * because we want the first aggregation queue to be queue #10,
+        * but do not use 8 or 9 otherwise yet.
+        */
        iwl_txq_ctx_activate(priv, 7);
        iwl_txq_ctx_activate(priv, 8);
        iwl_txq_ctx_activate(priv, 9);
 
-       iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
 
 
-       iwl5000_send_wimax_coex(priv);
+       iwl_send_wimax_coex(priv);
 
        iwl5000_set_Xtal_calib(priv);
        iwl_send_calib_results(priv);
@@ -824,62 +685,43 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
        return 0;
 }
 
-static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
+int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 {
-       if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) ||
-           (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
-               IWL_ERR(priv,
-                       "invalid queues_num, should be between %d and %d\n",
-                       IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES);
-               return -EINVAL;
-       }
+       if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
+           priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES)
+               priv->cfg->num_of_queues =
+                       priv->cfg->mod_params->num_of_queues;
 
-       priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
+       priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
        priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
-                       IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl);
+                       priv->cfg->num_of_queues *
+                       sizeof(struct iwl5000_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWL5000_STATION_COUNT;
        priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
 
-       switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
-       case CSR_HW_REV_TYPE_6x00:
-       case CSR_HW_REV_TYPE_6x50:
-               priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
-               priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
-               break;
-       default:
-               priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
-               priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE;
-       }
+       priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
+       priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE;
 
        priv->hw_params.max_bsm_size = 0;
-       priv->hw_params.fat_channel =  BIT(IEEE80211_BAND_2GHZ) |
+       priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
                                        BIT(IEEE80211_BAND_5GHZ);
        priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
 
-       priv->hw_params.sens = &iwl5000_sensitivity;
-
        priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
        priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
        priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
        priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
 
-       switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
-       case CSR_HW_REV_TYPE_5150:
-               /* 5150 wants in Kelvin */
-               priv->hw_params.ct_kill_threshold =
-                               iwl5150_get_ct_threshold(priv);
-               break;
-       default:
-               /* all others want Celsius */
-               priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
-               break;
-       }
+       if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
+               priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
 
+       /* Set initial sensitivity parameters */
        /* Set initial calibration set */
        switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
        case CSR_HW_REV_TYPE_5150:
+               priv->hw_params.sens = &iwl5150_sensitivity;
                priv->hw_params.calib_init_cfg =
                        BIT(IWL_CALIB_DC)               |
                        BIT(IWL_CALIB_LO)               |
@@ -888,6 +730,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 
                break;
        default:
+               priv->hw_params.sens = &iwl5000_sensitivity;
                priv->hw_params.calib_init_cfg =
                        BIT(IWL_CALIB_XTAL)             |
                        BIT(IWL_CALIB_LO)               |
@@ -897,14 +740,13 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
                break;
        }
 
-
        return 0;
 }
 
 /**
  * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
  */
-static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
                                            struct iwl_tx_queue *txq,
                                            u16 byte_cnt)
 {
@@ -939,12 +781,12 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
 
        scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
 
-       if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+       if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
                scd_bc_tbl[txq_id].
                        tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
 }
 
-static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
                                           struct iwl_tx_queue *txq)
 {
        struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
@@ -958,12 +800,12 @@ static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
        if (txq_id != IWL_CMD_QUEUE_NUM)
                sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
 
-       bc_ent =  cpu_to_le16(1 | (sta_id << 12));
+       bc_ent = cpu_to_le16(1 | (sta_id << 12));
        scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
 
-       if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+       if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
                scd_bc_tbl[txq_id].
-                       tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] =  bc_ent;
+                       tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
 }
 
 static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
@@ -999,19 +841,20 @@ static void iwl5000_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
                (1 << IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
 }
 
-static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
+int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
                                  int tx_fifo, int sta_id, int tid, u16 ssn_idx)
 {
        unsigned long flags;
-       int ret;
        u16 ra_tid;
 
        if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
-           (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) {
+           (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
+            <= txq_id)) {
                IWL_WARN(priv,
                        "queue number out of range: %d, must be %d to %d\n",
                        txq_id, IWL50_FIRST_AMPDU_QUEUE,
-                       IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1);
+                       IWL50_FIRST_AMPDU_QUEUE +
+                       priv->cfg->num_of_ampdu_queues - 1);
                return -EINVAL;
        }
 
@@ -1021,11 +864,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
        iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
 
        spin_lock_irqsave(&priv->lock, flags);
-       ret = iwl_grab_nic_access(priv);
-       if (ret) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return ret;
-       }
 
        /* Stop this Tx queue before configuring it */
        iwl5000_tx_queue_stop_scheduler(priv, txq_id);
@@ -1061,30 +899,25 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
        /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
        iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
 
-       iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
 
        return 0;
 }
 
-static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
                                   u16 ssn_idx, u8 tx_fifo)
 {
-       int ret;
-
        if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
-           (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) {
-               IWL_WARN(priv,
+           (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
+            <= txq_id)) {
+               IWL_ERR(priv,
                        "queue number out of range: %d, must be %d to %d\n",
                        txq_id, IWL50_FIRST_AMPDU_QUEUE,
-                       IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1);
+                       IWL50_FIRST_AMPDU_QUEUE +
+                       priv->cfg->num_of_ampdu_queues - 1);
                return -EINVAL;
        }
 
-       ret = iwl_grab_nic_access(priv);
-       if (ret)
-               return ret;
-
        iwl5000_tx_queue_stop_scheduler(priv, txq_id);
 
        iwl_clear_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1 << txq_id));
@@ -1098,15 +931,16 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
        iwl_txq_ctx_deactivate(priv, txq_id);
        iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
 
-       iwl_release_nic_access(priv);
-
        return 0;
 }
 
-static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
+u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
 {
        u16 size = (u16)sizeof(struct iwl_addsta_cmd);
-       memcpy(data, cmd, size);
+       struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data;
+       memcpy(addsta, cmd, size);
+       /* resrved in 5000 */
+       addsta->rate_n_flags = cpu_to_le16(0);
        return size;
 }
 
@@ -1115,7 +949,7 @@ static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
  * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
  * must be called under priv->lock and mac access
  */
-static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
+void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
 {
        iwl_write_prph(priv, IWL50_SCD_TXFACT, mask);
 }
@@ -1161,8 +995,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
                info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
                info->status.rates[0].count = tx_resp->failure_frame + 1;
                info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-               info->flags |= iwl_is_tx_success(status) ?
-                                       IEEE80211_TX_STAT_ACK : 0;
+               info->flags |= iwl_tx_status_to_mac80211(status);
                iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
 
                /* FIXME: code repetition end */
@@ -1193,6 +1026,12 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
                                           agg->frame_count, txq_id, idx);
 
                        hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
+                       if (!hdr) {
+                               IWL_ERR(priv,
+                                       "BUG_ON idx doesn't point to valid skb"
+                                       " idx=%d, txq_id=%d\n", idx, txq_id);
+                               return -1;
+                       }
 
                        sc = le16_to_cpu(hdr->seq_ctrl);
                        if (idx != (SEQ_TO_SN(sc) & 0xff)) {
@@ -1241,7 +1080,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
 static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
                                struct iwl_rx_mem_buffer *rxb)
 {
-       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
        u16 sequence = le16_to_cpu(pkt->hdr.sequence);
        int txq_id = SEQ_TO_QUEUE(sequence);
        int index = SEQ_TO_INDEX(sequence);
@@ -1292,18 +1131,16 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
                            (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
                            (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
                                if (agg->state == IWL_AGG_OFF)
-                                       ieee80211_wake_queue(priv->hw, txq_id);
+                                       iwl_wake_queue(priv, txq_id);
                                else
-                                       ieee80211_wake_queue(priv->hw,
-                                                            txq->swq_id);
+                                       iwl_wake_queue(priv, txq->swq_id);
                        }
                }
        } else {
                BUG_ON(txq_id != txq->swq_id);
 
                info->status.rates[0].count = tx_resp->failure_frame + 1;
-               info->flags |= iwl_is_tx_success(status) ?
-                                       IEEE80211_TX_STAT_ACK : 0;
+               info->flags |= iwl_tx_status_to_mac80211(status);
                iwl_hwrate_to_tx_control(priv,
                                        le32_to_cpu(tx_resp->rate_n_flags),
                                        info);
@@ -1321,7 +1158,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
 
                if (priv->mac80211_registered &&
                    (iwl_queue_space(&txq->q) > txq->q.low_mark))
-                       ieee80211_wake_queue(priv->hw, txq_id);
+                       iwl_wake_queue(priv, txq_id);
        }
 
        if (ieee80211_is_data_qos(tx_resp->frame_ctrl))
@@ -1332,18 +1169,18 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
 }
 
 /* Currently 5000 is the superset of everything */
-static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len)
+u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len)
 {
        return len;
 }
 
-static void iwl5000_setup_deferred_work(struct iwl_priv *priv)
+void iwl5000_setup_deferred_work(struct iwl_priv *priv)
 {
        /* in 5000 the tx power calibration is done in uCode */
        priv->disable_tx_power_cal = 1;
 }
 
-static void iwl5000_rx_handler_setup(struct iwl_priv *priv)
+void iwl5000_rx_handler_setup(struct iwl_priv *priv)
 {
        /* init calibration handlers */
        priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
@@ -1354,7 +1191,7 @@ static void iwl5000_rx_handler_setup(struct iwl_priv *priv)
 }
 
 
-static int iwl5000_hw_valid_rtc_data_addr(u32 addr)
+int iwl5000_hw_valid_rtc_data_addr(u32 addr)
 {
        return (addr >= IWL50_RTC_DATA_LOWER_BOUND) &&
                (addr < IWL50_RTC_DATA_UPPER_BOUND);
@@ -1406,27 +1243,63 @@ static int iwl5000_send_rxon_assoc(struct iwl_priv *priv)
 
        return ret;
 }
-static int  iwl5000_send_tx_power(struct iwl_priv *priv)
+int  iwl5000_send_tx_power(struct iwl_priv *priv)
 {
        struct iwl5000_tx_power_dbm_cmd tx_power_cmd;
+       u8 tx_ant_cfg_cmd;
 
        /* half dBm need to multiply */
        tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
+
+       if (priv->tx_power_lmt_in_half_dbm &&
+           priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) {
+               /*
+                * For the newer devices which using enhanced/extend tx power
+                * table in EEPROM, the format is in half dBm. driver need to
+                * convert to dBm format before report to mac80211.
+                * By doing so, there is a possibility of 1/2 dBm resolution
+                * lost. driver will perform "round-up" operation before
+                * reporting, but it will cause 1/2 dBm tx power over the
+                * regulatory limit. Perform the checking here, if the
+                * "tx_power_user_lmt" is higher than EEPROM value (in
+                * half-dBm format), lower the tx power based on EEPROM
+                */
+               tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm;
+       }
        tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED;
        tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO;
-       return  iwl_send_cmd_pdu_async(priv, REPLY_TX_POWER_DBM_CMD,
+
+       if (IWL_UCODE_API(priv->ucode_ver) == 1)
+               tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
+       else
+               tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
+
+       return  iwl_send_cmd_pdu_async(priv, tx_ant_cfg_cmd,
                                       sizeof(tx_power_cmd), &tx_power_cmd,
                                       NULL);
 }
 
-static void iwl5000_temperature(struct iwl_priv *priv)
+void iwl5000_temperature(struct iwl_priv *priv)
 {
        /* store temperature from statistics (in Celsius) */
        priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
+       iwl_tt_handler(priv);
+}
+
+static void iwl5150_temperature(struct iwl_priv *priv)
+{
+       u32 vt = 0;
+       s32 offset =  iwl_temp_calib_to_offset(priv);
+
+       vt = le32_to_cpu(priv->statistics.general.temperature);
+       vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
+       /* now vt hold the temperature in Kelvin */
+       priv->temperature = KELVIN_TO_CELSIUS(vt);
+       iwl_tt_handler(priv);
 }
 
 /* Calc max signal level (dBm) among 3 possible receivers */
-static int iwl5000_calc_rssi(struct iwl_priv *priv,
+int iwl5000_calc_rssi(struct iwl_priv *priv,
                             struct iwl_rx_phy_res *rx_resp)
 {
        /* data from PHY/DSP regarding signal strength, etc.,
@@ -1463,11 +1336,102 @@ static int iwl5000_calc_rssi(struct iwl_priv *priv,
        return max_rssi - agc - IWL49_RSSI_OFFSET;
 }
 
-static struct iwl_hcmd_ops iwl5000_hcmd = {
+static int iwl5000_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
+{
+       struct iwl_tx_ant_config_cmd tx_ant_cmd = {
+         .valid = cpu_to_le32(valid_tx_ant),
+       };
+
+       if (IWL_UCODE_API(priv->ucode_ver) > 1) {
+               IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
+               return iwl_send_cmd_pdu(priv, TX_ANT_CONFIGURATION_CMD,
+                                       sizeof(struct iwl_tx_ant_config_cmd),
+                                       &tx_ant_cmd);
+       } else {
+               IWL_DEBUG_HC(priv, "TX_ANT_CONFIGURATION_CMD not supported\n");
+               return -EOPNOTSUPP;
+       }
+}
+
+
+#define IWL5000_UCODE_GET(item)                                                \
+static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+                                   u32 api_ver)                        \
+{                                                                      \
+       if (api_ver <= 2)                                               \
+               return le32_to_cpu(ucode->u.v1.item);                   \
+       return le32_to_cpu(ucode->u.v2.item);                           \
+}
+
+static u32 iwl5000_ucode_get_header_size(u32 api_ver)
+{
+       if (api_ver <= 2)
+               return UCODE_HEADER_SIZE(1);
+       return UCODE_HEADER_SIZE(2);
+}
+
+static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode,
+                                  u32 api_ver)
+{
+       if (api_ver <= 2)
+               return 0;
+       return le32_to_cpu(ucode->u.v2.build);
+}
+
+static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode,
+                                 u32 api_ver)
+{
+       if (api_ver <= 2)
+               return (u8 *) ucode->u.v1.data;
+       return (u8 *) ucode->u.v2.data;
+}
+
+IWL5000_UCODE_GET(inst_size);
+IWL5000_UCODE_GET(data_size);
+IWL5000_UCODE_GET(init_size);
+IWL5000_UCODE_GET(init_data_size);
+IWL5000_UCODE_GET(boot_size);
+
+static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+{
+       struct iwl5000_channel_switch_cmd cmd;
+       const struct iwl_channel_info *ch_info;
+       struct iwl_host_cmd hcmd = {
+               .id = REPLY_CHANNEL_SWITCH,
+               .len = sizeof(cmd),
+               .flags = CMD_SIZE_HUGE,
+               .data = &cmd,
+       };
+
+       IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
+               priv->active_rxon.channel, channel);
+       cmd.band = priv->band == IEEE80211_BAND_2GHZ;
+       cmd.channel = cpu_to_le16(channel);
+       cmd.rxon_flags = priv->staging_rxon.flags;
+       cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
+       cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+       ch_info = iwl_get_channel_info(priv, priv->band, channel);
+       if (ch_info)
+               cmd.expect_beacon = is_channel_radar(ch_info);
+       else {
+               IWL_ERR(priv, "invalid channel switch from %u to %u\n",
+                       priv->active_rxon.channel, channel);
+               return -EFAULT;
+       }
+       priv->switch_rxon.channel = cpu_to_le16(channel);
+       priv->switch_rxon.switch_in_progress = true;
+
+       return iwl_send_cmd_sync(priv, &hcmd);
+}
+
+struct iwl_hcmd_ops iwl5000_hcmd = {
        .rxon_assoc = iwl5000_send_rxon_assoc,
+       .commit_rxon = iwl_commit_rxon,
+       .set_rxon_chain = iwl_set_rxon_chain,
+       .set_tx_ant = iwl5000_send_tx_ant_config,
 };
 
-static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
+struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
        .get_hcmd_size = iwl5000_get_hcmd_size,
        .build_addsta_hcmd = iwl5000_build_addsta_hcmd,
        .gain_computation = iwl5000_gain_computation,
@@ -1476,7 +1440,18 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
        .calc_rssi = iwl5000_calc_rssi,
 };
 
-static struct iwl_lib_ops iwl5000_lib = {
+struct iwl_ucode_ops iwl5000_ucode = {
+       .get_header_size = iwl5000_ucode_get_header_size,
+       .get_build = iwl5000_ucode_get_build,
+       .get_inst_size = iwl5000_ucode_get_inst_size,
+       .get_data_size = iwl5000_ucode_get_data_size,
+       .get_init_size = iwl5000_ucode_get_init_size,
+       .get_init_data_size = iwl5000_ucode_get_init_data_size,
+       .get_boot_size = iwl5000_ucode_get_boot_size,
+       .get_data = iwl5000_ucode_get_data,
+};
+
+struct iwl_lib_ops iwl5000_lib = {
        .set_hw_params = iwl5000_hw_set_hw_params,
        .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
        .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
@@ -1489,16 +1464,18 @@ static struct iwl_lib_ops iwl5000_lib = {
        .rx_handler_setup = iwl5000_rx_handler_setup,
        .setup_deferred_work = iwl5000_setup_deferred_work,
        .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+       .dump_nic_event_log = iwl_dump_nic_event_log,
+       .dump_nic_error_log = iwl_dump_nic_error_log,
+       .dump_csr = iwl_dump_csr,
        .load_ucode = iwl5000_load_ucode,
        .init_alive_start = iwl5000_init_alive_start,
        .alive_notify = iwl5000_alive_notify,
        .send_tx_power = iwl5000_send_tx_power,
-       .temperature = iwl5000_temperature,
        .update_chain_flags = iwl_update_chain_flags,
+       .set_channel_switch = iwl5000_hw_channel_switch,
        .apm_ops = {
-               .init = iwl5000_apm_init,
-               .reset = iwl5000_apm_reset,
-               .stop = iwl5000_apm_stop,
+               .init = iwl_apm_init,
+               .stop = iwl_apm_stop,
                .config = iwl5000_nic_config,
                .set_pwr_src = iwl_set_pwr_src,
        },
@@ -1509,8 +1486,8 @@ static struct iwl_lib_ops iwl5000_lib = {
                        EEPROM_5000_REG_BAND_3_CHANNELS,
                        EEPROM_5000_REG_BAND_4_CHANNELS,
                        EEPROM_5000_REG_BAND_5_CHANNELS,
-                       EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
-                       EEPROM_5000_REG_BAND_52_FAT_CHANNELS
+                       EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
+                       EEPROM_5000_REG_BAND_52_HT40_CHANNELS
                },
                .verify_signature  = iwlcore_eeprom_verify_signature,
                .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
@@ -1518,17 +1495,85 @@ static struct iwl_lib_ops iwl5000_lib = {
                .calib_version  = iwl5000_eeprom_calib_version,
                .query_addr = iwl5000_eeprom_query_addr,
        },
+       .post_associate = iwl_post_associate,
+       .isr = iwl_isr_ict,
+       .config_ap = iwl_config_ap,
+       .temp_ops = {
+               .temperature = iwl5000_temperature,
+               .set_ct_kill = iwl5000_set_ct_threshold,
+        },
 };
 
-struct iwl_ops iwl5000_ops = {
+static struct iwl_lib_ops iwl5150_lib = {
+       .set_hw_params = iwl5000_hw_set_hw_params,
+       .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
+       .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
+       .txq_set_sched = iwl5000_txq_set_sched,
+       .txq_agg_enable = iwl5000_txq_agg_enable,
+       .txq_agg_disable = iwl5000_txq_agg_disable,
+       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
+       .txq_free_tfd = iwl_hw_txq_free_tfd,
+       .txq_init = iwl_hw_tx_queue_init,
+       .rx_handler_setup = iwl5000_rx_handler_setup,
+       .setup_deferred_work = iwl5000_setup_deferred_work,
+       .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+       .dump_nic_event_log = iwl_dump_nic_event_log,
+       .dump_nic_error_log = iwl_dump_nic_error_log,
+       .dump_csr = iwl_dump_csr,
+       .load_ucode = iwl5000_load_ucode,
+       .init_alive_start = iwl5000_init_alive_start,
+       .alive_notify = iwl5000_alive_notify,
+       .send_tx_power = iwl5000_send_tx_power,
+       .update_chain_flags = iwl_update_chain_flags,
+       .set_channel_switch = iwl5000_hw_channel_switch,
+       .apm_ops = {
+               .init = iwl_apm_init,
+               .stop = iwl_apm_stop,
+               .config = iwl5000_nic_config,
+               .set_pwr_src = iwl_set_pwr_src,
+       },
+       .eeprom_ops = {
+               .regulatory_bands = {
+                       EEPROM_5000_REG_BAND_1_CHANNELS,
+                       EEPROM_5000_REG_BAND_2_CHANNELS,
+                       EEPROM_5000_REG_BAND_3_CHANNELS,
+                       EEPROM_5000_REG_BAND_4_CHANNELS,
+                       EEPROM_5000_REG_BAND_5_CHANNELS,
+                       EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
+                       EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+               },
+               .verify_signature  = iwlcore_eeprom_verify_signature,
+               .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+               .release_semaphore = iwlcore_eeprom_release_semaphore,
+               .calib_version  = iwl5000_eeprom_calib_version,
+               .query_addr = iwl5000_eeprom_query_addr,
+       },
+       .post_associate = iwl_post_associate,
+       .isr = iwl_isr_ict,
+       .config_ap = iwl_config_ap,
+       .temp_ops = {
+               .temperature = iwl5150_temperature,
+               .set_ct_kill = iwl5150_set_ct_threshold,
+        },
+};
+
+static const struct iwl_ops iwl5000_ops = {
+       .ucode = &iwl5000_ucode,
        .lib = &iwl5000_lib,
        .hcmd = &iwl5000_hcmd,
        .utils = &iwl5000_hcmd_utils,
+       .led = &iwlagn_led_ops,
+};
+
+static const struct iwl_ops iwl5150_ops = {
+       .ucode = &iwl5000_ucode,
+       .lib = &iwl5150_lib,
+       .hcmd = &iwl5000_hcmd,
+       .utils = &iwl5000_hcmd_utils,
+       .led = &iwlagn_led_ops,
 };
 
 struct iwl_mod_params iwl50_mod_params = {
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
        .amsdu_size_8K = 1,
        .restart_fw = 1,
        /* the rest are 0 by default */
@@ -1545,24 +1590,42 @@ struct iwl_cfg iwl5300_agn_cfg = {
        .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+       .num_of_queues = IWL50_NUM_QUEUES,
+       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
        .mod_params = &iwl50_mod_params,
        .valid_tx_ant = ANT_ABC,
        .valid_rx_ant = ANT_ABC,
+       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+       .set_l0s = true,
+       .use_bsm = false,
+       .ht_greenfield_support = true,
+       .led_compensation = 51,
+       .use_rts_for_ht = true, /* use rts/cts protection */
+       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 };
 
-struct iwl_cfg iwl5100_bg_cfg = {
-       .name = "5100BG",
+struct iwl_cfg iwl5100_bgn_cfg = {
+       .name = "5100BGN",
        .fw_name_pre = IWL5000_FW_PRE,
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
-       .sku = IWL_SKU_G,
+       .sku = IWL_SKU_G|IWL_SKU_N,
        .ops = &iwl5000_ops,
        .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+       .num_of_queues = IWL50_NUM_QUEUES,
+       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
        .mod_params = &iwl50_mod_params,
        .valid_tx_ant = ANT_B,
        .valid_rx_ant = ANT_AB,
+       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+       .set_l0s = true,
+       .use_bsm = false,
+       .ht_greenfield_support = true,
+       .led_compensation = 51,
+       .use_rts_for_ht = true, /* use rts/cts protection */
+       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 };
 
 struct iwl_cfg iwl5100_abg_cfg = {
@@ -1575,9 +1638,16 @@ struct iwl_cfg iwl5100_abg_cfg = {
        .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+       .num_of_queues = IWL50_NUM_QUEUES,
+       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
        .mod_params = &iwl50_mod_params,
        .valid_tx_ant = ANT_B,
        .valid_rx_ant = ANT_AB,
+       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+       .set_l0s = true,
+       .use_bsm = false,
+       .led_compensation = 51,
+       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 };
 
 struct iwl_cfg iwl5100_agn_cfg = {
@@ -1590,9 +1660,18 @@ struct iwl_cfg iwl5100_agn_cfg = {
        .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+       .num_of_queues = IWL50_NUM_QUEUES,
+       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
        .mod_params = &iwl50_mod_params,
        .valid_tx_ant = ANT_B,
        .valid_rx_ant = ANT_AB,
+       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+       .set_l0s = true,
+       .use_bsm = false,
+       .ht_greenfield_support = true,
+       .led_compensation = 51,
+       .use_rts_for_ht = true, /* use rts/cts protection */
+       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 };
 
 struct iwl_cfg iwl5350_agn_cfg = {
@@ -1605,9 +1684,18 @@ struct iwl_cfg iwl5350_agn_cfg = {
        .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
+       .num_of_queues = IWL50_NUM_QUEUES,
+       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
        .mod_params = &iwl50_mod_params,
        .valid_tx_ant = ANT_ABC,
        .valid_rx_ant = ANT_ABC,
+       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+       .set_l0s = true,
+       .use_bsm = false,
+       .ht_greenfield_support = true,
+       .led_compensation = 51,
+       .use_rts_for_ht = true, /* use rts/cts protection */
+       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 };
 
 struct iwl_cfg iwl5150_agn_cfg = {
@@ -1616,31 +1704,58 @@ struct iwl_cfg iwl5150_agn_cfg = {
        .ucode_api_max = IWL5150_UCODE_API_MAX,
        .ucode_api_min = IWL5150_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
-       .ops = &iwl5000_ops,
+       .ops = &iwl5150_ops,
        .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
+       .num_of_queues = IWL50_NUM_QUEUES,
+       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
+       .mod_params = &iwl50_mod_params,
+       .valid_tx_ant = ANT_A,
+       .valid_rx_ant = ANT_AB,
+       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+       .set_l0s = true,
+       .use_bsm = false,
+       .ht_greenfield_support = true,
+       .led_compensation = 51,
+       .use_rts_for_ht = true, /* use rts/cts protection */
+       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+};
+
+struct iwl_cfg iwl5150_abg_cfg = {
+       .name = "5150ABG",
+       .fw_name_pre = IWL5150_FW_PRE,
+       .ucode_api_max = IWL5150_UCODE_API_MAX,
+       .ucode_api_min = IWL5150_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G,
+       .ops = &iwl5150_ops,
+       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
+       .num_of_queues = IWL50_NUM_QUEUES,
+       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
        .mod_params = &iwl50_mod_params,
        .valid_tx_ant = ANT_A,
        .valid_rx_ant = ANT_AB,
+       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+       .set_l0s = true,
+       .use_bsm = false,
+       .led_compensation = 51,
+       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 };
 
 MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
 
-module_param_named(disable50, iwl50_mod_params.disable, int, 0444);
-MODULE_PARM_DESC(disable50,
-                 "manually disable the 50XX radio (default 0 [radio on])");
-module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
+module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, S_IRUGO);
 MODULE_PARM_DESC(swcrypto50,
                  "using software crypto engine (default 0 [hardware])\n");
-module_param_named(debug50, iwl50_mod_params.debug, uint, 0444);
-MODULE_PARM_DESC(debug50, "50XX debug output mask");
-module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
+module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, S_IRUGO);
 MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
-module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444);
+module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, S_IRUGO);
 MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality");
-module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444);
+module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K,
+                  int, S_IRUGO);
 MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series");
-module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, 0444);
+module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, S_IRUGO);
 MODULE_PARM_DESC(fw_restart50, "restart firmware in case of error");