summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-2000.c14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c18
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-calib.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rx.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rxon.c16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tt.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c53
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.c127
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h83
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.h65
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-mac80211.c20
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-pci.c18
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-shared.h13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-testmode.c411
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-testmode.h64
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c70
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie.c39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h190
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-ucode.c321
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-ucode.h47
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-wifi.h33
35 files changed, 1112 insertions, 611 deletions
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 9dc84a7354d..46622a0f017 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
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 8c1466c907f..605ee3df1d8 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 d4f5f3b8757..e6e8c79a80d 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 dc9317d0343..1527dec7a26 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 c36fb858a45..1e6fbf4fcb4 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, \
@@ -389,6 +388,8 @@ struct iwl_cfg iwl6005_2agn_d_cfg = {
.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 +459,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 +490,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 +517,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 +544,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 6aa00982786..988ee454a94 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 a8f7689aaac..c368433f8bc 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);
}
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index b9ba404d15c..f88e2e33e2e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -892,7 +892,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);
}
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
index a14ddab783e..aee7d060d31 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);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index 8ca9570ec36..35dd7e364b4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -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 c728ed75584..56d7c0e3816 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 64f8db685dc..da18a8fc9af 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -983,7 +983,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 8837171ad55..e8fed167f97 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -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);
}
@@ -1248,11 +1239,7 @@ 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);
/*******************
* 6. Setup priv
@@ -1273,17 +1260,17 @@ 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);
+ init_completion(&nic(priv)->request_firmware_complete);
- err = iwl_request_firmware(priv, true);
+ err = iwl_request_firmware(nic(priv), true);
if (err)
goto out_destroy_workqueue;
return 0;
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);
@@ -1296,7 +1283,7 @@ out:
void __devexit iwl_remove(struct iwl_priv * priv)
{
- wait_for_completion(&priv->firmware_loading_complete);
+ wait_for_completion(&nic(priv)->request_firmware_complete);
IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
@@ -1316,18 +1303,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);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 37c325ff6e8..79894aca964 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,14 @@ 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);
/* 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 */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 0677b3dfbfb..f3b72bc84d2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -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,
@@ -875,7 +874,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");
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 8d60dcf6f2e..930e247bbae 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,
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.c b/drivers/net/wireless/iwlwifi/iwl-debug.c
new file mode 100644
index 00000000000..4bc2e70051d
--- /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 351b41d7f4f..bfc08494ed2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -31,14 +31,33 @@
#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 +65,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 136de6fb3fa..ad74138e1c7 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 aa99457c3a5..494c696dc17 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -696,11 +696,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
@@ -721,6 +721,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 +787,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 +796,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 +863,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 +953,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 4d892211ce4..96e62338cec 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-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
index d8025fee7e0..9c29234221f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c
+++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
@@ -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");
@@ -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
@@ -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
}
@@ -1117,7 +1121,7 @@ static int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
{
struct iwl_priv *priv = hw->priv;
- queue_work(priv->shrd->workqueue, &priv->beacon_update);
+ queue_work(priv->workqueue, &priv->beacon_update);
return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c
index 3e2fce4ce00..51906702053 100644
--- a/drivers/net/wireless/iwlwifi/iwl-pci.c
+++ b/drivers/net/wireless/iwlwifi/iwl-pci.c
@@ -70,6 +70,7 @@
#include "iwl-trans.h"
#include "iwl-csr.h"
#include "iwl-cfg.h"
+#include "iwl-wifi.h"
#define IWL_PCI_DEVICE(dev, subdev, cfg) \
.vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \
@@ -282,13 +283,23 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
bus->shrd->bus = bus;
+ /* temporarily create this here */
+ bus->shrd->nic = kzalloc(sizeof(*bus->shrd->nic), GFP_KERNEL);
+ if (!bus->shrd->nic) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "Couldn't allocate iwl_nic");
+ err = -ENOMEM;
+ goto out_free_bus;
+ }
+ /* and initialize it as well, temporarily */
+ bus->shrd->nic->shrd = bus->shrd;
pci_set_drvdata(pdev, bus);
#ifdef CONFIG_IWLWIFI_IDI
trans(bus) = iwl_trans_idi_alloc(bus->shrd, pdev, ent);
if (trans(bus) == NULL) {
err = -ENOMEM;
- goto out_free_bus;
+ goto out_free_nic;
}
err = iwl_probe(bus, &trans_ops_idi, cfg);
@@ -296,7 +307,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
trans(bus) = iwl_trans_pcie_alloc(bus->shrd, pdev, ent);
if (trans(bus) == NULL) {
err = -ENOMEM;
- goto out_free_bus;
+ goto out_free_nic;
}
err = iwl_probe(bus, &trans_ops_pcie, cfg);
@@ -309,6 +320,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
out_free_trans:
iwl_trans_free(trans(bus));
pci_set_drvdata(pdev, NULL);
+out_free_nic:
+ kfree(bus->shrd->nic);
out_free_bus:
kfree(bus->shrd);
kfree(bus);
@@ -325,6 +338,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
+ kfree(bus->shrd->nic);
kfree(bus->shrd);
kfree(bus);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 7f2e3a1c80e..42ee1c410ef 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 63d4a4fc5b9..f810b41db9d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-shared.h
+++ b/drivers/net/wireless/iwlwifi/iwl-shared.h
@@ -173,8 +173,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 +190,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 +279,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 +318,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 +358,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.
@@ -389,9 +389,9 @@ struct iwl_shared {
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;
@@ -420,6 +420,7 @@ struct iwl_shared {
#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)
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c
index df7ab332c83..80955ed06e8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-testmode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c
@@ -81,6 +81,13 @@
#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 +117,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 +179,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 +190,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 +233,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,8 +245,10 @@ 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
@@ -247,25 +257,68 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
{
struct iwl_priv *priv = hw->priv;
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;
}
@@ -295,7 +348,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
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 +362,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 +374,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 +394,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 +402,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 +425,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;
@@ -448,8 +472,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 +481,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 +498,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 +513,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 +528,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 +538,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 +574,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 +614,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;
@@ -664,8 +681,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 +690,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 +701,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;
@@ -752,7 +766,7 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
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 +774,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 +873,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;
+ 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;
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;
@@ -898,14 +967,13 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
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 +987,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 +1016,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;
}
@@ -981,15 +1049,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 +1070,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 f97d06169b4..69b2e80f407 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 561865f29d5..8c30fea8c2b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
@@ -230,6 +230,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;
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
index 3826852ec5f..6715d04b72f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
@@ -34,6 +34,7 @@
#include "iwl-core.h"
#include "iwl-io.h"
#include "iwl-trans-pcie-int.h"
+#include "iwl-wifi.h"
#ifdef CONFIG_IWLWIFI_IDI
#include "iwl-amfh.h"
@@ -227,7 +228,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 +332,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 +353,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);
}
/**
@@ -594,17 +590,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 +612,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 +622,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,
@@ -723,7 +719,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 +727,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 +760,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 +774,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 +836,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 +945,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 +975,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) {
@@ -1232,7 +1228,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 +1245,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 +1256,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 +1277,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 +1321,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 +1331,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 +1365,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 +1436,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 +1447,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 08e0a7da48a..a3cebd76dc0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
@@ -492,7 +492,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 +532,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);
}
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
index f5cb5d3cd92..176063c4f78 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
@@ -219,10 +219,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 +585,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 +594,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 +803,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);
@@ -1078,10 +1079,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 +1101,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 +1197,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 +1220,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 +1236,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 +1256,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 +1291,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);
}
@@ -2259,6 +2267,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 ae68c51e532..cc7a3cfb5f2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -68,18 +68,75 @@
#include "iwl-shared.h"
#include "iwl-commands.h"
+#include "iwl-ucode.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.
+ */
+
+/**
+ * DOC: API needed by the transport layer from the op_mode
+ *
+ * TODO
+ */
struct iwl_priv;
struct iwl_shared;
+/**
+ * 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 +161,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 +197,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,7 +298,19 @@ 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
* @shrd - pointer to iwl_shared which holds shared data from the upper layer
* @hcmd_lock: protects HCMD
@@ -235,12 +318,9 @@ struct iwl_calib_result {
* @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
@@ -248,6 +328,7 @@ struct iwl_calib_result {
struct iwl_trans {
const struct iwl_trans_ops *ops;
struct iwl_shared *shrd;
+ enum iwl_trans_state state;
spinlock_t hcmd_lock;
spinlock_t reg_lock;
@@ -257,16 +338,11 @@ 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 */
@@ -276,17 +352,27 @@ struct iwl_trans {
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 +384,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 +405,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 +418,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 +428,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 +438,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 +463,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 +479,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 +536,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);
diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c
index 11b659ab261..61c6c0568c1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c
@@ -82,29 +82,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 +112,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 +122,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 +397,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 +422,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 +443,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 +455,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 +585,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 +620,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 +649,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)
@@ -688,39 +690,40 @@ 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 {
@@ -734,7 +737,7 @@ struct iwlagn_firmware_pieces {
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)
{
@@ -742,14 +745,14 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
u32 api_ver, hdr_size;
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);
@@ -764,7 +767,7 @@ 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;
@@ -781,7 +784,7 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
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 +802,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;
@@ -816,12 +819,12 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
const u8 *tlv_data;
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,11 +842,11 @@ 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);
+ nic->fw.ucode_ver = le32_to_cpu(ucode->ver);
pieces->build = le32_to_cpu(ucode->build);
data = ucode->data;
@@ -861,7 +864,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 +897,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 +965,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 +982,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 +1010,23 @@ 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_priv *priv = priv(nic); /* temporary */
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 +1034,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,15 +1054,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);
+ api_ver = IWL_UCODE_API(nic->fw.ucode_ver);
build = pieces.build;
/*
@@ -1066,9 +1071,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,39 +1082,39 @@ 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)
+ (nic->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),
+ IWL_INFO(nic, "loaded firmware version %u.%u.%u.%u%s\n",
+ 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);
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),
+ 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);
/*
@@ -1118,38 +1123,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 +1164,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 +1204,94 @@ 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;
+ nic->inst_evtlog_size =
+ cfg->base_params->max_event_log_size;
+ nic->inst_errlog_ptr = pieces.inst_errlog_ptr;
#ifndef CONFIG_IWLWIFI_P2P
- ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
+ fw->ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
#endif
priv->new_scan_threshold_behaviour =
- !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN);
+ !!(fw->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 (!(cfg->sku & EEPROM_SKU_CAP_IPAN_ENABLE))
+ fw->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;
+ if (!(fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN))
+ fw->ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
- if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) {
+ if (fw->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;
+ nic->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;
+ nic->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;
+ fw->ucode_capa.standard_phy_calibration_size;
priv->phy_calib_chain_noise_gain_cmd =
- ucode_capa.standard_phy_calibration_size + 1;
+ fw->ucode_capa.standard_phy_calibration_size + 1;
/* initialize all valid contexts */
- iwl_init_context(priv, ucode_capa.flags);
+ iwl_init_context(priv, fw->ucode_capa.flags);
/**************************************************
* 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);
+ err = iwlagn_mac_setup_register(priv, &fw->ucode_capa);
if (err)
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);
+ IWL_ERR(nic,
+ "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);
+ complete(&nic->request_firmware_complete);
return;
try_again:
/* try next, if any */
- if (iwl_request_firmware(priv, false))
+ if (iwl_request_firmware(nic, false))
goto out_unbind;
release_firmware(ucode_raw);
return;
err_pci_alloc:
- IWL_ERR(priv, "failed to allocate pci memory\n");
- iwl_dealloc_ucode(trans(priv));
+ IWL_ERR(nic, "failed to allocate pci memory\n");
+ iwl_dealloc_ucode(nic);
out_unbind:
- complete(&priv->firmware_loading_complete);
- device_release_driver(trans(priv)->dev);
+ complete(&nic->request_firmware_complete);
+ device_release_driver(trans(nic)->dev);
release_firmware(ucode_raw);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.h b/drivers/net/wireless/iwlwifi/iwl-ucode.h
index eccf92519a8..d13e6241f12 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,49 @@ 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 */
+};
-int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first);
+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 {
+
+ /* ucode image and variables */
+ u32 ucode_ver; /* version of ucode, copy of
+ iwl_ucode.ver */
+ 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 7e6eb20823c..84172f6de4b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-wifi.h
+++ b/drivers/net/wireless/iwlwifi/iwl-wifi.h
@@ -64,6 +64,39 @@
#define __iwl_wifi_h__
#include "iwl-shared.h"
+#include "iwl-ucode.h"
+
+/**
+ * struct iwl_nic - nic common data
+ * @fw: the iwl_fw structure
+ * @shrd: pointer to common shared structure
+ * @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;
+
+ 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);