diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-01-03 15:16:34 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-01-03 15:16:34 -0500 |
commit | 57adc1fcbae2c13104ce291b40f23e40a414fa87 (patch) | |
tree | a22d95cd3a96cbd515cd24fb0833739576c5e92f /drivers/net/wireless/iwlwifi | |
parent | faa85aa24286a9e14ae7cc797352350c3ac39986 (diff) | |
parent | dc0d633e35643662f27a0b1c531da3cd6b204b9c (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts:
drivers/net/wireless/b43/dma.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
38 files changed, 1052 insertions, 917 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 8d3bad7ea5d..1ef7bfc2ab2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -124,10 +124,10 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) { if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) - priv->cfg->base_params->num_of_queues = + cfg(priv)->base_params->num_of_queues = iwlagn_mod_params.num_of_queues; - hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues; + hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; @@ -135,14 +135,14 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ); - hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); - if (priv->cfg->rx_with_siso_diversity) + hw_params(priv).tx_chains_num = num_of_ant(cfg(priv)->valid_tx_ant); + if (cfg(priv)->rx_with_siso_diversity) hw_params(priv).rx_chains_num = 1; else hw_params(priv).rx_chains_num = - num_of_ant(priv->cfg->valid_rx_ant); - hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant; - hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant; + num_of_ant(cfg(priv)->valid_rx_ant); + hw_params(priv).valid_tx_ant = cfg(priv)->valid_tx_ant; + hw_params(priv).valid_rx_ant = cfg(priv)->valid_rx_ant; iwl1000_set_ct_threshold(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 0c4688d95b6..094693328db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -86,7 +86,7 @@ static void iwl2000_nic_config(struct iwl_priv *priv) { iwl_rf_config(priv); - if (priv->cfg->iq_invert) + if (cfg(priv)->iq_invert) iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); } @@ -120,10 +120,10 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) { if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) - priv->cfg->base_params->num_of_queues = + cfg(priv)->base_params->num_of_queues = iwlagn_mod_params.num_of_queues; - hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues; + hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE; @@ -131,14 +131,14 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ); - hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); - if (priv->cfg->rx_with_siso_diversity) + hw_params(priv).tx_chains_num = num_of_ant(cfg(priv)->valid_tx_ant); + if (cfg(priv)->rx_with_siso_diversity) hw_params(priv).rx_chains_num = 1; else hw_params(priv).rx_chains_num = - num_of_ant(priv->cfg->valid_rx_ant); - hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant; - hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant; + num_of_ant(cfg(priv)->valid_rx_ant); + hw_params(priv).valid_tx_ant = cfg(priv)->valid_tx_ant; + hw_params(priv).valid_rx_ant = cfg(priv)->valid_rx_ant; iwl2000_set_ct_threshold(priv); @@ -254,13 +254,13 @@ static struct iwl_bt_params iwl2030_bt_params = { .iq_invert = true \ struct iwl_cfg iwl2000_2bgn_cfg = { - .name = "2000 Series 2x2 BGN", + .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN", IWL_DEVICE_2000, .ht_params = &iwl2000_ht_params, }; struct iwl_cfg iwl2000_2bgn_d_cfg = { - .name = "2000D Series 2x2 BGN", + .name = "Intel(R) Centrino(R) Wireless-N 2200D BGN", IWL_DEVICE_2000, .ht_params = &iwl2000_ht_params, }; @@ -282,7 +282,7 @@ struct iwl_cfg iwl2000_2bgn_d_cfg = { .iq_invert = true \ struct iwl_cfg iwl2030_2bgn_cfg = { - .name = "2000 Series 2x2 BGN/BT", + .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN", IWL_DEVICE_2030, .ht_params = &iwl2000_ht_params, }; @@ -304,13 +304,13 @@ struct iwl_cfg iwl2030_2bgn_cfg = { .iq_invert = true \ struct iwl_cfg iwl105_bgn_cfg = { - .name = "105 Series 1x1 BGN", + .name = "Intel(R) Centrino(R) Wireless-N 105 BGN", IWL_DEVICE_105, .ht_params = &iwl2000_ht_params, }; struct iwl_cfg iwl105_bgn_d_cfg = { - .name = "105D Series 1x1 BGN", + .name = "Intel(R) Centrino(R) Wireless-N 105D BGN", IWL_DEVICE_105, .ht_params = &iwl2000_ht_params, }; @@ -333,7 +333,7 @@ struct iwl_cfg iwl105_bgn_d_cfg = { .iq_invert = true \ struct iwl_cfg iwl135_bgn_cfg = { - .name = "135 Series 1x1 BGN/BT", + .name = "Intel(R) Centrino(R) Wireless-N 135 BGN", IWL_DEVICE_135, .ht_params = &iwl2000_ht_params, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 6706d7c10bd..b3a365fea7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -166,10 +166,10 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) { if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) - priv->cfg->base_params->num_of_queues = + cfg(priv)->base_params->num_of_queues = iwlagn_mod_params.num_of_queues; - hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues; + hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; @@ -178,10 +178,10 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); - hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); - hw_params(priv).rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); - hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant; - hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant; + hw_params(priv).tx_chains_num = num_of_ant(cfg(priv)->valid_tx_ant); + hw_params(priv).rx_chains_num = num_of_ant(cfg(priv)->valid_rx_ant); + hw_params(priv).valid_tx_ant = cfg(priv)->valid_tx_ant; + hw_params(priv).valid_rx_ant = cfg(priv)->valid_rx_ant; iwl5000_set_ct_threshold(priv); @@ -195,10 +195,10 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) { if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) - priv->cfg->base_params->num_of_queues = + cfg(priv)->base_params->num_of_queues = iwlagn_mod_params.num_of_queues; - hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues; + hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; @@ -207,10 +207,10 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); - hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); - hw_params(priv).rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); - hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant; - hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant; + hw_params(priv).tx_chains_num = num_of_ant(cfg(priv)->valid_tx_ant); + hw_params(priv).rx_chains_num = num_of_ant(cfg(priv)->valid_rx_ant); + hw_params(priv).valid_tx_ant = cfg(priv)->valid_tx_ant; + hw_params(priv).valid_rx_ant = cfg(priv)->valid_rx_ant; iwl5150_set_ct_threshold(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 3e277b6774f..54b753399e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -102,14 +102,14 @@ static void iwl6000_nic_config(struct iwl_priv *priv) iwl_rf_config(priv); /* no locking required for register write */ - if (priv->cfg->pa_type == IWL_PA_INTERNAL) { + if (cfg(priv)->pa_type == IWL_PA_INTERNAL) { /* 2x2 IPA phy type */ iwl_write32(bus(priv), CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); } /* do additional nic configuration if needed */ - if (priv->cfg->additional_nic_config) - priv->cfg->additional_nic_config(priv); + if (cfg(priv)->additional_nic_config) + cfg(priv)->additional_nic_config(priv); } static struct iwl_sensitivity_ranges iwl6000_sensitivity = { @@ -141,10 +141,10 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) { if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) - priv->cfg->base_params->num_of_queues = + cfg(priv)->base_params->num_of_queues = iwlagn_mod_params.num_of_queues; - hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues; + hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE; @@ -153,14 +153,14 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); - hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); - if (priv->cfg->rx_with_siso_diversity) + hw_params(priv).tx_chains_num = num_of_ant(cfg(priv)->valid_tx_ant); + if (cfg(priv)->rx_with_siso_diversity) hw_params(priv).rx_chains_num = 1; else hw_params(priv).rx_chains_num = - num_of_ant(priv->cfg->valid_rx_ant); - hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant; - hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant; + num_of_ant(cfg(priv)->valid_rx_ant); + hw_params(priv).valid_tx_ant = cfg(priv)->valid_tx_ant; + hw_params(priv).valid_rx_ant = cfg(priv)->valid_rx_ant; iwl6000_set_ct_threshold(priv); @@ -423,7 +423,7 @@ struct iwl_cfg iwl6030_2bg_cfg = { }; struct iwl_cfg iwl6035_2agn_cfg = { - .name = "6035 Series 2x2 AGN/BT", + .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN", IWL_DEVICE_6030, .ht_params = &iwl6000_ht_params, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 16971a02029..50ff849c9f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -513,7 +513,7 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv) iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]); - if (priv->cfg->base_params->hd_v2) { + if (cfg(priv)->base_params->hd_v2) { cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] = HD_INA_NON_SQUARE_DET_OFDM_DATA_V2; cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] = @@ -847,7 +847,7 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig, * connect the first valid tx chain */ first_chain = - find_first_chain(priv->cfg->valid_tx_ant); + find_first_chain(cfg(priv)->valid_tx_ant); data->disconn_array[first_chain] = 0; active_chains |= BIT(first_chain); IWL_DEBUG_CALIB(priv, @@ -890,7 +890,7 @@ static void iwlagn_gain_computation(struct iwl_priv *priv, continue; } - delta_g = (priv->cfg->base_params->chain_noise_scale * + delta_g = (cfg(priv)->base_params->chain_noise_scale * ((s32)average_noise[default_chain] - (s32)average_noise[i])) / 1500; @@ -1047,8 +1047,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv) return; /* Analyze signal for disconnected antenna */ - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) { + if (cfg(priv)->bt_params && + cfg(priv)->bt_params->advanced_bt_coexist) { /* Disable disconnected antenna algorithm for advanced bt coex, assuming valid antennas are connected */ data->active_chains = hw_params(priv).valid_rx_ant; @@ -1082,7 +1082,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv) iwlagn_gain_computation(priv, average_noise, min_average_noise_antenna_i, min_average_noise, - find_first_chain(priv->cfg->valid_rx_ant)); + find_first_chain(cfg(priv)->valid_rx_ant)); /* Some power changes may have been made during the calibration. * Update and commit the RXON diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 057f9523356..64cf439035c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -32,6 +32,7 @@ #include <linux/init.h> #include <linux/sched.h> +#include "iwl-wifi.h" #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" @@ -150,7 +151,7 @@ static u32 eeprom_indirect_address(const struct iwl_shared *shrd, u32 address) const u8 *iwl_eeprom_query_addr(const struct iwl_shared *shrd, size_t offset) { u32 address = eeprom_indirect_address(shrd, offset); - BUG_ON(address >= shrd->priv->cfg->base_params->eeprom_size); + BUG_ON(address >= shrd->cfg->base_params->eeprom_size); return &shrd->eeprom[address]; } @@ -232,7 +233,7 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control) IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK | IWL_PAN_SCD_MULTICAST_MSK; - if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE) + if (cfg(priv)->sku & EEPROM_SKU_CAP_11N_ENABLE) flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK; IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n", @@ -374,15 +375,15 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) != sizeof(basic.bt3_lookup_table)); - if (priv->cfg->bt_params) { - if (priv->cfg->bt_params->bt_session_2) { + if (cfg(priv)->bt_params) { + if (cfg(priv)->bt_params->bt_session_2) { bt_cmd_2000.prio_boost = cpu_to_le32( - priv->cfg->bt_params->bt_prio_boost); + cfg(priv)->bt_params->bt_prio_boost); bt_cmd_2000.tx_prio_boost = 0; bt_cmd_2000.rx_prio_boost = 0; } else { bt_cmd_6000.prio_boost = - priv->cfg->bt_params->bt_prio_boost; + cfg(priv)->bt_params->bt_prio_boost; bt_cmd_6000.tx_prio_boost = 0; bt_cmd_6000.rx_prio_boost = 0; } @@ -430,7 +431,7 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) priv->bt_full_concurrent ? "full concurrency" : "3-wire"); - if (priv->cfg->bt_params->bt_session_2) { + if (cfg(priv)->bt_params->bt_session_2) { memcpy(&bt_cmd_2000.basic, &basic, sizeof(basic)); ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_BT_CONFIG, @@ -799,8 +800,8 @@ static bool is_single_rx_stream(struct iwl_priv *priv) */ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) { - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist && + if (cfg(priv)->bt_params && + cfg(priv)->bt_params->advanced_bt_coexist && (priv->bt_full_concurrent || priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { /* @@ -871,8 +872,8 @@ void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx) else active_chains = hw_params(priv).valid_rx_ant; - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist && + if (cfg(priv)->bt_params && + cfg(priv)->bt_params->advanced_bt_coexist && (priv->bt_full_concurrent || priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { /* @@ -1158,7 +1159,7 @@ int iwlagn_suspend(struct iwl_priv *priv, * since the uCode will add 0x10 before using the value. */ for (i = 0; i < IWL_MAX_TID_COUNT; i++) { - seq = priv->shrd->tid_data[IWL_AP_ID][i].seq_number; + seq = priv->tid_data[IWL_AP_ID][i].seq_number; seq -= 0x10; wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq); } @@ -1195,7 +1196,7 @@ int iwlagn_suspend(struct iwl_priv *priv, priv->shrd->wowlan = true; - ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN); + ret = iwl_load_ucode_wait_alive(trans(priv), IWL_UCODE_WOWLAN); if (ret) goto out; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index a23835a7797..334b5ae8fdd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1086,7 +1086,7 @@ done: (priv->tm_fixed_rate != lq_sta->dbg_fixed_rate)) rs_program_fix_rate(priv, lq_sta); #endif - if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) + if (cfg(priv)->bt_params && cfg(priv)->bt_params->advanced_bt_coexist) rs_bt_update_lq(priv, ctx, lq_sta); } @@ -2273,7 +2273,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, tid = rs_tl_add_packet(lq_sta, hdr); if ((tid != IWL_MAX_TID_COUNT) && (lq_sta->tx_agg_tid_en & (1 << tid))) { - tid_data = &priv->shrd->tid_data[lq_sta->lq.sta_id][tid]; + tid_data = &priv->tid_data[lq_sta->lq.sta_id][tid]; if (tid_data->agg.state == IWL_AGG_OFF) lq_sta->is_agg = 0; else @@ -2645,8 +2645,7 @@ lq_update: (lq_sta->tx_agg_tid_en & (1 << tid)) && (tid != IWL_MAX_TID_COUNT)) { u8 sta_id = lq_sta->lq.sta_id; - tid_data = - &priv->shrd->tid_data[sta_id][tid]; + tid_data = &priv->tid_data[sta_id][tid]; if (tid_data->agg.state == IWL_AGG_OFF) { IWL_DEBUG_RATE(priv, "try to aggregate tid %d\n", @@ -3055,11 +3054,11 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, * overwrite if needed, pass aggregation time limit * to uCode in uSec */ - if (priv && priv->cfg->bt_params && - priv->cfg->bt_params->agg_time_limit && + if (priv && cfg(priv)->bt_params && + cfg(priv)->bt_params->agg_time_limit && priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) lq_cmd->agg_params.agg_time_limit = - cpu_to_le16(priv->cfg->bt_params->agg_time_limit); + cpu_to_le16(cfg(priv)->bt_params->agg_time_limit); } static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index 9001c23f27b..b22b2976f89 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c @@ -318,7 +318,7 @@ static bool iwlagn_good_plcp_health(struct iwl_priv *priv, unsigned int msecs) { int delta; - int threshold = priv->cfg->base_params->plcp_delta_threshold; + int threshold = cfg(priv)->base_params->plcp_delta_threshold; if (threshold == IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) { IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n"); @@ -583,8 +583,8 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv, iwlagn_rx_calc_noise(priv); queue_work(priv->shrd->workqueue, &priv->run_time_calib_work); } - if (priv->cfg->lib->temperature && change) - priv->cfg->lib->temperature(priv); + if (cfg(priv)->lib->temperature && change) + cfg(priv)->lib->temperature(priv); return 0; } @@ -1136,8 +1136,8 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) init_waitqueue_head(&priv->shrd->notif_waitq); /* Set up BT Rx handlers */ - if (priv->cfg->lib->bt_rx_handler_setup) - priv->cfg->lib->bt_rx_handler_setup(priv); + if (cfg(priv)->lib->bt_rx_handler_setup) + cfg(priv)->lib->bt_rx_handler_setup(priv); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index d21f535a3b4..1c665941662 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -296,9 +296,9 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv, } if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION && - priv->cfg->ht_params && priv->cfg->ht_params->smps_mode) + cfg(priv)->ht_params && cfg(priv)->ht_params->smps_mode) ieee80211_request_smps(ctx->vif, - priv->cfg->ht_params->smps_mode); + cfg(priv)->ht_params->smps_mode); return 0; } @@ -445,8 +445,8 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) * force CTS-to-self frames protection if RTS-CTS is not preferred * one aggregation protection method */ - if (!(priv->cfg->ht_params && - priv->cfg->ht_params->use_rts_for_aggregation)) + if (!(cfg(priv)->ht_params && + cfg(priv)->ht_params->use_rts_for_aggregation)) ctx->staging.flags |= RXON_FLG_SELF_CTS_EN; if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) || diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index 63d948d21c0..7353826095f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -130,25 +130,15 @@ int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, return iwl_process_add_sta_resp(priv, addsta, pkt); } -static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) -{ - u16 size = (u16)sizeof(struct iwl_addsta_cmd); - struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data; - memcpy(addsta, cmd, size); - /* resrved in agn */ - addsta->legacy_reserved = cpu_to_le16(0); - return size; -} - int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags) { int ret = 0; - u8 data[sizeof(*sta)]; struct iwl_host_cmd cmd = { .id = REPLY_ADD_STA, .flags = flags, - .data = { data, }, + .data = { sta, }, + .len = { sizeof(*sta), }, }; u8 sta_id __maybe_unused = sta->sta.sta_id; @@ -160,7 +150,6 @@ int iwl_send_add_sta(struct iwl_priv *priv, might_sleep(); } - cmd.len[0] = iwlagn_build_addsta_hcmd(sta, data); ret = iwl_trans_send_cmd(trans(priv), &cmd); if (ret || (flags & CMD_ASYNC)) @@ -463,6 +452,7 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, const u8 *addr) { unsigned long flags; + u8 tid; if (!iwl_is_ready(priv->shrd)) { IWL_DEBUG_INFO(priv, @@ -501,6 +491,10 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, priv->stations[sta_id].lq = NULL; } + for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) + memset(&priv->tid_data[sta_id][tid], 0, + sizeof(priv->tid_data[sta_id][tid])); + priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; priv->num_stations--; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c index c27180a7335..b0dff7a753a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c @@ -633,7 +633,7 @@ void iwl_tt_initialize(struct iwl_priv *priv) INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit); - if (priv->cfg->base_params->adv_thermal_throttle) { + if (cfg(priv)->base_params->adv_thermal_throttle) { IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n"); tt->restriction = kcalloc(IWL_TI_STATE_MAX, sizeof(struct iwl_tt_restriction), diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 81754cddba7..c664c272655 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -74,8 +74,8 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, else if (ieee80211_is_back_req(fc)) tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK; else if (info->band == IEEE80211_BAND_2GHZ && - priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist && + cfg(priv)->bt_params && + cfg(priv)->bt_params->advanced_bt_coexist && (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc) || skb->protocol == cpu_to_be16(ETH_P_PAE))) @@ -191,8 +191,8 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, rate_flags |= RATE_MCS_CCK_MSK; /* Set up antennas */ - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist && + if (cfg(priv)->bt_params && + cfg(priv)->bt_params->advanced_bt_coexist && priv->bt_full_concurrent) { /* operated as 1x1 in full concurrency mode */ priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, @@ -262,8 +262,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) __le16 fc; u8 hdr_len; - u16 len; - u8 sta_id; + u16 len, seq_number = 0; + u8 sta_id, tid = IWL_MAX_TID_COUNT; unsigned long flags; bool is_agg = false; @@ -368,9 +368,51 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) info->driver_data[0] = ctx; info->driver_data[1] = dev_cmd; - if (iwl_trans_tx(trans(priv), skb, dev_cmd, ctx->ctxid, sta_id)) + if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { + u8 *qc = NULL; + struct iwl_tid_data *tid_data; + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) + goto drop_unlock_sta; + tid_data = &priv->tid_data[sta_id][tid]; + + /* aggregation is on for this <sta,tid> */ + if (info->flags & IEEE80211_TX_CTL_AMPDU && + tid_data->agg.state != IWL_AGG_ON) { + IWL_ERR(priv, "TX_CTL_AMPDU while not in AGG:" + " Tx flags = 0x%08x, agg.state = %d", + info->flags, tid_data->agg.state); + IWL_ERR(priv, "sta_id = %d, tid = %d seq_num = %d", + sta_id, tid, SEQ_TO_SN(tid_data->seq_number)); + goto drop_unlock_sta; + } + + /* We can receive packets from the stack in IWL_AGG_{ON,OFF} + * only. Check this here. + */ + if (WARN_ONCE(tid_data->agg.state != IWL_AGG_ON && + tid_data->agg.state != IWL_AGG_OFF, + "Tx while agg.state = %d", tid_data->agg.state)) + goto drop_unlock_sta; + + seq_number = tid_data->seq_number; + seq_number &= IEEE80211_SCTL_SEQ; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(seq_number); + seq_number += 0x10; + } + + /* Copy MAC header from skb into command buffer */ + memcpy(tx_cmd->hdr, hdr, hdr_len); + + if (iwl_trans_tx(trans(priv), skb, dev_cmd, ctx->ctxid, sta_id, tid)) goto drop_unlock_sta; + if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc) && + !ieee80211_has_morefrags(fc)) + priv->tid_data[sta_id][tid].seq_number = seq_number; + spin_unlock(&priv->shrd->sta_lock); spin_unlock_irqrestore(&priv->shrd->lock, flags); @@ -395,10 +437,81 @@ drop_unlock_priv: return -1; } +int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 tid) +{ + struct iwl_tid_data *tid_data; + unsigned long flags; + int sta_id; + + sta_id = iwl_sta_id(sta); + + if (sta_id == IWL_INVALID_STATION) { + IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); + return -ENXIO; + } + + spin_lock_irqsave(&priv->shrd->sta_lock, flags); + + tid_data = &priv->tid_data[sta_id][tid]; + + switch (priv->tid_data[sta_id][tid].agg.state) { + case IWL_EMPTYING_HW_QUEUE_ADDBA: + /* + * This can happen if the peer stops aggregation + * again before we've had a chance to drain the + * queue we selected previously, i.e. before the + * session was really started completely. + */ + IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); + goto turn_off; + case IWL_AGG_ON: + break; + default: + IWL_WARN(priv, "Stopping AGG while state not ON " + "or starting for %d on %d (%d)\n", sta_id, tid, + priv->tid_data[sta_id][tid].agg.state); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + return 0; + } + + tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number); + + /* There are still packets for this RA / TID in the HW */ + if (tid_data->agg.ssn != tid_data->next_reclaimed) { + IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, " + "next_recl = %d", + tid_data->agg.ssn, + tid_data->next_reclaimed); + priv->tid_data[sta_id][tid].agg.state = + IWL_EMPTYING_HW_QUEUE_DELBA; + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + return 0; + } + + IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d", + tid_data->agg.ssn); +turn_off: + priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF; + + /* do not restore/save irqs */ + spin_unlock(&priv->shrd->sta_lock); + spin_lock(&priv->shrd->lock); + + iwl_trans_tx_agg_disable(trans(priv), sta_id, tid); + + spin_unlock_irqrestore(&priv->shrd->lock, flags); + + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + + return 0; +} + int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { - struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; + struct iwl_tid_data *tid_data; + unsigned long flags; int sta_id; int ret; @@ -413,7 +526,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, if (unlikely(tid >= IWL_MAX_TID_COUNT)) return -EINVAL; - if (priv->shrd->tid_data[sta_id][tid].agg.state != IWL_AGG_OFF) { + if (priv->tid_data[sta_id][tid].agg.state != IWL_AGG_OFF) { IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n"); return -ENXIO; } @@ -422,27 +535,136 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, if (ret) return ret; - ret = iwl_trans_tx_agg_alloc(trans(priv), vif_priv->ctx->ctxid, sta_id, - tid, ssn); + spin_lock_irqsave(&priv->shrd->sta_lock, flags); + + tid_data = &priv->tid_data[sta_id][tid]; + tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number); + + *ssn = tid_data->agg.ssn; + + ret = iwl_trans_tx_agg_alloc(trans(priv), sta_id, tid); + if (ret) { + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + return ret; + } + + if (*ssn == tid_data->next_reclaimed) { + IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d", + tid_data->agg.ssn); + tid_data->agg.state = IWL_AGG_ON; + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + } else { + IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, " + "next_reclaimed = %d", + tid_data->agg.ssn, + tid_data->next_reclaimed); + tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; + } + + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); return ret; } -int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u16 tid) +int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 tid, u8 buf_size) { - int sta_id; - struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; + struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; + struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + unsigned long flags; + u16 ssn; - sta_id = iwl_sta_id(sta); + buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); - if (sta_id == IWL_INVALID_STATION) { - IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); - return -ENXIO; + spin_lock_irqsave(&priv->shrd->sta_lock, flags); + ssn = priv->tid_data[sta_priv->sta_id][tid].agg.ssn; + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + + iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, sta_priv->sta_id, tid, + buf_size, ssn); + + /* + * If the limit is 0, then it wasn't initialised yet, + * use the default. We can do that since we take the + * minimum below, and we don't want to go above our + * default due to hardware restrictions. + */ + if (sta_priv->max_agg_bufsize == 0) + sta_priv->max_agg_bufsize = + LINK_QUAL_AGG_FRAME_LIMIT_DEF; + + /* + * Even though in theory the peer could have different + * aggregation reorder buffer sizes for different sessions, + * our ucode doesn't allow for that and has a global limit + * for each station. Therefore, use the minimum of all the + * aggregation sessions and our default value. + */ + sta_priv->max_agg_bufsize = + min(sta_priv->max_agg_bufsize, buf_size); + + if (cfg(priv)->ht_params && + cfg(priv)->ht_params->use_rts_for_aggregation) { + /* + * switch to RTS/CTS if it is the prefer protection + * method for HT traffic + */ + + sta_priv->lq_sta.lq.general_params.flags |= + LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK; } + priv->agg_tids_count++; + IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n", + priv->agg_tids_count); - return iwl_trans_tx_agg_disable(trans(priv), vif_priv->ctx->ctxid, - sta_id, tid); + sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit = + sta_priv->max_agg_bufsize; + + IWL_INFO(priv, "Tx aggregation enabled on ra = %pM tid = %d\n", + sta->addr, tid); + + return iwl_send_lq_cmd(priv, ctx, + &sta_priv->lq_sta.lq, CMD_ASYNC, false); +} + +static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid) +{ + struct iwl_tid_data *tid_data = &priv->tid_data[sta_id][tid]; + enum iwl_rxon_context_id ctx; + struct ieee80211_vif *vif; + u8 *addr; + + lockdep_assert_held(&priv->shrd->sta_lock); + + addr = priv->stations[sta_id].sta.sta.addr; + ctx = priv->stations[sta_id].ctxid; + vif = priv->contexts[ctx].vif; + + switch (priv->tid_data[sta_id][tid].agg.state) { + case IWL_EMPTYING_HW_QUEUE_DELBA: + /* There are no packets for this RA / TID in the HW any more */ + if (tid_data->agg.ssn == tid_data->next_reclaimed) { + IWL_DEBUG_TX_QUEUES(priv, + "Can continue DELBA flow ssn = next_recl =" + " %d", tid_data->next_reclaimed); + iwl_trans_tx_agg_disable(trans(priv), sta_id, tid); + tid_data->agg.state = IWL_AGG_OFF; + ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); + } + break; + case IWL_EMPTYING_HW_QUEUE_ADDBA: + /* There are no packets for this RA / TID in the HW any more */ + if (tid_data->agg.ssn == tid_data->next_reclaimed) { + IWL_DEBUG_TX_QUEUES(priv, + "Can continue ADDBA flow ssn = next_recl =" + " %d", tid_data->next_reclaimed); + tid_data->agg.state = IWL_AGG_ON; + ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); + } + break; + default: + break; + } } static void iwlagn_non_agg_tx_status(struct iwl_priv *priv, @@ -582,7 +804,7 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv, IWLAGN_TX_RES_TID_POS; int sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> IWLAGN_TX_RES_RA_POS; - struct iwl_ht_agg *agg = &priv->shrd->tid_data[sta_id][tid].agg; + struct iwl_ht_agg *agg = &priv->tid_data[sta_id][tid].agg; u32 status = le16_to_cpu(tx_resp->status.status); int i; @@ -598,8 +820,8 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv, * notification again. */ if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 && - priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) { + cfg(priv)->bt_params && + cfg(priv)->bt_params->advanced_bt_coexist) { IWL_DEBUG_COEX(priv, "receive reply tx w/ bt_kill\n"); } @@ -772,7 +994,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; struct ieee80211_hdr *hdr; u32 status = le16_to_cpu(tx_resp->status.status); - u32 ssn = iwlagn_get_scd_ssn(tx_resp); + u16 ssn = iwlagn_get_scd_ssn(tx_resp); int tid; int sta_id; int freed; @@ -794,11 +1016,34 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, iwl_rx_reply_tx_agg(priv, tx_resp); if (tx_resp->frame_count == 1) { - IWL_DEBUG_TX_REPLY(priv, "Q %d, ssn %d", txq_id, ssn); + u16 next_reclaimed = le16_to_cpu(tx_resp->seq_ctl); + next_reclaimed = SEQ_TO_SN(next_reclaimed + 0x10); + + if (is_agg) { + /* If this is an aggregation queue, we can rely on the + * ssn since the wifi sequence number corresponds to + * the index in the TFD ring (%256). + * The seq_ctl is the sequence control of the packet + * to which this Tx response relates. But if there is a + * hole in the bitmap of the BA we received, this Tx + * response may allow to reclaim the hole and all the + * subsequent packets that were already acked. + * In that case, seq_ctl != ssn, and the next packet + * to be reclaimed will be ssn and not seq_ctl. + */ + next_reclaimed = ssn; + } + __skb_queue_head_init(&skbs); + priv->tid_data[sta_id][tid].next_reclaimed = next_reclaimed; + + IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d", + next_reclaimed); + /*we can free until ssn % q.n_bd not inclusive */ - iwl_trans_reclaim(trans(priv), sta_id, tid, txq_id, - ssn, status, &skbs); + WARN_ON(iwl_trans_reclaim(trans(priv), sta_id, tid, txq_id, + ssn, status, &skbs)); + iwlagn_check_ratid_empty(priv, sta_id, tid); freed = 0; while (!skb_queue_empty(&skbs)) { skb = __skb_dequeue(&skbs); @@ -893,27 +1138,24 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, sta_id = ba_resp->sta_id; tid = ba_resp->tid; - agg = &priv->shrd->tid_data[sta_id][tid].agg; + agg = &priv->tid_data[sta_id][tid].agg; spin_lock_irqsave(&priv->shrd->sta_lock, flags); - if (unlikely(agg->txq_id != scd_flow)) { - /* - * FIXME: this is a uCode bug which need to be addressed, - * log the information and return for now! - * since it is possible happen very often and in order - * not to fill the syslog, don't enable the logging by default - */ - IWL_DEBUG_TX_REPLY(priv, - "BA scd_flow %d does not match txq_id %d\n", - scd_flow, agg->txq_id); + if (unlikely(!agg->wait_for_ba)) { + if (unlikely(ba_resp->bitmap)) + IWL_ERR(priv, "Received BA when not expected\n"); spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); return 0; } - if (unlikely(!agg->wait_for_ba)) { - if (unlikely(ba_resp->bitmap)) - IWL_ERR(priv, "Received BA when not expected\n"); + __skb_queue_head_init(&reclaimed_skbs); + + /* Release all TFDs before the SSN, i.e. all TFDs in front of + * block-ack window (we assume that they've been successfully + * transmitted ... if not, it's too late anyway). */ + if (iwl_trans_reclaim(trans(priv), sta_id, tid, scd_flow, + ba_resp_scd_ssn, 0, &reclaimed_skbs)) { spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); return 0; } @@ -925,7 +1167,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, ba_resp->sta_id); IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, " "scd_flow = %d, scd_ssn = %d\n", - ba_resp->tid, ba_resp->seq_ctl, + ba_resp->tid, le16_to_cpu(ba_resp->seq_ctl), (unsigned long long)le64_to_cpu(ba_resp->bitmap), scd_flow, ba_resp_scd_ssn); @@ -946,13 +1188,9 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", ba_resp->txed, ba_resp->txed_2_done); - __skb_queue_head_init(&reclaimed_skbs); + priv->tid_data[sta_id][tid].next_reclaimed = ba_resp_scd_ssn; - /* Release all TFDs before the SSN, i.e. all TFDs in front of - * block-ack window (we assume that they've been successfully - * transmitted ... if not, it's too late anyway). */ - iwl_trans_reclaim(trans(priv), sta_id, tid, scd_flow, ba_resp_scd_ssn, - 0, &reclaimed_skbs); + iwlagn_check_ratid_empty(priv, sta_id, tid); freed = 0; while (!skb_queue_empty(&reclaimed_skbs)) { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f5fe42dbb3b..b5c7c5f0a75 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -43,6 +43,7 @@ #include <asm/div64.h> #include "iwl-eeprom.h" +#include "iwl-wifi.h" #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" @@ -515,7 +516,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) { - const char *name_pre = priv->cfg->fw_name_pre; + const char *name_pre = cfg(priv)->fw_name_pre; char tag[8]; if (first) { @@ -524,14 +525,14 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) strcpy(tag, UCODE_EXPERIMENTAL_TAG); } else if (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) { #endif - priv->fw_index = priv->cfg->ucode_api_max; + priv->fw_index = cfg(priv)->ucode_api_max; sprintf(tag, "%d", priv->fw_index); } else { priv->fw_index--; sprintf(tag, "%d", priv->fw_index); } - if (priv->fw_index < priv->cfg->ucode_api_min) { + if (priv->fw_index < cfg(priv)->ucode_api_min) { IWL_ERR(priv, "no suitable firmware found!\n"); return -ENOENT; } @@ -836,9 +837,9 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) struct iwl_ucode_header *ucode; int err; struct iwlagn_firmware_pieces pieces; - const unsigned int api_max = priv->cfg->ucode_api_max; - unsigned int api_ok = priv->cfg->ucode_api_ok; - const unsigned int api_min = priv->cfg->ucode_api_min; + const unsigned int api_max = cfg(priv)->ucode_api_max; + unsigned int api_ok = cfg(priv)->ucode_api_ok; + const unsigned int api_min = cfg(priv)->ucode_api_min; u32 api_ver; char buildstr[25]; u32 build; @@ -1027,14 +1028,14 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; else priv->init_evtlog_size = - priv->cfg->base_params->max_event_log_size; + cfg(priv)->base_params->max_event_log_size; priv->init_errlog_ptr = pieces.init_errlog_ptr; priv->inst_evtlog_ptr = pieces.inst_evtlog_ptr; if (pieces.inst_evtlog_size) priv->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; else priv->inst_evtlog_size = - priv->cfg->base_params->max_event_log_size; + cfg(priv)->base_params->max_event_log_size; priv->inst_errlog_ptr = pieces.inst_errlog_ptr; #ifndef CONFIG_IWLWIFI_P2P ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; @@ -1043,7 +1044,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->new_scan_threshold_behaviour = !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); - if (!(priv->cfg->sku & EEPROM_SKU_CAP_IPAN_ENABLE)) + if (!(cfg(priv)->sku & EEPROM_SKU_CAP_IPAN_ENABLE)) ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; /* @@ -1124,7 +1125,7 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->shrd->lock, flags); priv->thermal_throttle.ct_kill_toggle = false; - if (priv->cfg->base_params->support_ct_kill_exit) { + if (cfg(priv)->base_params->support_ct_kill_exit) { adv_cmd.critical_temperature_enter = cpu_to_le32(hw_params(priv).ct_kill_threshold); adv_cmd.critical_temperature_exit = @@ -1219,10 +1220,10 @@ int iwl_alive_start(struct iwl_priv *priv) return -ERFKILL; /* download priority table before any calibration request */ - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) { + if (cfg(priv)->bt_params && + cfg(priv)->bt_params->advanced_bt_coexist) { /* Configure Bluetooth device coexistence support */ - if (priv->cfg->bt_params->bt_sco_disable) + if (cfg(priv)->bt_params->bt_sco_disable) priv->bt_enable_pspoll = false; else priv->bt_enable_pspoll = true; @@ -1252,16 +1253,17 @@ int iwl_alive_start(struct iwl_priv *priv) iwl_send_bt_config(priv); } - if (hw_params(priv).calib_rt_cfg) - iwlagn_send_calib_cfg_rt(priv, - hw_params(priv).calib_rt_cfg); + /* + * Perform runtime calibrations, including DC calibration. + */ + iwlagn_send_calib_cfg_rt(priv, IWL_CALIB_CFG_DC_IDX); 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, priv->cfg->valid_tx_ant); + iwlagn_send_tx_ant_config(priv, cfg(priv)->valid_tx_ant); if (iwl_is_associated_ctx(ctx) && !priv->shrd->wowlan) { struct iwl_rxon_cmd *active_rxon = @@ -1330,9 +1332,9 @@ void __iwl_down(struct iwl_priv *priv) priv->bt_status = 0; priv->cur_rssi_ctx = NULL; priv->bt_is_sco = 0; - if (priv->cfg->bt_params) + if (cfg(priv)->bt_params) priv->bt_traffic_load = - priv->cfg->bt_params->bt_init_traffic_load; + cfg(priv)->bt_params->bt_init_traffic_load; else priv->bt_traffic_load = 0; priv->bt_full_concurrent = false; @@ -1514,8 +1516,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) iwl_setup_scan_deferred_work(priv); - if (priv->cfg->lib->bt_setup_deferred_work) - priv->cfg->lib->bt_setup_deferred_work(priv); + if (cfg(priv)->lib->bt_setup_deferred_work) + cfg(priv)->lib->bt_setup_deferred_work(priv); init_timer(&priv->statistics_periodic); priv->statistics_periodic.data = (unsigned long)priv; @@ -1532,8 +1534,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) static void iwl_cancel_deferred_work(struct iwl_priv *priv) { - if (priv->cfg->lib->cancel_deferred_work) - priv->cfg->lib->cancel_deferred_work(priv); + if (cfg(priv)->lib->cancel_deferred_work) + cfg(priv)->lib->cancel_deferred_work(priv); cancel_work_sync(&priv->run_time_calib_work); cancel_work_sync(&priv->beacon_update); @@ -1602,8 +1604,8 @@ static int iwl_init_drv(struct iwl_priv *priv) iwl_init_scan_params(priv); /* init bt coex */ - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) { + if (cfg(priv)->bt_params && + cfg(priv)->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; @@ -1667,18 +1669,18 @@ static int iwl_set_hw_params(struct iwl_priv *priv) hw_params(priv).rx_page_order = get_order(IWL_RX_BUF_SIZE_4K); - if (iwlagn_mod_params.disable_11n) - priv->cfg->sku &= ~EEPROM_SKU_CAP_11N_ENABLE; + if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_ALL) + cfg(priv)->sku &= ~EEPROM_SKU_CAP_11N_ENABLE; hw_params(priv).num_ampdu_queues = - priv->cfg->base_params->num_of_ampdu_queues; + cfg(priv)->base_params->num_of_ampdu_queues; hw_params(priv).shadow_reg_enable = - priv->cfg->base_params->shadow_reg_enable; - hw_params(priv).sku = priv->cfg->sku; - hw_params(priv).wd_timeout = priv->cfg->base_params->wd_timeout; + cfg(priv)->base_params->shadow_reg_enable; + hw_params(priv).sku = cfg(priv)->sku; + hw_params(priv).wd_timeout = cfg(priv)->base_params->wd_timeout; /* Device-specific setup */ - return priv->cfg->lib->set_hw_params(priv); + return cfg(priv)->lib->set_hw_params(priv); } @@ -1757,7 +1759,7 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, iwl_debug_config(priv); IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); - priv->cfg = cfg; + cfg(priv) = cfg; /* is antenna coupling more than 35dB ? */ priv->bt_ant_couple_ok = @@ -1791,7 +1793,7 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, ***********************/ hw_rev = iwl_hw_detect(priv); IWL_INFO(priv, "Detected %s, REV=0x%X\n", - priv->cfg->name, hw_rev); + cfg(priv)->name, hw_rev); err = iwl_trans_request_irq(trans(priv)); if (err) @@ -1915,12 +1917,7 @@ void __devexit iwl_remove(struct iwl_priv * priv) set_bit(STATUS_EXIT_PENDING, &priv->shrd->status); iwl_testmode_cleanup(priv); - iwl_leds_exit(priv); - - if (priv->mac80211_registered) { - ieee80211_unregister_hw(priv->hw); - priv->mac80211_registered = 0; - } + iwlagn_mac_unregister(priv); iwl_tt_exit(priv); @@ -1999,8 +1996,9 @@ 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(queues_num, iwlagn_mod_params.num_of_queues, int, S_IRUGO); MODULE_PARM_DESC(queues_num, "number of hw queues."); -module_param_named(11n_disable, iwlagn_mod_params.disable_11n, int, S_IRUGO); -MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); +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"); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index eb453ea41c4..f84fb3c5356 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -91,6 +91,7 @@ void iwlagn_prepare_restart(struct iwl_priv *priv); struct ieee80211_hw *iwl_alloc_all(void); int iwlagn_mac_setup_register(struct iwl_priv *priv, struct iwlagn_ucode_capabilities *capa); +void iwlagn_mac_unregister(struct iwl_priv *priv); /* RXON */ int iwlagn_set_pan_params(struct iwl_priv *priv); @@ -108,11 +109,6 @@ void iwlagn_config_ht40(struct ieee80211_conf *conf, int iwlagn_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, struct iwl_device_cmd *cmd); -int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type); -void iwl_send_prio_tbl(struct iwl_trans *trans); -int iwlagn_run_init_ucode(struct iwl_priv *priv); -int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, - enum iwl_ucode_type ucode_type); /* lib */ int iwlagn_send_tx_power(struct iwl_priv *priv); @@ -137,6 +133,8 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv); int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn); +int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 tid, u8 buf_size); int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid); int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, @@ -356,7 +354,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv); void iwl_eeprom_get_mac(const struct iwl_shared *shrd, u8 *mac); -extern int iwlagn_init_alive_start(struct iwl_priv *priv); extern int iwl_alive_start(struct iwl_priv *priv); /* svtool */ #ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE diff --git a/drivers/net/wireless/iwlwifi/iwl-bus.h b/drivers/net/wireless/iwlwifi/iwl-bus.h index 08b97594e30..940d5038b39 100644 --- a/drivers/net/wireless/iwlwifi/iwl-bus.h +++ b/drivers/net/wireless/iwlwifi/iwl-bus.h @@ -122,7 +122,8 @@ struct iwl_bus; * struct iwl_bus_ops - bus specific operations * @get_pm_support: must returns true if the bus can go to sleep * @apm_config: will be called during the config of the APM - * @get_hw_id: prints the hw_id in the provided buffer + * @get_hw_id_string: prints the hw_id in the provided buffer + * @get_hw_id: get hw_id in u32 * @write8: write a byte to register at offset ofs * @write32: write a dword to register at offset ofs * @wread32: read a dword at register at offset ofs @@ -130,7 +131,8 @@ struct iwl_bus; struct iwl_bus_ops { bool (*get_pm_support)(struct iwl_bus *bus); void (*apm_config)(struct iwl_bus *bus); - void (*get_hw_id)(struct iwl_bus *bus, char buf[], int buf_len); + void (*get_hw_id_string)(struct iwl_bus *bus, char buf[], int buf_len); + u32 (*get_hw_id)(struct iwl_bus *bus); void (*write8)(struct iwl_bus *bus, u32 ofs, u8 val); void (*write32)(struct iwl_bus *bus, u32 ofs, u32 val); u32 (*read32)(struct iwl_bus *bus, u32 ofs); @@ -172,9 +174,15 @@ static inline void bus_apm_config(struct iwl_bus *bus) bus->ops->apm_config(bus); } -static inline void bus_get_hw_id(struct iwl_bus *bus, char buf[], int buf_len) +static inline void bus_get_hw_id_string(struct iwl_bus *bus, char buf[], + int buf_len) { - bus->ops->get_hw_id(bus, buf, buf_len); + bus->ops->get_hw_id_string(bus, buf, buf_len); +} + +static inline u32 bus_get_hw_id(struct iwl_bus *bus) +{ + return bus->ops->get_hw_id(bus); } static inline void bus_write8(struct iwl_bus *bus, u32 ofs, u8 val) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 3b6f48bfe0e..7bcfa781e0b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -60,8 +60,8 @@ static void iwl_init_ht_hw_capab(const struct iwl_priv *priv, ht_info->ht_supported = true; - if (priv->cfg->ht_params && - priv->cfg->ht_params->ht_greenfield_support) + if (cfg(priv)->ht_params && + cfg(priv)->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; @@ -76,11 +76,7 @@ static void iwl_init_ht_hw_capab(const struct iwl_priv *priv, ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; - if (priv->cfg->bt_params && priv->cfg->bt_params->ampdu_factor) - ht_info->ampdu_factor = priv->cfg->bt_params->ampdu_factor; ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; - if (priv->cfg->bt_params && priv->cfg->bt_params->ampdu_density) - ht_info->ampdu_density = priv->cfg->bt_params->ampdu_density; ht_info->mcs.rx_mask[0] = 0xFF; if (rx_chains_num >= 2) @@ -141,7 +137,7 @@ int iwl_init_geos(struct iwl_priv *priv) sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE; - if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE) + if (cfg(priv)->sku & EEPROM_SKU_CAP_11N_ENABLE) iwl_init_ht_hw_capab(priv, &sband->ht_cap, IEEE80211_BAND_5GHZ); @@ -151,7 +147,7 @@ int iwl_init_geos(struct iwl_priv *priv) sband->bitrates = rates; sband->n_bitrates = IWL_RATE_COUNT_LEGACY; - if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE) + if (cfg(priv)->sku & EEPROM_SKU_CAP_11N_ENABLE) iwl_init_ht_hw_capab(priv, &sband->ht_cap, IEEE80211_BAND_2GHZ); @@ -206,12 +202,12 @@ int iwl_init_geos(struct iwl_priv *priv) priv->tx_power_next = max_tx_power; if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && - priv->cfg->sku & EEPROM_SKU_CAP_BAND_52GHZ) { + cfg(priv)->sku & EEPROM_SKU_CAP_BAND_52GHZ) { char buf[32]; - bus_get_hw_id(bus(priv), buf, sizeof(buf)); + bus_get_hw_id_string(bus(priv), buf, sizeof(buf)); IWL_INFO(priv, "Incorrectly detected BG card as ABG. " "Please send your %s to maintainer.\n", buf); - priv->cfg->sku &= ~EEPROM_SKU_CAP_BAND_52GHZ; + cfg(priv)->sku &= ~EEPROM_SKU_CAP_BAND_52GHZ; } IWL_INFO(priv, "Tunable channels: %d 802.11bg, %d 802.11a channels\n", @@ -966,9 +962,9 @@ int iwl_apm_init(struct iwl_priv *priv) bus_apm_config(bus(priv)); /* Configure analog phase-lock-loop before activating to D0A */ - if (priv->cfg->base_params->pll_cfg_val) + if (cfg(priv)->base_params->pll_cfg_val) iwl_set_bit(bus(priv), CSR_ANA_PLL_CFG, - priv->cfg->base_params->pll_cfg_val); + cfg(priv)->base_params->pll_cfg_val); /* * Set "initialization complete" bit to move adapter from @@ -1465,7 +1461,7 @@ void iwl_bg_watchdog(unsigned long data) if (iwl_is_rfkill(priv->shrd)) return; - timeout = priv->cfg->base_params->wd_timeout; + timeout = cfg(priv)->base_params->wd_timeout; if (timeout == 0) return; @@ -1490,11 +1486,11 @@ void iwl_bg_watchdog(unsigned long data) void iwl_setup_watchdog(struct iwl_priv *priv) { - unsigned int timeout = priv->cfg->base_params->wd_timeout; + unsigned int timeout = cfg(priv)->base_params->wd_timeout; if (!iwlagn_mod_params.wd_disable) { /* use system default */ - if (timeout && !priv->cfg->base_params->wd_disable) + if (timeout && !cfg(priv)->base_params->wd_disable) mod_timer(&priv->watchdog, jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout))); @@ -1584,34 +1580,6 @@ __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, return cpu_to_le32(res); } -void iwl_start_tx_ba_trans_ready(struct iwl_priv *priv, - enum iwl_rxon_context_id ctx, - u8 sta_id, u8 tid) -{ - struct ieee80211_vif *vif; - u8 *addr = priv->stations[sta_id].sta.sta.addr; - - if (ctx == NUM_IWL_RXON_CTX) - ctx = priv->stations[sta_id].ctxid; - vif = priv->contexts[ctx].vif; - - ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); -} - -void iwl_stop_tx_ba_trans_ready(struct iwl_priv *priv, - enum iwl_rxon_context_id ctx, - u8 sta_id, u8 tid) -{ - struct ieee80211_vif *vif; - u8 *addr = priv->stations[sta_id].sta.sta.addr; - - if (ctx == NUM_IWL_RXON_CTX) - ctx = priv->stations[sta_id].ctxid; - vif = priv->contexts[ctx].vif; - - ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); -} - void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state) { wiphy_rfkill_set_hw_state(priv->hw->wiphy, state); @@ -1619,8 +1587,7 @@ void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state) void iwl_nic_config(struct iwl_priv *priv) { - priv->cfg->lib->nic_config(priv); - + cfg(priv)->lib->nic_config(priv); } void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 6da53a36c1b..7bf76ab94dd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -142,8 +142,6 @@ struct iwl_base_params { * @bt_init_traffic_load: specify initial bt traffic load * @bt_prio_boost: default bt priority boost value * @agg_time_limit: maximum number of uSec in aggregation - * @ampdu_factor: Maximum A-MPDU length factor - * @ampdu_density: Minimum A-MPDU spacing * @bt_sco_disable: uCode should not response to BT in SCO/ESCO mode */ struct iwl_bt_params { @@ -151,8 +149,6 @@ struct iwl_bt_params { u8 bt_init_traffic_load; u8 bt_prio_boost; u16 agg_time_limit; - u8 ampdu_factor; - u8 ampdu_density; bool bt_sco_disable; bool bt_session_2; }; @@ -165,77 +161,6 @@ struct iwl_ht_params { enum ieee80211_smps_mode smps_mode; }; -/** - * struct iwl_cfg - * @name: Offical name of the device - * @fw_name_pre: Firmware filename prefix. The api version and extension - * (.ucode) will be added to filename before loading from disk. The - * filename is constructed as fw_name_pre<api>.ucode. - * @ucode_api_max: Highest version of uCode API supported by driver. - * @ucode_api_ok: oldest version of the uCode API that is OK to load - * without a warning, for use in transitions - * @ucode_api_min: Lowest version of uCode API supported by driver. - * @valid_tx_ant: valid transmit antenna - * @valid_rx_ant: valid receive antenna - * @sku: sku information from EEPROM - * @eeprom_ver: EEPROM version - * @eeprom_calib_ver: EEPROM calibration version - * @lib: pointer to the lib ops - * @additional_nic_config: additional nic configuration - * @base_params: pointer to basic parameters - * @ht_params: point to ht patameters - * @bt_params: pointer to bt parameters - * @pa_type: used by 6000 series only to identify the type of Power Amplifier - * @need_temp_offset_calib: need to perform temperature offset calibration - * @no_xtal_calib: some devices do not need crystal calibration data, - * don't send it to those - * @scan_antennas: available antenna for scan operation - * @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off) - * @adv_pm: advance power management - * @rx_with_siso_diversity: 1x1 device with rx antenna diversity - * @internal_wimax_coex: internal wifi/wimax combo device - * @iq_invert: I/Q inversion - * @temp_offset_v2: support v2 of temperature offset calibration - * - * We enable the driver to be backward compatible wrt API version. The - * driver specifies which APIs it supports (with @ucode_api_max being the - * highest and @ucode_api_min the lowest). Firmware will only be loaded if - * it has a supported API version. - * - * The ideal usage of this infrastructure is to treat a new ucode API - * release as a new hardware revision. - */ -struct iwl_cfg { - /* params specific to an individual device within a device family */ - const char *name; - const char *fw_name_pre; - const unsigned int ucode_api_max; - const unsigned int ucode_api_ok; - const unsigned int ucode_api_min; - u8 valid_tx_ant; - u8 valid_rx_ant; - u16 sku; - u16 eeprom_ver; - u16 eeprom_calib_ver; - const struct iwl_lib_ops *lib; - void (*additional_nic_config)(struct iwl_priv *priv); - /* params not likely to change within a device family */ - struct iwl_base_params *base_params; - /* params likely to change within a device family */ - struct iwl_ht_params *ht_params; - struct iwl_bt_params *bt_params; - enum iwl_pa_type pa_type; /* if used set to IWL_PA_SYSTEM */ - const bool need_temp_offset_calib; /* if used set to true */ - const bool no_xtal_calib; - u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; - enum iwl_led_mode led_mode; - const bool adv_pm; - const bool rx_with_siso_diversity; - const bool internal_wimax_coex; - const bool iq_invert; - const bool temp_offset_v2; -}; - /*************************** * L i b * ***************************/ @@ -368,8 +293,8 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode( static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) { - return priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist; + return cfg(priv)->bt_params && + cfg(priv)->bt_params->advanced_bt_coexist; } static inline void iwl_enable_rfkill_int(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 6bf6845e1a5..04a3343f461 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -372,15 +372,13 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, i, station->sta.sta.addr, station->sta.station_flags_msk); pos += scnprintf(buf + pos, bufsz - pos, - "TID\tseq_num\ttxq_id\ttfds\trate_n_flags\n"); + "TID\tseq_num\trate_n_flags\n"); for (j = 0; j < IWL_MAX_TID_COUNT; j++) { - tid_data = &priv->shrd->tid_data[i][j]; + tid_data = &priv->tid_data[i][j]; pos += scnprintf(buf + pos, bufsz - pos, - "%d:\t%#x\t%#x\t%u\t%#x", + "%d:\t%#x\t%#x", j, tid_data->seq_number, - tid_data->agg.txq_id, - tid_data->tfds_in_queue, tid_data->agg.rate_n_flags); if (tid_data->agg.wait_for_ba) @@ -408,7 +406,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, const u8 *ptr; char *buf; u16 eeprom_ver; - size_t eeprom_len = priv->cfg->base_params->eeprom_size; + size_t eeprom_len = cfg(priv)->base_params->eeprom_size; buf_size = 4 * eeprom_len + 256; if (eeprom_len % 16) { @@ -1542,15 +1540,15 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) { pos += scnprintf(buf + pos, bufsz - pos, "tx power: (1/2 dB step)\n"); - if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a) + if ((cfg(priv)->valid_tx_ant & ANT_A) && tx->tx_power.ant_a) pos += scnprintf(buf + pos, bufsz - pos, fmt_hex, "antenna A:", tx->tx_power.ant_a); - if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b) + if ((cfg(priv)->valid_tx_ant & ANT_B) && tx->tx_power.ant_b) pos += scnprintf(buf + pos, bufsz - pos, fmt_hex, "antenna B:", tx->tx_power.ant_b); - if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c) + if ((cfg(priv)->valid_tx_ant & ANT_C) && tx->tx_power.ant_c) pos += scnprintf(buf + pos, bufsz - pos, fmt_hex, "antenna C:", tx->tx_power.ant_c); @@ -2221,7 +2219,7 @@ static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file, const size_t bufsz = sizeof(buf); pos += scnprintf(buf + pos, bufsz - pos, "%u\n", - priv->cfg->base_params->plcp_delta_threshold); + cfg(priv)->base_params->plcp_delta_threshold); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -2243,10 +2241,10 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file, return -EINVAL; if ((plcp < IWL_MAX_PLCP_ERR_THRESHOLD_MIN) || (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX)) - priv->cfg->base_params->plcp_delta_threshold = + cfg(priv)->base_params->plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE; else - priv->cfg->base_params->plcp_delta_threshold = plcp; + cfg(priv)->base_params->plcp_delta_threshold = plcp; return count; } @@ -2348,7 +2346,7 @@ static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file, if (timeout < 0 || timeout > IWL_MAX_WD_TIMEOUT) timeout = IWL_DEF_WD_TIMEOUT; - priv->cfg->base_params->wd_timeout = timeout; + cfg(priv)->base_params->wd_timeout = timeout; iwl_setup_watchdog(priv); return count; } @@ -2408,10 +2406,10 @@ static ssize_t iwl_dbgfs_protection_mode_read(struct file *file, char buf[40]; const size_t bufsz = sizeof(buf); - if (priv->cfg->ht_params) + if (cfg(priv)->ht_params) pos += scnprintf(buf + pos, bufsz - pos, "use %s for aggregation\n", - (priv->cfg->ht_params->use_rts_for_aggregation) ? + (cfg(priv)->ht_params->use_rts_for_aggregation) ? "rts/cts" : "cts-to-self"); else pos += scnprintf(buf + pos, bufsz - pos, "N/A"); @@ -2428,7 +2426,7 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file, int buf_size; int rts; - if (!priv->cfg->ht_params) + if (!cfg(priv)->ht_params) return -EINVAL; memset(buf, 0, sizeof(buf)); @@ -2438,9 +2436,9 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file, if (sscanf(buf, "%d", &rts) != 1) return -EINVAL; if (rts) - priv->cfg->ht_params->use_rts_for_aggregation = true; + cfg(priv)->ht_params->use_rts_for_aggregation = true; else - priv->cfg->ht_params->use_rts_for_aggregation = false; + cfg(priv)->ht_params->use_rts_for_aggregation = false; return count; } diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 69ecf6e2e65..e54a4d11e58 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -189,6 +189,69 @@ struct iwl_qos_info { struct iwl_qosparam_cmd def_qos_parm; }; +/** + * enum iwl_agg_state + * + * The state machine of the BA agreement establishment / tear down. + * These states relate to a specific RA / TID. + * + * @IWL_AGG_OFF: aggregation is not used + * @IWL_AGG_ON: aggregation session is up + * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the + * HW queue to be empty from packets for this RA /TID. + * @IWL_EMPTYING_HW_QUEUE_DELBA: tearing down a BA session - waiting for the + * HW queue to be empty from packets for this RA /TID. + */ +enum iwl_agg_state { + IWL_AGG_OFF = 0, + IWL_AGG_ON, + IWL_EMPTYING_HW_QUEUE_ADDBA, + IWL_EMPTYING_HW_QUEUE_DELBA, +}; + +/** + * struct iwl_ht_agg - aggregation state machine + + * This structs holds the states for the BA agreement establishment and tear + * down. It also holds the state during the BA session itself. This struct is + * duplicated for each RA / TID. + + * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the + * Tx response (REPLY_TX), and the block ack notification + * (REPLY_COMPRESSED_BA). + * @state: state of the BA agreement establishment / tear down. + * @txq_id: Tx queue used by the BA session - used by the transport layer. + * Needed by the upper layer for debugfs only. + * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or + * the first packet to be sent in legacy HW queue in Tx AGG stop flow. + * Basically when next_reclaimed reaches ssn, we can tell mac80211 that + * we are ready to finish the Tx AGG stop / start flow. + * @wait_for_ba: Expect block-ack before next Tx reply + */ +struct iwl_ht_agg { + u32 rate_n_flags; + enum iwl_agg_state state; + u16 txq_id; + u16 ssn; + bool wait_for_ba; +}; + +/** + * struct iwl_tid_data - one for each RA / TID + + * This structs holds the states for each RA / TID. + + * @seq_number: the next WiFi sequence number to use + * @next_reclaimed: the WiFi sequence number of the next packet to be acked. + * This is basically (last acked packet++). + * @agg: aggregation state machine + */ +struct iwl_tid_data { + u16 seq_number; + u16 next_reclaimed; + struct iwl_ht_agg agg; +}; + /* * Structure should be accessed with sta_lock held. When station addition * is in progress (IWL_STA_UCODE_INPROGRESS) it is possible to access only @@ -512,16 +575,6 @@ enum iwl_access_mode { IWL_OTP_ACCESS_RELATIVE, }; -/** - * enum iwl_pa_type - Power Amplifier type - * @IWL_PA_SYSTEM: based on uCode configuration - * @IWL_PA_INTERNAL: use Internal only - */ -enum iwl_pa_type { - IWL_PA_SYSTEM = 0, - IWL_PA_INTERNAL = 1, -}; - /* reply_tx_statistics (for _agn devices) */ struct reply_tx_error_statistics { u32 pp_delay; @@ -776,7 +829,6 @@ struct iwl_priv { struct ieee80211_channel *ieee_channels; struct ieee80211_rate *ieee_rates; struct kmem_cache *tx_cmd_pool; - struct iwl_cfg *cfg; enum ieee80211_band band; @@ -880,6 +932,7 @@ struct iwl_priv { int num_stations; struct iwl_station_entry stations[IWLAGN_STATION_COUNT]; unsigned long ucode_key_table; + struct iwl_tid_data tid_data[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT]; u8 mac80211_registered; diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index f9d3319ecad..9b212a8f30b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -90,6 +90,35 @@ TRACE_EVENT(iwlwifi_dev_iowrite32, TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val) ); +TRACE_EVENT(iwlwifi_dev_irq, + TP_PROTO(void *priv), + TP_ARGS(priv), + TP_STRUCT__entry( + PRIV_ENTRY + ), + TP_fast_assign( + PRIV_ASSIGN; + ), + /* TP_printk("") doesn't compile */ + TP_printk("%d", 0) +); + +TRACE_EVENT(iwlwifi_dev_ict_read, + TP_PROTO(void *priv, u32 index, u32 value), + TP_ARGS(priv, index, value), + TP_STRUCT__entry( + PRIV_ENTRY + __field(u32, index) + __field(u32, value) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->index = index; + __entry->value = value; + ), + TP_printk("read ict[%d] = %#.8x", __entry->index, __entry->value) +); + #undef TRACE_SYSTEM #define TRACE_SYSTEM iwlwifi_ucode diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 6fcc7d586b2..c1eda9724f4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -230,8 +230,8 @@ int iwl_eeprom_check_version(struct iwl_priv *priv) eeprom_ver = iwl_eeprom_query16(priv->shrd, EEPROM_VERSION); calib_ver = iwl_eeprom_calib_version(priv->shrd); - if (eeprom_ver < priv->cfg->eeprom_ver || - calib_ver < priv->cfg->eeprom_calib_ver) + if (eeprom_ver < cfg(priv)->eeprom_ver || + calib_ver < cfg(priv)->eeprom_calib_ver) goto err; IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n", @@ -241,8 +241,8 @@ int iwl_eeprom_check_version(struct iwl_priv *priv) err: IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x " "CALIB=0x%x < 0x%x\n", - eeprom_ver, priv->cfg->eeprom_ver, - calib_ver, priv->cfg->eeprom_calib_ver); + eeprom_ver, cfg(priv)->eeprom_ver, + calib_ver, cfg(priv)->eeprom_calib_ver); return -EINVAL; } @@ -252,35 +252,35 @@ int iwl_eeprom_check_sku(struct iwl_priv *priv) struct iwl_shared *shrd = priv->shrd; u16 radio_cfg; - if (!priv->cfg->sku) { + if (!cfg(priv)->sku) { /* not using sku overwrite */ - priv->cfg->sku = iwl_eeprom_query16(shrd, EEPROM_SKU_CAP); - if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE && - !priv->cfg->ht_params) { + cfg(priv)->sku = iwl_eeprom_query16(shrd, EEPROM_SKU_CAP); + if (cfg(priv)->sku & EEPROM_SKU_CAP_11N_ENABLE && + !cfg(priv)->ht_params) { IWL_ERR(priv, "Invalid 11n configuration\n"); return -EINVAL; } } - if (!priv->cfg->sku) { + if (!cfg(priv)->sku) { IWL_ERR(priv, "Invalid device sku\n"); return -EINVAL; } - IWL_INFO(priv, "Device SKU: 0X%x\n", priv->cfg->sku); + IWL_INFO(priv, "Device SKU: 0x%X\n", cfg(priv)->sku); - if (!priv->cfg->valid_tx_ant && !priv->cfg->valid_rx_ant) { + if (!cfg(priv)->valid_tx_ant && !cfg(priv)->valid_rx_ant) { /* not using .cfg overwrite */ radio_cfg = iwl_eeprom_query16(shrd, EEPROM_RADIO_CONFIG); - priv->cfg->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg); - priv->cfg->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg); - if (!priv->cfg->valid_tx_ant || !priv->cfg->valid_rx_ant) { - IWL_ERR(priv, "Invalid chain (0X%x, 0X%x)\n", - priv->cfg->valid_tx_ant, - priv->cfg->valid_rx_ant); + cfg(priv)->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg); + cfg(priv)->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg); + if (!cfg(priv)->valid_tx_ant || !cfg(priv)->valid_rx_ant) { + IWL_ERR(priv, "Invalid chain (0x%X, 0x%X)\n", + cfg(priv)->valid_tx_ant, + cfg(priv)->valid_rx_ant); return -EINVAL; } - IWL_INFO(priv, "Valid Tx ant: 0X%x, Valid Rx ant: 0X%x\n", - priv->cfg->valid_tx_ant, priv->cfg->valid_rx_ant); + IWL_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n", + cfg(priv)->valid_tx_ant, cfg(priv)->valid_rx_ant); } /* * for some special cases, @@ -369,7 +369,7 @@ static int iwl_init_otp_access(struct iwl_bus *bus) * CSR auto clock gate disable bit - * this is only applicable for HW with OTP shadow RAM */ - if (priv(bus)->cfg->base_params->shadow_ram_support) + if (cfg(bus)->base_params->shadow_ram_support) iwl_set_bit(bus, CSR_DBG_LINK_PWR_MGMT_REG, CSR_RESET_LINK_PWR_MGMT_DISABLED); } @@ -489,7 +489,7 @@ static int iwl_find_otp_image(struct iwl_bus *bus, } /* more in the link list, continue */ usedblocks++; - } while (usedblocks <= priv(bus)->cfg->base_params->max_ll_items); + } while (usedblocks <= cfg(bus)->base_params->max_ll_items); /* OTP has no valid blocks */ IWL_DEBUG_EEPROM(bus, "OTP has no valid blocks\n"); @@ -629,7 +629,7 @@ void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv) ((txp->delta_20_in_40 & 0xf0) >> 4), (txp->delta_20_in_40 & 0x0f)); - max_txp_avg = iwl_get_max_txpower_avg(priv->cfg, txp_array, idx, + max_txp_avg = iwl_get_max_txpower_avg(cfg(priv), txp_array, idx, &max_txp_avg_halfdbm); /* @@ -667,7 +667,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) if (trans(priv)->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ - sz = priv->cfg->base_params->eeprom_size; + sz = cfg(priv)->base_params->eeprom_size; IWL_DEBUG_EEPROM(priv, "NVM size = %d\n", sz); shrd->eeprom = kzalloc(sz, GFP_KERNEL); if (!shrd->eeprom) { @@ -709,7 +709,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); /* traversing the linked list if no shadow ram supported */ - if (!priv->cfg->base_params->shadow_ram_support) { + if (!cfg(priv)->base_params->shadow_ram_support) { if (iwl_find_otp_image(bus(priv), &validblockaddr)) { ret = -ENOENT; goto done; @@ -776,7 +776,7 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, const u8 **eeprom_ch_index) { struct iwl_shared *shrd = priv->shrd; - u32 offset = priv->cfg->lib-> + u32 offset = cfg(priv)->lib-> eeprom_ops.regulatory_bands[eep_band - 1]; switch (eep_band) { case 1: /* 2.4GHz band */ @@ -983,9 +983,9 @@ int iwl_init_channel_map(struct iwl_priv *priv) } /* Check if we do have HT40 channels */ - if (priv->cfg->lib->eeprom_ops.regulatory_bands[5] == + if (cfg(priv)->lib->eeprom_ops.regulatory_bands[5] == EEPROM_REGULATORY_BAND_NO_HT40 && - priv->cfg->lib->eeprom_ops.regulatory_bands[6] == + cfg(priv)->lib->eeprom_ops.regulatory_bands[6] == EEPROM_REGULATORY_BAND_NO_HT40) return 0; @@ -1021,8 +1021,8 @@ int iwl_init_channel_map(struct iwl_priv *priv) * driver need to process addition information * to determine the max channel tx power limits */ - if (priv->cfg->lib->eeprom_ops.update_enhanced_txpower) - priv->cfg->lib->eeprom_ops.update_enhanced_txpower(priv); + if (cfg(priv)->lib->eeprom_ops.update_enhanced_txpower) + cfg(priv)->lib->eeprom_ops.update_enhanced_txpower(priv); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 3464cad7e38..d57ea6484bb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -283,16 +283,29 @@ u32 iwl_read_targ_mem(struct iwl_bus *bus, u32 addr) return value; } -void iwl_write_targ_mem(struct iwl_bus *bus, u32 addr, u32 val) +int _iwl_write_targ_mem_words(struct iwl_bus *bus, u32 addr, + void *buf, int words) { unsigned long flags; + int offs, result = 0; + u32 *vals = buf; spin_lock_irqsave(&bus->reg_lock, flags); if (!iwl_grab_nic_access(bus)) { iwl_write32(bus, HBUS_TARG_MEM_WADDR, addr); wmb(); - iwl_write32(bus, HBUS_TARG_MEM_WDAT, val); + + for (offs = 0; offs < words; offs++) + iwl_write32(bus, HBUS_TARG_MEM_WDAT, vals[offs]); iwl_release_nic_access(bus); - } + } else + result = -EBUSY; spin_unlock_irqrestore(&bus->reg_lock, flags); + + return result; +} + +int iwl_write_targ_mem(struct iwl_bus *bus, u32 addr, u32 val) +{ + return _iwl_write_targ_mem_words(bus, addr, &val, 1); } diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index ced2cbeb6ea..aae2eeb331a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -85,6 +85,9 @@ void _iwl_read_targ_mem_words(struct iwl_bus *bus, u32 addr, (bufsize) / sizeof(u32));\ } while (0) +int _iwl_write_targ_mem_words(struct iwl_bus *bus, u32 addr, + void *buf, int words); + u32 iwl_read_targ_mem(struct iwl_bus *bus, u32 addr); -void iwl_write_targ_mem(struct iwl_bus *bus, u32 addr, u32 val); +int iwl_write_targ_mem(struct iwl_bus *bus, u32 addr, u32 val); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index eb541735296..14dcbfcdc0f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -137,11 +137,11 @@ static int iwl_led_cmd(struct iwl_priv *priv, } IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n", - priv->cfg->base_params->led_compensation); + cfg(priv)->base_params->led_compensation); led_cmd.on = iwl_blink_compensation(priv, on, - priv->cfg->base_params->led_compensation); + cfg(priv)->base_params->led_compensation); led_cmd.off = iwl_blink_compensation(priv, off, - priv->cfg->base_params->led_compensation); + cfg(priv)->base_params->led_compensation); ret = iwl_send_led_cmd(priv, &led_cmd); if (!ret) { @@ -178,7 +178,7 @@ void iwl_leds_init(struct iwl_priv *priv) int ret; if (mode == IWL_LED_DEFAULT) - mode = priv->cfg->led_mode; + mode = cfg(priv)->led_mode; priv->led.name = kasprintf(GFP_KERNEL, "%s-led", wiphy_name(priv->hw->wiphy)); diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 1c93dfef693..2550b3c7dcb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -36,20 +36,6 @@ struct iwl_priv; #define IWL_LED_ACTIVITY (0<<1) #define IWL_LED_LINK (1<<1) -/* - * LED mode - * IWL_LED_DEFAULT: use device default - * IWL_LED_RF_STATE: turn LED on/off based on RF state - * LED ON = RF ON - * LED OFF = RF OFF - * IWL_LED_BLINK: adjust led blink rate based on blink table - */ -enum iwl_led_mode { - IWL_LED_DEFAULT, - IWL_LED_RF_STATE, - IWL_LED_BLINK, -}; - void iwlagn_led_enable(struct iwl_priv *priv); void iwl_leds_init(struct iwl_priv *priv); void iwl_leds_exit(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index e3944f4e4fd..f980e574e1f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c @@ -44,6 +44,7 @@ #include <asm/div64.h> #include "iwl-eeprom.h" +#include "iwl-wifi.h" #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" @@ -160,7 +161,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, hw->flags |= IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; - if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE) + if (cfg(priv)->sku & EEPROM_SKU_CAP_11N_ENABLE) hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_SUPPORTS_STATIC_SMPS; @@ -233,6 +234,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->bands[IEEE80211_BAND_5GHZ]; + hw->wiphy->hw_version = bus_get_hw_id(bus(priv)); + iwl_leds_init(priv); ret = ieee80211_register_hw(priv->hw); @@ -245,6 +248,15 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, return 0; } +void iwlagn_mac_unregister(struct iwl_priv *priv) +{ + if (!priv->mac80211_registered) + return; + iwl_leds_exit(priv); + ieee80211_unregister_hw(priv->hw); + priv->mac80211_registered = 0; +} + static int __iwl_up(struct iwl_priv *priv) { struct iwl_rxon_context *ctx; @@ -265,13 +277,13 @@ static int __iwl_up(struct iwl_priv *priv) } } - ret = iwlagn_run_init_ucode(priv); + ret = iwl_run_init_ucode(trans(priv)); if (ret) { IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret); goto error; } - ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR); + ret = iwl_load_ucode_wait_alive(trans(priv), IWL_UCODE_REGULAR); if (ret) { IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret); goto error; @@ -611,12 +623,11 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, struct iwl_priv *priv = hw->priv; int ret = -EINVAL; struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; - struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n", sta->addr, tid); - if (!(priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)) + if (!(cfg(priv)->sku & EEPROM_SKU_CAP_11N_ENABLE)) return -EACCES; IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -624,6 +635,8 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: + if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) + break; IWL_DEBUG_HT(priv, "start Rx\n"); ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn); break; @@ -634,6 +647,8 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, ret = 0; break; case IEEE80211_AMPDU_TX_START: + if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) + break; IWL_DEBUG_HT(priv, "start Tx\n"); ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); break; @@ -647,8 +662,8 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, } if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) ret = 0; - if (!priv->agg_tids_count && priv->cfg->ht_params && - priv->cfg->ht_params->use_rts_for_aggregation) { + if (!priv->agg_tids_count && cfg(priv)->ht_params && + cfg(priv)->ht_params->use_rts_for_aggregation) { /* * switch off RTS/CTS if it was previously enabled */ @@ -659,54 +674,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, } break; case IEEE80211_AMPDU_TX_OPERATIONAL: - buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); - - iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, iwl_sta_id(sta), - tid, buf_size); - - /* - * If the limit is 0, then it wasn't initialised yet, - * use the default. We can do that since we take the - * minimum below, and we don't want to go above our - * default due to hardware restrictions. - */ - if (sta_priv->max_agg_bufsize == 0) - sta_priv->max_agg_bufsize = - LINK_QUAL_AGG_FRAME_LIMIT_DEF; - - /* - * Even though in theory the peer could have different - * aggregation reorder buffer sizes for different sessions, - * our ucode doesn't allow for that and has a global limit - * for each station. Therefore, use the minimum of all the - * aggregation sessions and our default value. - */ - sta_priv->max_agg_bufsize = - min(sta_priv->max_agg_bufsize, buf_size); - - if (priv->cfg->ht_params && - priv->cfg->ht_params->use_rts_for_aggregation) { - /* - * switch to RTS/CTS if it is the prefer protection - * method for HT traffic - */ - - sta_priv->lq_sta.lq.general_params.flags |= - LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK; - } - priv->agg_tids_count++; - IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n", - priv->agg_tids_count); - - sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit = - sta_priv->max_agg_bufsize; - - iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif), - &sta_priv->lq_sta.lq, CMD_ASYNC, false); - - IWL_INFO(priv, "Tx aggregation enabled on ra = %pM tid = %d\n", - sta->addr, tid); - ret = 0; + ret = iwlagn_tx_agg_oper(priv, vif, sta, tid, buf_size); break; } mutex_unlock(&priv->shrd->mutex); @@ -792,7 +760,7 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, if (!iwl_is_associated_ctx(ctx)) goto out; - if (!priv->cfg->lib->set_channel_switch) + if (!cfg(priv)->lib->set_channel_switch) goto out; ch = channel->hw_value; @@ -832,7 +800,7 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, */ set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status); priv->switch_channel = cpu_to_le16(ch); - if (priv->cfg->lib->set_channel_switch(priv, ch_switch)) { + if (cfg(priv)->lib->set_channel_switch(priv, ch_switch)) { clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status); priv->switch_channel = 0; ieee80211_chswitch_done(ctx->vif, false); @@ -1125,8 +1093,8 @@ static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "enter\n"); mutex_lock(&priv->shrd->mutex); - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) { + if (cfg(priv)->bt_params && + cfg(priv)->bt_params->advanced_bt_coexist) { if (rssi_event == RSSI_EVENT_LOW) priv->bt_enable_pspoll = true; else if (rssi_event == RSSI_EVENT_HIGH) @@ -1237,7 +1205,7 @@ static int iwl_setup_interface(struct iwl_priv *priv, return err; } - if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist && + if (cfg(priv)->bt_params && cfg(priv)->bt_params->advanced_bt_coexist && vif->type == NL80211_IFTYPE_ADHOC) { /* * pretend to have high BT traffic as long as we diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c index 850ec8e51b1..fb30ea7ca96 100644 --- a/drivers/net/wireless/iwlwifi/iwl-pci.c +++ b/drivers/net/wireless/iwlwifi/iwl-pci.c @@ -135,7 +135,7 @@ static void iwl_pci_apm_config(struct iwl_bus *bus) } } -static void iwl_pci_get_hw_id(struct iwl_bus *bus, char buf[], +static void iwl_pci_get_hw_id_string(struct iwl_bus *bus, char buf[], int buf_len) { struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus); @@ -144,6 +144,13 @@ static void iwl_pci_get_hw_id(struct iwl_bus *bus, char buf[], pci_dev->subsystem_device); } +static u32 iwl_pci_get_hw_id(struct iwl_bus *bus) +{ + struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus); + + return (pci_dev->device << 16) + pci_dev->subsystem_device; +} + static void iwl_pci_write8(struct iwl_bus *bus, u32 ofs, u8 val) { iowrite8(val, IWL_BUS_GET_PCI_BUS(bus)->hw_base + ofs); @@ -163,6 +170,7 @@ static u32 iwl_pci_read32(struct iwl_bus *bus, u32 ofs) static const struct iwl_bus_ops bus_ops_pci = { .get_pm_support = iwl_pci_is_pm_supported, .apm_config = iwl_pci_apm_config, + .get_hw_id_string = iwl_pci_get_hw_id_string, .get_hw_id = iwl_pci_get_hw_id, .write8 = iwl_pci_write8, .write32 = iwl_pci_write32, diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 4eaab204322..2b188a6025b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -167,7 +167,7 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, u8 skip; u32 slp_itrvl; - if (priv->cfg->adv_pm) { + if (cfg(priv)->adv_pm) { table = apm_range_2; if (period <= IWL_DTIM_RANGE_1_MAX) table = apm_range_1; @@ -221,7 +221,7 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA; if (iwl_advanced_bt_coexist(priv)) { - if (!priv->cfg->bt_params->bt_sco_disable) + if (!cfg(priv)->bt_params->bt_sco_disable) cmd->flags |= IWL_POWER_BT_SCO_ENA; else cmd->flags &= ~IWL_POWER_BT_SCO_ENA; @@ -307,7 +307,7 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA; if (iwl_advanced_bt_coexist(priv)) { - if (!priv->cfg->bt_params->bt_sco_disable) + if (!cfg(priv)->bt_params->bt_sco_disable) cmd->flags |= IWL_POWER_BT_SCO_ENA; else cmd->flags &= ~IWL_POWER_BT_SCO_ENA; @@ -350,7 +350,7 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, if (priv->shrd->wowlan) iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper); - else if (!priv->cfg->base_params->no_idle_support && + else if (!cfg(priv)->base_params->no_idle_support && priv->hw->conf.flags & IEEE80211_CONF_IDLE) iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); else if (iwl_tt_is_low_power_state(priv)) { diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 359d2182757..084aa2c4ccf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -691,8 +691,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) * Internal scans are passive, so we can indiscriminately set * the BT ignore flag on 2.4 GHz since it applies to TX only. */ - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) + if (cfg(priv)->bt_params && + cfg(priv)->bt_params->advanced_bt_coexist) scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT; break; case IEEE80211_BAND_5GHZ: @@ -733,12 +733,12 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) band = priv->scan_band; - if (priv->cfg->scan_rx_antennas[band]) - rx_ant = priv->cfg->scan_rx_antennas[band]; + if (cfg(priv)->scan_rx_antennas[band]) + rx_ant = cfg(priv)->scan_rx_antennas[band]; if (band == IEEE80211_BAND_2GHZ && - priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) { + cfg(priv)->bt_params && + cfg(priv)->bt_params->advanced_bt_coexist) { /* transmit 2.4 GHz probes only on first antenna */ scan_tx_antennas = first_antenna(scan_tx_antennas); } @@ -762,8 +762,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) rx_ant = first_antenna(active_chains); } - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist && + if (cfg(priv)->bt_params && + cfg(priv)->bt_params->advanced_bt_coexist && priv->bt_full_concurrent) { /* operated as 1x1 in full concurrency mode */ rx_ant = first_antenna(rx_ant); diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h index 29a7284aa3e..dc55cc4a810 100644 --- a/drivers/net/wireless/iwlwifi/iwl-shared.h +++ b/drivers/net/wireless/iwlwifi/iwl-shared.h @@ -94,7 +94,6 @@ * This implementation is iwl-pci.c */ -struct iwl_cfg; struct iwl_bus; struct iwl_priv; struct iwl_trans; @@ -108,6 +107,10 @@ struct iwl_trans_ops; extern struct iwl_mod_params iwlagn_mod_params; +#define IWL_DISABLE_HT_ALL BIT(0) +#define IWL_DISABLE_HT_TXAGG BIT(1) +#define IWL_DISABLE_HT_RXAGG BIT(2) + /** * struct iwl_mod_params * @@ -115,7 +118,8 @@ extern struct iwl_mod_params iwlagn_mod_params; * * @sw_crypto: using hardware encryption, default = 0 * @num_of_queues: number of tx queue, HW dependent - * @disable_11n: 11n capabilities enabled, default = 0 + * @disable_11n: disable 11n capabilities, default = 0, + * use IWL_DISABLE_HT_* constants * @amsdu_size_8K: enable 8K amsdu size, default = 1 * @antenna: both antennas (use diversity), default = 0 * @restart_fw: restart firmware, default = 1 @@ -136,7 +140,7 @@ extern struct iwl_mod_params iwlagn_mod_params; struct iwl_mod_params { int sw_crypto; int num_of_queues; - int disable_11n; + unsigned int disable_11n; int amsdu_size_8K; int antenna; int restart_fw; @@ -175,7 +179,6 @@ struct iwl_mod_params { * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit * relevant for 1000, 6000 and up * @wd_timeout: TX queues watchdog timeout - * @calib_rt_cfg: setup runtime calibrations for the hw * @struct iwl_sensitivity_ranges: range of sensitivity values */ struct iwl_hw_params { @@ -195,69 +198,10 @@ struct iwl_hw_params { u32 ct_kill_exit_threshold; unsigned int wd_timeout; - u32 calib_rt_cfg; const struct iwl_sensitivity_ranges *sens; }; /** - * enum iwl_agg_state - * - * The state machine of the BA agreement establishment / tear down. - * These states relate to a specific RA / TID. - * - * @IWL_AGG_OFF: aggregation is not used - * @IWL_AGG_ON: aggregation session is up - * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the - * HW queue to be empty from packets for this RA /TID. - * @IWL_EMPTYING_HW_QUEUE_DELBA: tearing down a BA session - waiting for the - * HW queue to be empty from packets for this RA /TID. - */ -enum iwl_agg_state { - IWL_AGG_OFF = 0, - IWL_AGG_ON, - IWL_EMPTYING_HW_QUEUE_ADDBA, - IWL_EMPTYING_HW_QUEUE_DELBA, -}; - -/** - * struct iwl_ht_agg - aggregation state machine - - * This structs holds the states for the BA agreement establishment and tear - * down. It also holds the state during the BA session itself. This struct is - * duplicated for each RA / TID. - - * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the - * Tx response (REPLY_TX), and the block ack notification - * (REPLY_COMPRESSED_BA). - * @state: state of the BA agreement establishment / tear down. - * @txq_id: Tx queue used by the BA session - used by the transport layer. - * Needed by the upper layer for debugfs only. - * @wait_for_ba: Expect block-ack before next Tx reply - */ -struct iwl_ht_agg { - u32 rate_n_flags; - enum iwl_agg_state state; - u16 txq_id; - bool wait_for_ba; -}; - -/** - * struct iwl_tid_data - one for each RA / TID - - * This structs holds the states for each RA / TID. - - * @seq_number: the next WiFi sequence number to use - * @tfds_in_queue: number of packets sent to the HW queues. - * Exported for debugfs only - * @agg: aggregation state machine - */ -struct iwl_tid_data { - u16 seq_number; - u16 tfds_in_queue; - struct iwl_ht_agg agg; -}; - -/** * enum iwl_ucode_type * * The type of ucode currently loaded on the hardware. @@ -304,6 +248,101 @@ struct iwl_notification_wait { }; /** + * enum iwl_pa_type - Power Amplifier type + * @IWL_PA_SYSTEM: based on uCode configuration + * @IWL_PA_INTERNAL: use Internal only + */ +enum iwl_pa_type { + IWL_PA_SYSTEM = 0, + IWL_PA_INTERNAL = 1, +}; + +/* + * LED mode + * IWL_LED_DEFAULT: use device default + * IWL_LED_RF_STATE: turn LED on/off based on RF state + * LED ON = RF ON + * LED OFF = RF OFF + * IWL_LED_BLINK: adjust led blink rate based on blink table + */ +enum iwl_led_mode { + IWL_LED_DEFAULT, + IWL_LED_RF_STATE, + IWL_LED_BLINK, +}; + +/** + * struct iwl_cfg + * @name: Offical name of the device + * @fw_name_pre: Firmware filename prefix. The api version and extension + * (.ucode) will be added to filename before loading from disk. The + * filename is constructed as fw_name_pre<api>.ucode. + * @ucode_api_max: Highest version of uCode API supported by driver. + * @ucode_api_ok: oldest version of the uCode API that is OK to load + * without a warning, for use in transitions + * @ucode_api_min: Lowest version of uCode API supported by driver. + * @valid_tx_ant: valid transmit antenna + * @valid_rx_ant: valid receive antenna + * @sku: sku information from EEPROM + * @eeprom_ver: EEPROM version + * @eeprom_calib_ver: EEPROM calibration version + * @lib: pointer to the lib ops + * @additional_nic_config: additional nic configuration + * @base_params: pointer to basic parameters + * @ht_params: point to ht patameters + * @bt_params: pointer to bt parameters + * @pa_type: used by 6000 series only to identify the type of Power Amplifier + * @need_temp_offset_calib: need to perform temperature offset calibration + * @no_xtal_calib: some devices do not need crystal calibration data, + * don't send it to those + * @scan_rx_antennas: available antenna for scan operation + * @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off) + * @adv_pm: advance power management + * @rx_with_siso_diversity: 1x1 device with rx antenna diversity + * @internal_wimax_coex: internal wifi/wimax combo device + * @iq_invert: I/Q inversion + * @temp_offset_v2: support v2 of temperature offset calibration + * + * We enable the driver to be backward compatible wrt API version. The + * driver specifies which APIs it supports (with @ucode_api_max being the + * highest and @ucode_api_min the lowest). Firmware will only be loaded if + * it has a supported API version. + * + * The ideal usage of this infrastructure is to treat a new ucode API + * release as a new hardware revision. + */ +struct iwl_cfg { + /* params specific to an individual device within a device family */ + const char *name; + const char *fw_name_pre; + const unsigned int ucode_api_max; + const unsigned int ucode_api_ok; + const unsigned int ucode_api_min; + u8 valid_tx_ant; + u8 valid_rx_ant; + u16 sku; + u16 eeprom_ver; + u16 eeprom_calib_ver; + const struct iwl_lib_ops *lib; + void (*additional_nic_config)(struct iwl_priv *priv); + /* params not likely to change within a device family */ + struct iwl_base_params *base_params; + /* params likely to change within a device family */ + struct iwl_ht_params *ht_params; + struct iwl_bt_params *bt_params; + enum iwl_pa_type pa_type; /* if used set to IWL_PA_SYSTEM */ + const bool need_temp_offset_calib; /* if used set to true */ + const bool no_xtal_calib; + u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; + enum iwl_led_mode led_mode; + const bool adv_pm; + const bool rx_with_siso_diversity; + const bool internal_wimax_coex; + const bool iq_invert; + const bool temp_offset_v2; +}; + +/** * struct iwl_shared - shared fields for all the layers of the driver * * @dbg_level_dev: dbg level set per device. Prevails on @@ -311,15 +350,20 @@ struct iwl_notification_wait { * @ucode_owner: IWL_OWNERSHIP_* * @cmd_queue: command queue number * @status: STATUS_* + * @wowlan: are we running wowlan uCode * @valid_contexts: microcode/device supports multiple contexts * @bus: pointer to the bus layer data + * @cfg: see struct iwl_cfg * @priv: pointer to the upper layer data + * @trans: pointer to the transport layer data * @hw_params: see struct iwl_hw_params * @workqueue: the workqueue used by all the layers of the driver * @lock: protect general shared data * @sta_lock: protects the station table. * If lock and sta_lock are needed, lock must be acquired first. * @mutex: + * @wait_command_queue: the wait_queue for SYNC host command nad uCode load + * @eeprom: pointer to the eeprom/OTP image * @ucode_type: indicator of loaded ucode image * @notif_waits: things waiting for notification * @notif_wait_lock: lock protecting notification @@ -340,6 +384,7 @@ struct iwl_shared { u8 valid_contexts; struct iwl_bus *bus; + struct iwl_cfg *cfg; struct iwl_priv *priv; struct iwl_trans *trans; struct iwl_hw_params hw_params; @@ -349,8 +394,6 @@ struct iwl_shared { spinlock_t sta_lock; struct mutex mutex; - struct iwl_tid_data tid_data[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT]; - wait_queue_head_t wait_command_queue; /* eeprom -- this is in the card's little endian byte order */ @@ -373,6 +416,7 @@ struct iwl_shared { /*Whatever _m is (iwl_trans, iwl_priv, iwl_bus, these macros will work */ #define priv(_m) ((_m)->shrd->priv) +#define cfg(_m) ((_m)->shrd->cfg) #define bus(_m) ((_m)->shrd->bus) #define trans(_m) ((_m)->shrd->trans) #define hw_params(_m) ((_m)->shrd->hw_params) @@ -494,12 +538,6 @@ int __must_check iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_device_cmd *cmd); int iwlagn_hw_valid_rtc_data_addr(u32 addr); -void iwl_start_tx_ba_trans_ready(struct iwl_priv *priv, - enum iwl_rxon_context_id ctx, - u8 sta_id, u8 tid); -void iwl_stop_tx_ba_trans_ready(struct iwl_priv *priv, - enum iwl_rxon_context_id ctx, - u8 sta_id, u8 tid); void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state); void iwl_nic_config(struct iwl_priv *priv); void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb); diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c index a874eb7b5f8..4a5cddd2d56 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.c +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c @@ -70,6 +70,7 @@ #include <net/mac80211.h> #include <net/netlink.h> +#include "iwl-wifi.h" #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-debug.h" @@ -380,7 +381,7 @@ static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv) iwl_init_notification_wait(priv->shrd, &calib_wait, CALIBRATION_COMPLETE_NOTIFICATION, NULL, NULL); - ret = iwlagn_init_alive_start(priv); + ret = iwl_init_alive_start(trans(priv)); if (ret) { IWL_DEBUG_INFO(priv, "Error configuring init calibration: %d\n", ret); @@ -417,16 +418,16 @@ cfg_init_calib_error: static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) { struct iwl_priv *priv = hw->priv; + struct iwl_trans *trans = trans(priv); struct sk_buff *skb; unsigned char *rsp_data_ptr = NULL; int status = 0, rsp_data_len = 0; - char buf[32], *ptr = NULL; - unsigned int num, devid; + u32 devid; switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { case IWL_TM_CMD_APP2DEV_GET_DEVICENAME: - rsp_data_ptr = (unsigned char *)priv->cfg->name; - rsp_data_len = strlen(priv->cfg->name); + rsp_data_ptr = (unsigned char *)cfg(priv)->name; + rsp_data_len = strlen(cfg(priv)->name); skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, rsp_data_len + 20); if (!skb) { @@ -445,7 +446,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) break; case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: - status = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_INIT); + status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_INIT); if (status) IWL_DEBUG_INFO(priv, "Error loading init ucode: %d\n", status); @@ -453,11 +454,11 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: iwl_testmode_cfg_init_calib(priv); - iwl_trans_stop_device(trans(priv)); + iwl_trans_stop_device(trans); break; case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: - status = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR); + status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_REGULAR); if (status) { IWL_DEBUG_INFO(priv, "Error loading runtime ucode: %d\n", status); @@ -471,8 +472,8 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: iwl_scan_cancel_timeout(priv, 200); - iwl_trans_stop_device(trans(priv)); - status = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN); + iwl_trans_stop_device(trans); + status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_WOWLAN); if (status) { IWL_DEBUG_INFO(priv, "Error loading WOWLAN ucode: %d\n", status); @@ -487,7 +488,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) case IWL_TM_CMD_APP2DEV_GET_EEPROM: if (priv->shrd->eeprom) { skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, - priv->cfg->base_params->eeprom_size + 20); + cfg(priv)->base_params->eeprom_size + 20); if (!skb) { IWL_DEBUG_INFO(priv, "Error allocating memory\n"); @@ -496,7 +497,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_EEPROM_RSP); NLA_PUT(skb, IWL_TM_ATTR_EEPROM, - priv->cfg->base_params->eeprom_size, + cfg(priv)->base_params->eeprom_size, priv->shrd->eeprom); status = cfg80211_testmode_reply(skb); if (status < 0) @@ -532,14 +533,8 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) break; case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: - bus_get_hw_id(bus(priv), buf, sizeof(buf)); - ptr = buf; - strsep(&ptr, ":"); - sscanf(strsep(&ptr, ":"), "%x", &num); - sscanf(strsep(&ptr, ":"), "%x", &devid); - IWL_INFO(priv, "Device ID = 0x%04x, SubDevice ID= 0x%04x\n", - num, devid); - devid |= (num << 16); + devid = bus_get_hw_id(bus(priv)); + IWL_INFO(priv, "hw version: 0x%x\n", devid); skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); if (!skb) { diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h index 5a384b309b0..f6debf91d7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h @@ -219,9 +219,7 @@ struct iwl_trans_pcie { /* INT ICT Table */ __le32 *ict_tbl; - void *ict_tbl_vir; dma_addr_t ict_tbl_dma; - dma_addr_t aligned_ict_tbl_dma; int ict_index; u32 inta; bool use_ict; @@ -236,6 +234,7 @@ struct iwl_trans_pcie { const u8 *ac_to_fifo[NUM_IWL_RXON_CTX]; const u8 *ac_to_queue[NUM_IWL_RXON_CTX]; u8 mcast_queue[NUM_IWL_RXON_CTX]; + u8 agg_txq[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT]; struct iwl_tx_queue *txq; unsigned long txq_ctx_active_msk; @@ -280,20 +279,16 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans, struct iwl_tx_queue *txq, u16 byte_cnt); -void iwl_trans_pcie_txq_agg_disable(struct iwl_trans *trans, int txq_id); int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx, int sta_id, - int tid); + int sta_id, int tid); void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index); void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, struct iwl_tx_queue *txq, int tx_fifo_id, int scd_retry); -int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx, int sta_id, - int tid, u16 *ssn); +int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans, int sta_id, int tid); void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, enum iwl_rxon_context_id ctx, - int sta_id, int tid, int frame_limit); + int sta_id, int tid, int frame_limit, u16 ssn); void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, int index, enum dma_data_direction dma_dir); int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index, diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c index 2ee00e0f39d..752493f0040 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c @@ -672,7 +672,7 @@ static void iwl_irq_handle_error(struct iwl_trans *trans) { struct iwl_priv *priv = priv(trans); /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ - if (priv->cfg->internal_wimax_coex && + if (cfg(priv)->internal_wimax_coex && (!(iwl_read_prph(bus(trans), APMG_CLK_CTRL_REG) & APMS_CLK_VAL_MRB_FUNC_MODE) || (iwl_read_prph(bus(trans), APMG_PS_CTRL_REG) & @@ -1151,7 +1151,11 @@ void iwl_irq_tasklet(struct iwl_trans *trans) * ICT functions * ******************************************************************************/ -#define ICT_COUNT (PAGE_SIZE/sizeof(u32)) + +/* a device (PCI-E) page is 4096 bytes long */ +#define ICT_SHIFT 12 +#define ICT_SIZE (1 << ICT_SHIFT) +#define ICT_COUNT (ICT_SIZE / sizeof(u32)) /* Free dram table */ void iwl_free_isr_ict(struct iwl_trans *trans) @@ -1159,21 +1163,19 @@ void iwl_free_isr_ict(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - if (trans_pcie->ict_tbl_vir) { - dma_free_coherent(bus(trans)->dev, - (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, - trans_pcie->ict_tbl_vir, + if (trans_pcie->ict_tbl) { + dma_free_coherent(bus(trans)->dev, ICT_SIZE, + trans_pcie->ict_tbl, trans_pcie->ict_tbl_dma); - trans_pcie->ict_tbl_vir = NULL; - memset(&trans_pcie->ict_tbl_dma, 0, - sizeof(trans_pcie->ict_tbl_dma)); - memset(&trans_pcie->aligned_ict_tbl_dma, 0, - sizeof(trans_pcie->aligned_ict_tbl_dma)); + trans_pcie->ict_tbl = NULL; + trans_pcie->ict_tbl_dma = 0; } } -/* allocate dram shared table it is a PAGE_SIZE aligned +/* + * allocate dram shared table, it is an aligned memory + * block of ICT_SIZE. * also reset all data related to ICT table interrupt. */ int iwl_alloc_isr_ict(struct iwl_trans *trans) @@ -1181,36 +1183,26 @@ int iwl_alloc_isr_ict(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - /* allocate shrared data table */ - trans_pcie->ict_tbl_vir = - dma_alloc_coherent(bus(trans)->dev, - (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, - &trans_pcie->ict_tbl_dma, GFP_KERNEL); - if (!trans_pcie->ict_tbl_vir) + trans_pcie->ict_tbl = + dma_alloc_coherent(bus(trans)->dev, ICT_SIZE, + &trans_pcie->ict_tbl_dma, + GFP_KERNEL); + if (!trans_pcie->ict_tbl) return -ENOMEM; - /* align table to PAGE_SIZE boundary */ - trans_pcie->aligned_ict_tbl_dma = - ALIGN(trans_pcie->ict_tbl_dma, PAGE_SIZE); - - IWL_DEBUG_ISR(trans, "ict dma addr %Lx dma aligned %Lx diff %d\n", - (unsigned long long)trans_pcie->ict_tbl_dma, - (unsigned long long)trans_pcie->aligned_ict_tbl_dma, - (int)(trans_pcie->aligned_ict_tbl_dma - - trans_pcie->ict_tbl_dma)); + /* just an API sanity check ... it is guaranteed to be aligned */ + if (WARN_ON(trans_pcie->ict_tbl_dma & (ICT_SIZE - 1))) { + iwl_free_isr_ict(trans); + return -EINVAL; + } - trans_pcie->ict_tbl = trans_pcie->ict_tbl_vir + - (trans_pcie->aligned_ict_tbl_dma - - trans_pcie->ict_tbl_dma); + IWL_DEBUG_ISR(trans, "ict dma addr %Lx\n", + (unsigned long long)trans_pcie->ict_tbl_dma); - IWL_DEBUG_ISR(trans, "ict vir addr %p vir aligned %p diff %d\n", - trans_pcie->ict_tbl, trans_pcie->ict_tbl_vir, - (int)(trans_pcie->aligned_ict_tbl_dma - - trans_pcie->ict_tbl_dma)); + IWL_DEBUG_ISR(trans, "ict vir addr %p\n", trans_pcie->ict_tbl); /* reset table and index to all 0 */ - memset(trans_pcie->ict_tbl_vir, 0, - (sizeof(u32) * ICT_COUNT) + PAGE_SIZE); + memset(trans_pcie->ict_tbl, 0, ICT_SIZE); trans_pcie->ict_index = 0; /* add periodic RX interrupt */ @@ -1228,23 +1220,20 @@ int iwl_reset_ict(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - if (!trans_pcie->ict_tbl_vir) + if (!trans_pcie->ict_tbl) return 0; spin_lock_irqsave(&trans->shrd->lock, flags); iwl_disable_interrupts(trans); - memset(&trans_pcie->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT); + memset(trans_pcie->ict_tbl, 0, ICT_SIZE); - val = trans_pcie->aligned_ict_tbl_dma >> PAGE_SHIFT; + val = trans_pcie->ict_tbl_dma >> ICT_SHIFT; val |= CSR_DRAM_INT_TBL_ENABLE; val |= CSR_DRAM_INIT_TBL_WRAP_CHECK; - IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%X " - "aligned dma address %Lx\n", - val, - (unsigned long long)trans_pcie->aligned_ict_tbl_dma); + IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%x\n", val); iwl_write32(bus(trans), CSR_DRAM_INT_TBL_REG, val); trans_pcie->use_ict = true; @@ -1281,6 +1270,8 @@ static irqreturn_t iwl_isr(int irq, void *data) if (!trans) return IRQ_NONE; + trace_iwlwifi_dev_irq(priv(trans)); + trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); spin_lock_irqsave(&trans->shrd->lock, flags); @@ -1355,6 +1346,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data) struct iwl_trans_pcie *trans_pcie; u32 inta, inta_mask; u32 val = 0; + u32 read; unsigned long flags; if (!trans) @@ -1368,6 +1360,8 @@ irqreturn_t iwl_isr_ict(int irq, void *data) if (!trans_pcie->use_ict) return iwl_isr(irq, data); + trace_iwlwifi_dev_irq(priv(trans)); + spin_lock_irqsave(&trans->shrd->lock, flags); /* Disable (but don't clear!) interrupts here to avoid @@ -1382,24 +1376,29 @@ irqreturn_t iwl_isr_ict(int irq, void *data) /* Ignore interrupt if there's nothing in NIC to service. * This may be due to IRQ shared with another device, * or due to sporadic interrupts thrown from our NIC. */ - if (!trans_pcie->ict_tbl[trans_pcie->ict_index]) { + read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]); + trace_iwlwifi_dev_ict_read(priv(trans), trans_pcie->ict_index, read); + if (!read) { IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); goto none; } - /* read all entries that not 0 start with ict_index */ - while (trans_pcie->ict_tbl[trans_pcie->ict_index]) { - - val |= le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]); + /* + * Collect all entries up to the first 0, starting from ict_index; + * note we already read at ict_index. + */ + do { + val |= read; IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n", - trans_pcie->ict_index, - le32_to_cpu( - trans_pcie->ict_tbl[trans_pcie->ict_index])); + trans_pcie->ict_index, read); trans_pcie->ict_tbl[trans_pcie->ict_index] = 0; trans_pcie->ict_index = iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT); - } + read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]); + trace_iwlwifi_dev_ict_read(priv(trans), trans_pcie->ict_index, + read); + } while (read); /* We should not get this value, just ignore it. */ if (val == 0xffffffff) @@ -1426,7 +1425,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data) if (likely(inta)) tasklet_schedule(&trans_pcie->irq_tasklet); else if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && - !trans_pcie->inta) { + !trans_pcie->inta) { /* Allow interrupt if was disabled by this handler and * no tasklet was schedules, We should not enable interrupt, * tasklet will enable it. @@ -1442,7 +1441,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data) * only Re-enable if disabled by irq. */ if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && - !trans_pcie->inta) + !trans_pcie->inta) iwl_enable_interrupts(trans); spin_unlock_irqrestore(&trans->shrd->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c index 79331fb10aa..bd29568177e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c @@ -408,6 +408,7 @@ static void iwlagn_tx_queue_stop_scheduler(struct iwl_trans *trans, u16 txq_id) void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index) { + IWL_DEBUG_TX_QUEUES(trans, "Q %d WrPtr: %d", txq_id, index & 0xff); iwl_write_direct32(bus(trans), HBUS_TARG_WRPTR, (index & 0xff) | (txq_id << 8)); iwl_write_prph(bus(trans), SCD_QUEUE_RDPTR(txq_id), index); @@ -446,14 +447,21 @@ static inline int get_fifo_from_tid(struct iwl_trans_pcie *trans_pcie, return -EINVAL; } +static inline bool is_agg_txqid_valid(struct iwl_trans *trans, int txq_id) +{ + if (txq_id < IWLAGN_FIRST_AMPDU_QUEUE) + return false; + return txq_id < (IWLAGN_FIRST_AMPDU_QUEUE + + hw_params(trans).num_ampdu_queues); +} + void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, enum iwl_rxon_context_id ctx, int sta_id, - int tid, int frame_limit) + int tid, int frame_limit, u16 ssn) { - int tx_fifo, txq_id, ssn_idx; + int tx_fifo, txq_id; u16 ra_tid; unsigned long flags; - struct iwl_tid_data *tid_data; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -469,11 +477,15 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, return; } - spin_lock_irqsave(&trans->shrd->sta_lock, flags); - tid_data = &trans->shrd->tid_data[sta_id][tid]; - ssn_idx = SEQ_TO_SN(tid_data->seq_number); - txq_id = tid_data->agg.txq_id; - spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); + txq_id = trans_pcie->agg_txq[sta_id][tid]; + if (WARN_ON_ONCE(is_agg_txqid_valid(trans, txq_id) == false)) { + IWL_ERR(trans, + "queue number out of range: %d, must be %d to %d\n", + txq_id, IWLAGN_FIRST_AMPDU_QUEUE, + IWLAGN_FIRST_AMPDU_QUEUE + + hw_params(trans).num_ampdu_queues - 1); + return; + } ra_tid = BUILD_RAxTID(sta_id, tid); @@ -493,9 +505,9 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, /* Place first TFD at index corresponding to start sequence number. * Assumes that ssn_idx is valid (!= 0xFFF) */ - trans_pcie->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); - trans_pcie->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); - iwl_trans_set_wr_ptrs(trans, txq_id, ssn_idx); + trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff); + trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff); + iwl_trans_set_wr_ptrs(trans, txq_id, ssn); /* Set up Tx window size and frame limit for this queue */ iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr + @@ -539,12 +551,9 @@ static int iwlagn_txq_ctx_activate_free(struct iwl_trans *trans) } int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx, int sta_id, - int tid, u16 *ssn) + int sta_id, int tid) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_tid_data *tid_data; - unsigned long flags; int txq_id; txq_id = iwlagn_txq_ctx_activate_free(trans); @@ -553,118 +562,39 @@ int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans, return -ENXIO; } - spin_lock_irqsave(&trans->shrd->sta_lock, flags); - tid_data = &trans->shrd->tid_data[sta_id][tid]; - *ssn = SEQ_TO_SN(tid_data->seq_number); - tid_data->agg.txq_id = txq_id; + trans_pcie->agg_txq[sta_id][tid] = txq_id; iwl_set_swq_id(&trans_pcie->txq[txq_id], get_ac_from_tid(tid), txq_id); - if (tid_data->tfds_in_queue == 0) { - IWL_DEBUG_TX_QUEUES(trans, "HW queue is empty\n"); - tid_data->agg.state = IWL_AGG_ON; - iwl_start_tx_ba_trans_ready(priv(trans), ctx, sta_id, tid); - } else { - IWL_DEBUG_TX_QUEUES(trans, - "HW queue is NOT empty: %d packets in HW" - " queue\n", tid_data->tfds_in_queue); - tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; - } - spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); - return 0; } -void iwl_trans_pcie_txq_agg_disable(struct iwl_trans *trans, int txq_id) +int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int sta_id, int tid) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - iwlagn_tx_queue_stop_scheduler(trans, txq_id); - - iwl_clear_bits_prph(bus(trans), SCD_AGGR_SEL, (1 << txq_id)); - - trans_pcie->txq[txq_id].q.read_ptr = 0; - trans_pcie->txq[txq_id].q.write_ptr = 0; - /* supposes that ssn_idx is valid (!= 0xFFF) */ - iwl_trans_set_wr_ptrs(trans, txq_id, 0); + u8 txq_id = trans_pcie->agg_txq[sta_id][tid]; - iwl_clear_bits_prph(bus(trans), SCD_INTERRUPT_MASK, (1 << txq_id)); - iwl_txq_ctx_deactivate(trans_pcie, txq_id); - iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id], 0, 0); -} - -int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx, int sta_id, - int tid) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - unsigned long flags; - int read_ptr, write_ptr; - struct iwl_tid_data *tid_data; - int txq_id; - - spin_lock_irqsave(&trans->shrd->sta_lock, flags); - - tid_data = &trans->shrd->tid_data[sta_id][tid]; - txq_id = tid_data->agg.txq_id; - - if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || - (IWLAGN_FIRST_AMPDU_QUEUE + - hw_params(trans).num_ampdu_queues <= txq_id)) { + if (WARN_ON_ONCE(is_agg_txqid_valid(trans, txq_id) == false)) { IWL_ERR(trans, "queue number out of range: %d, must be %d to %d\n", txq_id, IWLAGN_FIRST_AMPDU_QUEUE, IWLAGN_FIRST_AMPDU_QUEUE + hw_params(trans).num_ampdu_queues - 1); - spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); return -EINVAL; } - switch (trans->shrd->tid_data[sta_id][tid].agg.state) { - case IWL_EMPTYING_HW_QUEUE_ADDBA: - /* - * This can happen if the peer stops aggregation - * again before we've had a chance to drain the - * queue we selected previously, i.e. before the - * session was really started completely. - */ - IWL_DEBUG_HT(trans, "AGG stop before setup done\n"); - goto turn_off; - case IWL_AGG_ON: - break; - default: - IWL_WARN(trans, "Stopping AGG while state not ON " - "or starting for %d on %d (%d)\n", sta_id, tid, - trans->shrd->tid_data[sta_id][tid].agg.state); - spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); - return 0; - } - - write_ptr = trans_pcie->txq[txq_id].q.write_ptr; - read_ptr = trans_pcie->txq[txq_id].q.read_ptr; - - /* The queue is not empty */ - if (write_ptr != read_ptr) { - IWL_DEBUG_TX_QUEUES(trans, - "Stopping a non empty AGG HW QUEUE\n"); - trans->shrd->tid_data[sta_id][tid].agg.state = - IWL_EMPTYING_HW_QUEUE_DELBA; - spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); - return 0; - } - - IWL_DEBUG_TX_QUEUES(trans, "HW queue is empty\n"); -turn_off: - trans->shrd->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF; - - /* do not restore/save irqs */ - spin_unlock(&trans->shrd->sta_lock); - spin_lock(&trans->shrd->lock); - - iwl_trans_pcie_txq_agg_disable(trans, txq_id); + iwlagn_tx_queue_stop_scheduler(trans, txq_id); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + iwl_clear_bits_prph(bus(trans), SCD_AGGR_SEL, (1 << txq_id)); - iwl_stop_tx_ba_trans_ready(priv(trans), ctx, sta_id, tid); + trans_pcie->agg_txq[sta_id][tid] = 0; + trans_pcie->txq[txq_id].q.read_ptr = 0; + trans_pcie->txq[txq_id].q.write_ptr = 0; + /* supposes that ssn_idx is valid (!= 0xFFF) */ + iwl_trans_set_wr_ptrs(trans, txq_id, 0); + iwl_clear_bits_prph(bus(trans), SCD_INTERRUPT_MASK, (1 << txq_id)); + iwl_txq_ctx_deactivate(trans_pcie, txq_id); + iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id], 0, 0); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index 3cf62c363bc..cb9da25bd81 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -1044,7 +1044,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx, - u8 sta_id) + u8 sta_id, u8 tid) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; @@ -1058,13 +1058,12 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, dma_addr_t txcmd_phys; dma_addr_t scratch_phys; u16 len, firstlen, secondlen; - u16 seq_number = 0; u8 wait_write_ptr = 0; u8 txq_id; - u8 tid = 0; bool is_agg = false; __le16 fc = hdr->frame_control; u8 hdr_len = ieee80211_hdrlen(fc); + u16 __maybe_unused wifi_seq; /* * Send this frame after DTIM -- there's a special queue @@ -1085,44 +1084,28 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, txq_id = trans_pcie->ac_to_queue[ctx][skb_get_queue_mapping(skb)]; - if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { - u8 *qc = NULL; - struct iwl_tid_data *tid_data; - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - tid_data = &trans->shrd->tid_data[sta_id][tid]; - - if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) - return -1; - - seq_number = tid_data->seq_number; - seq_number &= IEEE80211_SCTL_SEQ; - hdr->seq_ctrl = hdr->seq_ctrl & - cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(seq_number); - /* aggregation is on for this <sta,tid> */ - if (info->flags & IEEE80211_TX_CTL_AMPDU) { - if (WARN_ON_ONCE(tid_data->agg.state != IWL_AGG_ON)) { - IWL_ERR(trans, "TX_CTL_AMPDU while not in AGG:" - " Tx flags = 0x%08x, agg.state = %d", - info->flags, tid_data->agg.state); - IWL_ERR(trans, "sta_id = %d, tid = %d " - "txq_id = %d, seq_num = %d", sta_id, - tid, tid_data->agg.txq_id, - seq_number >> 4); - } - txq_id = tid_data->agg.txq_id; - is_agg = true; - } - seq_number += 0x10; + /* aggregation is on for this <sta,tid> */ + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + WARN_ON(tid >= IWL_MAX_TID_COUNT); + txq_id = trans_pcie->agg_txq[sta_id][tid]; + is_agg = true; } - /* Copy MAC header from skb into command buffer */ - memcpy(tx_cmd->hdr, hdr, hdr_len); - txq = &trans_pcie->txq[txq_id]; q = &txq->q; + /* In AGG mode, the index in the ring must correspond to the WiFi + * sequence number. This is a HW requirements to help the SCD to parse + * the BA. + * Check here that the packets are in the right place on the ring. + */ +#ifdef CONFIG_IWLWIFI_DEBUG + wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + WARN_ONCE(is_agg && ((wifi_seq & 0xff) != q->write_ptr), + "Q: %d WiFi Seq %d tfdNum %d", + txq_id, wifi_seq, q->write_ptr); +#endif + /* Set up driver data for this TFD */ txq->skbs[q->write_ptr] = skb; txq->cmd[q->write_ptr] = dev_cmd; @@ -1220,13 +1203,6 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); iwl_txq_update_write_ptr(trans, txq); - if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { - trans->shrd->tid_data[sta_id][tid].tfds_in_queue++; - if (!ieee80211_has_morefrags(fc)) - trans->shrd->tid_data[sta_id][tid].seq_number = - seq_number; - } - /* * At this point the frame is "transmitted" successfully * and we will get a TX status notification eventually, @@ -1275,85 +1251,30 @@ static int iwl_trans_pcie_request_irq(struct iwl_trans *trans) return 0; } -static int iwlagn_txq_check_empty(struct iwl_trans *trans, - int sta_id, u8 tid, int txq_id) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_queue *q = &trans_pcie->txq[txq_id].q; - struct iwl_tid_data *tid_data = &trans->shrd->tid_data[sta_id][tid]; - - lockdep_assert_held(&trans->shrd->sta_lock); - - switch (trans->shrd->tid_data[sta_id][tid].agg.state) { - case IWL_EMPTYING_HW_QUEUE_DELBA: - /* We are reclaiming the last packet of the */ - /* aggregated HW queue */ - if ((txq_id == tid_data->agg.txq_id) && - (q->read_ptr == q->write_ptr)) { - IWL_DEBUG_TX_QUEUES(trans, - "HW queue empty: continue DELBA flow\n"); - iwl_trans_pcie_txq_agg_disable(trans, txq_id); - tid_data->agg.state = IWL_AGG_OFF; - iwl_stop_tx_ba_trans_ready(priv(trans), - NUM_IWL_RXON_CTX, - sta_id, tid); - iwl_wake_queue(trans, &trans_pcie->txq[txq_id], - "DELBA flow complete"); - } - break; - case IWL_EMPTYING_HW_QUEUE_ADDBA: - /* We are reclaiming the last packet of the queue */ - if (tid_data->tfds_in_queue == 0) { - IWL_DEBUG_TX_QUEUES(trans, - "HW queue empty: continue ADDBA flow\n"); - tid_data->agg.state = IWL_AGG_ON; - iwl_start_tx_ba_trans_ready(priv(trans), - NUM_IWL_RXON_CTX, - sta_id, tid); - } - break; - default: - break; - } - - return 0; -} - -static void iwl_free_tfds_in_queue(struct iwl_trans *trans, - int sta_id, int tid, int freed) -{ - lockdep_assert_held(&trans->shrd->sta_lock); - - if (trans->shrd->tid_data[sta_id][tid].tfds_in_queue >= freed) - trans->shrd->tid_data[sta_id][tid].tfds_in_queue -= freed; - else { - IWL_DEBUG_TX(trans, "free more than tfds_in_queue (%u:%d)\n", - trans->shrd->tid_data[sta_id][tid].tfds_in_queue, - freed); - trans->shrd->tid_data[sta_id][tid].tfds_in_queue = 0; - } -} - -static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid, +static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid, int txq_id, int ssn, u32 status, struct sk_buff_head *skbs) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; - enum iwl_agg_state agg_state; /* n_bd is usually 256 => n_bd - 1 = 0xff */ int tfd_num = ssn & (txq->q.n_bd - 1); int freed = 0; - bool cond; txq->time_stamp = jiffies; - if (txq->sched_retry) { - agg_state = - trans->shrd->tid_data[txq->sta_id][txq->tid].agg.state; - cond = (agg_state != IWL_EMPTYING_HW_QUEUE_DELBA); - } else { - cond = (status != TX_STATUS_FAIL_PASSIVE_NO_RX); + if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE && + txq_id != trans_pcie->agg_txq[sta_id][tid])) { + /* + * FIXME: this is a uCode bug which need to be addressed, + * log the information and return for now. + * Since it is can possibly happen very often and in order + * not to fill the syslog, don't use IWL_ERR or IWL_WARN + */ + IWL_DEBUG_TX_QUEUES(trans, "Bad queue mapping txq_id %d, " + "agg_txq[sta_id[tid] %d", txq_id, + trans_pcie->agg_txq[sta_id][tid]); + return 1; } if (txq->q.read_ptr != tfd_num) { @@ -1361,12 +1282,12 @@ static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid, txq_id, iwl_get_queue_ac(txq), txq->q.read_ptr, tfd_num, ssn); freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs); - if (iwl_queue_space(&txq->q) > txq->q.low_mark && cond) + if (iwl_queue_space(&txq->q) > txq->q.low_mark && + (!txq->sched_retry || + status != TX_STATUS_FAIL_PASSIVE_NO_RX)) iwl_wake_queue(trans, txq, "Packets reclaimed"); } - - iwl_free_tfds_in_queue(trans, sta_id, tid, freed); - iwlagn_txq_check_empty(trans, sta_id, tid, txq_id); + return 0; } static void iwl_trans_pcie_free(struct iwl_trans *trans) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index f94a6ee5f82..e6bf3f55477 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -178,20 +178,18 @@ struct iwl_trans_ops { int (*tx)(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx, - u8 sta_id); - void (*reclaim)(struct iwl_trans *trans, int sta_id, int tid, + u8 sta_id, u8 tid); + int (*reclaim)(struct iwl_trans *trans, int sta_id, int tid, int txq_id, int ssn, u32 status, struct sk_buff_head *skbs); int (*tx_agg_disable)(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx, int sta_id, - int tid); + int sta_id, int tid); int (*tx_agg_alloc)(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx, int sta_id, int tid, - u16 *ssn); + int sta_id, int tid); void (*tx_agg_setup)(struct iwl_trans *trans, enum iwl_rxon_context_id ctx, int sta_id, int tid, - int frame_limit); + int frame_limit, u16 ssn); void (*kick_nic)(struct iwl_trans *trans); @@ -305,39 +303,38 @@ int iwl_trans_send_cmd_pdu(struct iwl_trans *trans, u8 id, static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx, - u8 sta_id) + u8 sta_id, u8 tid) { - return trans->ops->tx(trans, skb, dev_cmd, ctx, sta_id); + return trans->ops->tx(trans, skb, dev_cmd, ctx, sta_id, tid); } -static inline void iwl_trans_reclaim(struct iwl_trans *trans, int sta_id, +static inline int iwl_trans_reclaim(struct iwl_trans *trans, int sta_id, int tid, int txq_id, int ssn, u32 status, struct sk_buff_head *skbs) { - trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn, status, skbs); + return trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn, + status, skbs); } static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx, int sta_id, int tid) { - return trans->ops->tx_agg_disable(trans, ctx, sta_id, tid); + return trans->ops->tx_agg_disable(trans, sta_id, tid); } static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx, - int sta_id, int tid, u16 *ssn) + int sta_id, int tid) { - return trans->ops->tx_agg_alloc(trans, ctx, sta_id, tid, ssn); + return trans->ops->tx_agg_alloc(trans, sta_id, tid); } static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans, enum iwl_rxon_context_id ctx, int sta_id, int tid, - int frame_limit) + int frame_limit, u16 ssn) { - trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit); + trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit, ssn); } static inline void iwl_trans_kick_nic(struct iwl_trans *trans) diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index 0577212ad3f..36a1b5b2585 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -33,6 +33,7 @@ #include <linux/sched.h> #include <linux/dma-mapping.h> +#include "iwl-wifi.h" #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" @@ -213,23 +214,23 @@ static int iwl_load_given_ucode(struct iwl_trans *trans, /* * Calibration */ -static int iwl_set_Xtal_calib(struct iwl_priv *priv) +static int iwl_set_Xtal_calib(struct iwl_trans *trans) { struct iwl_calib_xtal_freq_cmd cmd; __le16 *xtal_calib = - (__le16 *)iwl_eeprom_query_addr(priv->shrd, EEPROM_XTAL); + (__le16 *)iwl_eeprom_query_addr(trans->shrd, EEPROM_XTAL); iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD); cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]); cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]); - return iwl_calib_set(trans(priv), (void *)&cmd, sizeof(cmd)); + return iwl_calib_set(trans, (void *)&cmd, sizeof(cmd)); } -static int iwl_set_temperature_offset_calib(struct iwl_priv *priv) +static int iwl_set_temperature_offset_calib(struct iwl_trans *trans) { struct iwl_calib_temperature_offset_cmd cmd; __le16 *offset_calib = - (__le16 *)iwl_eeprom_query_addr(priv->shrd, + (__le16 *)iwl_eeprom_query_addr(trans->shrd, EEPROM_RAW_TEMPERATURE); memset(&cmd, 0, sizeof(cmd)); @@ -238,45 +239,45 @@ static int iwl_set_temperature_offset_calib(struct iwl_priv *priv) if (!(cmd.radio_sensor_offset)) cmd.radio_sensor_offset = DEFAULT_RADIO_SENSOR_OFFSET; - IWL_DEBUG_CALIB(priv, "Radio sensor offset: %d\n", + IWL_DEBUG_CALIB(trans, "Radio sensor offset: %d\n", le16_to_cpu(cmd.radio_sensor_offset)); - return iwl_calib_set(trans(priv), (void *)&cmd, sizeof(cmd)); + return iwl_calib_set(trans, (void *)&cmd, sizeof(cmd)); } -static int iwl_set_temperature_offset_calib_v2(struct iwl_priv *priv) +static int iwl_set_temperature_offset_calib_v2(struct iwl_trans *trans) { struct iwl_calib_temperature_offset_v2_cmd cmd; - __le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(priv->shrd, + __le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(trans->shrd, EEPROM_KELVIN_TEMPERATURE); __le16 *offset_calib_low = - (__le16 *)iwl_eeprom_query_addr(priv->shrd, + (__le16 *)iwl_eeprom_query_addr(trans->shrd, EEPROM_RAW_TEMPERATURE); struct iwl_eeprom_calib_hdr *hdr; memset(&cmd, 0, sizeof(cmd)); iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD); - hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv->shrd, + hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(trans->shrd, EEPROM_CALIB_ALL); memcpy(&cmd.radio_sensor_offset_high, offset_calib_high, sizeof(*offset_calib_high)); memcpy(&cmd.radio_sensor_offset_low, offset_calib_low, sizeof(*offset_calib_low)); if (!(cmd.radio_sensor_offset_low)) { - IWL_DEBUG_CALIB(priv, "no info in EEPROM, use default\n"); + IWL_DEBUG_CALIB(trans, "no info in EEPROM, use default\n"); cmd.radio_sensor_offset_low = DEFAULT_RADIO_SENSOR_OFFSET; cmd.radio_sensor_offset_high = DEFAULT_RADIO_SENSOR_OFFSET; } memcpy(&cmd.burntVoltageRef, &hdr->voltage, sizeof(hdr->voltage)); - IWL_DEBUG_CALIB(priv, "Radio sensor offset high: %d\n", + IWL_DEBUG_CALIB(trans, "Radio sensor offset high: %d\n", le16_to_cpu(cmd.radio_sensor_offset_high)); - IWL_DEBUG_CALIB(priv, "Radio sensor offset low: %d\n", + IWL_DEBUG_CALIB(trans, "Radio sensor offset low: %d\n", le16_to_cpu(cmd.radio_sensor_offset_low)); - IWL_DEBUG_CALIB(priv, "Voltage Ref: %d\n", + IWL_DEBUG_CALIB(trans, "Voltage Ref: %d\n", le16_to_cpu(cmd.burntVoltageRef)); - return iwl_calib_set(trans(priv), (void *)&cmd, sizeof(cmd)); + return iwl_calib_set(trans, (void *)&cmd, sizeof(cmd)); } static int iwl_send_calib_cfg(struct iwl_trans *trans) @@ -316,26 +317,26 @@ int iwlagn_rx_calib_result(struct iwl_priv *priv, return 0; } -int iwlagn_init_alive_start(struct iwl_priv *priv) +int iwl_init_alive_start(struct iwl_trans *trans) { int ret; - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) { + if (cfg(trans)->bt_params && + cfg(trans)->bt_params->advanced_bt_coexist) { /* * Tell uCode we are ready to perform calibration * need to perform this before any calibration * no need to close the envlope since we are going * to load the runtime uCode later. */ - ret = iwl_send_bt_env(trans(priv), IWL_BT_COEX_ENV_OPEN, + ret = iwl_send_bt_env(trans, IWL_BT_COEX_ENV_OPEN, BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); if (ret) return ret; } - ret = iwl_send_calib_cfg(trans(priv)); + ret = iwl_send_calib_cfg(trans); if (ret) return ret; @@ -343,21 +344,21 @@ int iwlagn_init_alive_start(struct iwl_priv *priv) * temperature offset calibration is only needed for runtime ucode, * so prepare the value now. */ - if (priv->cfg->need_temp_offset_calib) { - if (priv->cfg->temp_offset_v2) - return iwl_set_temperature_offset_calib_v2(priv); + if (cfg(trans)->need_temp_offset_calib) { + if (cfg(trans)->temp_offset_v2) + return iwl_set_temperature_offset_calib_v2(trans); else - return iwl_set_temperature_offset_calib(priv); + return iwl_set_temperature_offset_calib(trans); } return 0; } -static int iwl_send_wimax_coex(struct iwl_priv *priv) +static int iwl_send_wimax_coex(struct iwl_trans *trans) { struct iwl_wimax_coex_cmd coex_cmd; - if (priv->cfg->base_params->support_wimax_coexist) { + if (cfg(trans)->base_params->support_wimax_coexist) { /* UnMask wake up src at associated sleep */ coex_cmd.flags = COEX_FLAGS_ASSOC_WA_UNMASK_MSK; @@ -376,7 +377,7 @@ static int iwl_send_wimax_coex(struct iwl_priv *priv) /* coexistence is disabled */ memset(&coex_cmd, 0, sizeof(coex_cmd)); } - return iwl_trans_send_cmd_pdu(trans(priv), + return iwl_trans_send_cmd_pdu(trans, COEX_PRIORITY_TABLE_CMD, CMD_SYNC, sizeof(coex_cmd), &coex_cmd); } @@ -431,8 +432,9 @@ int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type) } -static int iwl_alive_notify(struct iwl_priv *priv) +static int iwl_alive_notify(struct iwl_trans *trans) { + struct iwl_priv *priv = priv(trans); struct iwl_rxon_context *ctx; int ret; @@ -445,21 +447,21 @@ static int iwl_alive_notify(struct iwl_priv *priv) if (!priv->tx_cmd_pool) return -ENOMEM; - iwl_trans_tx_start(trans(priv)); + iwl_trans_tx_start(trans); for_each_context(priv, ctx) ctx->last_tx_rejected = false; - ret = iwl_send_wimax_coex(priv); + ret = iwl_send_wimax_coex(trans); if (ret) return ret; - if (!priv->cfg->no_xtal_calib) { - ret = iwl_set_Xtal_calib(priv); + if (!cfg(priv)->no_xtal_calib) { + ret = iwl_set_Xtal_calib(trans); if (ret) return ret; } - return iwl_send_calib_results(trans(priv)); + return iwl_send_calib_results(trans); } @@ -545,7 +547,7 @@ static int iwl_verify_ucode(struct iwl_trans *trans, return -EIO; } -struct iwlagn_alive_data { +struct iwl_alive_data { bool valid; u8 subtype; }; @@ -554,7 +556,7 @@ static void iwl_alive_fn(struct iwl_trans *trans, struct iwl_rx_packet *pkt, void *data) { - struct iwlagn_alive_data *alive_data = data; + struct iwl_alive_data *alive_data = data; struct iwl_alive_resp *palive; palive = &pkt->u.alive_frame; @@ -640,12 +642,11 @@ void iwl_abort_notification_waits(struct iwl_shared *shrd) #define UCODE_ALIVE_TIMEOUT HZ #define UCODE_CALIB_TIMEOUT (2*HZ) -int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, +int iwl_load_ucode_wait_alive(struct iwl_trans *trans, enum iwl_ucode_type ucode_type) { struct iwl_notification_wait alive_wait; - struct iwlagn_alive_data alive_data; - struct iwl_trans *trans = trans(priv); + struct iwl_alive_data alive_data; int ret; enum iwl_ucode_type old_type; @@ -680,7 +681,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, } if (!alive_data.valid) { - IWL_ERR(priv, "Loaded ucode is not valid!\n"); + IWL_ERR(trans, "Loaded ucode is not valid!\n"); trans->shrd->ucode_type = old_type; return -EIO; } @@ -701,9 +702,9 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, msleep(5); } - ret = iwl_alive_notify(priv); + ret = iwl_alive_notify(trans); if (ret) { - IWL_WARN(priv, + IWL_WARN(trans, "Could not complete ALIVE transition: %d\n", ret); trans->shrd->ucode_type = old_type; return ret; @@ -712,30 +713,30 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, return 0; } -int iwlagn_run_init_ucode(struct iwl_priv *priv) +int iwl_run_init_ucode(struct iwl_trans *trans) { struct iwl_notification_wait calib_wait; int ret; - lockdep_assert_held(&priv->shrd->mutex); + lockdep_assert_held(&trans->shrd->mutex); /* No init ucode required? Curious, but maybe ok */ - if (!trans(priv)->ucode_init.code.len) + if (!trans->ucode_init.code.len) return 0; - if (priv->shrd->ucode_type != IWL_UCODE_NONE) + if (trans->shrd->ucode_type != IWL_UCODE_NONE) return 0; - iwl_init_notification_wait(priv->shrd, &calib_wait, + iwl_init_notification_wait(trans->shrd, &calib_wait, CALIBRATION_COMPLETE_NOTIFICATION, NULL, NULL); /* Will also start the device */ - ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_INIT); + ret = iwl_load_ucode_wait_alive(trans, IWL_UCODE_INIT); if (ret) goto error; - ret = iwlagn_init_alive_start(priv); + ret = iwl_init_alive_start(trans); if (ret) goto error; @@ -743,15 +744,15 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv) * Some things may run in the background now, but we * just wait for the calibration complete notification. */ - ret = iwl_wait_notification(priv->shrd, &calib_wait, + ret = iwl_wait_notification(trans->shrd, &calib_wait, UCODE_CALIB_TIMEOUT); goto out; error: - iwl_remove_notification(priv->shrd, &calib_wait); + iwl_remove_notification(trans->shrd, &calib_wait); out: /* Whatever happened, stop the device */ - iwl_trans_stop_device(trans(priv)); + iwl_trans_stop_device(trans); return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-wifi.h b/drivers/net/wireless/iwlwifi/iwl-wifi.h new file mode 100644 index 00000000000..18501101a53 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-wifi.h @@ -0,0 +1,74 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifndef __iwl_wifi_h__ +#define __iwl_wifi_h__ + +#include "iwl-shared.h" + +int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type); +void iwl_send_prio_tbl(struct iwl_trans *trans); +int iwl_init_alive_start(struct iwl_trans *trans); +int iwl_run_init_ucode(struct iwl_trans *trans); +int iwl_load_ucode_wait_alive(struct iwl_trans *trans, + enum iwl_ucode_type ucode_type); +#endif /* __iwl_wifi_h__ */ |