headers: remove sched.h from interrupt.h
[safe/jmp/linux-2.6] / drivers / net / wireless / iwlwifi / iwl-5000.c
index f8158ed..d6bc0e0 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>
@@ -46,8 +47,8 @@
 #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
@@ -91,7 +92,7 @@ static int iwl5000_apm_stop_master(struct iwl_priv *priv)
 }
 
 
-static int iwl5000_apm_init(struct iwl_priv *priv)
+int iwl5000_apm_init(struct iwl_priv *priv)
 {
        int ret = 0;
 
@@ -124,10 +125,6 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
                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);
 
@@ -137,13 +134,11 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
        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)
+void iwl5000_apm_stop(struct iwl_priv *priv)
 {
        unsigned long flags;
 
@@ -162,15 +157,12 @@ static void iwl5000_apm_stop(struct iwl_priv *priv)
 }
 
 
-static int iwl5000_apm_reset(struct iwl_priv *priv)
+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);
@@ -193,10 +185,6 @@ static int iwl5000_apm_reset(struct iwl_priv *priv)
                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);
 
@@ -205,32 +193,30 @@ static int iwl5000_apm_reset(struct iwl_priv *priv)
        /* 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 and up */
+void iwl5000_nic_config(struct iwl_priv *priv)
 {
        unsigned long flags;
        u16 radio_cfg;
-       u16 link;
+       u16 lctl;
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &link);
+       lctl = iwl_pcie_link_ctl(priv);
 
-       /* 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 */
+       /* HW bug W/A */
+       /* L1-ASPM is enabled by BIOS */
+       if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
+               /* L1-APSM enabled: disable L0S  */
                iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
        else
-               /* L0S enabled L1A disabled */
+               /* L1-ASPM disabled: enable L0S */
                iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
 
        radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
@@ -251,17 +237,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
  */
@@ -301,7 +285,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;
@@ -394,7 +378,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) ||
@@ -406,7 +390,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,
@@ -425,7 +409,29 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
        .nrg_th_ofdm = 95,
 };
 
-static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
+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,
+};
+
+const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
                                           size_t offset)
 {
        u32 address = eeprom_indirect_address(priv, offset);
@@ -433,15 +439,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 = 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)
 {
-       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;
+       /* want Celsius */
+       priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
 }
 
 /*
@@ -485,7 +495,7 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv,
 {
        struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
        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 */
@@ -532,19 +542,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);
@@ -573,8 +573,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;
 }
 
@@ -628,7 +626,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;
 
@@ -655,7 +653,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;
 
@@ -731,22 +729,15 @@ static int iwl5000_send_wimax_coex(struct iwl_priv *priv)
                                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;
@@ -814,7 +805,6 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
        iwl_txq_ctx_activate(priv, 8);
        iwl_txq_ctx_activate(priv, 9);
 
-       iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
 
 
@@ -826,7 +816,7 @@ 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)) {
@@ -856,32 +846,23 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
        }
 
        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)               |
@@ -890,6 +871,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)               |
@@ -899,14 +881,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)
 {
@@ -946,7 +927,7 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
                        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;
@@ -1001,11 +982,10 @@ 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) ||
@@ -1023,11 +1003,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);
@@ -1063,30 +1038,23 @@ 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,
+               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);
                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));
@@ -1100,15 +1068,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;
 }
 
@@ -1117,7 +1086,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);
 }
@@ -1195,6 +1164,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)) {
@@ -1294,10 +1269,9 @@ 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 {
@@ -1323,7 +1297,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))
@@ -1334,18 +1308,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] =
@@ -1356,7 +1330,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);
@@ -1408,27 +1382,47 @@ 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);
        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.,
@@ -1465,11 +1459,51 @@ static int iwl5000_calc_rssi(struct iwl_priv *priv,
        return max_rssi - agc - IWL49_RSSI_OFFSET;
 }
 
-static struct iwl_hcmd_ops iwl5000_hcmd = {
+#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);
+
+struct iwl_hcmd_ops iwl5000_hcmd = {
        .rxon_assoc = iwl5000_send_rxon_assoc,
+       .commit_rxon = iwl_commit_rxon,
+       .set_rxon_chain = iwl_set_rxon_chain,
 };
 
-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,
@@ -1478,7 +1512,70 @@ 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,
+       .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,
+       .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,
+       .apm_ops = {
+               .init = iwl5000_apm_init,
+               .reset = iwl5000_apm_reset,
+               .stop = iwl5000_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 = iwl5000_temperature,
+               .set_ct_kill = iwl5000_set_ct_threshold,
+        },
+};
+
+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,
@@ -1491,11 +1588,12 @@ 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,
        .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,
        .apm_ops = {
                .init = iwl5000_apm_init,
@@ -1511,8 +1609,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,
@@ -1520,14 +1618,29 @@ 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 = iwl5150_temperature,
+               .set_ct_kill = iwl5150_set_ct_threshold,
+        },
 };
 
 struct iwl_ops iwl5000_ops = {
+       .ucode = &iwl5000_ucode,
        .lib = &iwl5000_lib,
        .hcmd = &iwl5000_hcmd,
        .utils = &iwl5000_hcmd_utils,
 };
 
+static struct iwl_ops iwl5150_ops = {
+       .ucode = &iwl5000_ucode,
+       .lib = &iwl5150_lib,
+       .hcmd = &iwl5000_hcmd,
+       .utils = &iwl5000_hcmd_utils,
+};
+
 struct iwl_mod_params iwl50_mod_params = {
        .num_of_queues = IWL50_NUM_QUEUES,
        .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
@@ -1551,6 +1664,7 @@ struct iwl_cfg iwl5300_agn_cfg = {
        .valid_tx_ant = ANT_ABC,
        .valid_rx_ant = ANT_ABC,
        .need_pll_cfg = true,
+       .ht_greenfield_support = true,
 };
 
 struct iwl_cfg iwl5100_bg_cfg = {
@@ -1567,6 +1681,7 @@ struct iwl_cfg iwl5100_bg_cfg = {
        .valid_tx_ant = ANT_B,
        .valid_rx_ant = ANT_AB,
        .need_pll_cfg = true,
+       .ht_greenfield_support = true,
 };
 
 struct iwl_cfg iwl5100_abg_cfg = {
@@ -1583,6 +1698,7 @@ struct iwl_cfg iwl5100_abg_cfg = {
        .valid_tx_ant = ANT_B,
        .valid_rx_ant = ANT_AB,
        .need_pll_cfg = true,
+       .ht_greenfield_support = true,
 };
 
 struct iwl_cfg iwl5100_agn_cfg = {
@@ -1599,6 +1715,7 @@ struct iwl_cfg iwl5100_agn_cfg = {
        .valid_tx_ant = ANT_B,
        .valid_rx_ant = ANT_AB,
        .need_pll_cfg = true,
+       .ht_greenfield_support = true,
 };
 
 struct iwl_cfg iwl5350_agn_cfg = {
@@ -1615,6 +1732,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
        .valid_tx_ant = ANT_ABC,
        .valid_rx_ant = ANT_ABC,
        .need_pll_cfg = true,
+       .ht_greenfield_support = true,
 };
 
 struct iwl_cfg iwl5150_agn_cfg = {
@@ -1623,7 +1741,7 @@ 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,
@@ -1631,19 +1749,15 @@ struct iwl_cfg iwl5150_agn_cfg = {
        .valid_tx_ant = ANT_A,
        .valid_rx_ant = ANT_AB,
        .need_pll_cfg = true,
+       .ht_greenfield_support = true,
 };
 
 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_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_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
 module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444);