diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
42 files changed, 1902 insertions, 1048 deletions
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 9dc84a7354db..afa0bb8f3245 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,7 +1,7 @@ # WIFI obj-$(CONFIG_IWLWIFI) += iwlwifi.o iwlwifi-objs := iwl-agn.o iwl-agn-rs.o iwl-mac80211.o -iwlwifi-objs += iwl-ucode.o iwl-agn-tx.o +iwlwifi-objs += iwl-ucode.o iwl-agn-tx.o iwl-debug.o iwlwifi-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o @@ -13,6 +13,7 @@ iwlwifi-objs += iwl-6000.o iwlwifi-objs += iwl-1000.o iwlwifi-objs += iwl-2000.o iwlwifi-objs += iwl-pci.o +iwlwifi-objs += iwl-drv.o iwlwifi-objs += iwl-trans.o iwlwifi-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 8c1466c907ff..605ee3df1d82 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -120,7 +120,7 @@ static struct iwl_sensitivity_ranges iwl1000_sensitivity = { .nrg_th_cca = 62, }; -static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) +static void 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) @@ -128,8 +128,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ); @@ -146,8 +144,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl1000_sensitivity; - - return 0; } static struct iwl_lib_ops iwl1000_lib = { @@ -193,6 +189,8 @@ static struct iwl_ht_params iwl1000_ht_params = { .ucode_api_max = IWL1000_UCODE_API_MAX, \ .ucode_api_ok = IWL1000_UCODE_API_OK, \ .ucode_api_min = IWL1000_UCODE_API_MIN, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .lib = &iwl1000_lib, \ @@ -215,6 +213,8 @@ struct iwl_cfg iwl1000_bg_cfg = { .ucode_api_max = IWL100_UCODE_API_MAX, \ .ucode_api_ok = IWL100_UCODE_API_OK, \ .ucode_api_min = IWL100_UCODE_API_MIN, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .lib = &iwl1000_lib, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index d4f5f3b87578..e6e8c79a80d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -116,7 +116,7 @@ static struct iwl_sensitivity_ranges iwl2000_sensitivity = { .nrg_th_cca = 62, }; -static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) +static void 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) @@ -124,8 +124,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWL60_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ); @@ -142,8 +140,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl2000_sensitivity; - - return 0; } static struct iwl_lib_ops iwl2000_lib = { @@ -242,6 +238,8 @@ static struct iwl_bt_params iwl2030_bt_params = { .ucode_api_max = IWL2000_UCODE_API_MAX, \ .ucode_api_ok = IWL2000_UCODE_API_OK, \ .ucode_api_min = IWL2000_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .lib = &iwl2000_lib, \ @@ -268,6 +266,8 @@ struct iwl_cfg iwl2000_2bgn_d_cfg = { .ucode_api_max = IWL2030_UCODE_API_MAX, \ .ucode_api_ok = IWL2030_UCODE_API_OK, \ .ucode_api_min = IWL2030_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .lib = &iwl2030_lib, \ @@ -290,6 +290,8 @@ struct iwl_cfg iwl2030_2bgn_cfg = { .ucode_api_max = IWL105_UCODE_API_MAX, \ .ucode_api_ok = IWL105_UCODE_API_OK, \ .ucode_api_min = IWL105_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .lib = &iwl2000_lib, \ @@ -318,6 +320,8 @@ struct iwl_cfg iwl105_bgn_d_cfg = { .ucode_api_max = IWL135_UCODE_API_MAX, \ .ucode_api_ok = IWL135_UCODE_API_OK, \ .ucode_api_min = IWL135_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .lib = &iwl2030_lib, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index dc9317d0343e..1527dec7a267 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -162,7 +162,7 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv) hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; } -static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) +static void 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) @@ -170,8 +170,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); @@ -185,11 +183,9 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl5000_sensitivity; - - return 0; } -static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) +static void 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) @@ -197,8 +193,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); @@ -212,8 +206,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl5150_sensitivity; - - return 0; } static void iwl5150_temperature(struct iwl_priv *priv) @@ -356,6 +348,8 @@ static struct iwl_ht_params iwl5000_ht_params = { .fw_name_pre = IWL5000_FW_PRE, \ .ucode_api_max = IWL5000_UCODE_API_MAX, \ .ucode_api_min = IWL5000_UCODE_API_MIN, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_5000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, \ .lib = &iwl5000_lib, \ @@ -399,6 +393,8 @@ struct iwl_cfg iwl5350_agn_cfg = { .fw_name_pre = IWL5000_FW_PRE, .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_min = IWL5000_UCODE_API_MIN, + .max_inst_size = IWLAGN_RTC_INST_SIZE, + .max_data_size = IWLAGN_RTC_DATA_SIZE, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, .lib = &iwl5000_lib, @@ -412,6 +408,8 @@ struct iwl_cfg iwl5350_agn_cfg = { .fw_name_pre = IWL5150_FW_PRE, \ .ucode_api_max = IWL5150_UCODE_API_MAX, \ .ucode_api_min = IWL5150_UCODE_API_MIN, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_5050_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ .lib = &iwl5150_lib, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index c36fb858a45b..223e60a1b79d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -137,7 +137,7 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { .nrg_th_cca = 62, }; -static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) +static void 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) @@ -145,8 +145,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) iwlagn_mod_params.num_of_queues; hw_params(priv).max_txq_num = cfg(priv)->base_params->num_of_queues; - hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE; - hw_params(priv).max_inst_size = IWL60_RTC_INST_SIZE; hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); @@ -165,7 +163,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ hw_params(priv).sens = &iwl6000_sensitivity; - return 0; } static int iwl6000_hw_channel_switch(struct iwl_priv *priv, @@ -349,6 +346,8 @@ static struct iwl_bt_params iwl6000_bt_params = { .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ .ucode_api_ok = IWL6000G2_UCODE_API_OK, \ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_6005_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ .lib = &iwl6000_lib, \ @@ -384,11 +383,24 @@ struct iwl_cfg iwl6005_2agn_d_cfg = { .ht_params = &iwl6000_ht_params, }; +struct iwl_cfg iwl6005_2agn_mow1_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6206 AGN", + IWL_DEVICE_6005, + .ht_params = &iwl6000_ht_params, +}; +struct iwl_cfg iwl6005_2agn_mow2_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6207 AGN", + IWL_DEVICE_6005, + .ht_params = &iwl6000_ht_params, +}; + #define IWL_DEVICE_6030 \ .fw_name_pre = IWL6030_FW_PRE, \ .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ .ucode_api_ok = IWL6000G2_UCODE_API_OK, \ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_6030_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ .lib = &iwl6030_lib, \ @@ -458,6 +470,8 @@ struct iwl_cfg iwl130_bg_cfg = { .ucode_api_max = IWL6000_UCODE_API_MAX, \ .ucode_api_ok = IWL6000_UCODE_API_OK, \ .ucode_api_min = IWL6000_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .valid_tx_ant = ANT_BC, /* .cfg overwrite */ \ .valid_rx_ant = ANT_BC, /* .cfg overwrite */ \ .eeprom_ver = EEPROM_6000_EEPROM_VERSION, \ @@ -487,6 +501,8 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .fw_name_pre = IWL6050_FW_PRE, \ .ucode_api_max = IWL6050_UCODE_API_MAX, \ .ucode_api_min = IWL6050_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .valid_tx_ant = ANT_AB, /* .cfg overwrite */ \ .valid_rx_ant = ANT_AB, /* .cfg overwrite */ \ .lib = &iwl6000_lib, \ @@ -512,6 +528,8 @@ struct iwl_cfg iwl6050_2abg_cfg = { .fw_name_pre = IWL6050_FW_PRE, \ .ucode_api_max = IWL6050_UCODE_API_MAX, \ .ucode_api_min = IWL6050_UCODE_API_MIN, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ .lib = &iwl6000_lib, \ .additional_nic_config = iwl6150_additional_nic_config, \ .eeprom_ver = EEPROM_6150_EEPROM_VERSION, \ @@ -537,6 +555,8 @@ struct iwl_cfg iwl6000_3agn_cfg = { .ucode_api_max = IWL6000_UCODE_API_MAX, .ucode_api_ok = IWL6000_UCODE_API_OK, .ucode_api_min = IWL6000_UCODE_API_MIN, + .max_inst_size = IWL60_RTC_INST_SIZE, + .max_data_size = IWL60_RTC_DATA_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, .lib = &iwl6000_lib, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 6aa009827865..988ee454a944 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -68,6 +68,8 @@ #include "iwl-agn-calib.h" #include "iwl-trans.h" #include "iwl-agn.h" +#include "iwl-wifi.h" +#include "iwl-ucode.h" /***************************************************************************** * INIT calibrations framework @@ -634,7 +636,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv) data->last_bad_plcp_cnt_cck = 0; data->last_fa_cnt_cck = 0; - if (priv->enhance_sensitivity_table) + if (nic(priv)->fw.enhance_sensitivity_table) ret |= iwl_enhance_sensitivity_write(priv); else ret |= iwl_sensitivity_write(priv); @@ -745,7 +747,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv) iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time); iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis); - if (priv->enhance_sensitivity_table) + if (nic(priv)->fw.enhance_sensitivity_table) iwl_enhance_sensitivity_write(priv); else iwl_sensitivity_write(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index a8f7689aaacf..5be0d3695d03 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -77,7 +77,7 @@ int iwlagn_send_tx_power(struct iwl_priv *priv) tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED; tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO; - if (IWL_UCODE_API(priv->ucode_ver) == 1) + if (IWL_UCODE_API(nic(priv)->fw.ucode_ver) == 1) tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1; else tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD; @@ -700,7 +700,7 @@ static void iwlagn_set_kill_msk(struct iwl_priv *priv, priv->kill_cts_mask = bt_kill_cts_msg[kill_msk]; /* schedule to send runtime bt_config */ - queue_work(priv->shrd->workqueue, &priv->bt_runtime_config); + queue_work(priv->workqueue, &priv->bt_runtime_config); } } @@ -745,7 +745,7 @@ int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, IWL_BT_COEX_TRAFFIC_LOAD_NONE; } priv->bt_status = coex->bt_status; - queue_work(priv->shrd->workqueue, + queue_work(priv->workqueue, &priv->bt_traffic_change_work); } } @@ -959,7 +959,7 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw, struct ieee80211_key_conf *key, void *_data) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct wowlan_key_data *data = _data; struct iwl_rxon_context *ctx = data->ctx; struct aes_sc *aes_sc, *aes_tx_sc = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index b9ba404d15c1..a7d67135e3dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -38,6 +38,7 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-agn.h" +#include "iwl-op-mode.h" #define RS_NAME "iwl-agn-rs" @@ -892,7 +893,7 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, rs_fill_link_cmd(priv, lq_sta, tbl->current_rate); iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false); - queue_work(priv->shrd->workqueue, &priv->bt_full_concurrency); + queue_work(priv->workqueue, &priv->bt_full_concurrency); } } @@ -909,7 +910,8 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_link_quality_cmd *table; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl_priv *priv = (struct iwl_priv *)priv_r; + struct iwl_op_mode *op_mode = (struct iwl_op_mode *)priv_r; + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); enum mac80211_rate_control_flags mac_flags; u32 tx_rate; @@ -2737,7 +2739,9 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb = txrc->skb; struct ieee80211_supported_band *sband = txrc->sband; - struct iwl_priv *priv __maybe_unused = (struct iwl_priv *)priv_r; + struct iwl_op_mode *op_mode __maybe_unused = + (struct iwl_op_mode *)priv_r; + struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = priv_sta; int rate_idx; @@ -2805,9 +2809,10 @@ static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, gfp_t gfp) { struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv; - struct iwl_priv *priv; + struct iwl_op_mode *op_mode __maybe_unused = + (struct iwl_op_mode *)priv_rate; + struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode); - priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE(priv, "create station rate scale window\n"); return &sta_priv->lq_sta; @@ -3074,7 +3079,8 @@ static void rs_free(void *priv_rate) static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta, void *priv_sta) { - struct iwl_priv *priv __maybe_unused = priv_r; + struct iwl_op_mode *op_mode __maybe_unused = priv_r; + struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode); IWL_DEBUG_RATE(priv, "enter\n"); IWL_DEBUG_RATE(priv, "leave\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index a14ddab783ea..30bb5bbb0cd7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c @@ -581,7 +581,7 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv, if (unlikely(!test_bit(STATUS_SCANNING, &priv->shrd->status)) && (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { iwlagn_rx_calc_noise(priv); - queue_work(priv->shrd->workqueue, &priv->run_time_calib_work); + queue_work(priv->workqueue, &priv->run_time_calib_work); } if (cfg(priv)->lib->temperature && change) cfg(priv)->lib->temperature(priv); @@ -1141,10 +1141,11 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) } -int iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, +int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_mem_buffer *rxb, struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); int err = 0; /* diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 8ca9570ec365..73653a6cf32d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -549,7 +549,7 @@ void iwlagn_config_ht40(struct ieee80211_conf *conf, int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx; struct ieee80211_conf *conf = &hw->conf; struct ieee80211_channel *channel = conf->channel; @@ -805,7 +805,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changes) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); int ret; bool force = false; @@ -900,6 +900,22 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, } } + /* + * If the ucode decides to do beacon filtering before + * association, it will lose beacons that are needed + * before sending frames out on passive channels. This + * causes association failures on those channels. Enable + * receiving beacons in such cases. + */ + + if (vif->type == NL80211_IFTYPE_STATION) { + if (!bss_conf->assoc) + ctx->staging.filter_flags |= RXON_FILTER_BCON_AWARE_MSK; + else + ctx->staging.filter_flags &= + ~RXON_FILTER_BCON_AWARE_MSK; + } + if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) iwlagn_commit_rxon(priv, ctx); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c index c728ed75584e..56d7c0e38163 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c @@ -568,7 +568,7 @@ void iwl_tt_enter_ct_kill(struct iwl_priv *priv) return; IWL_DEBUG_TEMP(priv, "Queueing critical temperature enter.\n"); - queue_work(priv->shrd->workqueue, &priv->ct_enter); + queue_work(priv->workqueue, &priv->ct_enter); } void iwl_tt_exit_ct_kill(struct iwl_priv *priv) @@ -577,7 +577,7 @@ void iwl_tt_exit_ct_kill(struct iwl_priv *priv) return; IWL_DEBUG_TEMP(priv, "Queueing critical temperature exit.\n"); - queue_work(priv->shrd->workqueue, &priv->ct_exit); + queue_work(priv->workqueue, &priv->ct_exit); } static void iwl_bg_tt_work(struct work_struct *work) @@ -600,7 +600,7 @@ void iwl_tt_handler(struct iwl_priv *priv) return; IWL_DEBUG_TEMP(priv, "Queueing thermal throttling work.\n"); - queue_work(priv->shrd->workqueue, &priv->tt_work); + queue_work(priv->workqueue, &priv->tt_work); } /* Thermal throttling initialization diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 64f8db685dc5..5f78567f4180 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -322,7 +322,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) sta_priv = (void *)info->control.sta->drv_priv; if (sta_priv && sta_priv->asleep && - (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) { + (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) { /* * This sends an asynchronous command to the device, * but we can rely on it being processed before the @@ -331,6 +331,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) * counter. * For now set the counter to just 1 since we do not * support uAPSD yet. + * + * FIXME: If we get two non-bufferable frames one + * after the other, we might only send out one of + * them because this is racy. */ iwl_sta_modify_sleep_tx_count(priv, sta_id, 1); } @@ -983,7 +987,7 @@ static void iwl_check_abort_status(struct iwl_priv *priv, if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) { IWL_ERR(priv, "Tx flush command to flush out all frames\n"); if (!test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) - queue_work(priv->shrd->workqueue, &priv->tx_flush); + queue_work(priv->workqueue, &priv->tx_flush); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 8837171ad553..e0fef9f257c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -50,8 +50,8 @@ #include "iwl-agn-calib.h" #include "iwl-agn.h" #include "iwl-shared.h" -#include "iwl-bus.h" #include "iwl-trans.h" +#include "iwl-op-mode.h" /****************************************************************************** * @@ -618,7 +618,7 @@ static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) .valid = cpu_to_le32(valid_tx_ant), }; - if (IWL_UCODE_API(priv->ucode_ver) > 1) { + if (IWL_UCODE_API(nic(priv)->fw.ucode_ver) > 1) { IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant); return iwl_trans_send_cmd_pdu(trans(priv), TX_ANT_CONFIGURATION_CMD, @@ -738,14 +738,14 @@ int iwl_alive_start(struct iwl_priv *priv) return iwl_power_update_mode(priv, true); } -static void iwl_cancel_deferred_work(struct iwl_priv *priv); - -void __iwl_down(struct iwl_priv *priv) +void iwl_down(struct iwl_priv *priv) { int exit_pending; IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); + lockdep_assert_held(&priv->shrd->mutex); + iwl_scan_cancel_timeout(priv, 200); /* @@ -803,15 +803,6 @@ void __iwl_down(struct iwl_priv *priv) priv->beacon_skb = NULL; } -void iwl_down(struct iwl_priv *priv) -{ - mutex_lock(&priv->shrd->mutex); - __iwl_down(priv); - mutex_unlock(&priv->shrd->mutex); - - iwl_cancel_deferred_work(priv); -} - /***************************************************************************** * * Workqueue callbacks @@ -869,7 +860,7 @@ void iwlagn_prepare_restart(struct iwl_priv *priv) bt_status = priv->bt_status; bt_is_sco = priv->bt_is_sco; - __iwl_down(priv); + iwl_down(priv); priv->bt_full_concurrent = bt_full_concurrent; priv->bt_ci_compliance = bt_ci_compliance; @@ -939,7 +930,7 @@ static void iwlagn_disable_roc_work(struct work_struct *work) static void iwl_setup_deferred_work(struct iwl_priv *priv) { - priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME); + priv->workqueue = create_singlethread_workqueue(DRV_NAME); init_waitqueue_head(&priv->shrd->wait_command_queue); @@ -970,7 +961,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) priv->watchdog.function = iwl_bg_watchdog; } -static void iwl_cancel_deferred_work(struct iwl_priv *priv) +void iwl_cancel_deferred_work(struct iwl_priv *priv) { if (cfg(priv)->lib->cancel_deferred_work) cfg(priv)->lib->cancel_deferred_work(priv); @@ -1091,7 +1082,7 @@ static void iwl_uninit_drv(struct iwl_priv *priv) #define IWL_RX_BUF_SIZE_4K (4 * 1024) #define IWL_RX_BUF_SIZE_8K (8 * 1024) -static int iwl_set_hw_params(struct iwl_priv *priv) +static void iwl_set_hw_params(struct iwl_priv *priv) { if (iwlagn_mod_params.amsdu_size_8K) hw_params(priv).rx_page_order = @@ -1111,7 +1102,7 @@ static int iwl_set_hw_params(struct iwl_priv *priv) hw_params(priv).wd_timeout = cfg(priv)->base_params->wd_timeout; /* Device-specific setup */ - return cfg(priv)->lib->set_hw_params(priv); + cfg(priv)->lib->set_hw_params(priv); } @@ -1151,37 +1142,43 @@ static void iwl_debug_config(struct iwl_priv *priv) #endif } -int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, - struct iwl_cfg *cfg) +static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans) { + struct iwl_fw *fw = &nic(trans)->fw; int err = 0; struct iwl_priv *priv; struct ieee80211_hw *hw; + struct iwl_op_mode *op_mode; u16 num_mac; + u32 ucode_flags; /************************ * 1. Allocating HW data ************************/ hw = iwl_alloc_all(); if (!hw) { - pr_err("%s: Cannot allocate network device\n", cfg->name); + pr_err("%s: Cannot allocate network device\n", + cfg(trans)->name); err = -ENOMEM; goto out; } - priv = hw->priv; - priv->shrd = bus->shrd; + op_mode = hw->priv; + op_mode->ops = &iwl_dvm_ops; + priv = IWL_OP_MODE_GET_DVM(op_mode); + priv->shrd = trans->shrd; priv->shrd->priv = priv; + iwl_trans_configure(trans(priv), op_mode); + /* At this point both hw and priv are allocated. */ - SET_IEEE80211_DEV(hw, trans(priv)->dev); + SET_IEEE80211_DEV(priv->hw, trans(priv)->dev); /* show what debugging capabilities we have */ iwl_debug_config(priv); IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); - cfg(priv) = cfg; /* is antenna coupling more than 35dB ? */ priv->bt_ant_couple_ok = @@ -1217,7 +1214,7 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, * 4. Read EEPROM *****************/ /* Read the EEPROM */ - err = iwl_eeprom_init(priv, trans(priv)->hw_rev); + err = iwl_eeprom_init(trans(priv), trans(priv)->hw_rev); /* Reset chip to save power until we load uCode during "up". */ iwl_trans_stop_hw(trans(priv)); if (err) { @@ -1248,11 +1245,23 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, /************************ * 5. Setup HW constants ************************/ - if (iwl_set_hw_params(priv)) { - err = -ENOENT; - IWL_ERR(priv, "failed to set hw parameters\n"); - goto out_free_eeprom; - } + iwl_set_hw_params(priv); + + ucode_flags = fw->ucode_capa.flags; + +#ifndef CONFIG_IWLWIFI_P2P + ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN; +#endif + if (!(hw_params(priv).sku & EEPROM_SKU_CAP_IPAN_ENABLE)) + ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN; + + /* + * if not PAN, then don't support P2P -- might be a uCode + * packaging bug or due to the eeprom check above + */ + if (!(ucode_flags & IWL_UCODE_TLV_FLAGS_PAN)) + ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P; + /******************* * 6. Setup priv @@ -1273,17 +1282,49 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, iwl_power_initialize(priv); iwl_tt_initialize(priv); - init_completion(&priv->firmware_loading_complete); + snprintf(priv->hw->wiphy->fw_version, + sizeof(priv->hw->wiphy->fw_version), + "%s", fw->fw_version); + + priv->new_scan_threshold_behaviour = + !!(ucode_flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); + + if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) { + priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; + priv->shrd->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; + } else { + priv->sta_key_max_num = STA_KEY_MAX_NUM; + priv->shrd->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; + } + + priv->phy_calib_chain_noise_reset_cmd = + fw->ucode_capa.standard_phy_calibration_size; + priv->phy_calib_chain_noise_gain_cmd = + fw->ucode_capa.standard_phy_calibration_size + 1; - err = iwl_request_firmware(priv, true); + /* initialize all valid contexts */ + iwl_init_context(priv, ucode_flags); + + /************************************************** + * This is still part of probe() in a sense... + * + * 9. Setup and register with mac80211 and debugfs + **************************************************/ + err = iwlagn_mac_setup_register(priv, &fw->ucode_capa); if (err) goto out_destroy_workqueue; - return 0; + err = iwl_dbgfs_register(priv, DRV_NAME); + if (err) + IWL_ERR(priv, + "failed to create debugfs files. Ignoring error: %d\n", + err); + + return op_mode; out_destroy_workqueue: - destroy_workqueue(priv->shrd->workqueue); - priv->shrd->workqueue = NULL; + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; iwl_uninit_drv(priv); out_free_eeprom: iwl_eeprom_free(priv->shrd); @@ -1291,12 +1332,15 @@ out_free_traffic_mem: iwl_free_traffic_mem(priv); ieee80211_free_hw(priv->hw); out: - return err; + op_mode = NULL; + return op_mode; } -void __devexit iwl_remove(struct iwl_priv * priv) +static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) { - wait_for_completion(&priv->firmware_loading_complete); + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + + wait_for_completion(&nic(priv)->request_firmware_complete); IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); @@ -1316,18 +1360,18 @@ void __devexit iwl_remove(struct iwl_priv * priv) /*This will stop the queues, move the device to low power state */ iwl_trans_stop_device(trans(priv)); - iwl_dealloc_ucode(trans(priv)); + iwl_dealloc_ucode(nic(priv)); iwl_eeprom_free(priv->shrd); /*netif_stop_queue(dev); */ - flush_workqueue(priv->shrd->workqueue); + flush_workqueue(priv->workqueue); /* ieee80211_unregister_hw calls iwlagn_mac_stop, which flushes - * priv->shrd->workqueue... so we can't take down the workqueue + * priv->workqueue... so we can't take down the workqueue * until now... */ - destroy_workqueue(priv->shrd->workqueue); - priv->shrd->workqueue = NULL; + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; iwl_free_traffic_mem(priv); iwl_uninit_drv(priv); @@ -1337,6 +1381,16 @@ void __devexit iwl_remove(struct iwl_priv * priv) ieee80211_free_hw(priv->hw); } +const struct iwl_op_mode_ops iwl_dvm_ops = { + .start = iwl_op_mode_dvm_start, + .stop = iwl_op_mode_dvm_stop, + .rx = iwl_rx_dispatch, + .queue_full = iwl_stop_sw_queue, + .queue_not_full = iwl_wake_sw_queue, + .hw_rf_kill = iwl_set_hw_rfkill_state, + .free_skb = iwl_free_skb, + .nic_error = iwl_nic_error, +}; /***************************************************************************** * diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 37c325ff6e8c..cb484e273b93 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -65,11 +65,7 @@ #include "iwl-dev.h" -struct iwlagn_ucode_capabilities { - u32 max_probe_length; - u32 standard_phy_calibration_size; - u32 flags; -}; +struct iwl_ucode_capabilities; extern struct ieee80211_ops iwlagn_hw_ops; @@ -81,14 +77,23 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) hdr->data_valid = 1; } -void __iwl_down(struct iwl_priv *priv); void iwl_down(struct iwl_priv *priv); +void iwl_cancel_deferred_work(struct iwl_priv *priv); void iwlagn_prepare_restart(struct iwl_priv *priv); +void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb); +int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd); +void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac); +void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, u8 ac); +void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state); +void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac); +void iwl_nic_error(struct iwl_op_mode *op_mode); /* MAC80211 */ struct ieee80211_hw *iwl_alloc_all(void); int iwlagn_mac_setup_register(struct iwl_priv *priv, - struct iwlagn_ucode_capabilities *capa); + struct iwl_ucode_capabilities *capa); void iwlagn_mac_unregister(struct iwl_priv *priv); /* RXON */ @@ -387,4 +392,14 @@ void iwl_testmode_cleanup(struct iwl_priv *priv) } #endif +#ifdef CONFIG_IWLWIFI_DEBUG +void iwl_print_rx_config_cmd(struct iwl_priv *priv, + enum iwl_rxon_context_id ctxid); +#else +static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv, + enum iwl_rxon_context_id ctxid) +{ +} +#endif + #endif /* __iwl_agn_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-bus.h b/drivers/net/wireless/iwlwifi/iwl-bus.h deleted file mode 100644 index 30965e0e8ab4..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-bus.h +++ /dev/null @@ -1,145 +0,0 @@ -/****************************************************************************** - * - * 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) 2007 - 2012 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 - 2012 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_bus_h__ -#define __iwl_bus_h__ - -#include <linux/types.h> -#include <linux/spinlock.h> - -/** - * DOC: Bus layer - role and goal - * - * iwl-bus.h defines the API to the bus layer of the iwlwifi driver. - * The bus layer is responsible for doing very basic bus operations that are - * listed in the iwl_bus_ops structure. - * The bus layer registers to the bus driver, advertises the supported HW and - * gets notifications about enumeration, suspend, resume. - * For the moment, the bus layer is not a linux kernel module as itself, and - * the module_init function of the driver must call the bus specific - * registration functions. These functions are listed at the end of this file. - * For the moment, there is only one implementation of this interface: PCI-e. - * This implementation is iwl-pci.c - */ - -/** - * DOC: encapsulation and type safety - * - * The iwl_bus describes the data that is shared amongst all the bus layer - * implementations. This data is visible to other layers. Data in the bus - * specific area is not visible outside the bus specific implementation. - * iwl_bus holds a pointer to iwl_shared which holds pointer to all the other - * layers of the driver (iwl_priv, iwl_trans). In fact, this is the way to go - * when the transport layer needs to call a function of another layer. - * - * In order to achieve encapsulation, iwl_priv cannot be dereferenced from the - * bus layer. Type safety is still kept since functions that gets iwl_priv gets - * a typed pointer (as opposed to void *). - */ - -/** - * DOC: probe flow - * - * The module_init calls the bus specific registration function. The - * registration to the bus layer will trigger an enumeration of the bus which - * will call the bus specific probe function. - * The first thing this function must do is to allocate the memory needed by - * iwl_bus + the bus_specific data. - * Once the bus specific probe function has configured the hardware, it - * chooses the appropriate transport layer and calls iwl_probe that will run - * the bus independent probe flow. - * - * Note: The bus specific code must set the following data in iwl_bus before it - * calls iwl_probe: - * * bus->dev - * * bus->irq - * * bus->ops - */ - -struct iwl_shared; -struct iwl_bus; - -/** - * struct iwl_bus - bus common data - * - * This data is common to all bus layer implementations. - * - * @ops - pointer to iwl_bus_ops - * @shrd - pointer to iwl_shared which holds shared data from the upper layer - * NB: for the time being this needs to be set by the upper layer since - * it allocates the shared data - */ -struct iwl_bus { - struct iwl_shared *shrd; - - /* pointer to bus specific struct */ - /*Ensure that this pointer will always be aligned to sizeof pointer */ - char bus_specific[0] __attribute__((__aligned__(sizeof(void *)))); -}; - -/***************************************************** -* Bus layer registration functions -******************************************************/ -int __must_check iwl_pci_register_driver(void); -void iwl_pci_unregister_driver(void); - -#endif /* __iwl_bus_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-cfg.h b/drivers/net/wireless/iwlwifi/iwl-cfg.h index 957bc00cdaf0..1ad14bbccc99 100644 --- a/drivers/net/wireless/iwlwifi/iwl-cfg.h +++ b/drivers/net/wireless/iwlwifi/iwl-cfg.h @@ -80,6 +80,8 @@ extern struct iwl_cfg iwl6005_2abg_cfg; extern struct iwl_cfg iwl6005_2bg_cfg; extern struct iwl_cfg iwl6005_2agn_sff_cfg; extern struct iwl_cfg iwl6005_2agn_d_cfg; +extern struct iwl_cfg iwl6005_2agn_mow1_cfg; +extern struct iwl_cfg iwl6005_2agn_mow2_cfg; extern struct iwl_cfg iwl1030_bgn_cfg; extern struct iwl_cfg iwl1030_bg_cfg; extern struct iwl_cfg iwl6030_2agn_cfg; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 0677b3dfbfb2..275e08966059 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -38,10 +38,10 @@ #include "iwl-core.h" #include "iwl-io.h" #include "iwl-power.h" -#include "iwl-agn.h" #include "iwl-shared.h" #include "iwl-agn.h" #include "iwl-trans.h" +#include "iwl-wifi.h" const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; @@ -643,7 +643,7 @@ u8 iwl_get_single_channel_number(struct iwl_priv *priv, * NOTE: Does not commit to the hardware; it sets appropriate bit fields * in the staging RXON flag structure based on the ch->band */ -int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, +void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, struct iwl_rxon_context *ctx) { enum ieee80211_band band = ch->band; @@ -651,7 +651,7 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, if ((le16_to_cpu(ctx->staging.channel) == channel) && (priv->band == band)) - return 0; + return; ctx->staging.channel = cpu_to_le16(channel); if (band == IEEE80211_BAND_5GHZ) @@ -663,7 +663,6 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band); - return 0; } void iwl_set_flags_for_band(struct iwl_priv *priv, @@ -831,11 +830,16 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv, } #endif -void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) +static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) { unsigned int reload_msec; unsigned long reload_jiffies; +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_get_debug_level(priv->shrd) & IWL_DL_FW_ERRORS) + iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS); +#endif + /* Set the FW error flag -- cleared on iwl_down */ set_bit(STATUS_FW_ERROR, &priv->shrd->status); @@ -875,7 +879,7 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) if (iwlagn_mod_params.restart_fw) { IWL_DEBUG_FW_ERRORS(priv, "Restarting adapter due to uCode error.\n"); - queue_work(priv->shrd->workqueue, &priv->restart); + queue_work(priv->workqueue, &priv->restart); } else IWL_DEBUG_FW_ERRORS(priv, "Detected FW error, but not restarting\n"); @@ -1456,8 +1460,17 @@ __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, return cpu_to_le32(res); } -void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state) +void iwl_nic_error(struct iwl_op_mode *op_mode) { + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + + iwlagn_fw_error(priv, false); +} + +void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) +{ + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, state); } @@ -1466,8 +1479,9 @@ void iwl_nic_config(struct iwl_priv *priv) cfg(priv)->lib->nic_config(priv); } -void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb) +void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) { + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); struct ieee80211_tx_info *info; info = IEEE80211_SKB_CB(skb); @@ -1475,12 +1489,16 @@ void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb) dev_kfree_skb_any(skb); } -void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac) +void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac) { + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + ieee80211_stop_queue(priv->hw, ac); } -void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac) +void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, u8 ac) { + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + ieee80211_wake_queue(priv->hw, ac); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 8d60dcf6f2eb..42630f5e8de7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -76,7 +76,7 @@ struct iwl_cmd; struct iwl_lib_ops { /* set hw dependent parameters */ - int (*set_hw_params)(struct iwl_priv *priv); + void (*set_hw_params)(struct iwl_priv *priv); /* setup BT Rx handler */ void (*bt_rx_handler_setup)(struct iwl_priv *priv); /* setup BT related deferred work */ @@ -169,7 +169,7 @@ void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int hw_decrypt); int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx); int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, +void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, struct iwl_rxon_context *ctx); void iwl_set_flags_for_band(struct iwl_priv *priv, struct iwl_rxon_context *ctx, @@ -197,6 +197,8 @@ const char *get_ctrl_string(int cmd); void iwl_clear_traffic_stats(struct iwl_priv *priv); void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len); +void iwl_reset_traffic_log(struct iwl_priv *priv); + #else static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.c b/drivers/net/wireless/iwlwifi/iwl-debug.c new file mode 100644 index 000000000000..4bc2e70051d6 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-debug.c @@ -0,0 +1,127 @@ +/****************************************************************************** + * + * 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) 2007 - 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. + * + *****************************************************************************/ + +#include <linux/interrupt.h> +#include "iwl-debug.h" + +#define __iwl_fn(fn) \ +void __iwl_ ##fn(struct device *dev, const char *fmt, ...) \ +{ \ + struct va_format vaf = { \ + .fmt = fmt, \ + }; \ + va_list args; \ + \ + va_start(args, fmt); \ + vaf.va = &args; \ + dev_ ##fn(dev, "%pV", &vaf); \ + trace_iwlwifi_ ##fn(&vaf); \ + va_end(args); \ +} + +__iwl_fn(warn) +__iwl_fn(info) +__iwl_fn(crit) + +void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only, + const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; + if (!trace_only) { + if (rfkill_prefix) + dev_err(dev, "(RFKILL) %pV", &vaf); + else + dev_err(dev, "%pV", &vaf); + } + trace_iwlwifi_err(&vaf); + va_end(args); +} + +#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING) +void __iwl_dbg(struct iwl_shared *shared, struct device *dev, + u32 level, bool limit, const char *function, + const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_get_debug_level(shared) & level && + (!limit || net_ratelimit())) + dev_err(dev, "%c %s %pV", in_interrupt() ? 'I' : 'U', + function, &vaf); +#endif + trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf); + va_end(args); +} +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 351b41d7f4fd..01b23303d736 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -29,16 +29,34 @@ #ifndef __iwl_debug_h__ #define __iwl_debug_h__ -#include "iwl-bus.h" #include "iwl-shared.h" +#include "iwl-devtrace.h" struct iwl_priv; -/*No matter what is m (priv, bus, trans), this will work */ -#define IWL_ERR(m, f, a...) dev_err(trans(m)->dev, f, ## a) -#define IWL_WARN(m, f, a...) dev_warn(trans(m)->dev, f, ## a) -#define IWL_INFO(m, f, a...) dev_info(trans(m)->dev, f, ## a) -#define IWL_CRIT(m, f, a...) dev_crit(trans(m)->dev, f, ## a) +void __iwl_err(struct device *dev, bool rfkill_prefix, bool only_trace, + const char *fmt, ...); +void __iwl_warn(struct device *dev, const char *fmt, ...); +void __iwl_info(struct device *dev, const char *fmt, ...); +void __iwl_crit(struct device *dev, const char *fmt, ...); + +/* No matter what is m (priv, bus, trans), this will work */ +#define IWL_ERR(m, f, a...) __iwl_err(trans(m)->dev, false, false, f, ## a) +#define IWL_WARN(m, f, a...) __iwl_warn(trans(m)->dev, f, ## a) +#define IWL_INFO(m, f, a...) __iwl_info(trans(m)->dev, f, ## a) +#define IWL_CRIT(m, f, a...) __iwl_crit(trans(m)->dev, f, ## a) + +#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING) +void __iwl_dbg(struct iwl_shared *shared, struct device *dev, + u32 level, bool limit, const char *function, + const char *fmt, ...); +#else +static inline void +__iwl_dbg(struct iwl_shared *shared, struct device *dev, + u32 level, bool limit, const char *function, + const char *fmt, ...) +{} +#endif #define iwl_print_hex_error(m, p, len) \ do { \ @@ -46,53 +64,35 @@ do { \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) -#ifdef CONFIG_IWLWIFI_DEBUG -#define IWL_DEBUG(m, level, fmt, ...) \ -do { \ - if (iwl_get_debug_level((m)->shrd) & (level)) \ - dev_err(trans(m)->dev, "%c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __func__, \ - ##__VA_ARGS__); \ -} while (0) - -#define IWL_DEBUG_LIMIT(m, level, fmt, ...) \ -do { \ - if (iwl_get_debug_level((m)->shrd) & (level) && \ - net_ratelimit()) \ - dev_err(trans(m)->dev, "%c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __func__, \ - ##__VA_ARGS__); \ -} while (0) +#define IWL_DEBUG(m, level, fmt, args...) \ + __iwl_dbg((m)->shrd, trans(m)->dev, level, false, __func__, fmt, ##args) +#define IWL_DEBUG_LIMIT(m, level, fmt, args...) \ + __iwl_dbg((m)->shrd, trans(m)->dev, level, true, __func__, fmt, ##args) +#ifdef CONFIG_IWLWIFI_DEBUG #define iwl_print_hex_dump(m, level, p, len) \ do { \ if (iwl_get_debug_level((m)->shrd) & level) \ print_hex_dump(KERN_DEBUG, "iwl data: ", \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) - -#define IWL_DEBUG_QUIET_RFKILL(p, fmt, ...) \ +#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...) \ do { \ - if (!iwl_is_rfkill(p->shrd)) \ - dev_err(trans(p)->dev, "%s%c %s " fmt, \ - "", \ - in_interrupt() ? 'I' : 'U', __func__, \ - ##__VA_ARGS__); \ - else if (iwl_get_debug_level(p->shrd) & IWL_DL_RADIO) \ - dev_err(trans(p)->dev, "%s%c %s " fmt, \ - "(RFKILL) ", \ - in_interrupt() ? 'I' : 'U', __func__, \ - ##__VA_ARGS__); \ + if (!iwl_is_rfkill((m)->shrd)) \ + IWL_ERR(m, fmt, ##args); \ + else \ + __iwl_err(trans(m)->dev, true, \ + !(iwl_get_debug_level((m)->shrd) & IWL_DL_RADIO),\ + fmt, ##args); \ } while (0) - #else -#define IWL_DEBUG(m, level, fmt, args...) -#define IWL_DEBUG_LIMIT(m, level, fmt, args...) #define iwl_print_hex_dump(m, level, p, len) -#define IWL_DEBUG_QUIET_RFKILL(p, fmt, args...) \ -do { \ - if (!iwl_is_rfkill(p->shrd)) \ - IWL_ERR(p, fmt, ##args); \ +#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...) \ +do { \ + if (!iwl_is_rfkill((m)->shrd)) \ + IWL_ERR(m, fmt, ##args); \ + else \ + __iwl_err(trans(m)->dev, true, true, fmt, ##args); \ } while (0) #endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 136de6fb3fa4..ad74138e1c70 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -40,6 +40,7 @@ #include "iwl-core.h" #include "iwl-io.h" #include "iwl-agn.h" +#include "iwl-wifi.h" /* create and remove of files */ #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ @@ -234,12 +235,12 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, /* default is to dump the entire data segment */ if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { - struct iwl_trans *trans = trans(priv); + struct iwl_nic *nic = nic(priv); priv->dbgfs_sram_offset = 0x800000; - if (trans->shrd->ucode_type == IWL_UCODE_INIT) - priv->dbgfs_sram_len = trans->ucode_init.data.len; + if (nic->shrd->ucode_type == IWL_UCODE_INIT) + priv->dbgfs_sram_len = nic->fw.ucode_init.data.len; else - priv->dbgfs_sram_len = trans->ucode_rt.data.len; + priv->dbgfs_sram_len = nic->fw.ucode_rt.data.len; } len = priv->dbgfs_sram_len; @@ -342,7 +343,7 @@ static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, priv->wowlan_sram, - trans(priv)->ucode_wowlan.data.len); + nic(priv)->fw.ucode_wowlan.data.len); } static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index aa99457c3a52..6e5bf0a14609 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -47,9 +47,9 @@ #include "iwl-power.h" #include "iwl-agn-rs.h" #include "iwl-agn-tt.h" -#include "iwl-bus.h" #include "iwl-trans.h" #include "iwl-shared.h" +#include "iwl-op-mode.h" struct iwl_tx_queue; @@ -442,9 +442,6 @@ struct iwl_chain_noise_data { u8 state; }; -#define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ -#define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ - enum { MEASUREMENT_READY = (1 << 0), MEASUREMENT_ACTIVE = (1 << 1), @@ -696,11 +693,11 @@ struct iwl_testmode_trace { dma_addr_t dma_addr; bool trace_enabled; }; -struct iwl_testmode_sram { +struct iwl_testmode_mem { u32 buff_size; u32 num_chunks; u8 *buff_addr; - bool sram_readed; + bool read_in_progress; }; #endif @@ -710,6 +707,13 @@ struct iwl_wipan_noa_data { u8 data[]; }; +#define IWL_OP_MODE_GET_DVM(_iwl_op_mode) \ + ((struct iwl_priv *) ((_iwl_op_mode)->op_mode_specific)) + +#define IWL_MAC80211_GET_DVM(_hw) \ + ((struct iwl_priv *) ((struct iwl_op_mode *) \ + (_hw)->priv)->op_mode_specific) + struct iwl_priv { /*data shared among all the driver's layers */ @@ -721,6 +725,8 @@ struct iwl_priv { struct ieee80211_rate *ieee_rates; struct kmem_cache *tx_cmd_pool; + struct workqueue_struct *workqueue; + enum ieee80211_band band; void (*pre_rx_handler)(struct iwl_priv *priv, @@ -785,13 +791,6 @@ struct iwl_priv { /* EEPROM MAC addresses */ struct mac_address addresses[2]; - /* uCode images, save to reload in case of failure */ - int fw_index; /* firmware we're trying to load */ - u32 ucode_ver; /* version of ucode, copy of - iwl_ucode.ver */ - - char firmware_name[25]; - struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX]; __le16 switch_channel; @@ -801,7 +800,6 @@ struct iwl_priv { u8 start_calib; struct iwl_sensitivity_data sensitivity_data; struct iwl_chain_noise_data chain_noise_data; - bool enhance_sensitivity_table; __le16 sensitivity_tbl[HD_TABLE_SIZE]; __le16 enhance_sensitivity_tbl[ENHANCE_HD_TABLE_ENTRIES]; @@ -869,11 +867,6 @@ struct iwl_priv { struct iwl_rx_phy_res last_phy_res; bool last_phy_res_valid; - struct completion firmware_loading_complete; - - u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; - u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; - /* * chain noise reset and gain commands are the * two extra calibration commands follows the standard @@ -964,7 +957,7 @@ struct iwl_priv { bool led_registered; #ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE struct iwl_testmode_trace testmode_trace; - struct iwl_testmode_sram testmode_sram; + struct iwl_testmode_mem testmode_mem; u32 tm_fixed_rate; #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 4d892211ce4c..96e62338cec0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -34,6 +34,11 @@ #undef TRACE_EVENT #define TRACE_EVENT(name, proto, ...) \ static inline void trace_ ## name(proto) {} +#undef DECLARE_EVENT_CLASS +#define DECLARE_EVENT_CLASS(...) +#undef DEFINE_EVENT +#define DEFINE_EVENT(evt_class, name, proto, ...) \ +static inline void trace_ ## name(proto) {} #endif #define PRIV_ENTRY __field(void *, priv) @@ -164,6 +169,66 @@ TRACE_EVENT(iwlwifi_dev_ucode_wrap_event, ); #undef TRACE_SYSTEM +#define TRACE_SYSTEM iwlwifi_msg + +#define MAX_MSG_LEN 100 + +DECLARE_EVENT_CLASS(iwlwifi_msg_event, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf), + TP_STRUCT__entry( + __dynamic_array(char, msg, MAX_MSG_LEN) + ), + TP_fast_assign( + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + MAX_MSG_LEN, vaf->fmt, + *vaf->va) >= MAX_MSG_LEN); + ), + TP_printk("%s", (char *)__get_dynamic_array(msg)) +); + +DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_err, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_warn, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_info, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_crit, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); + +TRACE_EVENT(iwlwifi_dbg, + TP_PROTO(u32 level, bool in_interrupt, const char *function, + struct va_format *vaf), + TP_ARGS(level, in_interrupt, function, vaf), + TP_STRUCT__entry( + __field(u32, level) + __field(u8, in_interrupt) + __string(function, function) + __dynamic_array(char, msg, MAX_MSG_LEN) + ), + TP_fast_assign( + __entry->level = level; + __entry->in_interrupt = in_interrupt; + __assign_str(function, function); + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + MAX_MSG_LEN, vaf->fmt, + *vaf->va) >= MAX_MSG_LEN); + ), + TP_printk("%s", (char *)__get_dynamic_array(msg)) +); + +#undef TRACE_SYSTEM #define TRACE_SYSTEM iwlwifi TRACE_EVENT(iwlwifi_dev_hcmd, diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c new file mode 100644 index 000000000000..8ff52568cf6e --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -0,0 +1,103 @@ +/****************************************************************************** + * + * 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) 2007 - 2012 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 - 2012 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. + * + *****************************************************************************/ +#include <linux/completion.h> + +#include "iwl-drv.h" +#include "iwl-trans.h" +#include "iwl-wifi.h" +#include "iwl-op-mode.h" + +int iwl_drv_start(struct iwl_shared *shrd, + struct iwl_trans *trans, struct iwl_cfg *cfg) +{ + int ret; + + shrd->cfg = cfg; + + shrd->nic = kzalloc(sizeof(*shrd->nic), GFP_KERNEL); + if (!shrd->nic) { + dev_printk(KERN_ERR, trans->dev, "Couldn't allocate iwl_nic"); + return -ENOMEM; + } + shrd->nic->shrd = shrd; + + init_completion(&shrd->nic->request_firmware_complete); + + ret = iwl_request_firmware(shrd->nic, true); + + if (ret) { + dev_printk(KERN_ERR, trans->dev, "Couldn't request the fw"); + kfree(shrd->nic); + } + + return ret; +} + +void iwl_drv_stop(struct iwl_shared *shrd) +{ + /* op_mode can be NULL if its start failed */ + if (shrd->nic->op_mode) + iwl_op_mode_stop(shrd->nic->op_mode); + + kfree(shrd->nic); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h new file mode 100644 index 000000000000..90534a23ddc8 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h @@ -0,0 +1,123 @@ +/****************************************************************************** + * + * 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 - 2012 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 - 2012 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_drv_h__ +#define __iwl_drv_h__ + +#include "iwl-shared.h" + +/** + * DOC: Driver system flows - drv component + * + * This component implements the system flows such as bus enumeration, bus + * removal. Bus dependent parts of system flows (such as iwl_pci_probe) are in + * bus specific files (transport files). This is the code that is common among + * different buses. + * + * This component is also in charge of managing the several implementations of + * the wifi flows: it will allow to have several fw API implementation. These + * different implementations will differ in the way they implement mac80211's + * handlers too. + + * The init flow wrt to the drv component looks like this: + * 1) The bus specific component is called from module_init + * 2) The bus specific component registers the bus driver + * 3) The bus driver calls the probe function + * 4) The bus specific component configures the bus + * 5) The bus specific component calls to the drv bus agnostic part + * (iwl_drv_start) + * 6) iwl_drv_start fetches the fw ASYNC, iwl_ucode_callback + * 7) iwl_ucode_callback parses the fw file + * 8) iwl_ucode_callback starts the wifi implementation to matches the fw + */ + +/** + * iwl_drv_start - start the drv + * + * @shrd: the shrd area + * @trans_ops: the ops of the transport + * @cfg: device specific constants / virtual functions + * + * TODO: review the parameters given to this function + * + * starts the driver: fetches the firmware. This should be called by bus + * specific system flows implementations. For example, the bus specific probe + * function should do bus related operations only, and then call to this + * function. + */ +int iwl_drv_start(struct iwl_shared *shrd, + struct iwl_trans *trans, struct iwl_cfg *cfg); + +/** + * iwl_drv_stop - stop the drv + * + * @shrd: the shrd area + * + * TODO: review the parameters given to this function + * + * Stop the driver. This should be called by bus specific system flows + * implementations. For example, the bus specific remove function should first + * call this function and then do the bus related operations only. + */ +void iwl_drv_stop(struct iwl_shared *shrd); + +#endif /* __iwl_drv_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index d1fd1cdb29c2..07e93787bce8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -149,23 +149,27 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ * EEPROM chip, not a single event, so even reads could conflict if they * weren't arbitrated by the semaphore. */ -static int iwl_eeprom_acquire_semaphore(struct iwl_bus *bus) + +#define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ +#define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ + +static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans) { u16 count; int ret; for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { /* Request semaphore */ - iwl_set_bit(trans(bus), CSR_HW_IF_CONFIG_REG, + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); /* See if we got it */ - ret = iwl_poll_bit(trans(bus), CSR_HW_IF_CONFIG_REG, + ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, EEPROM_SEM_TIMEOUT); if (ret >= 0) { - IWL_DEBUG_EEPROM(trans(bus), + IWL_DEBUG_EEPROM(trans, "Acquired semaphore after %d tries.\n", count+1); return ret; @@ -175,9 +179,9 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_bus *bus) return ret; } -static void iwl_eeprom_release_semaphore(struct iwl_bus *bus) +static void iwl_eeprom_release_semaphore(struct iwl_trans *trans) { - iwl_clear_bit(trans(bus), CSR_HW_IF_CONFIG_REG, + iwl_clear_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); } @@ -304,19 +308,20 @@ void iwl_eeprom_get_mac(const struct iwl_shared *shrd, u8 *mac) * ******************************************************************************/ -static void iwl_set_otp_access(struct iwl_bus *bus, enum iwl_access_mode mode) +static void iwl_set_otp_access(struct iwl_trans *trans, + enum iwl_access_mode mode) { - iwl_read32(trans(bus), CSR_OTP_GP_REG); + iwl_read32(trans, CSR_OTP_GP_REG); if (mode == IWL_OTP_ACCESS_ABSOLUTE) - iwl_clear_bit(trans(bus), CSR_OTP_GP_REG, + iwl_clear_bit(trans, CSR_OTP_GP_REG, CSR_OTP_GP_REG_OTP_ACCESS_MODE); else - iwl_set_bit(trans(bus), CSR_OTP_GP_REG, + iwl_set_bit(trans, CSR_OTP_GP_REG, CSR_OTP_GP_REG_OTP_ACCESS_MODE); } -static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev) +static int iwl_get_nvm_type(struct iwl_trans *trans, u32 hw_rev) { u32 otpgp; int nvm_type; @@ -324,7 +329,7 @@ static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev) /* OTP only valid for CP/PP and after */ switch (hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_NONE: - IWL_ERR(bus, "Unknown hardware type\n"); + IWL_ERR(trans, "Unknown hardware type\n"); return -ENOENT; case CSR_HW_REV_TYPE_5300: case CSR_HW_REV_TYPE_5350: @@ -333,7 +338,7 @@ static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev) nvm_type = NVM_DEVICE_TYPE_EEPROM; break; default: - otpgp = iwl_read32(trans(bus), CSR_OTP_GP_REG); + otpgp = iwl_read32(trans, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT) nvm_type = NVM_DEVICE_TYPE_OTP; else @@ -343,73 +348,74 @@ static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev) return nvm_type; } -static int iwl_init_otp_access(struct iwl_bus *bus) +static int iwl_init_otp_access(struct iwl_trans *trans) { int ret; /* Enable 40MHz radio clock */ - iwl_write32(trans(bus), CSR_GP_CNTRL, - iwl_read32(trans(bus), CSR_GP_CNTRL) | + iwl_write32(trans, CSR_GP_CNTRL, + iwl_read32(trans, CSR_GP_CNTRL) | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock to be ready */ - ret = iwl_poll_bit(trans(bus), CSR_GP_CNTRL, + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) - IWL_ERR(bus, "Time out access OTP\n"); + IWL_ERR(trans, "Time out access OTP\n"); else { - iwl_set_bits_prph(trans(bus), APMG_PS_CTRL_REG, + iwl_set_bits_prph(trans, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); udelay(5); - iwl_clear_bits_prph(trans(bus), APMG_PS_CTRL_REG, + iwl_clear_bits_prph(trans, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); /* * CSR auto clock gate disable bit - * this is only applicable for HW with OTP shadow RAM */ - if (cfg(bus)->base_params->shadow_ram_support) - iwl_set_bit(trans(bus), CSR_DBG_LINK_PWR_MGMT_REG, + if (cfg(trans)->base_params->shadow_ram_support) + iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, CSR_RESET_LINK_PWR_MGMT_DISABLED); } return ret; } -static int iwl_read_otp_word(struct iwl_bus *bus, u16 addr, __le16 *eeprom_data) +static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr, + __le16 *eeprom_data) { int ret = 0; u32 r; u32 otpgp; - iwl_write32(trans(bus), CSR_EEPROM_REG, + iwl_write32(trans, CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bit(trans(bus), CSR_EEPROM_REG, + ret = iwl_poll_bit(trans, CSR_EEPROM_REG, CSR_EEPROM_REG_READ_VALID_MSK, CSR_EEPROM_REG_READ_VALID_MSK, IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { - IWL_ERR(bus, "Time out reading OTP[%d]\n", addr); + IWL_ERR(trans, "Time out reading OTP[%d]\n", addr); return ret; } - r = iwl_read32(trans(bus), CSR_EEPROM_REG); + r = iwl_read32(trans, CSR_EEPROM_REG); /* check for ECC errors: */ - otpgp = iwl_read32(trans(bus), CSR_OTP_GP_REG); + otpgp = iwl_read32(trans, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { /* stop in this case */ /* set the uncorrectable OTP ECC bit for acknowledgement */ - iwl_set_bit(trans(bus), CSR_OTP_GP_REG, + iwl_set_bit(trans, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); - IWL_ERR(bus, "Uncorrectable OTP ECC error, abort OTP read\n"); + IWL_ERR(trans, "Uncorrectable OTP ECC error, abort OTP read\n"); return -EINVAL; } if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { /* continue in this case */ /* set the correctable OTP ECC bit for acknowledgement */ - iwl_set_bit(trans(bus), CSR_OTP_GP_REG, + iwl_set_bit(trans, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); - IWL_ERR(bus, "Correctable OTP ECC error, continue read\n"); + IWL_ERR(trans, "Correctable OTP ECC error, continue read\n"); } *eeprom_data = cpu_to_le16(r >> 16); return 0; @@ -418,20 +424,20 @@ static int iwl_read_otp_word(struct iwl_bus *bus, u16 addr, __le16 *eeprom_data) /* * iwl_is_otp_empty: check for empty OTP */ -static bool iwl_is_otp_empty(struct iwl_bus *bus) +static bool iwl_is_otp_empty(struct iwl_trans *trans) { u16 next_link_addr = 0; __le16 link_value; bool is_empty = false; /* locate the beginning of OTP link list */ - if (!iwl_read_otp_word(bus, next_link_addr, &link_value)) { + if (!iwl_read_otp_word(trans, next_link_addr, &link_value)) { if (!link_value) { - IWL_ERR(bus, "OTP is empty\n"); + IWL_ERR(trans, "OTP is empty\n"); is_empty = true; } } else { - IWL_ERR(bus, "Unable to read first block of OTP list.\n"); + IWL_ERR(trans, "Unable to read first block of OTP list.\n"); is_empty = true; } @@ -448,7 +454,7 @@ static bool iwl_is_otp_empty(struct iwl_bus *bus) * we should read and used to configure the device. * only perform this operation if shadow RAM is disabled */ -static int iwl_find_otp_image(struct iwl_bus *bus, +static int iwl_find_otp_image(struct iwl_trans *trans, u16 *validblockaddr) { u16 next_link_addr = 0, valid_addr; @@ -456,10 +462,10 @@ static int iwl_find_otp_image(struct iwl_bus *bus, int usedblocks = 0; /* set addressing mode to absolute to traverse the link list */ - iwl_set_otp_access(bus, IWL_OTP_ACCESS_ABSOLUTE); + iwl_set_otp_access(trans, IWL_OTP_ACCESS_ABSOLUTE); /* checking for empty OTP or error */ - if (iwl_is_otp_empty(bus)) + if (iwl_is_otp_empty(trans)) return -EINVAL; /* @@ -473,9 +479,9 @@ static int iwl_find_otp_image(struct iwl_bus *bus, */ valid_addr = next_link_addr; next_link_addr = le16_to_cpu(link_value) * sizeof(u16); - IWL_DEBUG_EEPROM(bus, "OTP blocks %d addr 0x%x\n", + IWL_DEBUG_EEPROM(trans, "OTP blocks %d addr 0x%x\n", usedblocks, next_link_addr); - if (iwl_read_otp_word(bus, next_link_addr, &link_value)) + if (iwl_read_otp_word(trans, next_link_addr, &link_value)) return -EINVAL; if (!link_value) { /* @@ -490,10 +496,10 @@ static int iwl_find_otp_image(struct iwl_bus *bus, } /* more in the link list, continue */ usedblocks++; - } while (usedblocks <= cfg(bus)->base_params->max_ll_items); + } while (usedblocks <= cfg(trans)->base_params->max_ll_items); /* OTP has no valid blocks */ - IWL_DEBUG_EEPROM(bus, "OTP has no valid blocks\n"); + IWL_DEBUG_EEPROM(trans, "OTP has no valid blocks\n"); return -EINVAL; } @@ -653,63 +659,62 @@ void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv) * * NOTE: This routine uses the non-debug IO access functions. */ -int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) +int iwl_eeprom_init(struct iwl_trans *trans, u32 hw_rev) { - struct iwl_shared *shrd = priv->shrd; __le16 *e; - u32 gp = iwl_read32(trans(priv), CSR_EEPROM_GP); + u32 gp = iwl_read32(trans, CSR_EEPROM_GP); int sz; int ret; u16 addr; u16 validblockaddr = 0; u16 cache_addr = 0; - trans(priv)->nvm_device_type = iwl_get_nvm_type(bus(priv), hw_rev); - if (trans(priv)->nvm_device_type == -ENOENT) + trans->nvm_device_type = iwl_get_nvm_type(trans, hw_rev); + if (trans->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ - 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) { + sz = cfg(trans)->base_params->eeprom_size; + IWL_DEBUG_EEPROM(trans, "NVM size = %d\n", sz); + trans->shrd->eeprom = kzalloc(sz, GFP_KERNEL); + if (!trans->shrd->eeprom) { ret = -ENOMEM; goto alloc_err; } - e = (__le16 *)shrd->eeprom; + e = (__le16 *)trans->shrd->eeprom; - ret = iwl_eeprom_verify_signature(trans(priv)); + ret = iwl_eeprom_verify_signature(trans); if (ret < 0) { - IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); + IWL_ERR(trans, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); ret = -ENOENT; goto err; } /* Make sure driver (instead of uCode) is allowed to read EEPROM */ - ret = iwl_eeprom_acquire_semaphore(bus(priv)); + ret = iwl_eeprom_acquire_semaphore(trans); if (ret < 0) { - IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n"); + IWL_ERR(trans, "Failed to acquire EEPROM semaphore.\n"); ret = -ENOENT; goto err; } - if (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) { + if (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP) { - ret = iwl_init_otp_access(bus(priv)); + ret = iwl_init_otp_access(trans); if (ret) { - IWL_ERR(priv, "Failed to initialize OTP access.\n"); + IWL_ERR(trans, "Failed to initialize OTP access.\n"); ret = -ENOENT; goto done; } - iwl_write32(trans(priv), CSR_EEPROM_GP, - iwl_read32(trans(priv), CSR_EEPROM_GP) & + iwl_write32(trans, CSR_EEPROM_GP, + iwl_read32(trans, CSR_EEPROM_GP) & ~CSR_EEPROM_GP_IF_OWNER_MSK); - iwl_set_bit(trans(priv), CSR_OTP_GP_REG, + iwl_set_bit(trans, CSR_OTP_GP_REG, 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 (!cfg(priv)->base_params->shadow_ram_support) { - if (iwl_find_otp_image(bus(priv), &validblockaddr)) { + if (!cfg(trans)->base_params->shadow_ram_support) { + if (iwl_find_otp_image(trans, &validblockaddr)) { ret = -ENOENT; goto done; } @@ -718,7 +723,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) addr += sizeof(u16)) { __le16 eeprom_data; - ret = iwl_read_otp_word(bus(priv), addr, &eeprom_data); + ret = iwl_read_otp_word(trans, addr, &eeprom_data); if (ret) goto done; e[cache_addr / 2] = eeprom_data; @@ -729,34 +734,35 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) for (addr = 0; addr < sz; addr += sizeof(u16)) { u32 r; - iwl_write32(trans(priv), CSR_EEPROM_REG, + iwl_write32(trans, CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bit(trans(priv), CSR_EEPROM_REG, + ret = iwl_poll_bit(trans, CSR_EEPROM_REG, CSR_EEPROM_REG_READ_VALID_MSK, CSR_EEPROM_REG_READ_VALID_MSK, IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { - IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); + IWL_ERR(trans, + "Time out reading EEPROM[%d]\n", addr); goto done; } - r = iwl_read32(trans(priv), CSR_EEPROM_REG); + r = iwl_read32(trans, CSR_EEPROM_REG); e[addr / 2] = cpu_to_le16(r >> 16); } } - IWL_DEBUG_EEPROM(priv, "NVM Type: %s, version: 0x%x\n", - (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) + IWL_DEBUG_EEPROM(trans, "NVM Type: %s, version: 0x%x\n", + (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP) ? "OTP" : "EEPROM", - iwl_eeprom_query16(shrd, EEPROM_VERSION)); + iwl_eeprom_query16(trans->shrd, EEPROM_VERSION)); ret = 0; done: - iwl_eeprom_release_semaphore(bus(priv)); + iwl_eeprom_release_semaphore(trans); err: if (ret) - iwl_eeprom_free(priv->shrd); + iwl_eeprom_free(trans->shrd); alloc_err: return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 13f2d3928ef8..cbb86116917b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -67,6 +67,7 @@ struct iwl_priv; struct iwl_shared; +struct iwl_trans; /* * EEPROM access time values: @@ -305,7 +306,7 @@ struct iwl_eeprom_ops { }; -int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev); +int iwl_eeprom_init(struct iwl_trans *trans, u32 hw_rev); void iwl_eeprom_free(struct iwl_shared *shrd); int iwl_eeprom_check_version(struct iwl_priv *priv); int iwl_eeprom_check_sku(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index d8025fee7e0d..03f770543d8e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c @@ -51,8 +51,8 @@ #include "iwl-agn-calib.h" #include "iwl-agn.h" #include "iwl-shared.h" -#include "iwl-bus.h" #include "iwl-trans.h" +#include "iwl-op-mode.h" /***************************************************************************** * @@ -136,7 +136,7 @@ iwlagn_iface_combinations_p2p[] = { * other mac80211 functions grouped here. */ int iwlagn_mac_setup_register(struct iwl_priv *priv, - struct iwlagn_ucode_capabilities *capa) + struct iwl_ucode_capabilities *capa) { int ret; struct ieee80211_hw *hw = priv->hw; @@ -195,7 +195,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, WIPHY_FLAG_DISABLE_BEACON_HINTS | WIPHY_FLAG_IBSS_RSN; - if (trans(priv)->ucode_wowlan.code.len && + if (nic(priv)->fw.ucode_wowlan.code.len && device_can_wakeup(trans(priv)->dev)) { hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | @@ -296,7 +296,7 @@ static int __iwl_up(struct iwl_priv *priv) error: set_bit(STATUS_EXIT_PENDING, &priv->shrd->status); - __iwl_down(priv); + iwl_down(priv); clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status); IWL_ERR(priv, "Unable to initialize device.\n"); @@ -305,7 +305,7 @@ static int __iwl_up(struct iwl_priv *priv) static int iwlagn_mac_start(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int ret; IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -332,7 +332,7 @@ static int iwlagn_mac_start(struct ieee80211_hw *hw) static void iwlagn_mac_stop(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -341,9 +341,13 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw) priv->is_open = 0; + mutex_lock(&priv->shrd->mutex); iwl_down(priv); + mutex_unlock(&priv->shrd->mutex); + + iwl_cancel_deferred_work(priv); - flush_workqueue(priv->shrd->workqueue); + flush_workqueue(priv->workqueue); /* User space software may expect getting rfkill changes * even if interface is down, trans->down will leave the RF @@ -358,7 +362,7 @@ static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_gtk_rekey_data *data) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); if (iwlagn_mod_params.sw_crypto) return; @@ -385,7 +389,7 @@ static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, static int iwlagn_mac_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; int ret; @@ -427,7 +431,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, static int iwlagn_mac_resume(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct ieee80211_vif *vif; unsigned long flags; @@ -453,17 +457,17 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) #ifdef CONFIG_IWLWIFI_DEBUGFS if (ret == 0) { - struct iwl_trans *trans = trans(priv); + struct iwl_nic *nic = nic(priv); if (!priv->wowlan_sram) priv->wowlan_sram = - kzalloc(trans->ucode_wowlan.data.len, + kzalloc(nic->fw.ucode_wowlan.data.len, GFP_KERNEL); if (priv->wowlan_sram) _iwl_read_targ_mem_words( trans(priv), 0x800000, priv->wowlan_sram, - trans->ucode_wowlan.data.len / 4); + nic->fw.ucode_wowlan.data.len / 4); } #endif } @@ -493,7 +497,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); @@ -508,7 +512,7 @@ static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u32 iv32, u16 *phase1key) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key); } @@ -518,7 +522,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *ctx = vif_priv->ctx; int ret; @@ -622,7 +626,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int ret = -EINVAL; struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; @@ -688,7 +692,7 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; bool is_ap = vif->type == NL80211_IFTYPE_STATION; @@ -731,7 +735,7 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_channel_switch *ch_switch) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); const struct iwl_channel_info *ch_info; struct ieee80211_conf *conf = &hw->conf; struct ieee80211_channel *channel = ch_switch->channel; @@ -818,7 +822,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); __le32 filter_or = 0, filter_nand = 0; struct iwl_rxon_context *ctx; @@ -865,7 +869,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw, static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); mutex_lock(&priv->shrd->mutex); IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -902,7 +906,7 @@ static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, enum nl80211_channel_type channel_type, int duration) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; int err = 0; @@ -992,7 +996,7 @@ static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN))) return -EOPNOTSUPP; @@ -1012,7 +1016,7 @@ static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw, const u8 *bssid, enum ieee80211_tx_sync_type type) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *ctx = vif_priv->ctx; int ret; @@ -1066,7 +1070,7 @@ static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw, const u8 *bssid, enum ieee80211_tx_sync_type type) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *ctx = vif_priv->ctx; @@ -1090,7 +1094,7 @@ static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw, static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, enum ieee80211_rssi_event rssi_event) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); IWL_DEBUG_MAC80211(priv, "enter\n"); mutex_lock(&priv->shrd->mutex); @@ -1115,9 +1119,9 @@ static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, static int iwlagn_mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); - queue_work(priv->shrd->workqueue, &priv->beacon_update); + queue_work(priv->workqueue, &priv->beacon_update); return 0; } @@ -1126,7 +1130,7 @@ static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *ctx = vif_priv->ctx; unsigned long flags; @@ -1169,7 +1173,7 @@ static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, static int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); return priv->ibss_manager == IWL_IBSS_MANAGER; } @@ -1223,7 +1227,7 @@ static int iwl_setup_interface(struct iwl_priv *priv, static int iwlagn_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *tmp, *ctx = NULL; int err; @@ -1320,7 +1324,7 @@ static void iwl_teardown_interface(struct iwl_priv *priv, static void iwlagn_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -1348,7 +1352,7 @@ static int iwlagn_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum nl80211_iftype newtype, bool newp2p) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_rxon_context *tmp; @@ -1434,7 +1438,7 @@ static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_scan_request *req) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int ret; IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -1480,7 +1484,7 @@ static int iwlagn_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; int ret; @@ -1519,7 +1523,7 @@ static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; int sta_id; @@ -1587,15 +1591,18 @@ struct ieee80211_ops iwlagn_hw_ops = { struct ieee80211_hw *iwl_alloc_all(void) { struct iwl_priv *priv; + struct iwl_op_mode *op_mode; /* mac80211 allocates memory for this device instance, including * space for this driver's private structure */ struct ieee80211_hw *hw; - hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops); + hw = ieee80211_alloc_hw(sizeof(struct iwl_priv) + + sizeof(struct iwl_op_mode), &iwlagn_hw_ops); if (!hw) goto out; - priv = hw->priv; + op_mode = hw->priv; + priv = IWL_OP_MODE_GET_DVM(op_mode); priv->hw = hw; out: diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h new file mode 100644 index 000000000000..d4fc9be2d2f3 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -0,0 +1,198 @@ +/****************************************************************************** + * + * 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) 2007 - 2012 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 - 2012 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_op_mode_h__ +#define __iwl_op_mode_h__ + +struct iwl_op_mode; +struct iwl_trans; +struct sk_buff; +struct iwl_device_cmd; +struct iwl_rx_mem_buffer; + +/** + * DOC: Operational mode - what is it ? + * + * The operational mode (a.k.a. op_mode) is the layer that implements + * mac80211's handlers. It knows two APIs: mac80211's and the fw's. It uses + * the transport API to access the HW. The op_mode doesn't need to know how the + * underlying HW works, since the transport layer takes care of that. + * + * There can be several op_mode: i.e. different fw APIs will require two + * different op_modes. This is why the op_mode is virtualized. + */ + +/** + * DOC: Life cycle of the Operational mode + * + * The operational mode has a very simple life cycle. + * + * 1) The driver layer (iwl-drv.c) chooses the op_mode based on the + * capabilities advertized by the fw file (in TLV format). + * 2) The driver layer starts the op_mode (ops->start) + * 3) The op_mode registers registers mac80211 + * 4) The op_mode is governed by mac80211 + * 5) The driver layer stops the op_mode + */ + +/** + * struct iwl_op_mode_ops - op_mode specific operations + * + * The op_mode exports its ops so that external components can start it and + * interact with it. The driver layer typically calls the start and stop + * handlers, the transport layer calls the others. + * + * All the handlers MUST be implemented + * + * @start: start the op_mode. The transport layer is already allocated. + * May sleep + * @stop: stop the op_mode. Must free all the memory allocated. + * May sleep + * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the + * HCMD the this Rx responds to. + * Must be atomic. + * @queue_full: notifies that a HW queue is full. Ac is the ac of the queue + * Must be atomic + * @queue_not_full: notifies that a HW queue is not full any more. + * Ac is the ac of the queue. Must be atomic + * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that + * the radio is killed. Must be atomic. + * @free_skb: allows the transport layer to free skbs that haven't been + * reclaimed by the op_mode. This can happen when the driver is freed and + * there are Tx packets pending in the transport layer. + * Must be atomic + * @nic_error: error notification. Must be atomic + */ +struct iwl_op_mode_ops { + struct iwl_op_mode *(*start)(struct iwl_trans *trans); + void (*stop)(struct iwl_op_mode *op_mode); + int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd); + void (*queue_full)(struct iwl_op_mode *op_mode, u8 ac); + void (*queue_not_full)(struct iwl_op_mode *op_mode, u8 ac); + void (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state); + void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb); + void (*nic_error)(struct iwl_op_mode *op_mode); +}; + +/** + * struct iwl_op_mode - operational mode + * + * This holds an implementation of the mac80211 / fw API. + * + * @ops - pointer to its own ops + */ +struct iwl_op_mode { + const struct iwl_op_mode_ops *ops; + const struct iwl_trans *trans; + + char op_mode_specific[0] __aligned(sizeof(void *)); +}; + +static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode) +{ + might_sleep(); + + op_mode->ops->stop(op_mode); +} + +static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) +{ + return op_mode->ops->rx(op_mode, rxb, cmd); +} + +static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, u8 ac) +{ + op_mode->ops->queue_full(op_mode, ac); +} + +static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode, + u8 ac) +{ + op_mode->ops->queue_not_full(op_mode, ac); +} + +static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, + bool state) +{ + op_mode->ops->hw_rf_kill(op_mode, state); +} + +static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode, + struct sk_buff *skb) +{ + op_mode->ops->free_skb(op_mode, skb); +} + +static inline void iwl_op_mode_nic_error(struct iwl_op_mode *op_mode) +{ + op_mode->ops->nic_error(op_mode); +} + +/***************************************************** +* Op mode layers implementations +******************************************************/ +extern const struct iwl_op_mode_ops iwl_dvm_ops; + +#endif /* __iwl_op_mode_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c index 3e2fce4ce00c..06e004157dcc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-pci.c +++ b/drivers/net/wireless/iwlwifi/iwl-pci.c @@ -64,12 +64,13 @@ #include <linux/pci.h> #include <linux/pci-aspm.h> -#include "iwl-bus.h" #include "iwl-io.h" #include "iwl-shared.h" #include "iwl-trans.h" #include "iwl-csr.h" #include "iwl-cfg.h" +#include "iwl-drv.h" +#include "iwl-trans.h" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ @@ -157,9 +158,9 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)}, {IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)}, {IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)}, - {IWL_PCI_DEVICE(0x0082, 0x1341, iwl6005_2agn_d_cfg)}, - {IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_cfg)},/* low 5GHz active */ - {IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_cfg)},/* high 5GHz active */ + {IWL_PCI_DEVICE(0x0082, 0x4820, iwl6005_2agn_d_cfg)}, + {IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_mow1_cfg)},/* low 5GHz active */ + {IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_mow2_cfg)},/* high 5GHz active */ /* 6x30 Series */ {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)}, @@ -240,6 +241,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)}, {IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)}, {IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4860, iwl6035_2agn_cfg)}, /* 105 Series */ {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)}, @@ -262,44 +264,40 @@ MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); - struct iwl_bus *bus; + struct iwl_shared *shrd; + struct iwl_trans *iwl_trans; int err; - bus = kzalloc(sizeof(*bus), GFP_KERNEL); - if (!bus) { - dev_printk(KERN_ERR, &pdev->dev, - "Couldn't allocate iwl_pci_bus"); - return -ENOMEM; - } - - bus->shrd = kzalloc(sizeof(*bus->shrd), GFP_KERNEL); - if (!bus->shrd) { + shrd = kzalloc(sizeof(*iwl_trans->shrd), GFP_KERNEL); + if (!shrd) { dev_printk(KERN_ERR, &pdev->dev, "Couldn't allocate iwl_shared"); err = -ENOMEM; goto out_free_bus; } - bus->shrd->bus = bus; - - pci_set_drvdata(pdev, bus); - #ifdef CONFIG_IWLWIFI_IDI - trans(bus) = iwl_trans_idi_alloc(bus->shrd, pdev, ent); - if (trans(bus) == NULL) { + iwl_trans = iwl_trans_idi_alloc(shrd, pdev, ent); + if (iwl_trans == NULL) { err = -ENOMEM; goto out_free_bus; } - err = iwl_probe(bus, &trans_ops_idi, cfg); + shrd->trans = iwl_trans; + pci_set_drvdata(pdev, iwl_trans); + + err = iwl_drv_start(shrd, iwl_trans, cfg); #else - trans(bus) = iwl_trans_pcie_alloc(bus->shrd, pdev, ent); - if (trans(bus) == NULL) { + iwl_trans = iwl_trans_pcie_alloc(shrd, pdev, ent); + if (iwl_trans == NULL) { err = -ENOMEM; goto out_free_bus; } - err = iwl_probe(bus, &trans_ops_pcie, cfg); + shrd->trans = iwl_trans; + pci_set_drvdata(pdev, iwl_trans); + + err = iwl_drv_start(shrd, iwl_trans, cfg); #endif if (err) goto out_free_trans; @@ -307,26 +305,24 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; out_free_trans: - iwl_trans_free(trans(bus)); + iwl_trans_free(iwl_trans); pci_set_drvdata(pdev, NULL); out_free_bus: - kfree(bus->shrd); - kfree(bus); + kfree(shrd); return err; } static void __devexit iwl_pci_remove(struct pci_dev *pdev) { - struct iwl_bus *bus = pci_get_drvdata(pdev); - struct iwl_shared *shrd = bus->shrd; + struct iwl_trans *iwl_trans = pci_get_drvdata(pdev); + struct iwl_shared *shrd = iwl_trans->shrd; - iwl_remove(shrd->priv); + iwl_drv_stop(shrd); iwl_trans_free(shrd->trans); pci_set_drvdata(pdev, NULL); - kfree(bus->shrd); - kfree(bus); + kfree(shrd); } #ifdef CONFIG_PM_SLEEP @@ -334,22 +330,20 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) static int iwl_pci_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); - struct iwl_bus *bus = pci_get_drvdata(pdev); - struct iwl_shared *shrd = bus->shrd; + struct iwl_trans *iwl_trans = pci_get_drvdata(pdev); /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if * WoWLAN is enabled - don't kill the NIC, someone may need it in Sx. */ - return iwl_trans_suspend(shrd->trans); + return iwl_trans_suspend(iwl_trans); } static int iwl_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); - struct iwl_bus *bus = pci_get_drvdata(pdev); - struct iwl_shared *shrd = bus->shrd; + struct iwl_trans *iwl_trans = pci_get_drvdata(pdev); /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if @@ -362,7 +356,7 @@ static int iwl_pci_resume(struct device *device) */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); - return iwl_trans_resume(shrd->trans); + return iwl_trans_resume(iwl_trans); } static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume); diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 7f2e3a1c80ef..42ee1c410efd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -218,7 +218,7 @@ static void iwl_do_scan_abort(struct iwl_priv *priv) int iwl_scan_cancel(struct iwl_priv *priv) { IWL_DEBUG_SCAN(priv, "Queuing abort scan\n"); - queue_work(priv->shrd->workqueue, &priv->abort_scan); + queue_work(priv->workqueue, &priv->abort_scan); return 0; } @@ -354,7 +354,7 @@ static int iwl_rx_scan_complete_notif(struct iwl_priv *priv, */ set_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status); clear_bit(STATUS_SCAN_HW, &priv->shrd->status); - queue_work(priv->shrd->workqueue, &priv->scan_completed); + queue_work(priv->workqueue, &priv->scan_completed); if (priv->iw_mode != NL80211_IFTYPE_ADHOC && iwl_advanced_bt_coexist(priv) && @@ -374,7 +374,7 @@ static int iwl_rx_scan_complete_notif(struct iwl_priv *priv, IWL_BT_COEX_TRAFFIC_LOAD_NONE; } priv->bt_status = scan_notif->bt_status; - queue_work(priv->shrd->workqueue, + queue_work(priv->workqueue, &priv->bt_traffic_change_work); } return 0; @@ -950,7 +950,7 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, return ret; } - queue_delayed_work(priv->shrd->workqueue, &priv->scan_check, + queue_delayed_work(priv->workqueue, &priv->scan_check, IWL_SCAN_CHECK_WATCHDOG); return 0; @@ -963,7 +963,7 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, */ void iwl_internal_short_hw_scan(struct iwl_priv *priv) { - queue_work(priv->shrd->workqueue, &priv->start_internal_scan); + queue_work(priv->workqueue, &priv->start_internal_scan); } static void iwl_bg_start_internal_scan(struct work_struct *work) diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h index 63d4a4fc5b9e..a6441623e6b1 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_bus; struct iwl_priv; struct iwl_trans; struct iwl_sensitivity_ranges; @@ -173,8 +172,6 @@ struct iwl_mod_params { * @ht40_channel: is 40MHz width possible: BIT(IEEE80211_BAND_XXX) * @sku: sku read from EEPROM * @rx_page_order: Rx buffer page order - * @max_inst_size: for ucode use - * @max_data_size: for ucode use * @ct_kill_threshold: temperature threshold - in hw dependent unit * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit * relevant for 1000, 6000 and up @@ -192,8 +189,6 @@ struct iwl_hw_params { bool shadow_reg_enable; u16 sku; u32 rx_page_order; - u32 max_inst_size; - u32 max_data_size; u32 ct_kill_threshold; u32 ct_kill_exit_threshold; unsigned int wd_timeout; @@ -283,6 +278,8 @@ enum iwl_led_mode { * @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. + * @max_inst_size: The maximal length of the fw inst section + * @max_data_size: The maximal length of the fw data section * @valid_tx_ant: valid transmit antenna * @valid_rx_ant: valid receive antenna * @sku: sku information from EEPROM @@ -320,6 +317,8 @@ struct iwl_cfg { const unsigned int ucode_api_max; const unsigned int ucode_api_ok; const unsigned int ucode_api_min; + const u32 max_data_size; + const u32 max_inst_size; u8 valid_tx_ant; u8 valid_rx_ant; u16 sku; @@ -358,8 +357,8 @@ struct iwl_cfg { * @cfg: see struct iwl_cfg * @priv: pointer to the upper layer data * @trans: pointer to the transport layer data + * @nic: pointer to the nic 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. @@ -385,13 +384,12 @@ struct iwl_shared { bool wowlan; u8 valid_contexts; - struct iwl_bus *bus; struct iwl_cfg *cfg; struct iwl_priv *priv; struct iwl_trans *trans; + struct iwl_nic *nic; struct iwl_hw_params hw_params; - struct workqueue_struct *workqueue; spinlock_t lock; spinlock_t sta_lock; struct mutex mutex; @@ -416,10 +414,10 @@ struct iwl_shared { }; -/*Whatever _m is (iwl_trans, iwl_priv, iwl_bus, these macros will work */ +/*Whatever _m is (iwl_trans, iwl_priv, these macros will work */ #define priv(_m) ((_m)->shrd->priv) #define cfg(_m) ((_m)->shrd->cfg) -#define bus(_m) ((_m)->shrd->bus) +#define nic(_m) ((_m)->shrd->nic) #define trans(_m) ((_m)->shrd->trans) #define hw_params(_m) ((_m)->shrd->hw_params) @@ -531,24 +529,11 @@ enum iwl_rxon_context_id { NUM_IWL_RXON_CTX }; -int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, - struct iwl_cfg *cfg); -void __devexit iwl_remove(struct iwl_priv * priv); -struct iwl_device_cmd; -int __must_check iwl_rx_dispatch(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb, - struct iwl_device_cmd *cmd); - int iwlagn_hw_valid_rtc_data_addr(u32 addr); -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); -void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand); const char *get_cmd_string(u8 cmd); bool iwl_check_for_ct_kill(struct iwl_priv *priv); -void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac); -void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac); /* notification wait support */ void iwl_abort_notification_waits(struct iwl_shared *shrd); @@ -568,20 +553,6 @@ void __releases(wait_entry) iwl_remove_notification(struct iwl_shared *shrd, struct iwl_notification_wait *wait_entry); -#ifdef CONFIG_IWLWIFI_DEBUGFS -void iwl_reset_traffic_log(struct iwl_priv *priv); -#endif /* CONFIG_IWLWIFI_DEBUGFS */ - -#ifdef CONFIG_IWLWIFI_DEBUG -void iwl_print_rx_config_cmd(struct iwl_priv *priv, - enum iwl_rxon_context_id ctxid); -#else -static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv, - enum iwl_rxon_context_id ctxid) -{ -} -#endif - #define IWL_CMD(x) case x: return #x #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c index df7ab332c833..23eea06a74ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.c +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c @@ -78,9 +78,15 @@ #include "iwl-agn.h" #include "iwl-testmode.h" #include "iwl-trans.h" -#include "iwl-bus.h" #include "iwl-fh.h" + +/* Periphery registers absolute lower bound. This is used in order to + * differentiate registery access through HBUS_TARG_PRPH_* and + * HBUS_TARG_MEM_* accesses. + */ +#define IWL_TM_ABS_PRPH_START (0xA00000) + /* The TLVs used in the gnl message policy between the kernel module and * user space application. iwl_testmode_gnl_msg_policy is to be carried * through the NL80211_CMD_TESTMODE channel regulated by nl80211. @@ -110,9 +116,9 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = { [IWL_TM_ATTR_UCODE_OWNER] = { .type = NLA_U8, }, - [IWL_TM_ATTR_SRAM_ADDR] = { .type = NLA_U32, }, - [IWL_TM_ATTR_SRAM_SIZE] = { .type = NLA_U32, }, - [IWL_TM_ATTR_SRAM_DUMP] = { .type = NLA_UNSPEC, }, + [IWL_TM_ATTR_MEM_ADDR] = { .type = NLA_U32, }, + [IWL_TM_ATTR_BUFFER_SIZE] = { .type = NLA_U32, }, + [IWL_TM_ATTR_BUFFER_DUMP] = { .type = NLA_UNSPEC, }, [IWL_TM_ATTR_FW_VERSION] = { .type = NLA_U32, }, [IWL_TM_ATTR_DEVICE_ID] = { .type = NLA_U32, }, @@ -172,7 +178,7 @@ static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv, skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length, GFP_ATOMIC); if (skb == NULL) { - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Run out of memory for messages to user space ?\n"); return; } @@ -183,24 +189,24 @@ static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv, nla_put_failure: kfree_skb(skb); - IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n"); + IWL_ERR(priv, "Ouch, overran buffer, check allocation!\n"); } void iwl_testmode_init(struct iwl_priv *priv) { priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt; priv->testmode_trace.trace_enabled = false; - priv->testmode_sram.sram_readed = false; + priv->testmode_mem.read_in_progress = false; } -static void iwl_sram_cleanup(struct iwl_priv *priv) +static void iwl_mem_cleanup(struct iwl_priv *priv) { - if (priv->testmode_sram.sram_readed) { - kfree(priv->testmode_sram.buff_addr); - priv->testmode_sram.buff_addr = NULL; - priv->testmode_sram.buff_size = 0; - priv->testmode_sram.num_chunks = 0; - priv->testmode_sram.sram_readed = false; + if (priv->testmode_mem.read_in_progress) { + kfree(priv->testmode_mem.buff_addr); + priv->testmode_mem.buff_addr = NULL; + priv->testmode_mem.buff_size = 0; + priv->testmode_mem.num_chunks = 0; + priv->testmode_mem.read_in_progress = false; } } @@ -226,9 +232,10 @@ static void iwl_trace_cleanup(struct iwl_priv *priv) void iwl_testmode_cleanup(struct iwl_priv *priv) { iwl_trace_cleanup(priv); - iwl_sram_cleanup(priv); + iwl_mem_cleanup(priv); } + /* * This function handles the user application commands to the ucode. * @@ -237,35 +244,80 @@ void iwl_testmode_cleanup(struct iwl_priv *priv) * host command to the ucode. * * If any mandatory field is missing, -ENOMSG is replied to the user space - * application; otherwise, the actual execution result of the host command to - * ucode is replied. + * application; otherwise, waits for the host command to be sent and checks + * the return code. In case or error, it is returned, otherwise a reply is + * allocated and the reply RX packet + * is returned. * * @hw: ieee80211_hw object that represents the device * @tb: gnl message fields from the user space */ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_host_cmd cmd; + struct iwl_rx_packet *pkt; + struct sk_buff *skb; + void *reply_buf; + u32 reply_len; + int ret; + bool cmd_want_skb; memset(&cmd, 0, sizeof(struct iwl_host_cmd)); if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] || !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) { - IWL_DEBUG_INFO(priv, - "Error finding ucode command mandatory fields\n"); + IWL_ERR(priv, "Missing ucode command mandatory fields\n"); return -ENOMSG; } - cmd.flags = CMD_ON_DEMAND; + cmd.flags = CMD_ON_DEMAND | CMD_SYNC; + cmd_want_skb = nla_get_flag(tb[IWL_TM_ATTR_UCODE_CMD_SKB]); + if (cmd_want_skb) + cmd.flags |= CMD_WANT_SKB; + cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]); cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; - IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x," + IWL_DEBUG_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x," " len %d\n", cmd.id, cmd.flags, cmd.len[0]); - /* ok, let's submit the command to ucode */ - return iwl_trans_send_cmd(trans(priv), &cmd); + + ret = iwl_trans_send_cmd(trans(priv), &cmd); + if (ret) { + IWL_ERR(priv, "Failed to send hcmd\n"); + return ret; + } + if (!cmd_want_skb) + return ret; + + /* Handling return of SKB to the user */ + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (!pkt) { + IWL_ERR(priv, "HCMD received a null response packet\n"); + return ret; + } + + reply_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, reply_len + 20); + reply_buf = kmalloc(reply_len, GFP_KERNEL); + if (!skb || !reply_buf) { + kfree_skb(skb); + kfree(reply_buf); + return -ENOMEM; + } + + /* The reply is in a page, that we cannot send to user space. */ + memcpy(reply_buf, &(pkt->hdr), reply_len); + iwl_free_pages(priv->shrd, cmd.reply_page); + + NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT); + NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, reply_len, reply_buf); + return cfg80211_testmode_reply(skb); + +nla_put_failure: + IWL_DEBUG_INFO(priv, "Failed creating NL attributes\n"); + return -ENOMSG; } @@ -288,14 +340,14 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb) */ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); u32 ofs, val32, cmd; u8 val8; struct sk_buff *skb; int status = 0; if (!tb[IWL_TM_ATTR_REG_OFFSET]) { - IWL_DEBUG_INFO(priv, "Error finding register offset\n"); + IWL_ERR(priv, "Missing register offset\n"); return -ENOMSG; } ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]); @@ -309,7 +361,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32 || cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8) && (ofs >= FH_MEM_UPPER_BOUND)) { - IWL_DEBUG_INFO(priv, "offset out of segment (0x0 - 0x%x)\n", + IWL_ERR(priv, "offset out of segment (0x0 - 0x%x)\n", FH_MEM_UPPER_BOUND); return -EINVAL; } @@ -321,19 +373,17 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); if (!skb) { - IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", status); + IWL_ERR(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32: if (!tb[IWL_TM_ATTR_REG_VALUE32]) { - IWL_DEBUG_INFO(priv, - "Error finding value to write\n"); + IWL_ERR(priv, "Missing value to write\n"); return -ENOMSG; } else { val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]); @@ -343,7 +393,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) break; case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8: if (!tb[IWL_TM_ATTR_REG_VALUE8]) { - IWL_DEBUG_INFO(priv, "Error finding value to write\n"); + IWL_ERR(priv, "Missing value to write\n"); return -ENOMSG; } else { val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]); @@ -351,34 +401,8 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) iwl_write8(trans(priv), ofs, val8); } break; - case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32: - val32 = iwl_read_prph(trans(priv), ofs); - IWL_INFO(priv, "32bit value to read 0x%x\n", val32); - - skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); - if (!skb) { - IWL_DEBUG_INFO(priv, "Error allocating memory\n"); - return -ENOMEM; - } - NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32); - status = cfg80211_testmode_reply(skb); - if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", status); - break; - case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32: - if (!tb[IWL_TM_ATTR_REG_VALUE32]) { - IWL_DEBUG_INFO(priv, - "Error finding value to write\n"); - return -ENOMSG; - } else { - val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]); - IWL_INFO(priv, "32bit value to write 0x%x\n", val32); - iwl_write_prph(trans(priv), ofs, val32); - } - break; default: - IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n"); + IWL_ERR(priv, "Unknown testmode register command ID\n"); return -ENOSYS; } @@ -400,14 +424,13 @@ static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv) NULL, NULL); ret = iwl_init_alive_start(trans(priv)); if (ret) { - IWL_DEBUG_INFO(priv, - "Error configuring init calibration: %d\n", ret); + IWL_ERR(priv, "Fail init calibration: %d\n", ret); goto cfg_init_calib_error; } ret = iwl_wait_notification(priv->shrd, &calib_wait, 2 * HZ); if (ret) - IWL_DEBUG_INFO(priv, "Error detecting" + IWL_ERR(priv, "Error detecting" " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret); return ret; @@ -434,7 +457,7 @@ cfg_init_calib_error: */ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_trans *trans = trans(priv); struct sk_buff *skb; unsigned char *rsp_data_ptr = NULL; @@ -448,8 +471,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, rsp_data_len + 20); if (!skb) { - IWL_DEBUG_INFO(priv, - "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, @@ -458,15 +480,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) rsp_data_len, rsp_data_ptr); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, "Error sending msg : %d\n", - status); + IWL_ERR(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_INIT); if (status) - IWL_DEBUG_INFO(priv, - "Error loading init ucode: %d\n", status); + IWL_ERR(priv, "Error loading init ucode: %d\n", status); break; case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: @@ -477,13 +497,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_REGULAR); if (status) { - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Error loading runtime ucode: %d\n", status); break; } status = iwl_alive_start(priv); if (status) - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Error starting the device: %d\n", status); break; @@ -492,13 +512,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) iwl_trans_stop_device(trans); status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_WOWLAN); if (status) { - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Error loading WOWLAN ucode: %d\n", status); break; } status = iwl_alive_start(priv); if (status) - IWL_DEBUG_INFO(priv, + IWL_ERR(priv, "Error starting the device: %d\n", status); break; @@ -507,8 +527,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, cfg(priv)->base_params->eeprom_size + 20); if (!skb) { - IWL_DEBUG_INFO(priv, - "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, @@ -518,35 +537,34 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) priv->shrd->eeprom); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", - status); + IWL_ERR(priv, "Error sending msg : %d\n", + status); } else return -EFAULT; break; case IWL_TM_CMD_APP2DEV_FIXRATE_REQ: if (!tb[IWL_TM_ATTR_FIXRATE]) { - IWL_DEBUG_INFO(priv, - "Error finding fixrate setting\n"); + IWL_ERR(priv, "Missing fixrate setting\n"); return -ENOMSG; } priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]); break; case IWL_TM_CMD_APP2DEV_GET_FW_VERSION: - IWL_INFO(priv, "uCode version raw: 0x%x\n", priv->ucode_ver); + IWL_INFO(priv, "uCode version raw: 0x%x\n", + nic(priv)->fw.ucode_ver); skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); if (!skb) { - IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } - NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, priv->ucode_ver); + NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, + nic(priv)->fw.ucode_ver); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", status); + IWL_ERR(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: @@ -555,40 +573,39 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); if (!skb) { - IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_DEVICE_ID, devid); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", status); + IWL_ERR(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_GET_FW_INFO: skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20 + 8); if (!skb) { - IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } switch (priv->shrd->ucode_type) { case IWL_UCODE_REGULAR: - inst_size = trans(priv)->ucode_rt.code.len; - data_size = trans(priv)->ucode_rt.data.len; + inst_size = nic(priv)->fw.ucode_rt.code.len; + data_size = nic(priv)->fw.ucode_rt.data.len; break; case IWL_UCODE_INIT: - inst_size = trans(priv)->ucode_init.code.len; - data_size = trans(priv)->ucode_init.data.len; + inst_size = nic(priv)->fw.ucode_init.code.len; + data_size = nic(priv)->fw.ucode_init.data.len; break; case IWL_UCODE_WOWLAN: - inst_size = trans(priv)->ucode_wowlan.code.len; - data_size = trans(priv)->ucode_wowlan.data.len; + inst_size = nic(priv)->fw.ucode_wowlan.code.len; + data_size = nic(priv)->fw.ucode_wowlan.data.len; break; case IWL_UCODE_NONE: - IWL_DEBUG_INFO(priv, "The uCode has not been loaded\n"); + IWL_ERR(priv, "No uCode has not been loaded\n"); break; default: - IWL_DEBUG_INFO(priv, "Unsupported uCode type\n"); + IWL_ERR(priv, "Unsupported uCode type\n"); break; } NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type); @@ -596,12 +613,11 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) NLA_PUT_U32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size); status = cfg80211_testmode_reply(skb); if (status < 0) - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", status); + IWL_ERR(priv, "Error sending msg : %d\n", status); break; default: - IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n"); + IWL_ERR(priv, "Unknown testmode driver command ID\n"); return -ENOSYS; } return status; @@ -626,7 +642,7 @@ nla_put_failure: */ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct sk_buff *skb; int status = 0; struct device *dev = trans(priv)->dev; @@ -664,8 +680,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, sizeof(priv->testmode_trace.dma_addr) + 20); if (!skb) { - IWL_DEBUG_INFO(priv, - "Error allocating memory\n"); + IWL_ERR(priv, "Memory allocation fail\n"); iwl_trace_cleanup(priv); return -ENOMEM; } @@ -674,9 +689,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) (u64 *)&priv->testmode_trace.dma_addr); status = cfg80211_testmode_reply(skb); if (status < 0) { - IWL_DEBUG_INFO(priv, - "Error sending msg : %d\n", - status); + IWL_ERR(priv, "Error sending msg : %d\n", status); } priv->testmode_trace.num_chunks = DIV_ROUND_UP(priv->testmode_trace.buff_size, @@ -687,7 +700,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) iwl_trace_cleanup(priv); break; default: - IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n"); + IWL_ERR(priv, "Unknown testmode mem command ID\n"); return -ENOSYS; } return status; @@ -704,7 +717,7 @@ static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, struct nlattr **tb, struct sk_buff *skb, struct netlink_callback *cb) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int idx, length; if (priv->testmode_trace.trace_enabled && @@ -748,11 +761,11 @@ static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, struct nlattr **tb, */ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); u8 owner; if (!tb[IWL_TM_ATTR_UCODE_OWNER]) { - IWL_DEBUG_INFO(priv, "Error finding ucode owner\n"); + IWL_ERR(priv, "Missing ucode owner\n"); return -ENOMSG; } @@ -760,12 +773,89 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) if ((owner == IWL_OWNERSHIP_DRIVER) || (owner == IWL_OWNERSHIP_TM)) priv->shrd->ucode_owner = owner; else { - IWL_DEBUG_INFO(priv, "Invalid owner\n"); + IWL_ERR(priv, "Invalid owner\n"); return -EINVAL; } return 0; } +static int iwl_testmode_indirect_read(struct iwl_priv *priv, u32 addr, u32 size) +{ + struct iwl_trans *trans = trans(priv); + unsigned long flags; + int i; + + if (size & 0x3) + return -EINVAL; + priv->testmode_mem.buff_size = size; + priv->testmode_mem.buff_addr = + kmalloc(priv->testmode_mem.buff_size, GFP_KERNEL); + if (priv->testmode_mem.buff_addr == NULL) + return -ENOMEM; + + /* Hard-coded periphery absolute address */ + if (IWL_TM_ABS_PRPH_START <= addr && + addr < IWL_TM_ABS_PRPH_START + PRPH_END) { + spin_lock_irqsave(&trans->reg_lock, flags); + iwl_grab_nic_access(trans); + iwl_write32(trans, HBUS_TARG_PRPH_RADDR, + addr | (3 << 24)); + for (i = 0; i < size; i += 4) + *(u32 *)(priv->testmode_mem.buff_addr + i) = + iwl_read32(trans, HBUS_TARG_PRPH_RDAT); + iwl_release_nic_access(trans); + spin_unlock_irqrestore(&trans->reg_lock, flags); + } else { /* target memory (SRAM) */ + _iwl_read_targ_mem_words(trans, addr, + priv->testmode_mem.buff_addr, + priv->testmode_mem.buff_size / 4); + } + + priv->testmode_mem.num_chunks = + DIV_ROUND_UP(priv->testmode_mem.buff_size, DUMP_CHUNK_SIZE); + priv->testmode_mem.read_in_progress = true; + return 0; + +} + +static int iwl_testmode_indirect_write(struct iwl_priv *priv, u32 addr, + u32 size, unsigned char *buf) +{ + struct iwl_trans *trans = trans(priv); + u32 val, i; + unsigned long flags; + + if (IWL_TM_ABS_PRPH_START <= addr && + addr < IWL_TM_ABS_PRPH_START + PRPH_END) { + /* Periphery writes can be 1-3 bytes long, or DWORDs */ + if (size < 4) { + memcpy(&val, buf, size); + spin_lock_irqsave(&trans->reg_lock, flags); + iwl_grab_nic_access(trans); + iwl_write32(trans, HBUS_TARG_PRPH_WADDR, + (addr & 0x0000FFFF) | + ((size - 1) << 24)); + iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); + iwl_release_nic_access(trans); + /* needed after consecutive writes w/o read */ + mmiowb(); + spin_unlock_irqrestore(&trans->reg_lock, flags); + } else { + if (size % 4) + return -EINVAL; + for (i = 0; i < size; i += 4) + iwl_write_prph(trans, addr+i, + *(u32 *)(buf+i)); + } + } else if (iwlagn_hw_valid_rtc_data_addr(addr) || + (IWLAGN_RTC_INST_LOWER_BOUND <= addr && + addr < IWLAGN_RTC_INST_UPPER_BOUND)) { + _iwl_write_targ_mem_words(trans, addr, buf, size/4); + } else + return -EINVAL; + return 0; +} + /* * This function handles the user application commands for SRAM data dump * @@ -782,82 +872,60 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) * @hw: ieee80211_hw object that represents the device * @tb: gnl message fields from the user space */ -static int iwl_testmode_sram(struct ieee80211_hw *hw, struct nlattr **tb) +static int iwl_testmode_indirect_mem(struct ieee80211_hw *hw, + struct nlattr **tb) { - struct iwl_priv *priv = hw->priv; - u32 ofs, size, maxsize; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); + u32 addr, size, cmd; + unsigned char *buf; - if (priv->testmode_sram.sram_readed) + /* Both read and write should be blocked, for atomicity */ + if (priv->testmode_mem.read_in_progress) return -EBUSY; - if (!tb[IWL_TM_ATTR_SRAM_ADDR]) { - IWL_DEBUG_INFO(priv, "Error finding SRAM offset address\n"); + cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]); + if (!tb[IWL_TM_ATTR_MEM_ADDR]) { + IWL_ERR(priv, "Error finding memory offset address\n"); return -ENOMSG; } - ofs = nla_get_u32(tb[IWL_TM_ATTR_SRAM_ADDR]); - if (!tb[IWL_TM_ATTR_SRAM_SIZE]) { - IWL_DEBUG_INFO(priv, "Error finding size for SRAM reading\n"); + addr = nla_get_u32(tb[IWL_TM_ATTR_MEM_ADDR]); + if (!tb[IWL_TM_ATTR_BUFFER_SIZE]) { + IWL_ERR(priv, "Error finding size for memory reading\n"); return -ENOMSG; } - size = nla_get_u32(tb[IWL_TM_ATTR_SRAM_SIZE]); - switch (priv->shrd->ucode_type) { - case IWL_UCODE_REGULAR: - maxsize = trans(priv)->ucode_rt.data.len; - break; - case IWL_UCODE_INIT: - maxsize = trans(priv)->ucode_init.data.len; - break; - case IWL_UCODE_WOWLAN: - maxsize = trans(priv)->ucode_wowlan.data.len; - break; - case IWL_UCODE_NONE: - IWL_ERR(priv, "Error, uCode does not been loaded\n"); - return -ENOSYS; - default: - IWL_ERR(priv, "Error, unsupported uCode type\n"); - return -ENOSYS; - } - if ((ofs + size) > (maxsize + SRAM_DATA_SEG_OFFSET)) { - IWL_ERR(priv, "Invalid offset/size: out of range\n"); - return -EINVAL; - } - priv->testmode_sram.buff_size = (size / 4) * 4; - priv->testmode_sram.buff_addr = - kmalloc(priv->testmode_sram.buff_size, GFP_KERNEL); - if (priv->testmode_sram.buff_addr == NULL) { - IWL_ERR(priv, "Error allocating memory\n"); - return -ENOMEM; + size = nla_get_u32(tb[IWL_TM_ATTR_BUFFER_SIZE]); + + if (cmd == IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ) + return iwl_testmode_indirect_read(priv, addr, size); + else { + if (!tb[IWL_TM_ATTR_BUFFER_DUMP]) + return -EINVAL; + buf = (unsigned char *) nla_data(tb[IWL_TM_ATTR_BUFFER_DUMP]); + return iwl_testmode_indirect_write(priv, addr, size, buf); } - _iwl_read_targ_mem_words(trans(priv), ofs, - priv->testmode_sram.buff_addr, - priv->testmode_sram.buff_size / 4); - priv->testmode_sram.num_chunks = - DIV_ROUND_UP(priv->testmode_sram.buff_size, DUMP_CHUNK_SIZE); - priv->testmode_sram.sram_readed = true; - return 0; } -static int iwl_testmode_sram_dump(struct ieee80211_hw *hw, struct nlattr **tb, +static int iwl_testmode_buffer_dump(struct ieee80211_hw *hw, struct nlattr **tb, struct sk_buff *skb, struct netlink_callback *cb) { - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int idx, length; - if (priv->testmode_sram.sram_readed) { + if (priv->testmode_mem.read_in_progress) { idx = cb->args[4]; - if (idx >= priv->testmode_sram.num_chunks) { - iwl_sram_cleanup(priv); + if (idx >= priv->testmode_mem.num_chunks) { + iwl_mem_cleanup(priv); return -ENOENT; } length = DUMP_CHUNK_SIZE; - if (((idx + 1) == priv->testmode_sram.num_chunks) && - (priv->testmode_sram.buff_size % DUMP_CHUNK_SIZE)) - length = priv->testmode_sram.buff_size % + if (((idx + 1) == priv->testmode_mem.num_chunks) && + (priv->testmode_mem.buff_size % DUMP_CHUNK_SIZE)) + length = priv->testmode_mem.buff_size % DUMP_CHUNK_SIZE; - NLA_PUT(skb, IWL_TM_ATTR_SRAM_DUMP, length, - priv->testmode_sram.buff_addr + + NLA_PUT(skb, IWL_TM_ATTR_BUFFER_DUMP, length, + priv->testmode_mem.buff_addr + (DUMP_CHUNK_SIZE * idx)); idx++; cb->args[4] = idx; @@ -892,20 +960,19 @@ static int iwl_testmode_sram_dump(struct ieee80211_hw *hw, struct nlattr **tb, int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) { struct nlattr *tb[IWL_TM_ATTR_MAX]; - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int result; result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len, iwl_testmode_gnl_msg_policy); if (result != 0) { - IWL_DEBUG_INFO(priv, - "Error parsing the gnl message : %d\n", result); + IWL_ERR(priv, "Error parsing the gnl message : %d\n", result); return result; } /* IWL_TM_ATTR_COMMAND is absolutely mandatory */ if (!tb[IWL_TM_ATTR_COMMAND]) { - IWL_DEBUG_INFO(priv, "Error finding testmode command type\n"); + IWL_ERR(priv, "Missing testmode command type\n"); return -ENOMSG; } /* in case multiple accesses to the device happens */ @@ -919,8 +986,6 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32: case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32: case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8: - case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32: - case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32: IWL_DEBUG_INFO(priv, "testmode cmd to register\n"); result = iwl_testmode_reg(hw, tb); break; @@ -950,13 +1015,15 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) result = iwl_testmode_ownership(hw, tb); break; - case IWL_TM_CMD_APP2DEV_READ_SRAM: - IWL_DEBUG_INFO(priv, "testmode sram read cmd to driver\n"); - result = iwl_testmode_sram(hw, tb); + case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ: + case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE: + IWL_DEBUG_INFO(priv, "testmode indirect memory cmd " + "to driver\n"); + result = iwl_testmode_indirect_mem(hw, tb); break; default: - IWL_DEBUG_INFO(priv, "Unknown testmode command\n"); + IWL_ERR(priv, "Unknown testmode command\n"); result = -ENOSYS; break; } @@ -970,7 +1037,7 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, void *data, int len) { struct nlattr *tb[IWL_TM_ATTR_MAX]; - struct iwl_priv *priv = hw->priv; + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int result; u32 cmd; @@ -981,15 +1048,14 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len, iwl_testmode_gnl_msg_policy); if (result) { - IWL_DEBUG_INFO(priv, - "Error parsing the gnl message : %d\n", result); + IWL_ERR(priv, + "Error parsing the gnl message : %d\n", result); return result; } /* IWL_TM_ATTR_COMMAND is absolutely mandatory */ if (!tb[IWL_TM_ATTR_COMMAND]) { - IWL_DEBUG_INFO(priv, - "Error finding testmode command type\n"); + IWL_ERR(priv, "Missing testmode command type\n"); return -ENOMSG; } cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]); @@ -1003,9 +1069,9 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n"); result = iwl_testmode_trace_dump(hw, tb, skb, cb); break; - case IWL_TM_CMD_APP2DEV_DUMP_SRAM: + case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP: IWL_DEBUG_INFO(priv, "testmode sram dump cmd to driver\n"); - result = iwl_testmode_sram_dump(hw, tb, skb, cb); + result = iwl_testmode_buffer_dump(hw, tb, skb, cb); break; default: result = -EINVAL; diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h index f97d06169b45..69b2e80f4071 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.h +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h @@ -99,7 +99,7 @@ * to user application * @IWL_TM_CMD_DEV2APP_UCODE_RX_PKT: * commands from kernel space to multicast the spontaneous messages - * to user application + * to user application, or reply of host commands * @IWL_TM_CMD_DEV2APP_EEPROM_RSP: * commands from kernel space to carry the eeprom response * to user application @@ -109,20 +109,19 @@ * if application has the ownership, the only host command from * testmode will deliver to uCode. Default owner is driver * - * @IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32: - * @IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32: - * commands from user application to indirectly access peripheral register - * - * @IWL_TM_CMD_APP2DEV_READ_SRAM: - * @IWL_TM_CMD_APP2DEV_DUMP_SRAM: - * commands from user application to read data in sram - * * @IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: load Wake On Wireless LAN uCode image * @IWL_TM_CMD_APP2DEV_GET_FW_VERSION: retrieve uCode version * @IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: retrieve ID information in device * @IWL_TM_CMD_APP2DEV_GET_FW_INFO: * retrieve information of existing loaded uCode image * + * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ: + * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP: + * @IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE: + * Commands to read/write data from periphery or SRAM memory ranges. + * Fore reading, a READ command is sent from the userspace and the data + * is returned when the user calls a DUMP command. + * For writing, only a WRITE command is used. */ enum iwl_tm_cmd_t { IWL_TM_CMD_APP2DEV_UCODE = 1, @@ -142,15 +141,18 @@ enum iwl_tm_cmd_t { IWL_TM_CMD_DEV2APP_UCODE_RX_PKT = 15, IWL_TM_CMD_DEV2APP_EEPROM_RSP = 16, IWL_TM_CMD_APP2DEV_OWNERSHIP = 17, - IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32 = 18, - IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32 = 19, - IWL_TM_CMD_APP2DEV_READ_SRAM = 20, - IWL_TM_CMD_APP2DEV_DUMP_SRAM = 21, + RESERVED_18 = 18, + RESERVED_19 = 19, + RESERVED_20 = 20, + RESERVED_21 = 21, IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW = 22, IWL_TM_CMD_APP2DEV_GET_FW_VERSION = 23, IWL_TM_CMD_APP2DEV_GET_DEVICE_ID = 24, IWL_TM_CMD_APP2DEV_GET_FW_INFO = 25, - IWL_TM_CMD_MAX = 26, + IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ = 26, + IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP = 27, + IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE = 28, + IWL_TM_CMD_MAX = 29, }; /* @@ -171,8 +173,6 @@ enum iwl_tm_cmd_t { * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE, * The mandatory fields are : * IWL_TM_ATTR_UCODE_CMD_ID for recognizable command ID; - * IWL_TM_ATTR_COMMAND_FLAG for the flags of the commands; - * The optional fields are: * IWL_TM_ATTR_UCODE_CMD_DATA for the actual command payload * to the ucode * @@ -221,16 +221,19 @@ enum iwl_tm_cmd_t { * The mandatory fields are: * IWL_TM_ATTR_UCODE_OWNER for the new owner * - * @IWL_TM_ATTR_SRAM_ADDR: - * @IWL_TM_ATTR_SRAM_SIZE: - * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_READ_SRAM, + * @IWL_TM_ATTR_MEM_ADDR: + * @IWL_TM_ATTR_BUFFER_SIZE: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ + * or IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE. * The mandatory fields are: - * IWL_TM_ATTR_SRAM_ADDR for the address in sram - * IWL_TM_ATTR_SRAM_SIZE for the buffer size of data reading + * IWL_TM_ATTR_MEM_ADDR for the address in SRAM/periphery to read/write + * IWL_TM_ATTR_BUFFER_SIZE for the buffer size of data to read/write. * - * @IWL_TM_ATTR_SRAM_DUMP: - * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_DUMP_SRAM, - * IWL_TM_ATTR_SRAM_DUMP for the data in sram + * @IWL_TM_ATTR_BUFFER_DUMP: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP, + * IWL_TM_ATTR_BUFFER_DUMP is used for the data that was read. + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE, + * this attribute contains the data to write. * * @IWL_TM_ATTR_FW_VERSION: * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_GET_FW_VERSION, @@ -249,6 +252,10 @@ enum iwl_tm_cmd_t { * IWL_TM_ATTR_FW_INST_SIZE for the size of instruction section * IWL_TM_ATTR_FW_DATA_SIZE for the size of data section * + * @IWL_TM_ATTR_UCODE_CMD_SKB: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE this flag + * indicates that the user wants to receive the response of the command + * in a reply SKB. If it's not present, the response is not returned. */ enum iwl_tm_attr_t { IWL_TM_ATTR_NOT_APPLICABLE = 0, @@ -266,15 +273,16 @@ enum iwl_tm_attr_t { IWL_TM_ATTR_TRACE_DUMP = 12, IWL_TM_ATTR_FIXRATE = 13, IWL_TM_ATTR_UCODE_OWNER = 14, - IWL_TM_ATTR_SRAM_ADDR = 15, - IWL_TM_ATTR_SRAM_SIZE = 16, - IWL_TM_ATTR_SRAM_DUMP = 17, + IWL_TM_ATTR_MEM_ADDR = 15, + IWL_TM_ATTR_BUFFER_SIZE = 16, + IWL_TM_ATTR_BUFFER_DUMP = 17, IWL_TM_ATTR_FW_VERSION = 18, IWL_TM_ATTR_DEVICE_ID = 19, IWL_TM_ATTR_FW_TYPE = 20, IWL_TM_ATTR_FW_INST_SIZE = 21, IWL_TM_ATTR_FW_DATA_SIZE = 22, - IWL_TM_ATTR_MAX = 23, + IWL_TM_ATTR_UCODE_CMD_SKB = 23, + IWL_TM_ATTR_MAX = 24, }; /* uCode trace buffer */ diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h index 561865f29d56..5b26b71ae3d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h @@ -40,6 +40,7 @@ #include "iwl-trans.h" #include "iwl-debug.h" #include "iwl-io.h" +#include "iwl-op-mode.h" struct iwl_tx_queue; struct iwl_queue; @@ -230,6 +231,7 @@ struct iwl_trans_pcie { struct tasklet_struct irq_tasklet; struct isr_statistics isr_stats; + spinlock_t irq_lock; u32 inta_mask; u32 scd_base_addr; struct iwl_dma_ptr scd_bc_tbls; @@ -373,7 +375,7 @@ static inline void iwl_wake_queue(struct iwl_trans *trans, if (test_and_clear_bit(hwq, trans_pcie->queue_stopped)) { if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0) { - iwl_wake_sw_queue(priv(trans), ac); + iwl_op_mode_queue_not_full(trans->op_mode, ac); IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d ac %d. %s", hwq, ac, msg); } else { @@ -396,7 +398,7 @@ static inline void iwl_stop_queue(struct iwl_trans *trans, if (!test_and_set_bit(hwq, trans_pcie->queue_stopped)) { if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0) { - iwl_stop_sw_queue(priv(trans), ac); + iwl_op_mode_queue_full(trans->op_mode, ac); IWL_DEBUG_TX_QUEUES(trans, "Stop hwq %d ac %d" " stop count %d. %s", hwq, ac, atomic_read(&trans_pcie-> diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c index 3826852ec5f0..2c910fddaaf6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c @@ -34,6 +34,8 @@ #include "iwl-core.h" #include "iwl-io.h" #include "iwl-trans-pcie-int.h" +#include "iwl-wifi.h" +#include "iwl-op-mode.h" #ifdef CONFIG_IWLWIFI_IDI #include "iwl-amfh.h" @@ -227,7 +229,7 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans) /* If the pre-allocated buffer pool is dropping low, schedule to * refill it */ if (rxq->free_count <= RX_LOW_WATERMARK) - queue_work(trans->shrd->workqueue, &trans_pcie->rx_replenish); + schedule_work(&trans_pcie->rx_replenish); /* If we've added more space for the firmware to place data, tell it. @@ -331,13 +333,14 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) void iwlagn_rx_replenish(struct iwl_trans *trans) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); unsigned long flags; iwlagn_rx_allocate(trans, GFP_KERNEL); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwlagn_rx_queue_restock(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } static void iwlagn_rx_replenish_now(struct iwl_trans *trans) @@ -351,14 +354,8 @@ void iwl_bg_rx_replenish(struct work_struct *data) { struct iwl_trans_pcie *trans_pcie = container_of(data, struct iwl_trans_pcie, rx_replenish); - struct iwl_trans *trans = trans_pcie->trans; - - if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status)) - return; - mutex_lock(&trans->shrd->mutex); - iwlagn_rx_replenish(trans); - mutex_unlock(&trans->shrd->mutex); + iwlagn_rx_replenish(trans_pcie->trans); } /** @@ -464,7 +461,7 @@ static void iwl_rx_handle(struct iwl_trans *trans) "reclaim is false, SEQ_RX_FRAME unset: %s\n", get_cmd_string(pkt->hdr.cmd)); - err = iwl_rx_dispatch(priv(trans), rxb, cmd); + err = iwl_op_mode_rx(trans->op_mode, rxb, cmd); /* * XXX: After here, we should always check rxb->page @@ -594,17 +591,17 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans) { u32 base; struct iwl_error_event_table table; - struct iwl_priv *priv = priv(trans); + struct iwl_nic *nic = nic(trans); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); base = trans->shrd->device_pointers.error_event_table; if (trans->shrd->ucode_type == IWL_UCODE_INIT) { if (!base) - base = priv->init_errlog_ptr; + base = nic->init_errlog_ptr; } else { if (!base) - base = priv->inst_errlog_ptr; + base = nic->inst_errlog_ptr; } if (!iwlagn_hw_valid_rtc_data_addr(base)) { @@ -616,7 +613,7 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans) return; } - iwl_read_targ_mem_words(trans(priv), base, &table, sizeof(table)); + iwl_read_targ_mem_words(trans, base, &table, sizeof(table)); if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { IWL_ERR(trans, "Start IWL Error Log Dump:\n"); @@ -626,7 +623,7 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans) trans_pcie->isr_stats.err_code = table.error_id; - trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low, + trace_iwlwifi_dev_ucode_error(priv(nic), table.error_id, table.tsf_low, table.data1, table.data2, table.line, table.blink1, table.blink2, table.ilink1, table.ilink2, table.bcon_time, table.gp1, @@ -674,9 +671,8 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans) */ 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 (cfg(priv)->internal_wimax_coex && + if (cfg(trans)->internal_wimax_coex && (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) & APMS_CLK_VAL_MRB_FUNC_MODE) || (iwl_read_prph(trans, APMG_PS_CTRL_REG) & @@ -687,24 +683,20 @@ static void iwl_irq_handle_error(struct iwl_trans *trans) */ clear_bit(STATUS_READY, &trans->shrd->status); clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); - wake_up(&priv->shrd->wait_command_queue); + wake_up(&trans->shrd->wait_command_queue); IWL_ERR(trans, "RF is used by WiMAX\n"); return; } IWL_ERR(trans, "Loaded firmware version: %s\n", - priv->hw->wiphy->fw_version); + nic(trans)->fw.fw_version); iwl_dump_nic_error_log(trans); iwl_dump_csr(trans); iwl_dump_fh(trans, NULL, false); iwl_dump_nic_event_log(trans, false, NULL, false); -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) - iwl_print_rx_config_cmd(priv(trans), IWL_RXON_CTX_BSS); -#endif - iwlagn_fw_error(priv, false); + iwl_op_mode_nic_error(trans->op_mode); } #define EVENT_START_OFFSET (4 * sizeof(u32)) @@ -723,7 +715,7 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, u32 ptr; /* SRAM byte address of log data */ u32 ev, time, data; /* event log data */ unsigned long reg_flags; - struct iwl_priv *priv = priv(trans); + struct iwl_nic *nic = nic(trans); if (num_events == 0) return pos; @@ -731,10 +723,10 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, base = trans->shrd->device_pointers.log_event_table; if (trans->shrd->ucode_type == IWL_UCODE_INIT) { if (!base) - base = priv->init_evtlog_ptr; + base = nic->init_evtlog_ptr; } else { if (!base) - base = priv->inst_evtlog_ptr; + base = nic->inst_evtlog_ptr; } if (mode == 0) @@ -764,7 +756,7 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, "EVT_LOG:0x%08x:%04u\n", time, ev); } else { - trace_iwlwifi_dev_ucode_event(priv, 0, + trace_iwlwifi_dev_ucode_event(priv(trans), 0, time, ev); IWL_ERR(trans, "EVT_LOG:0x%08x:%04u\n", time, ev); @@ -778,7 +770,7 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, } else { IWL_ERR(trans, "EVT_LOGT:%010u:0x%08x:%04u\n", time, data, ev); - trace_iwlwifi_dev_ucode_event(priv, time, + trace_iwlwifi_dev_ucode_event(priv(trans), time, data, ev); } } @@ -840,17 +832,17 @@ int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, u32 logsize; int pos = 0; size_t bufsz = 0; - struct iwl_priv *priv = priv(trans); + struct iwl_nic *nic = nic(trans); base = trans->shrd->device_pointers.log_event_table; if (trans->shrd->ucode_type == IWL_UCODE_INIT) { - logsize = priv->init_evtlog_size; + logsize = nic->init_evtlog_size; if (!base) - base = priv->init_evtlog_ptr; + base = nic->init_evtlog_ptr; } else { - logsize = priv->inst_evtlog_size; + logsize = nic->inst_evtlog_size; if (!base) - base = priv->inst_evtlog_ptr; + base = nic->inst_evtlog_ptr; } if (!iwlagn_hw_valid_rtc_data_addr(base)) { @@ -949,7 +941,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) struct isr_statistics *isr_stats = &trans_pcie->isr_stats; - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); /* Ack/clear/reset pending uCode interrupts. * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, @@ -979,7 +971,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) /* saved interrupt in inta variable now we can reset trans_pcie->inta */ trans_pcie->inta = 0; - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* Now service all interrupt bits discovered above. */ if (inta & CSR_INT_BIT_HW_ERR) { @@ -1039,7 +1031,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) else clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status); - iwl_set_hw_rfkill_state(priv(trans), hw_rf_kill); + iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rf_kill); } handled |= CSR_INT_BIT_RF_KILL; @@ -1232,7 +1224,7 @@ void iwl_reset_ict(struct iwl_trans *trans) if (!trans_pcie->ict_tbl) return; - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_disable_interrupts(trans); memset(trans_pcie->ict_tbl, 0, ICT_SIZE); @@ -1249,7 +1241,7 @@ void iwl_reset_ict(struct iwl_trans *trans) trans_pcie->ict_index = 0; iwl_write32(trans, CSR_INT, trans_pcie->inta_mask); iwl_enable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } /* Device is going down disable ict interrupt usage */ @@ -1260,9 +1252,9 @@ void iwl_disable_ict(struct iwl_trans *trans) unsigned long flags; - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); trans_pcie->use_ict = false; - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } static irqreturn_t iwl_isr(int irq, void *data) @@ -1281,7 +1273,7 @@ static irqreturn_t iwl_isr(int irq, void *data) trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); /* Disable (but don't clear!) interrupts here to avoid * back-to-back ISRs and sporadic interrupts from our NIC. @@ -1325,7 +1317,7 @@ static irqreturn_t iwl_isr(int irq, void *data) iwl_enable_interrupts(trans); unplugged: - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return IRQ_HANDLED; none: @@ -1335,7 +1327,7 @@ static irqreturn_t iwl_isr(int irq, void *data) !trans_pcie->inta) iwl_enable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return IRQ_NONE; } @@ -1369,7 +1361,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data) trace_iwlwifi_dev_irq(priv(trans)); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); /* Disable (but don't clear!) interrupts here to avoid * back-to-back ISRs and sporadic interrupts from our NIC. @@ -1440,7 +1432,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data) iwl_enable_interrupts(trans); } - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return IRQ_HANDLED; none: @@ -1451,6 +1443,6 @@ irqreturn_t iwl_isr_ict(int irq, void *data) !trans_pcie->inta) iwl_enable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return IRQ_NONE; } diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c index a8dfecadea11..4e1e74e1b794 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c @@ -35,6 +35,7 @@ #include "iwl-prph.h" #include "iwl-io.h" #include "iwl-agn-hw.h" +#include "iwl-op-mode.h" #include "iwl-trans-pcie-int.h" #define IWL_TX_CRC_SIZE 4 @@ -229,7 +230,7 @@ void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, * freed and that the queue is not empty - free the skb */ if (skb) { - iwl_free_skb(priv(trans), skb); + iwl_op_mode_free_skb(trans->op_mode, skb); txq->skbs[index] = NULL; } } @@ -492,7 +493,7 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, ra_tid = BUILD_RAxTID(sta_id, tid); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); /* Stop this Tx queue before configuring it */ iwlagn_tx_queue_stop_scheduler(trans, txq_id); @@ -532,7 +533,7 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, trans_pcie->txq[txq_id].sta_id = sta_id; trans_pcie->txq[txq_id].tid = tid; - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } /* @@ -688,7 +689,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) is_ct_kill = iwl_check_for_ct_kill(priv(trans)); if (!is_ct_kill) { IWL_ERR(trans, "Restarting adapter queue is full\n"); - iwlagn_fw_error(priv(trans), false); + iwl_op_mode_nic_error(trans->op_mode); } return -ENOSPC; } @@ -821,7 +822,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id, if (nfreed++ > 0) { IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", idx, q->write_ptr, q->read_ptr); - iwlagn_fw_error(priv(trans), false); + iwl_op_mode_nic_error(trans->op_mode); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index f5cb5d3cd926..9f8b23909404 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -76,6 +76,7 @@ #include "iwl-eeprom.h" #include "iwl-agn-hw.h" #include "iwl-core.h" +#include "iwl-ucode.h" static int iwl_trans_rx_alloc(struct iwl_trans *trans) { @@ -219,10 +220,10 @@ static int iwl_rx_init(struct iwl_trans *trans) iwl_trans_rx_hw_init(trans, rxq); - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); rxq->need_update = 1; iwl_rx_queue_update_write_ptr(trans, rxq); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); return 0; } @@ -585,7 +586,7 @@ static int iwl_tx_init(struct iwl_trans *trans) alloc = true; } - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); /* Turn off all Tx DMA fifos */ iwl_write_prph(trans, SCD_TXFACT, 0); @@ -594,7 +595,7 @@ static int iwl_tx_init(struct iwl_trans *trans) iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, trans_pcie->kw.dma >> 4); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* Alloc and init all Tx queues, including the command queue (#4/#9) */ for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++) { @@ -803,17 +804,18 @@ static void iwl_apm_stop(struct iwl_trans *trans) static int iwl_nic_init(struct iwl_trans *trans) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); unsigned long flags; /* nic_init */ - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_apm_init(trans); /* Set interrupt coalescing calibration timer to default (512 usecs) */ iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); iwl_set_pwr_vmain(trans); @@ -1044,7 +1046,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, struct fw_img *fw) set_bit(STATUS_RF_KILL_HW, &trans->shrd->status); if (iwl_is_rfkill(trans->shrd)) { - iwl_set_hw_rfkill_state(priv(trans), true); + iwl_op_mode_hw_rf_kill(trans->op_mode, true); iwl_enable_interrupts(trans); return -ERFKILL; } @@ -1078,10 +1080,15 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, struct fw_img *fw) /* * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask - * must be called under priv->shrd->lock and mac access + * must be called under the irq lock and with MAC access */ static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask) { + struct iwl_trans_pcie __maybe_unused *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + lockdep_assert_held(&trans_pcie->irq_lock); + iwl_write_prph(trans, SCD_TXFACT, mask); } @@ -1095,7 +1102,7 @@ static void iwl_tx_start(struct iwl_trans *trans) int i, chan; u32 reg_val; - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); trans_pcie->scd_base_addr = iwl_read_prph(trans, SCD_SRAM_BASE_ADDR); @@ -1191,7 +1198,7 @@ static void iwl_tx_start(struct iwl_trans *trans) fifo, 0); } - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* Enable L1-Active */ iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, @@ -1214,7 +1221,7 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); /* Turn off all Tx DMA fifos */ - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_trans_txq_set_sched(trans, 0); @@ -1230,7 +1237,7 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans) iwl_read_direct32(trans, FH_TSSR_TX_STATUS_REG)); } - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); if (!trans_pcie->txq) { IWL_WARN(trans, "Stopping tx queues that aren't allocated..."); @@ -1250,9 +1257,9 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); /* tell the device to stop sending interrupts */ - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_disable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* device going down, Stop using ICT table */ iwl_disable_ict(trans); @@ -1285,14 +1292,16 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) /* Upon stop, the APM issues an interrupt if HW RF kill is set. * Clean again the interrupt here */ - spin_lock_irqsave(&trans->shrd->lock, flags); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); iwl_disable_interrupts(trans); - spin_unlock_irqrestore(&trans->shrd->lock, flags); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* wait to make sure we flush pending tasklet*/ synchronize_irq(trans->irq); tasklet_kill(&trans_pcie->irq_tasklet); + cancel_work_sync(&trans_pcie->rx_replenish); + /* stop and reset the on-board processor */ iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); } @@ -1516,7 +1525,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) else set_bit(STATUS_RF_KILL_HW, &trans->shrd->status); - iwl_set_hw_rfkill_state(priv(trans), + iwl_op_mode_hw_rf_kill(trans->op_mode, test_bit(STATUS_RF_KILL_HW, &trans->shrd->status)); @@ -1661,7 +1670,7 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans) else clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status); - iwl_set_hw_rfkill_state(priv(trans), hw_rfkill); + iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); return 0; } @@ -2259,6 +2268,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd, trans->shrd = shrd; trans_pcie->trans = trans; spin_lock_init(&trans->hcmd_lock); + spin_lock_init(&trans_pcie->irq_lock); /* W/A - seems to solve weird behavior. We need to remove this if we * don't want to stay in L1 all the time. This wastes a lot of power */ diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index ae68c51e5327..4e7e6c0eede9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -63,23 +63,75 @@ #ifndef __iwl_trans_h__ #define __iwl_trans_h__ -#include <linux/debugfs.h> -#include <linux/skbuff.h> +#include <linux/ieee80211.h> #include "iwl-shared.h" -#include "iwl-commands.h" +#include "iwl-debug.h" - /*This file includes the declaration that are exported from the transport - * layer */ +/** + * DOC: Transport layer - what is it ? + * + * The tranport layer is the layer that deals with the HW directly. It provides + * an abstraction of the underlying HW to the upper layer. The transport layer + * doesn't provide any policy, algorithm or anything of this kind, but only + * mechanisms to make the HW do something.It is not completely stateless but + * close to it. + * We will have an implementation for each different supported bus. + */ + +/** + * DOC: Life cycle of the transport layer + * + * The transport layer has a very precise life cycle. + * + * 1) A helper function is called during the module initialization and + * registers the bus driver's ops with the transport's alloc function. + * 2) Bus's probe calls to the transport layer's allocation functions. + * Of course this function is bus specific. + * 3) This allocation functions will spawn the upper layer which will + * register mac80211. + * + * 4) At some point (i.e. mac80211's start call), the op_mode will call + * the following sequence: + * start_hw + * start_fw + * + * 5) Then when finished (or reset): + * stop_fw (a.k.a. stop device for the moment) + * stop_hw + * + * 6) Eventually, the free function will be called. + */ struct iwl_priv; struct iwl_shared; +struct iwl_op_mode; +struct fw_img; +struct sk_buff; +struct dentry; +/** + * DOC: Host command section + * + * A host command is a commaned issued by the upper layer to the fw. There are + * several versions of fw that have several APIs. The transport layer is + * completely agnostic to these differences. + * The transport does provide helper functionnality (i.e. SYNC / ASYNC mode), + */ #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) -enum { +/** + * enum CMD_MODE - how to send the host commands ? + * + * @CMD_SYNC: The caller will be stalled until the fw responds to the command + * @CMD_ASYNC: Return right away and don't want for the response + * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the + * response. + * @CMD_ON_DEMAND: This command is sent by the test mode pipe. + */ +enum CMD_MODE { CMD_SYNC = 0, CMD_ASYNC = BIT(0), CMD_WANT_SKB = BIT(1), @@ -104,20 +156,29 @@ struct iwl_device_cmd { #define IWL_MAX_CMD_TFDS 2 +/** + * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command + * + * IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's + * ring. The transport layer doesn't map the command's buffer to DMA, but + * rather copies it to an previously allocated DMA buffer. This flag tells + * the transport layer not to copy the command, but to map the existing + * buffer. This can save memcpy and is worth with very big comamnds. + */ enum iwl_hcmd_dataflag { IWL_HCMD_DFL_NOCOPY = BIT(0), }; /** * struct iwl_host_cmd - Host command to the uCode + * * @data: array of chunks that composes the data of the host command * @reply_page: pointer to the page that holds the response to the host command * @handler_status: return value of the handler of the command * (put in setup_rx_handlers) - valid for SYNC mode only - * @callback: - * @flags: can be CMD_* note CMD_WANT_SKB is incompatible withe CMD_ASYNC + * @flags: can be CMD_* * @len: array of the lenths of the chunks in data - * @dataflags: + * @dataflags: IWL_HCMD_DFL_* * @id: id of the host command */ struct iwl_host_cmd { @@ -131,40 +192,45 @@ struct iwl_host_cmd { u8 id; }; -/* one for each uCode image (inst/data, boot/init/runtime) */ -struct fw_desc { - dma_addr_t p_addr; /* hardware address */ - void *v_addr; /* software address */ - u32 len; /* size in bytes */ -}; - -struct fw_img { - struct fw_desc code; /* firmware code image */ - struct fw_desc data; /* firmware data image */ -}; - /** * struct iwl_trans_ops - transport specific operations + * + * All the handlers MUST be implemented + * * @start_hw: starts the HW- from that point on, the HW can send interrupts + * May sleep * @stop_hw: stops the HW- from that point on, the HW will be in low power but * will still issue interrupt if the HW RF kill is triggered. + * May sleep * @start_fw: allocates and inits all the resources for the transport - * layer. Also kick a fw image. This handler may sleep. + * layer. Also kick a fw image. + * May sleep * @fw_alive: called when the fw sends alive notification + * May sleep * @wake_any_queue: wake all the queues of a specfic context IWL_RXON_CTX_* * @stop_device:stops the whole device (embedded CPU put to reset) + * May sleep * @send_cmd:send a host command + * May sleep only if CMD_SYNC is set * @tx: send an skb + * Must be atomic * @reclaim: free packet until ssn. Returns a list of freed packets. + * Must be atomic * @tx_agg_alloc: allocate resources for a TX BA session + * May sleep * @tx_agg_setup: setup a tx queue for AMPDU - will be called once the HW is - * ready and a successful ADDBA response has been received. + * ready and a successful ADDBA response has been received. + * May sleep * @tx_agg_disable: de-configure a Tx queue to send AMPDUs + * May sleep * @free: release all the ressource for the transport layer itself such as - * irq, tasklet etc... + * irq, tasklet etc... From this point on, the device may not issue + * any interrupt (incl. RFKILL). + * May sleep * @stop_queue: stop a specific queue * @check_stuck_queue: check if a specific queue is stuck * @wait_tx_queue_empty: wait until all tx queues are empty + * May sleep * @dbgfs_register: add the dbgfs files under this directory. Files will be * automatically deleted. * @suspend: stop the device unless WoWLAN is configured @@ -227,27 +293,39 @@ struct iwl_calib_result { }; /** + * enum iwl_trans_state - state of the transport layer + * + * @IWL_TRANS_NO_FW: no fw has sent an alive response + * @IWL_TRANS_FW_ALIVE: a fw has sent an alive response + */ +enum iwl_trans_state { + IWL_TRANS_NO_FW = 0, + IWL_TRANS_FW_ALIVE = 1, +}; + +/** * struct iwl_trans - transport common data + * * @ops - pointer to iwl_trans_ops + * @op_mode - pointer to the op_mode * @shrd - pointer to iwl_shared which holds shared data from the upper layer * @hcmd_lock: protects HCMD * @reg_lock - protect hw register access * @dev - pointer to struct device * that represents the device * @irq - the irq number for the device * @hw_id: a u32 with the ID of the device / subdevice. - * Set during transport alloaction. + * Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation. * @ucode_write_complete: indicates that the ucode has been copied. - * @ucode_rt: run time ucode image - * @ucode_init: init ucode image - * @ucode_wowlan: wake on wireless ucode image (optional) * @nvm_device_type: indicates OTP or eeprom * @pm_support: set to true in start_hw if link pm is supported * @calib_results: list head for init calibration results */ struct iwl_trans { const struct iwl_trans_ops *ops; + struct iwl_op_mode *op_mode; struct iwl_shared *shrd; + enum iwl_trans_state state; spinlock_t hcmd_lock; spinlock_t reg_lock; @@ -257,36 +335,51 @@ struct iwl_trans { u32 hw_id; char hw_id_str[52]; - u8 ucode_write_complete; /* the image write is complete */ - struct fw_img ucode_rt; - struct fw_img ucode_init; - struct fw_img ucode_wowlan; + u8 ucode_write_complete; - /* eeprom related variables */ int nvm_device_type; bool pm_support; - /* init calibration results */ struct list_head calib_results; /* pointer to trans specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ - char trans_specific[0] __attribute__((__aligned__(sizeof(void *)))); + char trans_specific[0] __aligned(sizeof(void *)); }; +static inline void iwl_trans_configure(struct iwl_trans *trans, + struct iwl_op_mode *op_mode) +{ + /* + * only set the op_mode for the moment. Later on, this function will do + * more + */ + trans->op_mode = op_mode; +} + static inline int iwl_trans_start_hw(struct iwl_trans *trans) { + might_sleep(); + return trans->ops->start_hw(trans); } static inline void iwl_trans_stop_hw(struct iwl_trans *trans) { + might_sleep(); + trans->ops->stop_hw(trans); + + trans->state = IWL_TRANS_NO_FW; } static inline void iwl_trans_fw_alive(struct iwl_trans *trans) { + might_sleep(); + trans->ops->fw_alive(trans); + + trans->state = IWL_TRANS_FW_ALIVE; } static inline int iwl_trans_start_fw(struct iwl_trans *trans, struct fw_img *fw) @@ -298,13 +391,20 @@ static inline int iwl_trans_start_fw(struct iwl_trans *trans, struct fw_img *fw) static inline void iwl_trans_stop_device(struct iwl_trans *trans) { + might_sleep(); + trans->ops->stop_device(trans); + + trans->state = IWL_TRANS_NO_FW; } static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans, enum iwl_rxon_context_id ctx, const char *msg) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + trans->ops->wake_any_queue(trans, ctx, msg); } @@ -312,6 +412,9 @@ static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans, static inline int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->send_cmd(trans, cmd); } @@ -322,6 +425,9 @@ 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 tid) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->tx(trans, skb, dev_cmd, ctx, sta_id, tid); } @@ -329,6 +435,9 @@ 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) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn, status, skbs); } @@ -336,12 +445,22 @@ static inline int iwl_trans_reclaim(struct iwl_trans *trans, int sta_id, static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans, int sta_id, int tid) { + might_sleep(); + + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->tx_agg_disable(trans, sta_id, tid); } static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans, int sta_id, int tid) { + might_sleep(); + + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->tx_agg_alloc(trans, sta_id, tid); } @@ -351,6 +470,11 @@ static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans, int sta_id, int tid, int frame_limit, u16 ssn) { + might_sleep(); + + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit, ssn); } @@ -362,16 +486,25 @@ static inline void iwl_trans_free(struct iwl_trans *trans) static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q, const char *msg) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + trans->ops->stop_queue(trans, q, msg); } static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->wait_tx_queue_empty(trans); } static inline int iwl_trans_check_stuck_queue(struct iwl_trans *trans, int q) { + if (trans->state != IWL_TRANS_FW_ALIVE) + IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); + return trans->ops->check_stuck_queue(trans, q); } static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, @@ -410,8 +543,6 @@ static inline u32 iwl_trans_read32(struct iwl_trans *trans, u32 ofs) /***************************************************** * Utils functions ******************************************************/ -void iwl_dealloc_ucode(struct iwl_trans *trans); - int iwl_send_calib_results(struct iwl_trans *trans); int iwl_calib_set(struct iwl_trans *trans, const struct iwl_calib_hdr *cmd, int len); @@ -426,6 +557,8 @@ extern const struct iwl_trans_ops trans_ops_pcie; struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd, struct pci_dev *pdev, const struct pci_device_id *ent); +int __must_check iwl_pci_register_driver(void); +void iwl_pci_unregister_driver(void); extern const struct iwl_trans_ops trans_ops_idi; struct iwl_trans *iwl_trans_idi_alloc(struct iwl_shared *shrd, diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index 11b659ab261d..b16efc00ba6e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -44,6 +44,7 @@ #include "iwl-agn-calib.h" #include "iwl-trans.h" #include "iwl-fh.h" +#include "iwl-op-mode.h" static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP, @@ -82,29 +83,29 @@ static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { * ******************************************************************************/ -static void iwl_free_fw_desc(struct iwl_trans *trans, struct fw_desc *desc) +static void iwl_free_fw_desc(struct iwl_nic *nic, struct fw_desc *desc) { if (desc->v_addr) - dma_free_coherent(trans->dev, desc->len, + dma_free_coherent(trans(nic)->dev, desc->len, desc->v_addr, desc->p_addr); desc->v_addr = NULL; desc->len = 0; } -static void iwl_free_fw_img(struct iwl_trans *trans, struct fw_img *img) +static void iwl_free_fw_img(struct iwl_nic *nic, struct fw_img *img) { - iwl_free_fw_desc(trans, &img->code); - iwl_free_fw_desc(trans, &img->data); + iwl_free_fw_desc(nic, &img->code); + iwl_free_fw_desc(nic, &img->data); } -void iwl_dealloc_ucode(struct iwl_trans *trans) +void iwl_dealloc_ucode(struct iwl_nic *nic) { - iwl_free_fw_img(trans, &trans->ucode_rt); - iwl_free_fw_img(trans, &trans->ucode_init); - iwl_free_fw_img(trans, &trans->ucode_wowlan); + iwl_free_fw_img(nic, &nic->fw.ucode_rt); + iwl_free_fw_img(nic, &nic->fw.ucode_init); + iwl_free_fw_img(nic, &nic->fw.ucode_wowlan); } -static int iwl_alloc_fw_desc(struct iwl_trans *trans, struct fw_desc *desc, +static int iwl_alloc_fw_desc(struct iwl_nic *nic, struct fw_desc *desc, const void *data, size_t len) { if (!len) { @@ -112,7 +113,7 @@ static int iwl_alloc_fw_desc(struct iwl_trans *trans, struct fw_desc *desc, return -EINVAL; } - desc->v_addr = dma_alloc_coherent(trans->dev, len, + desc->v_addr = dma_alloc_coherent(trans(nic)->dev, len, &desc->p_addr, GFP_KERNEL); if (!desc->v_addr) return -ENOMEM; @@ -122,16 +123,16 @@ static int iwl_alloc_fw_desc(struct iwl_trans *trans, struct fw_desc *desc, return 0; } -static inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans, +static inline struct fw_img *iwl_get_ucode_image(struct iwl_nic *nic, enum iwl_ucode_type ucode_type) { switch (ucode_type) { case IWL_UCODE_INIT: - return &trans->ucode_init; + return &nic->fw.ucode_init; case IWL_UCODE_WOWLAN: - return &trans->ucode_wowlan; + return &nic->fw.ucode_wowlan; case IWL_UCODE_REGULAR: - return &trans->ucode_rt; + return &nic->fw.ucode_rt; case IWL_UCODE_NONE: break; } @@ -397,15 +398,16 @@ static int iwl_alive_notify(struct iwl_trans *trans) * using sample data 100 bytes apart. If these sample points are good, * it's a pretty good bet that everything between them is good, too. */ -static int iwl_verify_inst_sparse(struct iwl_trans *trans, +static int iwl_verify_inst_sparse(struct iwl_nic *nic, struct fw_desc *fw_desc) { + struct iwl_trans *trans = trans(nic); __le32 *image = (__le32 *)fw_desc->v_addr; u32 len = fw_desc->len; u32 val; u32 i; - IWL_DEBUG_FW(trans, "ucode inst image size is %u\n", len); + IWL_DEBUG_FW(nic, "ucode inst image size is %u\n", len); for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { /* read data comes through single port, auto-incr addr */ @@ -421,16 +423,17 @@ static int iwl_verify_inst_sparse(struct iwl_trans *trans, return 0; } -static void iwl_print_mismatch_inst(struct iwl_trans *trans, +static void iwl_print_mismatch_inst(struct iwl_nic *nic, struct fw_desc *fw_desc) { + struct iwl_trans *trans = trans(nic); __le32 *image = (__le32 *)fw_desc->v_addr; u32 len = fw_desc->len; u32 val; u32 offs; int errors = 0; - IWL_DEBUG_FW(trans, "ucode inst image size is %u\n", len); + IWL_DEBUG_FW(nic, "ucode inst image size is %u\n", len); iwl_write_direct32(trans, HBUS_TARG_MEM_RADDR, IWLAGN_RTC_INST_LOWER_BOUND); @@ -441,7 +444,7 @@ static void iwl_print_mismatch_inst(struct iwl_trans *trans, /* read data comes through single port, auto-incr addr */ val = iwl_read32(trans, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { - IWL_ERR(trans, "uCode INST section at " + IWL_ERR(nic, "uCode INST section at " "offset 0x%x, is 0x%x, s/b 0x%x\n", offs, val, le32_to_cpu(*image)); errors++; @@ -453,24 +456,24 @@ static void iwl_print_mismatch_inst(struct iwl_trans *trans, * iwl_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ -static int iwl_verify_ucode(struct iwl_trans *trans, +static int iwl_verify_ucode(struct iwl_nic *nic, enum iwl_ucode_type ucode_type) { - struct fw_img *img = iwl_get_ucode_image(trans, ucode_type); + struct fw_img *img = iwl_get_ucode_image(nic, ucode_type); if (!img) { - IWL_ERR(trans, "Invalid ucode requested (%d)\n", ucode_type); + IWL_ERR(nic, "Invalid ucode requested (%d)\n", ucode_type); return -EINVAL; } - if (!iwl_verify_inst_sparse(trans, &img->code)) { - IWL_DEBUG_FW(trans, "uCode is good in inst SRAM\n"); + if (!iwl_verify_inst_sparse(nic, &img->code)) { + IWL_DEBUG_FW(nic, "uCode is good in inst SRAM\n"); return 0; } - IWL_ERR(trans, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); + IWL_ERR(nic, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); - iwl_print_mismatch_inst(trans, &img->code); + iwl_print_mismatch_inst(nic, &img->code); return -EIO; } @@ -583,7 +586,7 @@ int iwl_load_ucode_wait_alive(struct iwl_trans *trans, old_type = trans->shrd->ucode_type; trans->shrd->ucode_type = ucode_type; - fw = iwl_get_ucode_image(trans, ucode_type); + fw = iwl_get_ucode_image(nic(trans), ucode_type); if (!fw) return -EINVAL; @@ -618,7 +621,7 @@ int iwl_load_ucode_wait_alive(struct iwl_trans *trans, * skip it for WoWLAN. */ if (ucode_type != IWL_UCODE_WOWLAN) { - ret = iwl_verify_ucode(trans, ucode_type); + ret = iwl_verify_ucode(nic(trans), ucode_type); if (ret) { trans->shrd->ucode_type = old_type; return ret; @@ -647,7 +650,7 @@ int iwl_run_init_ucode(struct iwl_trans *trans) lockdep_assert_held(&trans->shrd->mutex); /* No init ucode required? Curious, but maybe ok */ - if (!trans->ucode_init.code.len) + if (!nic(trans)->fw.ucode_init.code.len) return 0; if (trans->shrd->ucode_type != IWL_UCODE_NONE) @@ -685,42 +688,42 @@ int iwl_run_init_ucode(struct iwl_trans *trans) static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); -#define UCODE_EXPERIMENTAL_INDEX 100 #define UCODE_EXPERIMENTAL_TAG "exp" -int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) +int __must_check iwl_request_firmware(struct iwl_nic *nic, bool first) { - const char *name_pre = cfg(priv)->fw_name_pre; + struct iwl_cfg *cfg = cfg(nic); + const char *name_pre = cfg->fw_name_pre; char tag[8]; if (first) { #ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE - priv->fw_index = UCODE_EXPERIMENTAL_INDEX; + nic->fw_index = UCODE_EXPERIMENTAL_INDEX; strcpy(tag, UCODE_EXPERIMENTAL_TAG); - } else if (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) { + } else if (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) { #endif - priv->fw_index = cfg(priv)->ucode_api_max; - sprintf(tag, "%d", priv->fw_index); + nic->fw_index = cfg->ucode_api_max; + sprintf(tag, "%d", nic->fw_index); } else { - priv->fw_index--; - sprintf(tag, "%d", priv->fw_index); + nic->fw_index--; + sprintf(tag, "%d", nic->fw_index); } - if (priv->fw_index < cfg(priv)->ucode_api_min) { - IWL_ERR(priv, "no suitable firmware found!\n"); + if (nic->fw_index < cfg->ucode_api_min) { + IWL_ERR(nic, "no suitable firmware found!\n"); return -ENOENT; } - sprintf(priv->firmware_name, "%s%s%s", name_pre, tag, ".ucode"); + sprintf(nic->firmware_name, "%s%s%s", name_pre, tag, ".ucode"); - IWL_DEBUG_INFO(priv, "attempting to load firmware %s'%s'\n", - (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) + IWL_DEBUG_INFO(nic, "attempting to load firmware %s'%s'\n", + (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) ? "EXPERIMENTAL " : "", - priv->firmware_name); + nic->firmware_name); - return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name, - trans(priv)->dev, - GFP_KERNEL, priv, iwl_ucode_callback); + return request_firmware_nowait(THIS_MODULE, 1, nic->firmware_name, + trans(nic)->dev, + GFP_KERNEL, nic, iwl_ucode_callback); } struct iwlagn_firmware_pieces { @@ -728,31 +731,30 @@ struct iwlagn_firmware_pieces { size_t inst_size, data_size, init_size, init_data_size, wowlan_inst_size, wowlan_data_size; - u32 build; - u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; }; -static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, +static int iwl_parse_v1_v2_firmware(struct iwl_nic *nic, const struct firmware *ucode_raw, struct iwlagn_firmware_pieces *pieces) { struct iwl_ucode_header *ucode = (void *)ucode_raw->data; - u32 api_ver, hdr_size; + u32 api_ver, hdr_size, build; + char buildstr[25]; const u8 *src; - priv->ucode_ver = le32_to_cpu(ucode->ver); - api_ver = IWL_UCODE_API(priv->ucode_ver); + nic->fw.ucode_ver = le32_to_cpu(ucode->ver); + api_ver = IWL_UCODE_API(nic->fw.ucode_ver); switch (api_ver) { default: hdr_size = 28; if (ucode_raw->size < hdr_size) { - IWL_ERR(priv, "File size too small!\n"); + IWL_ERR(nic, "File size too small!\n"); return -EINVAL; } - pieces->build = le32_to_cpu(ucode->u.v2.build); + build = le32_to_cpu(ucode->u.v2.build); pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); @@ -764,10 +766,10 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, case 2: hdr_size = 24; if (ucode_raw->size < hdr_size) { - IWL_ERR(priv, "File size too small!\n"); + IWL_ERR(nic, "File size too small!\n"); return -EINVAL; } - pieces->build = 0; + build = 0; pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size); pieces->data_size = le32_to_cpu(ucode->u.v1.data_size); pieces->init_size = le32_to_cpu(ucode->u.v1.init_size); @@ -776,12 +778,28 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, break; } + if (build) + sprintf(buildstr, " build %u%s", build, + (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) + ? " (EXP)" : ""); + else + buildstr[0] = '\0'; + + snprintf(nic->fw.fw_version, + sizeof(nic->fw.fw_version), + "%u.%u.%u.%u%s", + IWL_UCODE_MAJOR(nic->fw.ucode_ver), + IWL_UCODE_MINOR(nic->fw.ucode_ver), + IWL_UCODE_API(nic->fw.ucode_ver), + IWL_UCODE_SERIAL(nic->fw.ucode_ver), + buildstr); + /* Verify size of file vs. image size info in file's header */ if (ucode_raw->size != hdr_size + pieces->inst_size + pieces->data_size + pieces->init_size + pieces->init_data_size) { - IWL_ERR(priv, + IWL_ERR(nic, "uCode file size %d does not match expected size\n", (int)ucode_raw->size); return -EINVAL; @@ -799,10 +817,10 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, return 0; } -static int iwlagn_load_firmware(struct iwl_priv *priv, +static int iwl_parse_tlv_firmware(struct iwl_nic *nic, const struct firmware *ucode_raw, struct iwlagn_firmware_pieces *pieces, - struct iwlagn_ucode_capabilities *capa) + struct iwl_ucode_capabilities *capa) { struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data; struct iwl_ucode_tlv *tlv; @@ -814,14 +832,16 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, u32 tlv_len; enum iwl_ucode_tlv_type tlv_type; const u8 *tlv_data; + char buildstr[25]; + u32 build; if (len < sizeof(*ucode)) { - IWL_ERR(priv, "uCode has invalid length: %zd\n", len); + IWL_ERR(nic, "uCode has invalid length: %zd\n", len); return -EINVAL; } if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) { - IWL_ERR(priv, "invalid uCode magic: 0X%x\n", + IWL_ERR(nic, "invalid uCode magic: 0X%x\n", le32_to_cpu(ucode->magic)); return -EINVAL; } @@ -839,12 +859,29 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, while (wanted_alternative && !(alternatives & BIT(wanted_alternative))) wanted_alternative--; if (wanted_alternative && wanted_alternative != tmp) - IWL_WARN(priv, + IWL_WARN(nic, "uCode alternative %d not available, choosing %d\n", tmp, wanted_alternative); - priv->ucode_ver = le32_to_cpu(ucode->ver); - pieces->build = le32_to_cpu(ucode->build); + nic->fw.ucode_ver = le32_to_cpu(ucode->ver); + build = le32_to_cpu(ucode->build); + + if (build) + sprintf(buildstr, " build %u%s", build, + (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) + ? " (EXP)" : ""); + else + buildstr[0] = '\0'; + + snprintf(nic->fw.fw_version, + sizeof(nic->fw.fw_version), + "%u.%u.%u.%u%s", + IWL_UCODE_MAJOR(nic->fw.ucode_ver), + IWL_UCODE_MINOR(nic->fw.ucode_ver), + IWL_UCODE_API(nic->fw.ucode_ver), + IWL_UCODE_SERIAL(nic->fw.ucode_ver), + buildstr); + data = ucode->data; len -= sizeof(*ucode); @@ -861,7 +898,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, tlv_data = tlv->data; if (len < tlv_len) { - IWL_ERR(priv, "invalid TLV len: %zd/%u\n", + IWL_ERR(nic, "invalid TLV len: %zd/%u\n", len, tlv_len); return -EINVAL; } @@ -894,7 +931,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, pieces->init_data_size = tlv_len; break; case IWL_UCODE_TLV_BOOT: - IWL_ERR(priv, "Found unexpected BOOT ucode\n"); + IWL_ERR(nic, "Found unexpected BOOT ucode\n"); break; case IWL_UCODE_TLV_PROBE_MAX_LEN: if (tlv_len != sizeof(u32)) @@ -962,7 +999,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, case IWL_UCODE_TLV_ENHANCE_SENS_TBL: if (tlv_len) goto invalid_tlv_len; - priv->enhance_sensitivity_table = true; + nic->fw.enhance_sensitivity_table = true; break; case IWL_UCODE_TLV_WOWLAN_INST: pieces->wowlan_inst = tlv_data; @@ -979,22 +1016,22 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, le32_to_cpup((__le32 *)tlv_data); break; default: - IWL_DEBUG_INFO(priv, "unknown TLV: %d\n", tlv_type); + IWL_DEBUG_INFO(nic, "unknown TLV: %d\n", tlv_type); break; } } if (len) { - IWL_ERR(priv, "invalid TLV after parsing: %zd\n", len); - iwl_print_hex_dump(priv, IWL_DL_FW, (u8 *)data, len); + IWL_ERR(nic, "invalid TLV after parsing: %zd\n", len); + iwl_print_hex_dump(nic, IWL_DL_FW, (u8 *)data, len); return -EINVAL; } return 0; invalid_tlv_len: - IWL_ERR(priv, "TLV %d has invalid size: %u\n", tlv_type, tlv_len); - iwl_print_hex_dump(priv, IWL_DL_FW, tlv_data, tlv_len); + IWL_ERR(nic, "TLV %d has invalid size: %u\n", tlv_type, tlv_len); + iwl_print_hex_dump(nic, IWL_DL_FW, tlv_data, tlv_len); return -EINVAL; } @@ -1007,21 +1044,20 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, */ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) { - struct iwl_priv *priv = context; + struct iwl_nic *nic = context; + struct iwl_cfg *cfg = cfg(nic); + struct iwl_fw *fw = &nic->fw; struct iwl_ucode_header *ucode; int err; struct iwlagn_firmware_pieces pieces; - 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; + const unsigned int api_max = cfg->ucode_api_max; + unsigned int api_ok = cfg->ucode_api_ok; + const unsigned int api_min = cfg->ucode_api_min; u32 api_ver; - char buildstr[25]; - u32 build; - struct iwlagn_ucode_capabilities ucode_capa = { - .max_probe_length = 200, - .standard_phy_calibration_size = - IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE, - }; + + fw->ucode_capa.max_probe_length = 200; + fw->ucode_capa.standard_phy_calibration_size = + IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; if (!api_ok) api_ok = api_max; @@ -1029,19 +1065,19 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) memset(&pieces, 0, sizeof(pieces)); if (!ucode_raw) { - if (priv->fw_index <= api_ok) - IWL_ERR(priv, + if (nic->fw_index <= api_ok) + IWL_ERR(nic, "request for firmware file '%s' failed.\n", - priv->firmware_name); + nic->firmware_name); goto try_again; } - IWL_DEBUG_INFO(priv, "Loaded firmware file '%s' (%zd bytes).\n", - priv->firmware_name, ucode_raw->size); + IWL_DEBUG_INFO(nic, "Loaded firmware file '%s' (%zd bytes).\n", + nic->firmware_name, ucode_raw->size); /* Make sure that we got at least the API version number */ if (ucode_raw->size < 4) { - IWL_ERR(priv, "File size way too small!\n"); + IWL_ERR(nic, "File size way too small!\n"); goto try_again; } @@ -1049,16 +1085,15 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) ucode = (struct iwl_ucode_header *)ucode_raw->data; if (ucode->ver) - err = iwlagn_load_legacy_firmware(priv, ucode_raw, &pieces); + err = iwl_parse_v1_v2_firmware(nic, ucode_raw, &pieces); else - err = iwlagn_load_firmware(priv, ucode_raw, &pieces, - &ucode_capa); + err = iwl_parse_tlv_firmware(nic, ucode_raw, &pieces, + &fw->ucode_capa); if (err) goto try_again; - api_ver = IWL_UCODE_API(priv->ucode_ver); - build = pieces.build; + api_ver = IWL_UCODE_API(nic->fw.ucode_ver); /* * api_ver should match the api version forming part of the @@ -1066,9 +1101,9 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) * on the API version read from firmware header from here on forward */ /* no api version check required for experimental uCode */ - if (priv->fw_index != UCODE_EXPERIMENTAL_INDEX) { + if (nic->fw_index != UCODE_EXPERIMENTAL_INDEX) { if (api_ver < api_min || api_ver > api_max) { - IWL_ERR(priv, + IWL_ERR(nic, "Driver unable to support your firmware API. " "Driver supports v%u, firmware is v%u.\n", api_max, api_ver); @@ -1077,40 +1112,19 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) if (api_ver < api_ok) { if (api_ok != api_max) - IWL_ERR(priv, "Firmware has old API version, " + IWL_ERR(nic, "Firmware has old API version, " "expected v%u through v%u, got v%u.\n", api_ok, api_max, api_ver); else - IWL_ERR(priv, "Firmware has old API version, " + IWL_ERR(nic, "Firmware has old API version, " "expected v%u, got v%u.\n", api_max, api_ver); - IWL_ERR(priv, "New firmware can be obtained from " + IWL_ERR(nic, "New firmware can be obtained from " "http://www.intellinuxwireless.org/.\n"); } } - if (build) - sprintf(buildstr, " build %u%s", build, - (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) - ? " (EXP)" : ""); - else - buildstr[0] = '\0'; - - IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u%s\n", - IWL_UCODE_MAJOR(priv->ucode_ver), - IWL_UCODE_MINOR(priv->ucode_ver), - IWL_UCODE_API(priv->ucode_ver), - IWL_UCODE_SERIAL(priv->ucode_ver), - buildstr); - - snprintf(priv->hw->wiphy->fw_version, - sizeof(priv->hw->wiphy->fw_version), - "%u.%u.%u.%u%s", - IWL_UCODE_MAJOR(priv->ucode_ver), - IWL_UCODE_MINOR(priv->ucode_ver), - IWL_UCODE_API(priv->ucode_ver), - IWL_UCODE_SERIAL(priv->ucode_ver), - buildstr); + IWL_INFO(nic, "loaded firmware version %s", nic->fw.fw_version); /* * For any of the failures below (before allocating pci memory) @@ -1118,38 +1132,38 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) * user just got a corrupted version of the latest API. */ - IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", - priv->ucode_ver); - IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %Zd\n", + IWL_DEBUG_INFO(nic, "f/w package hdr ucode version raw = 0x%x\n", + nic->fw.ucode_ver); + IWL_DEBUG_INFO(nic, "f/w package hdr runtime inst size = %Zd\n", pieces.inst_size); - IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %Zd\n", + IWL_DEBUG_INFO(nic, "f/w package hdr runtime data size = %Zd\n", pieces.data_size); - IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %Zd\n", + IWL_DEBUG_INFO(nic, "f/w package hdr init inst size = %Zd\n", pieces.init_size); - IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n", + IWL_DEBUG_INFO(nic, "f/w package hdr init data size = %Zd\n", pieces.init_data_size); /* Verify that uCode images will fit in card's SRAM */ - if (pieces.inst_size > hw_params(priv).max_inst_size) { - IWL_ERR(priv, "uCode instr len %Zd too large to fit in\n", + if (pieces.inst_size > cfg->max_inst_size) { + IWL_ERR(nic, "uCode instr len %Zd too large to fit in\n", pieces.inst_size); goto try_again; } - if (pieces.data_size > hw_params(priv).max_data_size) { - IWL_ERR(priv, "uCode data len %Zd too large to fit in\n", + if (pieces.data_size > cfg->max_data_size) { + IWL_ERR(nic, "uCode data len %Zd too large to fit in\n", pieces.data_size); goto try_again; } - if (pieces.init_size > hw_params(priv).max_inst_size) { - IWL_ERR(priv, "uCode init instr len %Zd too large to fit in\n", + if (pieces.init_size > cfg->max_inst_size) { + IWL_ERR(nic, "uCode init instr len %Zd too large to fit in\n", pieces.init_size); goto try_again; } - if (pieces.init_data_size > hw_params(priv).max_data_size) { - IWL_ERR(priv, "uCode init data len %Zd too large to fit in\n", + if (pieces.init_data_size > cfg->max_data_size) { + IWL_ERR(nic, "uCode init data len %Zd too large to fit in\n", pieces.init_data_size); goto try_again; } @@ -1159,34 +1173,34 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) /* Runtime instructions and 2 copies of data: * 1) unmodified from disk * 2) backup cache for save/restore during power-downs */ - if (iwl_alloc_fw_desc(trans(priv), &trans(priv)->ucode_rt.code, + if (iwl_alloc_fw_desc(nic, &nic->fw.ucode_rt.code, pieces.inst, pieces.inst_size)) goto err_pci_alloc; - if (iwl_alloc_fw_desc(trans(priv), &trans(priv)->ucode_rt.data, + if (iwl_alloc_fw_desc(nic, &nic->fw.ucode_rt.data, pieces.data, pieces.data_size)) goto err_pci_alloc; /* Initialization instructions and data */ if (pieces.init_size && pieces.init_data_size) { - if (iwl_alloc_fw_desc(trans(priv), - &trans(priv)->ucode_init.code, + if (iwl_alloc_fw_desc(nic, + &nic->fw.ucode_init.code, pieces.init, pieces.init_size)) goto err_pci_alloc; - if (iwl_alloc_fw_desc(trans(priv), - &trans(priv)->ucode_init.data, + if (iwl_alloc_fw_desc(nic, + &nic->fw.ucode_init.data, pieces.init_data, pieces.init_data_size)) goto err_pci_alloc; } /* WoWLAN instructions and data */ if (pieces.wowlan_inst_size && pieces.wowlan_data_size) { - if (iwl_alloc_fw_desc(trans(priv), - &trans(priv)->ucode_wowlan.code, + if (iwl_alloc_fw_desc(nic, + &nic->fw.ucode_wowlan.code, pieces.wowlan_inst, pieces.wowlan_inst_size)) goto err_pci_alloc; - if (iwl_alloc_fw_desc(trans(priv), - &trans(priv)->ucode_wowlan.data, + if (iwl_alloc_fw_desc(nic, + &nic->fw.ucode_wowlan.data, pieces.wowlan_data, pieces.wowlan_data_size)) goto err_pci_alloc; @@ -1199,92 +1213,54 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) * for each event, which is of mode 1 (including timestamp) for all * new microcodes that include this information. */ - priv->init_evtlog_ptr = pieces.init_evtlog_ptr; + nic->init_evtlog_ptr = pieces.init_evtlog_ptr; if (pieces.init_evtlog_size) - priv->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; + nic->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; else - priv->init_evtlog_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; + nic->init_evtlog_size = + cfg->base_params->max_event_log_size; + nic->init_errlog_ptr = pieces.init_errlog_ptr; + nic->inst_evtlog_ptr = pieces.inst_evtlog_ptr; if (pieces.inst_evtlog_size) - priv->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; + nic->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; else - priv->inst_evtlog_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; -#endif - - priv->new_scan_threshold_behaviour = - !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); - - if (!(cfg(priv)->sku & EEPROM_SKU_CAP_IPAN_ENABLE)) - ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; - - /* - * if not PAN, then don't support P2P -- might be a uCode - * packaging bug or due to the eeprom check above - */ - if (!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN)) - ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_P2P; + nic->inst_evtlog_size = + cfg->base_params->max_event_log_size; + nic->inst_errlog_ptr = pieces.inst_errlog_ptr; - if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { - priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; - priv->shrd->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; - } else { - priv->sta_key_max_num = STA_KEY_MAX_NUM; - priv->shrd->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; - } /* * figure out the offset of chain noise reset and gain commands * base on the size of standard phy calibration commands table size */ - if (ucode_capa.standard_phy_calibration_size > + if (fw->ucode_capa.standard_phy_calibration_size > IWL_MAX_PHY_CALIBRATE_TBL_SIZE) - ucode_capa.standard_phy_calibration_size = + fw->ucode_capa.standard_phy_calibration_size = IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE; - priv->phy_calib_chain_noise_reset_cmd = - ucode_capa.standard_phy_calibration_size; - priv->phy_calib_chain_noise_gain_cmd = - ucode_capa.standard_phy_calibration_size + 1; + /* We have our copies now, allow OS release its copies */ + release_firmware(ucode_raw); + complete(&nic->request_firmware_complete); - /* initialize all valid contexts */ - iwl_init_context(priv, ucode_capa.flags); + nic->op_mode = iwl_dvm_ops.start(nic->shrd->trans); - /************************************************** - * This is still part of probe() in a sense... - * - * 9. Setup and register with mac80211 and debugfs - **************************************************/ - err = iwlagn_mac_setup_register(priv, &ucode_capa); - if (err) + if (!nic->op_mode) goto out_unbind; - err = iwl_dbgfs_register(priv, DRV_NAME); - if (err) - IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); - - /* We have our copies now, allow OS release its copies */ - release_firmware(ucode_raw); - complete(&priv->firmware_loading_complete); return; try_again: /* try next, if any */ - if (iwl_request_firmware(priv, false)) - goto out_unbind; release_firmware(ucode_raw); + if (iwl_request_firmware(nic, false)) + goto out_unbind; return; err_pci_alloc: - IWL_ERR(priv, "failed to allocate pci memory\n"); - iwl_dealloc_ucode(trans(priv)); - out_unbind: - complete(&priv->firmware_loading_complete); - device_release_driver(trans(priv)->dev); + IWL_ERR(nic, "failed to allocate pci memory\n"); + iwl_dealloc_ucode(nic); release_firmware(ucode_raw); + out_unbind: + complete(&nic->request_firmware_complete); + device_release_driver(trans(nic)->dev); } diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.h b/drivers/net/wireless/iwlwifi/iwl-ucode.h index eccf92519a84..8bebeb003bef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.h +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.h @@ -63,6 +63,8 @@ #ifndef __iwl_ucode_h__ #define __iwl_ucode_h__ +#include <linux/netdevice.h> + /* v1/v2 uCode file layout */ struct iwl_ucode_header { __le32 ver; /* major/minor/API/serial */ @@ -171,8 +173,48 @@ struct iwl_tlv_ucode_header { u8 data[0]; }; -struct iwl_priv; +struct iwl_ucode_capabilities { + u32 max_probe_length; + u32 standard_phy_calibration_size; + u32 flags; +}; + +/* one for each uCode image (inst/data, boot/init/runtime) */ +struct fw_desc { + dma_addr_t p_addr; /* hardware address */ + void *v_addr; /* software address */ + u32 len; /* size in bytes */ +}; + +struct fw_img { + struct fw_desc code; /* firmware code image */ + struct fw_desc data; /* firmware data image */ +}; + +/** + * struct iwl_fw - variables associated with the firmware + * + * @ucode_ver: ucode version from the ucode file + * @fw_version: firmware version string + * @ucode_rt: run time ucode image + * @ucode_init: init ucode image + * @ucode_wowlan: wake on wireless ucode image (optional) + * @ucode_capa: capabilities parsed from the ucode file. + * @enhance_sensitivity_table: device can do enhanced sensitivity. + */ +struct iwl_fw { + + u32 ucode_ver; -int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first); + char fw_version[ETHTOOL_BUSINFO_LEN]; + + /* ucode images */ + struct fw_img ucode_rt; + struct fw_img ucode_init; + struct fw_img ucode_wowlan; + + struct iwl_ucode_capabilities ucode_capa; + bool enhance_sensitivity_table; +}; #endif /* __iwl_ucode_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-wifi.h b/drivers/net/wireless/iwlwifi/iwl-wifi.h index 7e6eb20823cf..d5cba07a24c8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-wifi.h +++ b/drivers/net/wireless/iwlwifi/iwl-wifi.h @@ -64,6 +64,43 @@ #define __iwl_wifi_h__ #include "iwl-shared.h" +#include "iwl-ucode.h" + +#define UCODE_EXPERIMENTAL_INDEX 100 + +/** + * struct iwl_nic - nic common data + * @fw: the iwl_fw structure + * @shrd: pointer to common shared structure + * @op_mode: the running op_mode + * @fw_index: firmware revision to try loading + * @firmware_name: composite filename of ucode file to load + * @init_evtlog_ptr: event log offset for init ucode. + * @init_evtlog_size: event log size for init ucode. + * @init_errlog_ptr: error log offfset for init ucode. + * @inst_evtlog_ptr: event log offset for runtime ucode. + * @inst_evtlog_size: event log size for runtime ucode. + * @inst_errlog_ptr: error log offfset for runtime ucode. + * @request_firmware_complete: the firmware has been obtained from user space + */ +struct iwl_nic { + struct iwl_fw fw; + + struct iwl_shared *shrd; + struct iwl_op_mode *op_mode; + + int fw_index; /* firmware we're trying to load */ + char firmware_name[25]; /* name of firmware file to load */ + + u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; + u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; + + struct completion request_firmware_complete; +}; + + +int __must_check iwl_request_firmware(struct iwl_nic *nic, bool first); +void iwl_dealloc_ucode(struct iwl_nic *nic); int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type); void iwl_send_prio_tbl(struct iwl_trans *trans); |