linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/14] iwlwifi driver updates 07/24/2009
@ 2009-07-24 18:12 Reinette Chatre
  2009-07-24 18:13 ` [PATCH 01/14] iwlwifi: revert to active table when rate is not valid Reinette Chatre
                   ` (14 more replies)
  0 siblings, 15 replies; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:12 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Reinette Chatre

In this series we introduce a new thermal throttling feature that places
NIC in a lower power state with fewer activities when temperature reaches
particular thresholds. We also include two fixes, one addresses a TX queue
race between driver and mac80211 and the other fixes a null pointer access
introduced by an earlier patch (which is not in 2.6.31). The TX queue race
problem is present in v2.6.31 so we include a patch for that kernel also.
The rest of this series is cleanup.

[PATCH 01/14] iwlwifi: revert to active table when rate is not valid
[PATCH 02/14] iwlwifi: critical temperature enter/exit condition
[PATCH 03/14] iwlwifi: Thermal Throttling Management - Part 1
[PATCH 04/14] iwlwifi: Thermal Throttling Management - part 2
[PATCH 05/14] iwlwifi: Thermal Throttling debugfs function
[PATCH 06/14] iwlwifi: fix up command sending
[PATCH 07/14] iwlwifi: remove command callback return value
[PATCH 08/14] iwlwifi: fix TX queue race
[PATCH 09/14] iwlwifi: print packet contents in error case
[PATCH 10/14] iwlwifi: Name fix for MPDU density for TX aggregation
[PATCH 11/14] iwlwifi: fix LED config option
[PATCH 12/14] iwlwifi: debugFs to enable/disable 40MHz channel support
[PATCH 13/14] iwlagn: fix null pointer access during ucode load on 1000
[PATCH 14/14] iwlagn: fix sparse warning when compiling without debug

[PATCH v2.6.31] iwlwifi: fix TX queue race

Thank you

Reinette

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 01/14] iwlwifi: revert to active table when rate is not valid
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  2009-07-24 18:13 ` [PATCH 02/14] iwlwifi: critical temperature enter/exit condition Reinette Chatre
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Wey-Yi Guy, Reinette Chatre

From: Wey-Yi Guy <wey-yi.w.guy@intel.com>

When performing rate scaling, if detected that the new rate
index is invalid, clear the search_better_tbl flag
so it will not be stuck in the loop.

Since the search table is already set up in uCode,
we need to empty out the the search table;
revert back to the "active" rate and throughput info.
Also pass the "active" table setup to uCode to make
sure the rate scale is functioning correctly.

Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-agn-rs.c |   37 +++++++++++++++++++++++++----
 1 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 6328041..40207da 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -2003,6 +2003,25 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
 }
 
 /*
+ * setup rate table in uCode
+ * return rate_n_flags as used in the table
+ */
+static u32 rs_update_rate_tbl(struct iwl_priv *priv,
+				struct iwl_lq_sta *lq_sta,
+				struct iwl_scale_tbl_info *tbl,
+				int index, u8 is_green)
+{
+	u32 rate;
+
+	/* Update uCode's rate table. */
+	rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
+	rs_fill_link_cmd(priv, lq_sta, rate);
+	iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
+
+	return rate;
+}
+
+/*
  * Do rate scaling and search for new modulation mode.
  */
 static void rs_rate_scale_perform(struct iwl_priv *priv,
@@ -2098,6 +2117,16 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 
 	if (!((1 << index) & rate_scale_index_msk)) {
 		IWL_ERR(priv, "Current Rate is not valid\n");
+		if (lq_sta->search_better_tbl) {
+			/* revert to active table if search table is not valid*/
+			tbl->lq_type = LQ_NONE;
+			lq_sta->search_better_tbl = 0;
+			tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+			/* get "active" rate info */
+			index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+			rate = rs_update_rate_tbl(priv, lq_sta,
+						  tbl, index, is_green);
+		}
 		return;
 	}
 
@@ -2308,11 +2337,9 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 
 lq_update:
 	/* Replace uCode's rate table for the destination station. */
-	if (update_lq) {
-		rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
-		rs_fill_link_cmd(priv, lq_sta, rate);
-		iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
-	}
+	if (update_lq)
+		rate = rs_update_rate_tbl(priv, lq_sta,
+					  tbl, index, is_green);
 
 	/* Should we stay with this modulation mode, or search for a new one? */
 	rs_stay_in_table(lq_sta);
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 02/14] iwlwifi: critical temperature enter/exit condition
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
  2009-07-24 18:13 ` [PATCH 01/14] iwlwifi: revert to active table when rate is not valid Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  2009-07-24 18:13 ` [PATCH 03/14] iwlwifi: Thermal Throttling Management - Part 1 Reinette Chatre
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Wey-Yi Guy, Reinette Chatre

From: Wey-Yi Guy <wey-yi.w.guy@intel.com>

If advance thermal throttling is used the driver need to pass both
"enter" and "exit" temperature to uCode.

Using different critical temperature threshold for legacy and advance
thermal throttling management based on the type of thermal throttling
method is used except 1000.
For 1000, it use advance thermal throttling critical temperature
threshold, but with legacy thermal management implementation until ucode
has the necessary implementations in place.

Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-1000.c     |   76 ++++++++++++++++++++++++++-
 drivers/net/wireless/iwlwifi/iwl-4965.c     |    3 +-
 drivers/net/wireless/iwlwifi/iwl-5000.c     |   44 ++++++++--------
 drivers/net/wireless/iwlwifi/iwl-6000.c     |   59 ++++++++++++++++++++-
 drivers/net/wireless/iwlwifi/iwl-commands.h |    7 +++
 drivers/net/wireless/iwlwifi/iwl-core.c     |   22 +++++++-
 drivers/net/wireless/iwlwifi/iwl-dev.h      |   34 ++++++++++++-
 7 files changed, 217 insertions(+), 28 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index a899be9..80a2818 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -55,13 +55,87 @@
 #define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode"
 #define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api)
 
+
+/*
+ * For 1000, use advance thermal throttling critical temperature threshold,
+ * but legacy thermal management implementation for now.
+ * This is for the reason of 1000 uCode using advance thermal throttling API
+ * but not implement ct_kill_exit based on ct_kill exit temperature
+ * so the thermal throttling will still based on legacy thermal throttling
+ * management.
+ * The code here need to be modified once 1000 uCode has the advanced thermal
+ * throttling algorithm in place
+ */
+static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
+{
+	/* want Celsius */
+	priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
+	priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+}
+
+static struct iwl_lib_ops iwl1000_lib = {
+	.set_hw_params = iwl5000_hw_set_hw_params,
+	.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
+	.txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
+	.txq_set_sched = iwl5000_txq_set_sched,
+	.txq_agg_enable = iwl5000_txq_agg_enable,
+	.txq_agg_disable = iwl5000_txq_agg_disable,
+	.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
+	.txq_free_tfd = iwl_hw_txq_free_tfd,
+	.txq_init = iwl_hw_tx_queue_init,
+	.rx_handler_setup = iwl5000_rx_handler_setup,
+	.setup_deferred_work = iwl5000_setup_deferred_work,
+	.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+	.load_ucode = iwl5000_load_ucode,
+	.init_alive_start = iwl5000_init_alive_start,
+	.alive_notify = iwl5000_alive_notify,
+	.send_tx_power = iwl5000_send_tx_power,
+	.update_chain_flags = iwl_update_chain_flags,
+	.apm_ops = {
+		.init =	iwl5000_apm_init,
+		.reset = iwl5000_apm_reset,
+		.stop = iwl5000_apm_stop,
+		.config = iwl5000_nic_config,
+		.set_pwr_src = iwl_set_pwr_src,
+	},
+	.eeprom_ops = {
+		.regulatory_bands = {
+			EEPROM_5000_REG_BAND_1_CHANNELS,
+			EEPROM_5000_REG_BAND_2_CHANNELS,
+			EEPROM_5000_REG_BAND_3_CHANNELS,
+			EEPROM_5000_REG_BAND_4_CHANNELS,
+			EEPROM_5000_REG_BAND_5_CHANNELS,
+			EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
+			EEPROM_5000_REG_BAND_52_FAT_CHANNELS
+		},
+		.verify_signature  = iwlcore_eeprom_verify_signature,
+		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+		.release_semaphore = iwlcore_eeprom_release_semaphore,
+		.calib_version	= iwl5000_eeprom_calib_version,
+		.query_addr = iwl5000_eeprom_query_addr,
+	},
+	.post_associate = iwl_post_associate,
+	.isr = iwl_isr_ict,
+	.config_ap = iwl_config_ap,
+	.temp_ops = {
+		.temperature = iwl5000_temperature,
+		.set_ct_kill = iwl1000_set_ct_threshold,
+	 },
+};
+
+static struct iwl_ops iwl1000_ops = {
+	.lib = &iwl1000_lib,
+	.hcmd = &iwl5000_hcmd,
+	.utils = &iwl5000_hcmd_utils,
+};
+
 struct iwl_cfg iwl1000_bgn_cfg = {
 	.name = "1000 Series BGN",
 	.fw_name_pre = IWL1000_FW_PRE,
 	.ucode_api_max = IWL1000_UCODE_API_MAX,
 	.ucode_api_min = IWL1000_UCODE_API_MIN,
 	.sku = IWL_SKU_G|IWL_SKU_N,
-	.ops = &iwl5000_ops,
+	.ops = &iwl1000_ops,
 	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
 	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index c30a1b9..23925bd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -776,7 +776,8 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
 static void iwl4965_set_ct_threshold(struct iwl_priv *priv)
 {
 	/* want Kelvin */
-	priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD);
+	priv->hw_params.ct_kill_threshold =
+		CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY);
 }
 
 /**
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 702db07..076acb1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -91,7 +91,7 @@ static int iwl5000_apm_stop_master(struct iwl_priv *priv)
 }
 
 
-static int iwl5000_apm_init(struct iwl_priv *priv)
+int iwl5000_apm_init(struct iwl_priv *priv)
 {
 	int ret = 0;
 
@@ -137,7 +137,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
 }
 
 /* FIXME: this is identical to 4965 */
-static void iwl5000_apm_stop(struct iwl_priv *priv)
+void iwl5000_apm_stop(struct iwl_priv *priv)
 {
 	unsigned long flags;
 
@@ -156,7 +156,7 @@ static void iwl5000_apm_stop(struct iwl_priv *priv)
 }
 
 
-static int iwl5000_apm_reset(struct iwl_priv *priv)
+int iwl5000_apm_reset(struct iwl_priv *priv)
 {
 	int ret = 0;
 
@@ -198,7 +198,7 @@ out:
 }
 
 
-static void iwl5000_nic_config(struct iwl_priv *priv)
+void iwl5000_nic_config(struct iwl_priv *priv)
 {
 	unsigned long flags;
 	u16 radio_cfg;
@@ -290,7 +290,7 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
 	return (address & ADDRESS_MSK) + (offset << 1);
 }
 
-static u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
+u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
 {
 	struct iwl_eeprom_calib_hdr {
 		u8 version;
@@ -436,7 +436,7 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
 	.nrg_th_ofdm = 95,
 };
 
-static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
+const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
 					   size_t offset)
 {
 	u32 address = eeprom_indirect_address(priv, offset);
@@ -447,7 +447,7 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
 static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
 {
 	const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
-	s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) -
+	s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
 			iwl_temp_calib_to_offset(priv);
 
 	priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
@@ -456,7 +456,7 @@ static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
 static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
 {
 	/* want Celsius */
-	priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
+	priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
 }
 
 /*
@@ -631,7 +631,7 @@ static int iwl5000_load_given_ucode(struct iwl_priv *priv,
 	return ret;
 }
 
-static int iwl5000_load_ucode(struct iwl_priv *priv)
+int iwl5000_load_ucode(struct iwl_priv *priv)
 {
 	int ret = 0;
 
@@ -658,7 +658,7 @@ static int iwl5000_load_ucode(struct iwl_priv *priv)
 	return ret;
 }
 
-static void iwl5000_init_alive_start(struct iwl_priv *priv)
+void iwl5000_init_alive_start(struct iwl_priv *priv)
 {
 	int ret = 0;
 
@@ -734,7 +734,7 @@ static int iwl5000_send_wimax_coex(struct iwl_priv *priv)
 				sizeof(coex_cmd), &coex_cmd);
 }
 
-static int iwl5000_alive_notify(struct iwl_priv *priv)
+int iwl5000_alive_notify(struct iwl_priv *priv)
 {
 	u32 a;
 	unsigned long flags;
@@ -821,7 +821,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
 	return 0;
 }
 
-static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
+int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 {
 	if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) ||
 	    (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
@@ -892,7 +892,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 /**
  * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
  */
-static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
 					    struct iwl_tx_queue *txq,
 					    u16 byte_cnt)
 {
@@ -932,7 +932,7 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
 			tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
 }
 
-static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
 					   struct iwl_tx_queue *txq)
 {
 	struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
@@ -987,7 +987,7 @@ static void iwl5000_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
 		(1 << IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
 }
 
-static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
+int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
 				  int tx_fifo, int sta_id, int tid, u16 ssn_idx)
 {
 	unsigned long flags;
@@ -1048,7 +1048,7 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
 	return 0;
 }
 
-static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
 				   u16 ssn_idx, u8 tx_fifo)
 {
 	if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
@@ -1091,7 +1091,7 @@ u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
  * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
  * must be called under priv->lock and mac access
  */
-static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
+void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
 {
 	iwl_write_prph(priv, IWL50_SCD_TXFACT, mask);
 }
@@ -1312,13 +1312,13 @@ u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len)
 	return len;
 }
 
-static void iwl5000_setup_deferred_work(struct iwl_priv *priv)
+void iwl5000_setup_deferred_work(struct iwl_priv *priv)
 {
 	/* in 5000 the tx power calibration is done in uCode */
 	priv->disable_tx_power_cal = 1;
 }
 
-static void iwl5000_rx_handler_setup(struct iwl_priv *priv)
+void iwl5000_rx_handler_setup(struct iwl_priv *priv)
 {
 	/* init calibration handlers */
 	priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
@@ -1329,7 +1329,7 @@ static void iwl5000_rx_handler_setup(struct iwl_priv *priv)
 }
 
 
-static int iwl5000_hw_valid_rtc_data_addr(u32 addr)
+int iwl5000_hw_valid_rtc_data_addr(u32 addr)
 {
 	return (addr >= IWL50_RTC_DATA_LOWER_BOUND) &&
 		(addr < IWL50_RTC_DATA_UPPER_BOUND);
@@ -1381,7 +1381,7 @@ static int iwl5000_send_rxon_assoc(struct iwl_priv *priv)
 
 	return ret;
 }
-static int  iwl5000_send_tx_power(struct iwl_priv *priv)
+int  iwl5000_send_tx_power(struct iwl_priv *priv)
 {
 	struct iwl5000_tx_power_dbm_cmd tx_power_cmd;
 	u8 tx_ant_cfg_cmd;
@@ -1401,7 +1401,7 @@ static int  iwl5000_send_tx_power(struct iwl_priv *priv)
 				       NULL);
 }
 
-static void iwl5000_temperature(struct iwl_priv *priv)
+void iwl5000_temperature(struct iwl_priv *priv)
 {
 	/* store temperature from statistics (in Celsius) */
 	priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 26c5d4a..59ff735 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -61,6 +61,63 @@
 #define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode"
 #define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api)
 
+static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
+{
+	/* want Celsius */
+	priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
+	priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+}
+
+static struct iwl_lib_ops iwl6000_lib = {
+	.set_hw_params = iwl5000_hw_set_hw_params,
+	.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
+	.txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
+	.txq_set_sched = iwl5000_txq_set_sched,
+	.txq_agg_enable = iwl5000_txq_agg_enable,
+	.txq_agg_disable = iwl5000_txq_agg_disable,
+	.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
+	.txq_free_tfd = iwl_hw_txq_free_tfd,
+	.txq_init = iwl_hw_tx_queue_init,
+	.rx_handler_setup = iwl5000_rx_handler_setup,
+	.setup_deferred_work = iwl5000_setup_deferred_work,
+	.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+	.load_ucode = iwl5000_load_ucode,
+	.init_alive_start = iwl5000_init_alive_start,
+	.alive_notify = iwl5000_alive_notify,
+	.send_tx_power = iwl5000_send_tx_power,
+	.update_chain_flags = iwl_update_chain_flags,
+	.apm_ops = {
+		.init =	iwl5000_apm_init,
+		.reset = iwl5000_apm_reset,
+		.stop = iwl5000_apm_stop,
+		.config = iwl5000_nic_config,
+		.set_pwr_src = iwl_set_pwr_src,
+	},
+	.eeprom_ops = {
+		.regulatory_bands = {
+			EEPROM_5000_REG_BAND_1_CHANNELS,
+			EEPROM_5000_REG_BAND_2_CHANNELS,
+			EEPROM_5000_REG_BAND_3_CHANNELS,
+			EEPROM_5000_REG_BAND_4_CHANNELS,
+			EEPROM_5000_REG_BAND_5_CHANNELS,
+			EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
+			EEPROM_5000_REG_BAND_52_FAT_CHANNELS
+		},
+		.verify_signature  = iwlcore_eeprom_verify_signature,
+		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+		.release_semaphore = iwlcore_eeprom_release_semaphore,
+		.calib_version	= iwl5000_eeprom_calib_version,
+		.query_addr = iwl5000_eeprom_query_addr,
+	},
+	.post_associate = iwl_post_associate,
+	.isr = iwl_isr_ict,
+	.config_ap = iwl_config_ap,
+	.temp_ops = {
+		.temperature = iwl5000_temperature,
+		.set_ct_kill = iwl6000_set_ct_threshold,
+	 },
+};
+
 static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
 	.get_hcmd_size = iwl5000_get_hcmd_size,
 	.build_addsta_hcmd = iwl5000_build_addsta_hcmd,
@@ -70,7 +127,7 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
 
 static struct iwl_ops iwl6000_ops = {
 	.ucode = &iwl5000_ucode,
-	.lib = &iwl5000_lib,
+	.lib = &iwl6000_lib,
 	.hcmd = &iwl5000_hcmd,
 	.utils = &iwl6000_hcmd_utils,
 };
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index ebb2fbc..39ede57 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -2413,6 +2413,13 @@ struct iwl_ct_kill_config {
 	__le32   critical_temperature_R;
 }  __attribute__ ((packed));
 
+/* 1000, and 6x00 */
+struct iwl_ct_kill_throttling_config {
+	__le32   critical_temperature_exit;
+	__le32   reserved;
+	__le32   critical_temperature_enter;
+}  __attribute__ ((packed));
+
 /******************************************************************************
  * (8)
  * Scan Commands, Responses, Notifications:
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 6aea026..5ef3c37 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -2224,6 +2224,7 @@ EXPORT_SYMBOL(iwl_verify_ucode);
 void iwl_rf_kill_ct_config(struct iwl_priv *priv)
 {
 	struct iwl_ct_kill_config cmd;
+	struct iwl_ct_kill_throttling_config adv_cmd;
 	unsigned long flags;
 	int ret = 0;
 
@@ -2232,9 +2233,26 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
 		    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	cmd.critical_temperature_R =
-		cpu_to_le32(priv->hw_params.ct_kill_threshold);
+	switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+	case CSR_HW_REV_TYPE_1000:
+	case CSR_HW_REV_TYPE_6x00:
+	case CSR_HW_REV_TYPE_6x50:
+		adv_cmd.critical_temperature_enter =
+			cpu_to_le32(priv->hw_params.ct_kill_threshold);
+		adv_cmd.critical_temperature_exit =
+			cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
+
+		ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
+				       sizeof(adv_cmd), &adv_cmd);
+		break;
+	default:
+		cmd.critical_temperature_R =
+			cpu_to_le32(priv->hw_params.ct_kill_threshold);
 
+		ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
+				       sizeof(cmd), &cmd);
+		break;
+	}
 	ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
 			       sizeof(cmd), &cmd);
 	if (ret)
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 0751891..cddf173 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -63,6 +63,8 @@ extern struct iwl_cfg iwl6050_2agn_cfg;
 extern struct iwl_cfg iwl6050_3agn_cfg;
 extern struct iwl_cfg iwl1000_bgn_cfg;
 
+struct iwl_tx_queue;
+
 /* shared structures from iwl-5000.c */
 extern struct iwl_mod_params iwl50_mod_params;
 extern struct iwl_ops iwl5000_ops;
@@ -79,9 +81,37 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
 				    __le32 *tx_flags);
 extern int iwl5000_calc_rssi(struct iwl_priv *priv,
 			     struct iwl_rx_phy_res *rx_resp);
+extern int iwl5000_apm_init(struct iwl_priv *priv);
+extern void iwl5000_apm_stop(struct iwl_priv *priv);
+extern int iwl5000_apm_reset(struct iwl_priv *priv);
+extern void iwl5000_nic_config(struct iwl_priv *priv);
+extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv);
+extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
+				    size_t offset);
+extern void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+					    struct iwl_tx_queue *txq,
+					    u16 byte_cnt);
+extern void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+				    struct iwl_tx_queue *txq);
+extern int iwl5000_load_ucode(struct iwl_priv *priv);
+extern void iwl5000_init_alive_start(struct iwl_priv *priv);
+extern int iwl5000_alive_notify(struct iwl_priv *priv);
+extern int iwl5000_hw_set_hw_params(struct iwl_priv *priv);
+extern int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
+			   int tx_fifo, int sta_id, int tid, u16 ssn_idx);
+extern int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+			    u16 ssn_idx, u8 tx_fifo);
+extern void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask);
+extern void iwl5000_setup_deferred_work(struct iwl_priv *priv);
+extern void iwl5000_rx_handler_setup(struct iwl_priv *priv);
+extern int iwl5000_hw_valid_rtc_data_addr(u32 addr);
+extern int iwl5000_send_tx_power(struct iwl_priv *priv);
+extern void iwl5000_temperature(struct iwl_priv *priv);
 
 /* CT-KILL constants */
-#define CT_KILL_THRESHOLD	110 /* in Celsius */
+#define CT_KILL_THRESHOLD_LEGACY   110 /* in Celsius */
+#define CT_KILL_THRESHOLD	   114 /* in Celsius */
+#define CT_KILL_EXIT_THRESHOLD     95  /* in Celsius */
 
 /* Default noise level to report when noise measurement is not available.
  *   This may be because we're:
@@ -630,6 +660,8 @@ struct iwl_hw_params {
 	u32 max_data_size;
 	u32 max_bsm_size;
 	u32 ct_kill_threshold; /* value in hw-dependent units */
+	u32 ct_kill_exit_threshold; /* value in hw-dependent units */
+				    /* for 1000, 6000 series and up */
 	u32 calib_init_cfg;
 	const struct iwl_sensitivity_ranges *sens;
 };
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 03/14] iwlwifi: Thermal Throttling Management - Part 1
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
  2009-07-24 18:13 ` [PATCH 01/14] iwlwifi: revert to active table when rate is not valid Reinette Chatre
  2009-07-24 18:13 ` [PATCH 02/14] iwlwifi: critical temperature enter/exit condition Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  2009-07-24 18:13 ` [PATCH 04/14] iwlwifi: Thermal Throttling Management - part 2 Reinette Chatre
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Wey-Yi Guy, Reinette Chatre

From: Wey-Yi Guy <wey-yi.w.guy@intel.com>

Part 1 of Thermal Throttling Management -

Thermal Throttling feature is used to put NIC into low power state when
driver detect the Radio temperature reach pre-defined threshold

Two Thermal Throttling Management Methods; this patch introduce the
Legacy Thermal Management:
   IWL_TI_0: normal temperature, system power state
   IWL_TI_1: high temperature detect, low power state
   IWL_TI_2: higher temperature detected, lower power state
   IWL_TI_CT_KILL: critical temperature detected, lowest power state

Once get into CT_KILL state, uCode go into sleep, driver will stop all
the active queues, then move to IWL_TI_CT_KILL state; also set up 5
seconds timer to toggle CSR flag, uCode wake up upon CSR flag change,
then measure the temperature.
If temperature is above CT_KILL exit threshold, uCode go backto sleep;
if temperature is below CT_KILL exit threshold, uCode send Card State
Notification response with appropriate CT_KILL status flag, and uCode
remain awake, Driver receive Card State Notification Response and update
the card temperature to the CT_KILL exit threshold.

Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-4965.c  |    1 +
 drivers/net/wireless/iwlwifi/iwl-5000.c  |    1 +
 drivers/net/wireless/iwlwifi/iwl-agn.c   |   19 +--
 drivers/net/wireless/iwlwifi/iwl-core.c  |    1 +
 drivers/net/wireless/iwlwifi/iwl-power.c |  249 ++++++++++++++++++++++++++++++
 drivers/net/wireless/iwlwifi/iwl-power.h |   42 +++++
 6 files changed, 301 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 23925bd..6702148 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -1797,6 +1797,7 @@ static void iwl4965_temperature_calib(struct iwl_priv *priv)
 	}
 
 	priv->temperature = temp;
+	iwl_tt_handler(priv);
 	set_bit(STATUS_TEMPERATURE, &priv->status);
 
 	if (!priv->disable_tx_power_cal &&
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 076acb1..ddd64fe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1405,6 +1405,7 @@ void iwl5000_temperature(struct iwl_priv *priv)
 {
 	/* store temperature from statistics (in Celsius) */
 	priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
+	iwl_tt_handler(priv);
 }
 
 static void iwl5150_temperature(struct iwl_priv *priv)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 44c7f23..23ae991 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -637,7 +637,6 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
 	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
 	u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
 	unsigned long status = priv->status;
-	unsigned long reg_flags;
 
 	IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
 			  (flags & HW_CARD_DISABLED) ? "Kill" : "On",
@@ -657,19 +656,12 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
 				    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
 			iwl_write_direct32(priv, HBUS_TARG_MBX_C,
 					HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
-
-		}
-
-		if (flags & RF_CARD_DISABLED) {
-			iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
-				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-			iwl_read32(priv, CSR_UCODE_DRV_GP1);
-			spin_lock_irqsave(&priv->reg_lock, reg_flags);
-			if (!iwl_grab_nic_access(priv))
-				iwl_release_nic_access(priv);
-			spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
 		}
+		if (flags & RF_CARD_DISABLED)
+			iwl_tt_enter_ct_kill(priv);
 	}
+	if (!(flags & RF_CARD_DISABLED))
+		iwl_tt_exit_ct_kill(priv);
 
 	if (flags & HW_CARD_DISABLED)
 		set_bit(STATUS_RF_KILL_HW, &priv->status);
@@ -3015,6 +3007,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		test_bit(STATUS_RF_KILL_HW, &priv->status));
 
 	iwl_power_initialize(priv);
+	iwl_tt_initialize(priv);
 	return 0;
 
  out_remove_sysfs:
@@ -3067,6 +3060,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
 		iwl_down(priv);
 	}
 
+	iwl_tt_exit(priv);
+
 	/* make sure we flush any pending irq or
 	 * tasklet for the driver
 	 */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 5ef3c37..d8aeb24 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -2232,6 +2232,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
 	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
 		    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
 	spin_unlock_irqrestore(&priv->lock, flags);
+	priv->power_data.ct_kill_toggle = false;
 
 	switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
 	case CSR_HW_REV_TYPE_1000:
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index f2ea3f0..d7fdb58 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -36,6 +36,7 @@
 #include "iwl-eeprom.h"
 #include "iwl-dev.h"
 #include "iwl-core.h"
+#include "iwl-io.h"
 #include "iwl-commands.h"
 #include "iwl-debug.h"
 #include "iwl-power.h"
@@ -211,6 +212,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
 {
 	struct iwl_power_mgr *setting = &(priv->power_data);
 	int ret = 0;
+	struct iwl_tt_mgmt *tt = &priv->power_data.tt;
 	u16 uninitialized_var(final_mode);
 	bool update_chains;
 
@@ -223,6 +225,10 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
 	if (setting->power_disabled)
 		final_mode = IWL_POWER_MODE_CAM;
 
+	if (tt->state >= IWL_TI_1) {
+		/* TT power setting overwrite user & system power setting */
+		final_mode = tt->tt_power_mode;
+	}
 	if (iwl_is_ready_rf(priv) &&
 	    ((setting->power_mode != final_mode) || force)) {
 		struct iwl_powertable_cmd cmd;
@@ -267,6 +273,249 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
 }
 EXPORT_SYMBOL(iwl_power_set_user_mode);
 
+#define CT_KILL_EXIT_DURATION (5)	/* 5 seconds duration */
+
+/*
+ * toggle the bit to wake up uCode and check the temperature
+ * if the temperature is below CT, uCode will stay awake and send card
+ * state notification with CT_KILL bit clear to inform Thermal Throttling
+ * Management to change state. Otherwise, uCode will go back to sleep
+ * without doing anything, driver should continue the 5 seconds timer
+ * to wake up uCode for temperature check until temperature drop below CT
+ */
+static void iwl_tt_check_exit_ct_kill(unsigned long data)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)data;
+	struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+	unsigned long flags;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (tt->state == IWL_TI_CT_KILL) {
+		if (priv->power_data.ct_kill_toggle) {
+			iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+			priv->power_data.ct_kill_toggle = false;
+		} else {
+			iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+			priv->power_data.ct_kill_toggle = true;
+		}
+		iwl_read32(priv, CSR_UCODE_DRV_GP1);
+		spin_lock_irqsave(&priv->reg_lock, flags);
+		if (!iwl_grab_nic_access(priv))
+			iwl_release_nic_access(priv);
+		spin_unlock_irqrestore(&priv->reg_lock, flags);
+
+		/* Reschedule the ct_kill timer to occur in
+		 * CT_KILL_EXIT_DURATION seconds to ensure we get a
+		 * thermal update */
+		mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies +
+			  CT_KILL_EXIT_DURATION * HZ);
+	}
+}
+
+static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
+			   bool stop)
+{
+	if (stop) {
+		IWL_DEBUG_POWER(priv, "Stop all queues\n");
+		if (priv->mac80211_registered)
+			ieee80211_stop_queues(priv->hw);
+		IWL_DEBUG_POWER(priv,
+				"Schedule 5 seconds CT_KILL Timer\n");
+		mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies +
+			  CT_KILL_EXIT_DURATION * HZ);
+	} else {
+		IWL_DEBUG_POWER(priv, "Wake all queues\n");
+		if (priv->mac80211_registered)
+			ieee80211_wake_queues(priv->hw);
+	}
+}
+
+#define IWL_MINIMAL_POWER_THRESHOLD		(CT_KILL_THRESHOLD_LEGACY)
+#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2	(100)
+#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1	(90)
+
+/*
+ * Legacy thermal throttling
+ * 1) Avoid NIC destruction due to high temperatures
+ *	Chip will identify dangerously high temperatures that can
+ *	harm the device and will power down
+ * 2) Avoid the NIC power down due to high temperature
+ *	Throttle early enough to lower the power consumption before
+ *	drastic steps are needed
+ */
+static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
+{
+	struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+	enum iwl_tt_state new_state;
+	struct iwl_power_mgr *setting = &priv->power_data;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if ((tt->tt_previous_temp) &&
+	    (temp > tt->tt_previous_temp) &&
+	    ((temp - tt->tt_previous_temp) >
+	    IWL_TT_INCREASE_MARGIN)) {
+		IWL_DEBUG_POWER(priv,
+			"Temperature increase %d degree Celsius\n",
+			(temp - tt->tt_previous_temp));
+	}
+#endif
+	/* in Celsius */
+	if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
+		new_state = IWL_TI_CT_KILL;
+	else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
+		new_state = IWL_TI_2;
+	else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
+		new_state = IWL_TI_1;
+	else
+		new_state = IWL_TI_0;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	tt->tt_previous_temp = temp;
+#endif
+	if (tt->state != new_state) {
+		if (tt->state == IWL_TI_0) {
+			tt->sys_power_mode = setting->power_mode;
+			IWL_DEBUG_POWER(priv, "current power mode: %u\n",
+				setting->power_mode);
+		}
+		switch (new_state) {
+		case IWL_TI_0:
+			/* when system ready to go back to IWL_TI_0 state
+			 * using system power mode instead of TT power mode
+			 * revert back to the orginal power mode which was saved
+			 * before enter Thermal Throttling state
+			 * update priv->power_data.user_power_setting to the
+			 * required power mode to make sure
+			 * iwl_power_update_mode() will update power correctly.
+			 */
+			priv->power_data.user_power_setting =
+				tt->sys_power_mode;
+			tt->tt_power_mode = tt->sys_power_mode;
+			break;
+		case IWL_TI_1:
+			tt->tt_power_mode = IWL_POWER_INDEX_3;
+			break;
+		case IWL_TI_2:
+			tt->tt_power_mode = IWL_POWER_INDEX_4;
+			break;
+		default:
+			tt->tt_power_mode = IWL_POWER_INDEX_5;
+			break;
+		}
+		if (iwl_power_update_mode(priv, true)) {
+			/* TT state not updated
+			 * try again during next temperature read
+			 */
+			IWL_ERR(priv, "Cannot update power mode, "
+					"TT state not updated\n");
+		} else {
+			if (new_state == IWL_TI_CT_KILL)
+				iwl_perform_ct_kill_task(priv, true);
+			else if (tt->state == IWL_TI_CT_KILL &&
+				 new_state != IWL_TI_CT_KILL)
+				iwl_perform_ct_kill_task(priv, false);
+			tt->state = new_state;
+			IWL_DEBUG_POWER(priv, "Temperature state changed %u\n",
+					tt->state);
+			IWL_DEBUG_POWER(priv, "Power Index change to %u\n",
+					tt->tt_power_mode);
+		}
+	}
+}
+
+/* Card State Notification indicated reach critical temperature
+ * if PSP not enable, no Thermal Throttling function will be performed
+ * just set the GP1 bit to acknowledge the event
+ * otherwise, go into IWL_TI_CT_KILL state
+ * since Card State Notification will not provide any temperature reading
+ * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
+ */
+void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
+{
+	struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (tt->state != IWL_TI_CT_KILL) {
+		IWL_ERR(priv, "Device reached critical temperature "
+			      "- ucode going to sleep!\n");
+		iwl_legacy_tt_handler(priv, IWL_MINIMAL_POWER_THRESHOLD);
+	}
+}
+EXPORT_SYMBOL(iwl_tt_enter_ct_kill);
+
+/* Card State Notification indicated out of critical temperature
+ * since Card State Notification will not provide any temperature reading
+ * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
+ * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
+ */
+void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
+{
+	struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	/* stop ct_kill_exit_tm timer */
+	del_timer_sync(&priv->power_data.ct_kill_exit_tm);
+
+	if (tt->state == IWL_TI_CT_KILL) {
+		IWL_ERR(priv,
+			"Device temperature below critical"
+			"- ucode awake!\n");
+		iwl_legacy_tt_handler(priv,
+			IWL_REDUCED_PERFORMANCE_THRESHOLD_2);
+	}
+}
+EXPORT_SYMBOL(iwl_tt_exit_ct_kill);
+
+void iwl_tt_handler(struct iwl_priv *priv)
+{
+	s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
+		temp = KELVIN_TO_CELSIUS(priv->temperature);
+
+	iwl_legacy_tt_handler(priv, temp);
+}
+EXPORT_SYMBOL(iwl_tt_handler);
+
+/* Thermal throttling initialization
+ */
+void iwl_tt_initialize(struct iwl_priv *priv)
+{
+	struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+	struct iwl_power_mgr *setting = &priv->power_data;
+
+	IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n");
+
+	memset(tt, 0, sizeof(struct iwl_tt_mgmt));
+
+	tt->state = IWL_TI_0;
+	tt->sys_power_mode = setting->power_mode;
+	tt->tt_power_mode = tt->sys_power_mode;
+	init_timer(&priv->power_data.ct_kill_exit_tm);
+	priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv;
+	priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill;
+}
+EXPORT_SYMBOL(iwl_tt_initialize);
+
+/* cleanup thermal throttling management related memory and timer */
+void iwl_tt_exit(struct iwl_priv *priv)
+{
+	/* stop ct_kill_exit_tm timer if activated */
+	del_timer_sync(&priv->power_data.ct_kill_exit_tm);
+}
+EXPORT_SYMBOL(iwl_tt_exit);
+
 /* initialize to default */
 void iwl_power_initialize(struct iwl_priv *priv)
 {
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index 37ba3bb..7bb10d4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -33,6 +33,38 @@
 
 struct iwl_priv;
 
+#define IWL_TT_INCREASE_MARGIN	5
+
+/* Thermal Throttling State Machine states */
+enum  iwl_tt_state {
+	IWL_TI_0,	/* normal temperature, system power state */
+	IWL_TI_1,	/* high temperature detect, low power state */
+	IWL_TI_2,	/* higher temperature detected, lower power state */
+	IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */
+	IWL_TI_STATE_MAX
+};
+
+/**
+ * struct iwl_tt_mgnt - Thermal Throttling Management structure
+ * @state:          current Thermal Throttling state
+ * @tt_power_mode:  Thermal Throttling power mode index
+ *		    being used to set power level when
+ * 		    when thermal throttling state != IWL_TI_0
+ *		    the tt_power_mode should set to different
+ *		    power mode based on the current tt state
+ * @sys_power_mode: previous system power mode
+ *                  before transition into TT state
+ * @tt_previous_temperature: last measured temperature
+ */
+struct iwl_tt_mgmt {
+	enum iwl_tt_state state;
+	u8 tt_power_mode;
+	u8 sys_power_mode;
+#ifdef CONFIG_IWLWIFI_DEBUG
+	s32 tt_previous_temp;
+#endif
+};
+
 enum {
 	IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */
 	IWL_POWER_INDEX_1,
@@ -59,10 +91,20 @@ struct iwl_power_mgr {
 	u8 power_mode;
 	u8 user_power_setting; /* set by user through sysfs */
 	u8 power_disabled; /* set by mac80211's CONF_PS */
+	struct iwl_tt_mgmt tt; /* Thermal Throttling Management */
+	bool ct_kill_toggle;   /* use to toggle the CSR bit when
+				* checking uCode temperature
+				*/
+	struct timer_list ct_kill_exit_tm;
 };
 
 int iwl_power_update_mode(struct iwl_priv *priv, bool force);
 int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);
+void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
+void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
+void iwl_tt_handler(struct iwl_priv *priv);
+void iwl_tt_initialize(struct iwl_priv *priv);
+void iwl_tt_exit(struct iwl_priv *priv);
 void iwl_power_initialize(struct iwl_priv *priv);
 
 #endif  /* __iwl_power_setting_h__ */
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 04/14] iwlwifi: Thermal Throttling Management - part 2
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
                   ` (2 preceding siblings ...)
  2009-07-24 18:13 ` [PATCH 03/14] iwlwifi: Thermal Throttling Management - Part 1 Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  2009-07-27 22:29   ` Johannes Berg
  2009-07-24 18:13 ` [PATCH 05/14] iwlwifi: Thermal Throttling debugfs function Reinette Chatre
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Wey-Yi Guy, Reinette Chatre

From: Wey-Yi Guy <wey-yi.w.guy@intel.com>

Part 2 of Thermal Throttling Management -

Thermal Throttling feature is used to put NIC into low power state when
driver detect the Radio temperature reach pre-defined threshold

Two Thermal Throttling Management Methods; this patch introduce the
Advance Thermal Throttling:
TI-0: system power index, no tx/rx restriction, HT enabled
TI-1: power index 5, 1 spatial stream Tx, multiple spatial stream Rx, HT
enabled
TI-2: power index 5: 1 spatial stream Tx, 1 spatial stream Rx, HT
disabled
TI-CT-KILL: power index 5, no Tx, no Rx, HT disabled

For advance Thermal Throttling, CT_KILL_ENTER threshold and CT_KILL_EXIT
threshold are different; uCode will not stay awake until reach
CT_KILL_EXIT threshold.

Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-agn-rs.c |   48 ++++-
 drivers/net/wireless/iwlwifi/iwl-power.c  |  285 ++++++++++++++++++++++++++++-
 drivers/net/wireless/iwlwifi/iwl-power.h  |   51 +++++
 3 files changed, 371 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 40207da..52a4810 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -177,7 +177,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 				   struct sk_buff *skb,
 				   struct ieee80211_sta *sta,
 				   struct iwl_lq_sta *lq_sta);
-static void rs_fill_link_cmd(const struct iwl_priv *priv,
+static void rs_fill_link_cmd(struct iwl_priv *priv,
 			     struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
 
 
@@ -1398,6 +1398,12 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
 	int ret = 0;
 	u8 update_search_tbl_counter = 0;
 
+	if (!iwl_ht_enabled(priv))
+		/* stay in Legacy */
+		tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+	else if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE &&
+		   tbl->action > IWL_LEGACY_SWITCH_SISO)
+		tbl->action = IWL_LEGACY_SWITCH_SISO;
 	for (; ;) {
 		lq_sta->action_counter++;
 		switch (tbl->action) {
@@ -1529,6 +1535,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
 	u8 update_search_tbl_counter = 0;
 	int ret;
 
+	if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE &&
+	    tbl->action > IWL_SISO_SWITCH_ANTENNA2) {
+		/* stay in SISO */
+		tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+	}
 	for (;;) {
 		lq_sta->action_counter++;
 		switch (tbl->action) {
@@ -1663,6 +1674,12 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
 	u8 update_search_tbl_counter = 0;
 	int ret;
 
+	if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) &&
+	    (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
+	     tbl->action > IWL_MIMO2_SWITCH_SISO_C)) {
+		/* switch in SISO */
+		tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+	}
 	for (;;) {
 		lq_sta->action_counter++;
 		switch (tbl->action) {
@@ -1799,6 +1816,12 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
 	int ret;
 	u8 update_search_tbl_counter = 0;
 
+	if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) &&
+	    (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
+	     tbl->action > IWL_MIMO3_SWITCH_SISO_C)) {
+		/* switch in SISO */
+		tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+	}
 	for (;;) {
 		lq_sta->action_counter++;
 		switch (tbl->action) {
@@ -2178,8 +2201,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 			tbl->expected_tpt[index] + 64) / 128));
 
 	/* If we are searching for better modulation mode, check success. */
-	if (lq_sta->search_better_tbl) {
-
+	if (lq_sta->search_better_tbl &&
+	    (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI)) {
 		/* If good success, continue using the "search" mode;
 		 * no need to send new link quality command, since we're
 		 * continuing to use the setup that we've been trying. */
@@ -2307,7 +2330,11 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 		    ((sr > IWL_RATE_HIGH_TH) ||
 		     (current_tpt > (100 * tbl->expected_tpt[low]))))
 		scale_action = 0;
-
+	if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type))
+		scale_action = -1;
+	if (iwl_tx_ant_restriction(priv) != IWL_TX_MULTI &&
+		(is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type)))
+		scale_action = -1;
 	switch (scale_action) {
 	case -1:
 		/* Decrease starting rate, update uCode's rate table */
@@ -2341,9 +2368,11 @@ lq_update:
 		rate = rs_update_rate_tbl(priv, lq_sta,
 					  tbl, index, is_green);
 
-	/* Should we stay with this modulation mode, or search for a new one? */
-	rs_stay_in_table(lq_sta);
-
+	if (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI) {
+		/* Should we stay with this modulation mode,
+		 * or search for a new one? */
+		rs_stay_in_table(lq_sta);
+	}
 	/*
 	 * Search for new modulation mode if we're:
 	 * 1)  Not changing rates right now
@@ -2400,7 +2429,8 @@ lq_update:
 		 * have been tried and compared, stay in this best modulation
 		 * mode for a while before next round of mode comparisons. */
 		if (lq_sta->enable_counter &&
-		    (lq_sta->action_counter >= tbl1->max_search)) {
+		    (lq_sta->action_counter >= tbl1->max_search) &&
+		    iwl_ht_enabled(priv)) {
 			if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
 			    (lq_sta->tx_agg_tid_en & (1 << tid)) &&
 			    (tid != MAX_TID_COUNT)) {
@@ -2686,7 +2716,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
 	rs_initialize_lq(priv, conf, sta, lq_sta);
 }
 
-static void rs_fill_link_cmd(const struct iwl_priv *priv,
+static void rs_fill_link_cmd(struct iwl_priv *priv,
 			     struct iwl_lq_sta *lq_sta, u32 new_rate)
 {
 	struct iwl_scale_tbl_info tbl_type;
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index d7fdb58..00937b3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -98,6 +98,45 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
 	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
 };
 
+/* default Thermal Throttling transaction table
+ * Current state   |         Throttling Down               |  Throttling Up
+ *=============================================================================
+ *                 Condition Nxt State  Condition Nxt State Condition Nxt State
+ *-----------------------------------------------------------------------------
+ *     IWL_TI_0     T >= 115   CT_KILL  115>T>=105   TI_1      N/A      N/A
+ *     IWL_TI_1     T >= 115   CT_KILL  115>T>=110   TI_2     T<=95     TI_0
+ *     IWL_TI_2     T >= 115   CT_KILL                        T<=100    TI_1
+ *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
+ *=============================================================================
+ */
+static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
+	{IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
+	{IWL_TI_1, 105, CT_KILL_THRESHOLD},
+	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
+	{IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
+	{IWL_TI_2, 110, CT_KILL_THRESHOLD},
+	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
+	{IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
+	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
+	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
+	{IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
+	{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
+	{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+};
+
+/* Advance Thermal Throttling default restriction table */
+static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
+	{IWL_TX_MULTI, true, IWL_RX_MULTI},
+	{IWL_TX_SINGLE, true, IWL_RX_MULTI},
+	{IWL_TX_SINGLE, false, IWL_RX_SINGLE},
+	{IWL_TX_NONE, false, IWL_RX_NONE}
+};
 
 /* set card power command */
 static int iwl_set_power(struct iwl_priv *priv, void *cmd)
@@ -273,6 +312,42 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
 }
 EXPORT_SYMBOL(iwl_power_set_user_mode);
 
+bool iwl_ht_enabled(struct iwl_priv *priv)
+{
+	struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+	struct iwl_tt_restriction *restriction;
+
+	if (!priv->power_data.adv_tt)
+		return true;
+	restriction = tt->restriction + tt->state;
+	return restriction->is_ht;
+}
+EXPORT_SYMBOL(iwl_ht_enabled);
+
+u8 iwl_tx_ant_restriction(struct iwl_priv *priv)
+{
+	struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+	struct iwl_tt_restriction *restriction;
+
+	if (!priv->power_data.adv_tt)
+		return IWL_TX_MULTI;
+	restriction = tt->restriction + tt->state;
+	return restriction->tx_stream;
+}
+EXPORT_SYMBOL(iwl_tx_ant_restriction);
+
+u8 iwl_rx_ant_restriction(struct iwl_priv *priv)
+{
+	struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+	struct iwl_tt_restriction *restriction;
+
+	if (!priv->power_data.adv_tt)
+		return IWL_RX_MULTI;
+	restriction = tt->restriction + tt->state;
+	return restriction->rx_stream;
+}
+EXPORT_SYMBOL(iwl_rx_ant_restriction);
+
 #define CT_KILL_EXIT_DURATION (5)	/* 5 seconds duration */
 
 /*
@@ -427,12 +502,147 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
 	}
 }
 
+/*
+ * Advance thermal throttling
+ * 1) Avoid NIC destruction due to high temperatures
+ *	Chip will identify dangerously high temperatures that can
+ *	harm the device and will power down
+ * 2) Avoid the NIC power down due to high temperature
+ *	Throttle early enough to lower the power consumption before
+ *	drastic steps are needed
+ *	Actions include relaxing the power down sleep thresholds and
+ *	decreasing the number of TX streams
+ * 3) Avoid throughput performance impact as much as possible
+ *
+ *=============================================================================
+ *                 Condition Nxt State  Condition Nxt State Condition Nxt State
+ *-----------------------------------------------------------------------------
+ *     IWL_TI_0     T >= 115   CT_KILL  115>T>=105   TI_1      N/A      N/A
+ *     IWL_TI_1     T >= 115   CT_KILL  115>T>=110   TI_2     T<=95     TI_0
+ *     IWL_TI_2     T >= 115   CT_KILL                        T<=100    TI_1
+ *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
+ *=============================================================================
+ */
+static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
+{
+	struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+	int i;
+	bool changed = false;
+	enum iwl_tt_state old_state;
+	struct iwl_tt_trans *transaction;
+
+	old_state = tt->state;
+	for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
+		/* based on the current TT state,
+		 * find the curresponding transaction table
+		 * each table has (IWL_TI_STATE_MAX - 1) entries
+		 * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
+		 * will advance to the correct table.
+		 * then based on the current temperature
+		 * find the next state need to transaction to
+		 * go through all the possible (IWL_TI_STATE_MAX - 1) entries
+		 * in the current table to see if transaction is needed
+		 */
+		transaction = tt->transaction +
+			((old_state * (IWL_TI_STATE_MAX - 1)) + i);
+		if (temp >= transaction->tt_low &&
+		    temp <= transaction->tt_high) {
+#ifdef CONFIG_IWLWIFI_DEBUG
+			if ((tt->tt_previous_temp) &&
+			    (temp > tt->tt_previous_temp) &&
+			    ((temp - tt->tt_previous_temp) >
+			    IWL_TT_INCREASE_MARGIN)) {
+				IWL_DEBUG_POWER(priv,
+					"Temperature increase %d "
+					"degree Celsius\n",
+					(temp - tt->tt_previous_temp));
+			}
+			tt->tt_previous_temp = temp;
+#endif
+			if (old_state !=
+			    transaction->next_state) {
+				changed = true;
+				tt->state =
+					transaction->next_state;
+			}
+			break;
+		}
+	}
+	if (changed) {
+		struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+		struct iwl_power_mgr *setting = &priv->power_data;
+
+		if (tt->state >= IWL_TI_1) {
+			/* if switching from IWL_TI_0 to other TT state
+			 * save previous power setting in tt->sys_power_mode */
+			if (old_state == IWL_TI_0)
+				tt->sys_power_mode = setting->power_mode;
+			/* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
+			tt->tt_power_mode = IWL_POWER_INDEX_5;
+			if (!iwl_ht_enabled(priv))
+				/* disable HT */
+				rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
+					RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
+					RXON_FLG_FAT_PROT_MSK |
+					RXON_FLG_HT_PROT_MSK);
+			else {
+				/* check HT capability and set
+				 * according to the system HT capability
+				 * in case get disabled before */
+				iwl_set_rxon_ht(priv, &priv->current_ht_config);
+			}
+
+		} else {
+			/* restore system power setting */
+			/* the previous power mode was saved in
+			 * tt->sys_power_mode when system move into
+			 * Thermal Throttling state
+			 * set power_data.user_power_setting to the previous
+			 * system power mode to make sure power will get
+			 * updated correctly
+			 */
+			priv->power_data.user_power_setting =
+				tt->sys_power_mode;
+			tt->tt_power_mode = tt->sys_power_mode;
+			/* check HT capability and set
+			 * according to the system HT capability
+			 * in case get disabled before */
+			iwl_set_rxon_ht(priv, &priv->current_ht_config);
+		}
+		if (iwl_power_update_mode(priv, true)) {
+			/* TT state not updated
+			 * try again during next temperature read
+			 */
+			IWL_ERR(priv, "Cannot update power mode, "
+					"TT state not updated\n");
+			tt->state = old_state;
+		} else {
+			IWL_DEBUG_POWER(priv,
+					"Thermal Throttling to new state: %u\n",
+					tt->state);
+			if (old_state != IWL_TI_CT_KILL &&
+			    tt->state == IWL_TI_CT_KILL) {
+				IWL_DEBUG_POWER(priv, "Enter IWL_TI_CT_KILL\n");
+				iwl_perform_ct_kill_task(priv, true);
+
+			} else if (old_state == IWL_TI_CT_KILL &&
+				  tt->state != IWL_TI_CT_KILL) {
+				IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n");
+				iwl_perform_ct_kill_task(priv, false);
+			}
+		}
+	}
+}
+
 /* Card State Notification indicated reach critical temperature
  * if PSP not enable, no Thermal Throttling function will be performed
  * just set the GP1 bit to acknowledge the event
  * otherwise, go into IWL_TI_CT_KILL state
  * since Card State Notification will not provide any temperature reading
+ * for Legacy mode
  * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
+ * for advance mode
+ * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
  */
 void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
 {
@@ -444,7 +654,12 @@ void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
 	if (tt->state != IWL_TI_CT_KILL) {
 		IWL_ERR(priv, "Device reached critical temperature "
 			      "- ucode going to sleep!\n");
-		iwl_legacy_tt_handler(priv, IWL_MINIMAL_POWER_THRESHOLD);
+		if (!priv->power_data.adv_tt)
+			iwl_legacy_tt_handler(priv,
+					      IWL_MINIMAL_POWER_THRESHOLD);
+		else
+			iwl_advance_tt_handler(priv,
+					       CT_KILL_THRESHOLD + 1);
 	}
 }
 EXPORT_SYMBOL(iwl_tt_enter_ct_kill);
@@ -468,8 +683,11 @@ void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
 		IWL_ERR(priv,
 			"Device temperature below critical"
 			"- ucode awake!\n");
-		iwl_legacy_tt_handler(priv,
-			IWL_REDUCED_PERFORMANCE_THRESHOLD_2);
+		if (!priv->power_data.adv_tt)
+			iwl_legacy_tt_handler(priv,
+					IWL_REDUCED_PERFORMANCE_THRESHOLD_2);
+		else
+			iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD);
 	}
 }
 EXPORT_SYMBOL(iwl_tt_exit_ct_kill);
@@ -484,16 +702,24 @@ void iwl_tt_handler(struct iwl_priv *priv)
 	if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
 		temp = KELVIN_TO_CELSIUS(priv->temperature);
 
-	iwl_legacy_tt_handler(priv, temp);
+	if (!priv->power_data.adv_tt)
+		iwl_legacy_tt_handler(priv, temp);
+	else
+		iwl_advance_tt_handler(priv, temp);
 }
 EXPORT_SYMBOL(iwl_tt_handler);
 
 /* Thermal throttling initialization
+ * For advance thermal throttling:
+ *     Initialize Thermal Index and temperature threshold table
+ *     Initialize thermal throttling restriction table
  */
 void iwl_tt_initialize(struct iwl_priv *priv)
 {
 	struct iwl_tt_mgmt *tt = &priv->power_data.tt;
 	struct iwl_power_mgr *setting = &priv->power_data;
+	int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
+	struct iwl_tt_trans *transaction;
 
 	IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n");
 
@@ -505,14 +731,65 @@ void iwl_tt_initialize(struct iwl_priv *priv)
 	init_timer(&priv->power_data.ct_kill_exit_tm);
 	priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv;
 	priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill;
+	switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+	case CSR_HW_REV_TYPE_6x00:
+	case CSR_HW_REV_TYPE_6x50:
+		IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n");
+		tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) *
+					 IWL_TI_STATE_MAX, GFP_KERNEL);
+		tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) *
+			IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1),
+			GFP_KERNEL);
+		if (!tt->restriction || !tt->transaction) {
+			IWL_ERR(priv, "Fallback to Legacy Throttling\n");
+			priv->power_data.adv_tt = false;
+			kfree(tt->restriction);
+			tt->restriction = NULL;
+			kfree(tt->transaction);
+			tt->transaction = NULL;
+		} else {
+			transaction = tt->transaction +
+				(IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
+			memcpy(transaction, &tt_range_0[0], size);
+			transaction = tt->transaction +
+				(IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
+			memcpy(transaction, &tt_range_1[0], size);
+			transaction = tt->transaction +
+				(IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
+			memcpy(transaction, &tt_range_2[0], size);
+			transaction = tt->transaction +
+				(IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
+			memcpy(transaction, &tt_range_3[0], size);
+			size = sizeof(struct iwl_tt_restriction) *
+				IWL_TI_STATE_MAX;
+			memcpy(tt->restriction,
+				&restriction_range[0], size);
+			priv->power_data.adv_tt = true;
+		}
+		break;
+	default:
+		IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n");
+		priv->power_data.adv_tt = false;
+		break;
+	}
 }
 EXPORT_SYMBOL(iwl_tt_initialize);
 
 /* cleanup thermal throttling management related memory and timer */
 void iwl_tt_exit(struct iwl_priv *priv)
 {
+	struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+
 	/* stop ct_kill_exit_tm timer if activated */
 	del_timer_sync(&priv->power_data.ct_kill_exit_tm);
+
+	if (priv->power_data.adv_tt) {
+		/* free advance thermal throttling memory */
+		kfree(tt->restriction);
+		tt->restriction = NULL;
+		kfree(tt->transaction);
+		tt->transaction = NULL;
+	}
 }
 EXPORT_SYMBOL(iwl_tt_exit);
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index 7bb10d4..3d49b7a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -33,8 +33,18 @@
 
 struct iwl_priv;
 
+#define IWL_ABSOLUTE_ZERO		0
+#define IWL_ABSOLUTE_MAX		0xFFFFFFFF
 #define IWL_TT_INCREASE_MARGIN	5
 
+/* Tx/Rx restrictions */
+#define IWL_TX_MULTI		0x02
+#define IWL_TX_SINGLE		0x01
+#define IWL_TX_NONE		0x00
+#define IWL_RX_MULTI		0x02
+#define IWL_RX_SINGLE		0x01
+#define IWL_RX_NONE		0x00
+
 /* Thermal Throttling State Machine states */
 enum  iwl_tt_state {
 	IWL_TI_0,	/* normal temperature, system power state */
@@ -45,6 +55,35 @@ enum  iwl_tt_state {
 };
 
 /**
+ * struct iwl_tt_restriction - Thermal Throttling restriction table used
+ *		by advance thermal throttling management
+ *		based on the current thermal throttling state, determine
+ *		number of tx/rx streams; and the status of HT operation
+ * @tx_stream: number of tx stream allowed
+ * @is_ht: ht enable/disable
+ * @rx_stream: number of rx stream allowed
+ */
+struct iwl_tt_restriction {
+	u8 tx_stream;
+	bool is_ht;
+	u8 rx_stream;
+};
+
+/**
+ * struct iwl_tt_trans - Thermal Throttling transaction table; used by
+ * 		advance thermal throttling algorithm to determine next
+ *		thermal state to go based on the current temperature
+ * @next_state:  next thermal throttling mode
+ * @tt_low: low temperature threshold to change state
+ * @tt_high: high temperature threshold to change state
+ */
+struct iwl_tt_trans {
+	enum iwl_tt_state next_state;
+	u32 tt_low;
+	u32 tt_high;
+};
+
+/**
  * struct iwl_tt_mgnt - Thermal Throttling Management structure
  * @state:          current Thermal Throttling state
  * @tt_power_mode:  Thermal Throttling power mode index
@@ -55,6 +94,11 @@ enum  iwl_tt_state {
  * @sys_power_mode: previous system power mode
  *                  before transition into TT state
  * @tt_previous_temperature: last measured temperature
+ * @iwl_tt_restriction: ptr to restriction tbl, used by advance
+ *		    thermal throttling to determine how many tx/rx streams
+ *		    should be used in tt state; and can HT be enabled or not
+ * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
+ *		    state transaction
  */
 struct iwl_tt_mgmt {
 	enum iwl_tt_state state;
@@ -63,6 +107,8 @@ struct iwl_tt_mgmt {
 #ifdef CONFIG_IWLWIFI_DEBUG
 	s32 tt_previous_temp;
 #endif
+	struct iwl_tt_restriction *restriction;
+	struct iwl_tt_trans *transaction;
 };
 
 enum {
@@ -92,6 +138,8 @@ struct iwl_power_mgr {
 	u8 user_power_setting; /* set by user through sysfs */
 	u8 power_disabled; /* set by mac80211's CONF_PS */
 	struct iwl_tt_mgmt tt; /* Thermal Throttling Management */
+	bool adv_tt;		/* false: legacy mode */
+				/* true: advance mode */
 	bool ct_kill_toggle;   /* use to toggle the CSR bit when
 				* checking uCode temperature
 				*/
@@ -100,6 +148,9 @@ struct iwl_power_mgr {
 
 int iwl_power_update_mode(struct iwl_priv *priv, bool force);
 int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);
+bool iwl_ht_enabled(struct iwl_priv *priv);
+u8 iwl_tx_ant_restriction(struct iwl_priv *priv);
+u8 iwl_rx_ant_restriction(struct iwl_priv *priv);
 void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
 void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
 void iwl_tt_handler(struct iwl_priv *priv);
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 05/14] iwlwifi: Thermal Throttling debugfs function
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
                   ` (3 preceding siblings ...)
  2009-07-24 18:13 ` [PATCH 04/14] iwlwifi: Thermal Throttling Management - part 2 Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  2009-07-24 18:13 ` [PATCH 06/14] iwlwifi: fix up command sending Reinette Chatre
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Wey-Yi Guy, Reinette Chatre

From: Wey-Yi Guy <wey-yi.w.guy@intel.com>

Add debugfs function to display current thermal throttling status for
both Legacy and Advance Thermal Throttling Management

Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-debug.h   |    1 +
 drivers/net/wireless/iwlwifi/iwl-debugfs.c |   38 ++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 9faf0c2..609a681 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -84,6 +84,7 @@ struct iwl_debugfs {
 		struct dentry *file_status;
 		struct dentry *file_interrupt;
 		struct dentry *file_qos;
+		struct dentry *file_thermal_throttling;
 #ifdef CONFIG_IWLWIFI_LEDS
 		struct dentry *file_led;
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 0ab3463..748dc31 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -618,6 +618,41 @@ static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
 }
 #endif
 
+static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
+				char __user *user_buf,
+				size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+	struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+	struct iwl_tt_restriction *restriction;
+	char buf[100];
+	int pos = 0;
+	const size_t bufsz = sizeof(buf);
+	ssize_t ret;
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"Thermal Throttling Mode: %s\n",
+			(priv->power_data.adv_tt)
+			? "Advance" : "Legacy");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"Thermal Throttling State: %d\n",
+			tt->state);
+	if (priv->power_data.adv_tt) {
+		restriction = tt->restriction + tt->state;
+		pos += scnprintf(buf + pos, bufsz - pos,
+				"Tx mode: %d\n",
+				restriction->tx_stream);
+		pos += scnprintf(buf + pos, bufsz - pos,
+				"Rx mode: %d\n",
+				restriction->rx_stream);
+		pos += scnprintf(buf + pos, bufsz - pos,
+				"HT mode: %d\n",
+				restriction->is_ht);
+	}
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	return ret;
+}
+
 DEBUGFS_READ_WRITE_FILE_OPS(sram);
 DEBUGFS_WRITE_FILE_OPS(log_event);
 DEBUGFS_READ_FILE_OPS(nvm);
@@ -631,6 +666,7 @@ DEBUGFS_READ_FILE_OPS(qos);
 #ifdef CONFIG_IWLWIFI_LEDS
 DEBUGFS_READ_FILE_OPS(led);
 #endif
+DEBUGFS_READ_FILE_OPS(thermal_throttling);
 
 /*
  * Create the debugfs files and directories
@@ -671,6 +707,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
 #ifdef CONFIG_IWLWIFI_LEDS
 	DEBUGFS_ADD_FILE(led, data);
 #endif
+	DEBUGFS_ADD_FILE(thermal_throttling, data);
 	DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
 	DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
 			 &priv->disable_chain_noise_cal);
@@ -709,6 +746,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
 #ifdef CONFIG_IWLWIFI_LEDS
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
 #endif
+	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling);
 	DEBUGFS_REMOVE(priv->dbgfs->dir_data);
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 06/14] iwlwifi: fix up command sending
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
                   ` (4 preceding siblings ...)
  2009-07-24 18:13 ` [PATCH 05/14] iwlwifi: Thermal Throttling debugfs function Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  2009-07-24 18:13 ` [PATCH 07/14] iwlwifi: remove command callback return value Reinette Chatre
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Johannes Berg, Reinette Chatre

From: Johannes Berg <johannes@sipsolutions.net>

The current command sending in iwlwifi is a bit of a mess:
 1) there is a struct, iwl_cmd, that contains both driver
    and device data in a single packed structure -- this
    is very confusing
 2) the on-stack data and the command metadata share a
    structure by embedding the latter in the former, which
    is also rather confusing because it leads to weird
    unions and similarly odd constructs
 3) each txq always has enough space for 256 commands,
    even if only 32 end up being used

This patch fixes these things:
 1) rename iwl_cmd to iwl_device_cmd and keep track of
    command metadata and device command separately, in
    two arrays in each tx queue
 2) remove the 'meta' member from iwl_host_cmd and only
    put in the required members
 3) allocate the cmd/meta arrays separately instead of
    embedding them into the txq structure

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-3945-led.c |    6 +-
 drivers/net/wireless/iwlwifi/iwl-3945.c     |   18 +++--
 drivers/net/wireless/iwlwifi/iwl-3945.h     |    9 ++-
 drivers/net/wireless/iwlwifi/iwl-agn.c      |    4 +-
 drivers/net/wireless/iwlwifi/iwl-calib.c    |    4 +-
 drivers/net/wireless/iwlwifi/iwl-core.c     |    4 +-
 drivers/net/wireless/iwlwifi/iwl-core.h     |    2 +-
 drivers/net/wireless/iwlwifi/iwl-dev.h      |   69 +++++++++++--------
 drivers/net/wireless/iwlwifi/iwl-hcmd.c     |   48 +++++++-------
 drivers/net/wireless/iwlwifi/iwl-led.c      |    4 +-
 drivers/net/wireless/iwlwifi/iwl-scan.c     |    8 +-
 drivers/net/wireless/iwlwifi/iwl-sta.c      |   30 +++++----
 drivers/net/wireless/iwlwifi/iwl-tx.c       |   96 ++++++++++++++++----------
 drivers/net/wireless/iwlwifi/iwl3945-base.c |   20 +++---
 14 files changed, 180 insertions(+), 142 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
index 225e5f8..b379382 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -80,7 +80,7 @@ static const struct {
 #define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
 
 static int iwl3945_led_cmd_callback(struct iwl_priv *priv,
-				    struct iwl_cmd *cmd,
+				    struct iwl_device_cmd *cmd,
 				    struct sk_buff *skb)
 {
 	return 1;
@@ -99,8 +99,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv,
 		.id = REPLY_LEDS_CMD,
 		.len = sizeof(struct iwl_led_cmd),
 		.data = led_cmd,
-		.meta.flags = CMD_ASYNC,
-		.meta.u.callback = iwl3945_led_cmd_callback,
+		.flags = CMD_ASYNC,
+		.callback = iwl3945_led_cmd_callback,
 	};
 
 	return iwl_send_cmd(priv, &cmd);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 8ee403c..e1b0ef3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -749,8 +749,8 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 	/* Unmap tx_cmd */
 	if (counter)
 		pci_unmap_single(dev,
-				pci_unmap_addr(&txq->cmd[index]->meta, mapping),
-				pci_unmap_len(&txq->cmd[index]->meta, len),
+				pci_unmap_addr(&txq->meta[index], mapping),
+				pci_unmap_len(&txq->meta[index], len),
 				PCI_DMA_TODEVICE);
 
 	/* unmap chunks if any */
@@ -774,9 +774,11 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
  * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
  *
 */
-void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd,
-			      struct ieee80211_tx_info *info,
-			      struct ieee80211_hdr *hdr, int sta_id, int tx_id)
+void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+				  struct iwl_device_cmd *cmd,
+				  struct ieee80211_tx_info *info,
+				  struct ieee80211_hdr *hdr,
+				  int sta_id, int tx_id)
 {
 	u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value;
 	u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1);
@@ -1858,7 +1860,7 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
 	struct iwl_host_cmd cmd = {
 		.id = REPLY_RXON_ASSOC,
 		.len = sizeof(rxon_assoc),
-		.meta.flags = CMD_WANT_SKB,
+		.flags = CMD_WANT_SKB,
 		.data = &rxon_assoc,
 	};
 	const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
@@ -1882,14 +1884,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
 	if (rc)
 		return rc;
 
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	res = (struct iwl_rx_packet *)cmd.reply_skb->data;
 	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n");
 		rc = -EIO;
 	}
 
 	priv->alloc_rxb_skb--;
-	dev_kfree_skb_any(cmd.meta.u.skb);
+	dev_kfree_skb_any(cmd.reply_skb);
 
 	return rc;
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index f2ffc48..f240369 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -254,10 +254,11 @@ extern int iwl3945_hw_tx_queue_init(struct iwl_priv *priv,
 				struct iwl_tx_queue *txq);
 extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl_priv *priv,
 				 struct iwl3945_frame *frame, u8 rate);
-void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd,
-				     struct ieee80211_tx_info *info,
-				     struct ieee80211_hdr *hdr,
-				     int sta_id, int tx_id);
+void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+				  struct iwl_device_cmd *cmd,
+				  struct ieee80211_tx_info *info,
+				  struct ieee80211_hdr *hdr,
+				  int sta_id, int tx_id);
 extern int iwl3945_hw_reg_send_txpower(struct iwl_priv *priv);
 extern int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
 extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 23ae991..4cb1a1b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -442,8 +442,8 @@ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 	/* Unmap tx_cmd */
 	if (num_tbs)
 		pci_unmap_single(dev,
-				pci_unmap_addr(&txq->cmd[index]->meta, mapping),
-				pci_unmap_len(&txq->cmd[index]->meta, len),
+				pci_unmap_addr(&txq->meta[index], mapping),
+				pci_unmap_len(&txq->meta[index], len),
 				PCI_DMA_BIDIRECTIONAL);
 
 	/* Unmap chunks, if any. */
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index f8bf592..13180d6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -86,7 +86,7 @@ int iwl_send_calib_results(struct iwl_priv *priv)
 
 	struct iwl_host_cmd hcmd = {
 		.id = REPLY_PHY_CALIBRATION_CMD,
-		.meta.flags = CMD_SIZE_HUGE,
+		.flags = CMD_SIZE_HUGE,
 	};
 
 	for (i = 0; i < IWL_CALIB_MAX; i++) {
@@ -419,7 +419,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
 	struct iwl_host_cmd cmd_out = {
 		.id = SENSITIVITY_CMD,
 		.len = sizeof(struct iwl_sensitivity_cmd),
-		.meta.flags = CMD_ASYNC,
+		.flags = CMD_ASYNC,
 		.data = &cmd,
 	};
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index d8aeb24..710dd41 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -2089,7 +2089,7 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags)
 	u32 stat_flags = 0;
 	struct iwl_host_cmd cmd = {
 		.id = REPLY_STATISTICS_CMD,
-		.meta.flags = flags,
+		.flags = flags,
 		.len = sizeof(stat_flags),
 		.data = (u8 *) &stat_flags,
 	};
@@ -2282,7 +2282,7 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
 		.id = REPLY_CARD_STATE_CMD,
 		.len = sizeof(u32),
 		.data = &flags,
-		.meta.flags = meta_flag,
+		.flags = meta_flag,
 	};
 
 	return iwl_send_cmd(priv, &cmd);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 614ec7c..4156deb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -447,7 +447,7 @@ int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id,
 int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
 			   const void *data,
 			   int (*callback)(struct iwl_priv *priv,
-					   struct iwl_cmd *cmd,
+					   struct iwl_device_cmd *cmd,
 					   struct sk_buff *skb));
 
 int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index cddf173..ce765f7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -150,6 +150,31 @@ struct iwl_rx_mem_buffer {
 	struct list_head list;
 };
 
+/* defined below */
+struct iwl_device_cmd;
+
+struct iwl_cmd_meta {
+	/* only for SYNC commands, iff the reply skb is wanted */
+	struct iwl_host_cmd *source;
+	/*
+	 * only for ASYNC commands
+	 * (which is somewhat stupid -- look at iwl-sta.c for instance
+	 * which duplicates a bunch of code because the callback isn't
+	 * invoked for SYNC commands, if it were and its result passed
+	 * through it would be simpler...)
+	 */
+	int (*callback)(struct iwl_priv *priv,
+			struct iwl_device_cmd *cmd,
+			struct sk_buff *skb);
+
+	/* The CMD_SIZE_HUGE flag bit indicates that the command
+	 * structure is stored at the end of the shared queue memory. */
+	u32 flags;
+
+	DECLARE_PCI_UNMAP_ADDR(mapping)
+	DECLARE_PCI_UNMAP_LEN(len)
+};
+
 /*
  * Generic queue structure
  *
@@ -177,7 +202,8 @@ struct iwl_tx_info {
  * struct iwl_tx_queue - Tx Queue for DMA
  * @q: generic Rx/Tx queue descriptor
  * @bd: base of circular buffer of TFDs
- * @cmd: array of command/Tx buffers
+ * @cmd: array of command/TX buffer pointers
+ * @meta: array of meta data for each command/tx buffer
  * @dma_addr_cmd: physical address of cmd/tx buffer array
  * @txb: array of per-TFD driver data
  * @need_update: indicates need to update read/write index
@@ -192,7 +218,8 @@ struct iwl_tx_info {
 struct iwl_tx_queue {
 	struct iwl_queue q;
 	void *tfds;
-	struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS];
+	struct iwl_device_cmd **cmd;
+	struct iwl_cmd_meta *meta;
 	struct iwl_tx_info *txb;
 	u8 need_update;
 	u8 sched_retry;
@@ -329,35 +356,16 @@ enum {
 	CMD_WANT_SKB = (1 << 2),
 };
 
-struct iwl_cmd;
-struct iwl_priv;
-
-struct iwl_cmd_meta {
-	struct iwl_cmd_meta *source;
-	union {
-		struct sk_buff *skb;
-		int (*callback)(struct iwl_priv *priv,
-				struct iwl_cmd *cmd, struct sk_buff *skb);
-	} __attribute__ ((packed)) u;
-
-	/* The CMD_SIZE_HUGE flag bit indicates that the command
-	 * structure is stored at the end of the shared queue memory. */
-	u32 flags;
-	DECLARE_PCI_UNMAP_ADDR(mapping)
-	DECLARE_PCI_UNMAP_LEN(len)
-} __attribute__ ((packed));
-
 #define IWL_CMD_MAX_PAYLOAD 320
 
 /**
- * struct iwl_cmd
+ * struct iwl_device_cmd
  *
  * For allocation of the command and tx queues, this establishes the overall
  * size of the largest command we send to uCode, except for a scan command
  * (which is relatively huge; space is allocated separately).
  */
-struct iwl_cmd {
-	struct iwl_cmd_meta meta;	/* driver data */
+struct iwl_device_cmd {
 	struct iwl_cmd_header hdr;	/* uCode API */
 	union {
 		u32 flags;
@@ -369,17 +377,20 @@ struct iwl_cmd {
 	} __attribute__ ((packed)) cmd;
 } __attribute__ ((packed));
 
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
+
 
 struct iwl_host_cmd {
-	u8 id;
-	u16 len;
-	struct iwl_cmd_meta meta;
 	const void *data;
+	struct sk_buff *reply_skb;
+	int (*callback)(struct iwl_priv *priv,
+			struct iwl_device_cmd *cmd,
+			struct sk_buff *skb);
+	u32 flags;
+	u16 len;
+	u8 id;
 };
 
-#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
-			      sizeof(struct iwl_cmd_meta))
-
 /*
  * RX related structures and functions
  */
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 17d61ac..d8a3eac 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -104,7 +104,8 @@ EXPORT_SYMBOL(get_cmd_string);
 #define HOST_COMPLETE_TIMEOUT (HZ / 2)
 
 static int iwl_generic_cmd_callback(struct iwl_priv *priv,
-				    struct iwl_cmd *cmd, struct sk_buff *skb)
+				    struct iwl_device_cmd *cmd,
+				    struct sk_buff *skb)
 {
 	struct iwl_rx_packet *pkt = NULL;
 
@@ -142,14 +143,14 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 {
 	int ret;
 
-	BUG_ON(!(cmd->meta.flags & CMD_ASYNC));
+	BUG_ON(!(cmd->flags & CMD_ASYNC));
 
 	/* An asynchronous command can not expect an SKB to be set. */
-	BUG_ON(cmd->meta.flags & CMD_WANT_SKB);
+	BUG_ON(cmd->flags & CMD_WANT_SKB);
 
 	/* Assign a generic callback if one is not provided */
-	if (!cmd->meta.u.callback)
-		cmd->meta.u.callback = iwl_generic_cmd_callback;
+	if (!cmd->callback)
+		cmd->callback = iwl_generic_cmd_callback;
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return -EBUSY;
@@ -168,10 +169,10 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 	int cmd_idx;
 	int ret;
 
-	BUG_ON(cmd->meta.flags & CMD_ASYNC);
+	BUG_ON(cmd->flags & CMD_ASYNC);
 
 	 /* A synchronous command can not have a callback set. */
-	BUG_ON(cmd->meta.u.callback != NULL);
+	BUG_ON(cmd->callback);
 
 	if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) {
 		IWL_ERR(priv,
@@ -183,9 +184,6 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 
 	set_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
-	if (cmd->meta.flags & CMD_WANT_SKB)
-		cmd->meta.source = &cmd->meta;
-
 	cmd_idx = iwl_enqueue_hcmd(priv, cmd);
 	if (cmd_idx < 0) {
 		ret = cmd_idx;
@@ -222,7 +220,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 		ret = -EIO;
 		goto fail;
 	}
-	if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) {
+	if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_skb) {
 		IWL_ERR(priv, "Error: Response NULL in '%s'\n",
 			  get_cmd_string(cmd->id));
 		ret = -EIO;
@@ -233,20 +231,20 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 	goto out;
 
 cancel:
-	if (cmd->meta.flags & CMD_WANT_SKB) {
-		struct iwl_cmd *qcmd;
-
-		/* Cancel the CMD_WANT_SKB flag for the cmd in the
+	if (cmd->flags & CMD_WANT_SKB) {
+		/*
+		 * Cancel the CMD_WANT_SKB flag for the cmd in the
 		 * TX cmd queue. Otherwise in case the cmd comes
 		 * in later, it will possibly set an invalid
-		 * address (cmd->meta.source). */
-		qcmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
-		qcmd->meta.flags &= ~CMD_WANT_SKB;
+		 * address (cmd->meta.source).
+		 */
+		priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_idx].flags &=
+							~CMD_WANT_SKB;
 	}
 fail:
-	if (cmd->meta.u.skb) {
-		dev_kfree_skb_any(cmd->meta.u.skb);
-		cmd->meta.u.skb = NULL;
+	if (cmd->reply_skb) {
+		dev_kfree_skb_any(cmd->reply_skb);
+		cmd->reply_skb = NULL;
 	}
 out:
 	clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
@@ -256,7 +254,7 @@ EXPORT_SYMBOL(iwl_send_cmd_sync);
 
 int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 {
-	if (cmd->meta.flags & CMD_ASYNC)
+	if (cmd->flags & CMD_ASYNC)
 		return iwl_send_cmd_async(priv, cmd);
 
 	return iwl_send_cmd_sync(priv, cmd);
@@ -278,7 +276,7 @@ EXPORT_SYMBOL(iwl_send_cmd_pdu);
 int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
 			   u8 id, u16 len, const void *data,
 			   int (*callback)(struct iwl_priv *priv,
-					   struct iwl_cmd *cmd,
+					   struct iwl_device_cmd *cmd,
 					   struct sk_buff *skb))
 {
 	struct iwl_host_cmd cmd = {
@@ -287,8 +285,8 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
 		.data = data,
 	};
 
-	cmd.meta.flags |= CMD_ASYNC;
-	cmd.meta.u.callback = callback;
+	cmd.flags |= CMD_ASYNC;
+	cmd.callback = callback;
 
 	return iwl_send_cmd_async(priv, &cmd);
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index 8c81152..7cce8f8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -91,8 +91,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
 		.id = REPLY_LEDS_CMD,
 		.len = sizeof(struct iwl_led_cmd),
 		.data = led_cmd,
-		.meta.flags = CMD_ASYNC,
-		.meta.u.callback = NULL,
+		.flags = CMD_ASYNC,
+		.callback = NULL,
 	};
 	u32 reg;
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 00398d9..c4c916d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -115,7 +115,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
 	struct iwl_rx_packet *res;
 	struct iwl_host_cmd cmd = {
 		.id = REPLY_SCAN_ABORT_CMD,
-		.meta.flags = CMD_WANT_SKB,
+		.flags = CMD_WANT_SKB,
 	};
 
 	/* If there isn't a scan actively going on in the hardware
@@ -132,7 +132,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
 		return ret;
 	}
 
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	res = (struct iwl_rx_packet *)cmd.reply_skb->data;
 	if (res->u.status != CAN_ABORT_STATUS) {
 		/* The scan abort will return 1 for success or
 		 * 2 for "failure".  A failure condition can be
@@ -146,7 +146,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
 	}
 
 	priv->alloc_rxb_skb--;
-	dev_kfree_skb_any(cmd.meta.u.skb);
+	dev_kfree_skb_any(cmd.reply_skb);
 
 	return ret;
 }
@@ -567,7 +567,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	struct iwl_host_cmd cmd = {
 		.id = REPLY_SCAN_CMD,
 		.len = sizeof(struct iwl_scan_cmd),
-		.meta.flags = CMD_SIZE_HUGE,
+		.flags = CMD_SIZE_HUGE,
 	};
 	struct iwl_scan_cmd *scan;
 	struct ieee80211_conf *conf = NULL;
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index cbe4e26..1571ace 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -98,7 +98,8 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
 }
 
 static int iwl_add_sta_callback(struct iwl_priv *priv,
-				   struct iwl_cmd *cmd, struct sk_buff *skb)
+				struct iwl_device_cmd *cmd,
+				struct sk_buff *skb)
 {
 	struct iwl_rx_packet *res = NULL;
 	struct iwl_addsta_cmd *addsta =
@@ -139,14 +140,14 @@ int iwl_send_add_sta(struct iwl_priv *priv,
 	u8 data[sizeof(*sta)];
 	struct iwl_host_cmd cmd = {
 		.id = REPLY_ADD_STA,
-		.meta.flags = flags,
+		.flags = flags,
 		.data = data,
 	};
 
 	if (flags & CMD_ASYNC)
-		cmd.meta.u.callback = iwl_add_sta_callback;
+		cmd.callback = iwl_add_sta_callback;
 	else
-		cmd.meta.flags |= CMD_WANT_SKB;
+		cmd.flags |= CMD_WANT_SKB;
 
 	cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
 	ret = iwl_send_cmd(priv, &cmd);
@@ -154,7 +155,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
 	if (ret || (flags & CMD_ASYNC))
 		return ret;
 
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	res = (struct iwl_rx_packet *)cmd.reply_skb->data;
 	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
 			  res->hdr.flags);
@@ -175,7 +176,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
 	}
 
 	priv->alloc_rxb_skb--;
-	dev_kfree_skb_any(cmd.meta.u.skb);
+	dev_kfree_skb_any(cmd.reply_skb);
 
 	return ret;
 }
@@ -325,7 +326,8 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
 }
 
 static int iwl_remove_sta_callback(struct iwl_priv *priv,
-				   struct iwl_cmd *cmd, struct sk_buff *skb)
+				   struct iwl_device_cmd *cmd,
+				   struct sk_buff *skb)
 {
 	struct iwl_rx_packet *res = NULL;
 	struct iwl_rem_sta_cmd *rm_sta =
@@ -368,7 +370,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
 	struct iwl_host_cmd cmd = {
 		.id = REPLY_REMOVE_STA,
 		.len = sizeof(struct iwl_rem_sta_cmd),
-		.meta.flags = flags,
+		.flags = flags,
 		.data = &rm_sta_cmd,
 	};
 
@@ -377,15 +379,15 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
 	memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN);
 
 	if (flags & CMD_ASYNC)
-		cmd.meta.u.callback = iwl_remove_sta_callback;
+		cmd.callback = iwl_remove_sta_callback;
 	else
-		cmd.meta.flags |= CMD_WANT_SKB;
+		cmd.flags |= CMD_WANT_SKB;
 	ret = iwl_send_cmd(priv, &cmd);
 
 	if (ret || (flags & CMD_ASYNC))
 		return ret;
 
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	res = (struct iwl_rx_packet *)cmd.reply_skb->data;
 	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
 			  res->hdr.flags);
@@ -406,7 +408,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
 	}
 
 	priv->alloc_rxb_skb--;
-	dev_kfree_skb_any(cmd.meta.u.skb);
+	dev_kfree_skb_any(cmd.reply_skb);
 
 	return ret;
 }
@@ -525,7 +527,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
 	struct iwl_host_cmd cmd = {
 		.id = REPLY_WEPKEY,
 		.data = wep_cmd,
-		.meta.flags = CMD_ASYNC,
+		.flags = CMD_ASYNC,
 	};
 
 	memset(wep_cmd, 0, cmd_size +
@@ -930,7 +932,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
 	struct iwl_host_cmd cmd = {
 		.id = REPLY_TX_LINK_QUALITY_CMD,
 		.len = sizeof(struct iwl_link_quality_cmd),
-		.meta.flags = flags,
+		.flags = flags,
 		.data = lq,
 	};
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 0912987..51ddbab 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -141,7 +141,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
 	     q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
 		priv->cfg->ops->lib->txq_free_tfd(priv, txq);
 
-	len = sizeof(struct iwl_cmd) * q->n_window;
+	len = sizeof(struct iwl_device_cmd) * q->n_window;
 
 	/* De-alloc array of command/tx buffers */
 	for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
@@ -156,6 +156,12 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
 	kfree(txq->txb);
 	txq->txb = NULL;
 
+	/* deallocate arrays */
+	kfree(txq->cmd);
+	kfree(txq->meta);
+	txq->cmd = NULL;
+	txq->meta = NULL;
+
 	/* 0-fill queue descriptor structure */
 	memset(txq, 0, sizeof(*txq));
 }
@@ -179,7 +185,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
 	if (q->n_bd == 0)
 		return;
 
-	len = sizeof(struct iwl_cmd) * q->n_window;
+	len = sizeof(struct iwl_device_cmd) * q->n_window;
 	len += IWL_MAX_SCAN_SIZE;
 
 	/* De-alloc array of command/tx buffers */
@@ -318,6 +324,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
 {
 	int i, len;
 	int ret;
+	int actual_slots = slots_num;
 
 	/*
 	 * Alloc buffer array for commands (Tx or other types of commands).
@@ -327,14 +334,22 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
 	 * For normal Tx queues (all other queues), no super-size command
 	 * space is needed.
 	 */
-	len = sizeof(struct iwl_cmd);
-	for (i = 0; i <= slots_num; i++) {
-		if (i == slots_num) {
-			if (txq_id == IWL_CMD_QUEUE_NUM)
-				len += IWL_MAX_SCAN_SIZE;
-			else
-				continue;
-		}
+	if (txq_id == IWL_CMD_QUEUE_NUM)
+		actual_slots++;
+
+	txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots,
+			    GFP_KERNEL);
+	txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * actual_slots,
+			   GFP_KERNEL);
+
+	if (!txq->meta || !txq->cmd)
+		goto out_free_arrays;
+
+	len = sizeof(struct iwl_device_cmd);
+	for (i = 0; i < actual_slots; i++) {
+		/* only happens for cmd queue */
+		if (i == slots_num)
+			len += IWL_MAX_SCAN_SIZE;
 
 		txq->cmd[i] = kmalloc(len, GFP_KERNEL);
 		if (!txq->cmd[i])
@@ -364,15 +379,12 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
 
 	return 0;
 err:
-	for (i = 0; i < slots_num; i++) {
+	for (i = 0; i < actual_slots; i++)
 		kfree(txq->cmd[i]);
-		txq->cmd[i] = NULL;
-	}
+out_free_arrays:
+	kfree(txq->meta);
+	kfree(txq->cmd);
 
-	if (txq_id == IWL_CMD_QUEUE_NUM) {
-		kfree(txq->cmd[slots_num]);
-		txq->cmd[slots_num] = NULL;
-	}
 	return -ENOMEM;
 }
 EXPORT_SYMBOL(iwl_tx_queue_init);
@@ -673,7 +685,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct iwl_tx_queue *txq;
 	struct iwl_queue *q;
-	struct iwl_cmd *out_cmd;
+	struct iwl_device_cmd *out_cmd;
+	struct iwl_cmd_meta *out_meta;
 	struct iwl_tx_cmd *tx_cmd;
 	int swq_id, txq_id;
 	dma_addr_t phys_addr;
@@ -766,6 +779,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
 	/* Set up first empty entry in queue's array of Tx/cmd buffers */
 	out_cmd = txq->cmd[q->write_ptr];
+	out_meta = &txq->meta[q->write_ptr];
 	tx_cmd = &out_cmd->cmd.tx;
 	memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
 	memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd));
@@ -828,8 +842,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 	txcmd_phys = pci_map_single(priv->pci_dev,
 				    &out_cmd->hdr, len,
 				    PCI_DMA_BIDIRECTIONAL);
-	pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys);
-	pci_unmap_len_set(&out_cmd->meta, len, len);
+	pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
+	pci_unmap_len_set(out_meta, len, len);
 	/* Add buffer containing Tx command and MAC(!) header to TFD's
 	 * first entry */
 	priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
@@ -923,7 +937,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 {
 	struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
 	struct iwl_queue *q = &txq->q;
-	struct iwl_cmd *out_cmd;
+	struct iwl_device_cmd *out_cmd;
+	struct iwl_cmd_meta *out_meta;
 	dma_addr_t phys_addr;
 	unsigned long flags;
 	int len, ret;
@@ -937,25 +952,31 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 	 * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
 	 * we will need to increase the size of the TFD entries */
 	BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
-	       !(cmd->meta.flags & CMD_SIZE_HUGE));
+	       !(cmd->flags & CMD_SIZE_HUGE));
 
 	if (iwl_is_rfkill(priv)) {
 		IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n");
 		return -EIO;
 	}
 
-	if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+	if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
 		IWL_ERR(priv, "No space for Tx\n");
 		return -ENOSPC;
 	}
 
 	spin_lock_irqsave(&priv->hcmd_lock, flags);
 
-	idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE);
+	idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
 	out_cmd = txq->cmd[idx];
+	out_meta = &txq->meta[idx];
+
+	out_meta->flags = cmd->flags;
+	if (cmd->flags & CMD_WANT_SKB)
+		out_meta->source = cmd;
+	if (cmd->flags & CMD_ASYNC)
+		out_meta->callback = cmd->callback;
 
 	out_cmd->hdr.cmd = cmd->id;
-	memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
 	memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
 
 	/* At this point, the out_cmd now has all of the incoming cmd
@@ -964,9 +985,9 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 	out_cmd->hdr.flags = 0;
 	out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
 			INDEX_TO_SEQ(q->write_ptr));
-	if (out_cmd->meta.flags & CMD_SIZE_HUGE)
+	if (cmd->flags & CMD_SIZE_HUGE)
 		out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
-	len = sizeof(struct iwl_cmd) - sizeof(struct iwl_cmd_meta);
+	len = sizeof(struct iwl_device_cmd);
 	len += (idx == TFD_CMD_SLOTS) ?  IWL_MAX_SCAN_SIZE : 0;
 
 
@@ -998,8 +1019,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 
 	phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
 				   fix_size, PCI_DMA_BIDIRECTIONAL);
-	pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr);
-	pci_unmap_len_set(&out_cmd->meta, len, fix_size);
+	pci_unmap_addr_set(out_meta, mapping, phys_addr);
+	pci_unmap_len_set(out_meta, len, fix_size);
 
 	priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
 						   phys_addr, fix_size, 1,
@@ -1068,8 +1089,8 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
 	}
 
 	pci_unmap_single(priv->pci_dev,
-		pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping),
-		pci_unmap_len(&txq->cmd[cmd_idx]->meta, len),
+		pci_unmap_addr(&txq->meta[cmd_idx], mapping),
+		pci_unmap_len(&txq->meta[cmd_idx], len),
 		PCI_DMA_BIDIRECTIONAL);
 
 	for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx;
@@ -1100,7 +1121,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 	int index = SEQ_TO_INDEX(sequence);
 	int cmd_index;
 	bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
-	struct iwl_cmd *cmd;
+	struct iwl_device_cmd *cmd;
+	struct iwl_cmd_meta *meta;
 
 	/* If a Tx command is being handled and it isn't in the actual
 	 * command queue then there a command routing bug has been introduced
@@ -1116,18 +1138,18 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 
 	cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
 	cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
+	meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index];
 
 	/* Input error checking is done when commands are added to queue. */
-	if (cmd->meta.flags & CMD_WANT_SKB) {
-		cmd->meta.source->u.skb = rxb->skb;
+	if (meta->flags & CMD_WANT_SKB) {
+		meta->source->reply_skb = rxb->skb;
 		rxb->skb = NULL;
-	} else if (cmd->meta.u.callback &&
-		   !cmd->meta.u.callback(priv, cmd, rxb->skb))
+	} else if (meta->callback && !meta->callback(priv, cmd, rxb->skb))
 		rxb->skb = NULL;
 
 	iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
 
-	if (!(cmd->meta.flags & CMD_ASYNC)) {
+	if (!(meta->flags & CMD_ASYNC)) {
 		clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 		wake_up_interruptible(&priv->wait_command_queue);
 	}
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 2cc7e30..5ded898 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -363,7 +363,7 @@ static void iwl3945_unset_hw_params(struct iwl_priv *priv)
 
 static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
 				      struct ieee80211_tx_info *info,
-				      struct iwl_cmd *cmd,
+				      struct iwl_device_cmd *cmd,
 				      struct sk_buff *skb_frag,
 				      int sta_id)
 {
@@ -403,7 +403,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
  * handle build REPLY_TX command notification.
  */
 static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
-				  struct iwl_cmd *cmd,
+				  struct iwl_device_cmd *cmd,
 				  struct ieee80211_tx_info *info,
 				  struct ieee80211_hdr *hdr, u8 std_id)
 {
@@ -476,7 +476,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 	struct iwl3945_tx_cmd *tx;
 	struct iwl_tx_queue *txq = NULL;
 	struct iwl_queue *q = NULL;
-	struct iwl_cmd *out_cmd = NULL;
+	struct iwl_device_cmd *out_cmd;
+	struct iwl_cmd_meta *out_meta;
 	dma_addr_t phys_addr;
 	dma_addr_t txcmd_phys;
 	int txq_id = skb_get_queue_mapping(skb);
@@ -565,6 +566,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
 	/* Init first empty entry in queue's array of Tx/cmd buffers */
 	out_cmd = txq->cmd[idx];
+	out_meta = &txq->meta[idx];
 	tx = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload;
 	memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
 	memset(tx, 0, sizeof(*tx));
@@ -642,8 +644,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 				    len, PCI_DMA_TODEVICE);
 	/* we do not map meta data ... so we can safely access address to
 	 * provide to unmap command*/
-	pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys);
-	pci_unmap_len_set(&out_cmd->meta, len, len);
+	pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
+	pci_unmap_len_set(out_meta, len, len);
 
 	/* Add buffer containing Tx command and MAC(!) header to TFD's
 	 * first entry */
@@ -753,7 +755,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
 	struct iwl_host_cmd cmd = {
 		.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
 		.data = (void *)&spectrum,
-		.meta.flags = CMD_WANT_SKB,
+		.flags = CMD_WANT_SKB,
 	};
 	u32 add_time = le64_to_cpu(params->start_time);
 	int rc;
@@ -794,7 +796,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
 	if (rc)
 		return rc;
 
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	res = (struct iwl_rx_packet *)cmd.reply_skb->data;
 	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n");
 		rc = -EIO;
@@ -817,7 +819,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
 		break;
 	}
 
-	dev_kfree_skb_any(cmd.meta.u.skb);
+	dev_kfree_skb_any(cmd.reply_skb);
 
 	return rc;
 }
@@ -2717,7 +2719,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
 	struct iwl_host_cmd cmd = {
 		.id = REPLY_SCAN_CMD,
 		.len = sizeof(struct iwl3945_scan_cmd),
-		.meta.flags = CMD_SIZE_HUGE,
+		.flags = CMD_SIZE_HUGE,
 	};
 	int rc = 0;
 	struct iwl3945_scan_cmd *scan;
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 07/14] iwlwifi: remove command callback return value
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
                   ` (5 preceding siblings ...)
  2009-07-24 18:13 ` [PATCH 06/14] iwlwifi: fix up command sending Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  2009-07-24 18:13 ` [PATCH 08/14] iwlwifi: fix TX queue race Reinette Chatre
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Johannes Berg, Reinette Chatre

From: Johannes Berg <johannes@sipsolutions.net>

No existing callbacks use anything other than the return
value 1, which means that the caller should free the
reply skb, so it seems safer in terms of not introducing
memory leaks to simply remove the return value and let
the caller always free the skb.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-3945-led.c |    7 +++----
 drivers/net/wireless/iwlwifi/iwl-core.h     |    6 +++---
 drivers/net/wireless/iwlwifi/iwl-dev.h      |   12 ++++++------
 drivers/net/wireless/iwlwifi/iwl-hcmd.c     |   21 +++++++++------------
 drivers/net/wireless/iwlwifi/iwl-sta.c      |   26 ++++++++++----------------
 drivers/net/wireless/iwlwifi/iwl-tx.c       |    4 ++--
 6 files changed, 33 insertions(+), 43 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
index b379382..8c29ded 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -79,11 +79,10 @@ static const struct {
 #define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/
 #define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
 
-static int iwl3945_led_cmd_callback(struct iwl_priv *priv,
-				    struct iwl_device_cmd *cmd,
-				    struct sk_buff *skb)
+static void iwl3945_led_cmd_callback(struct iwl_priv *priv,
+				     struct iwl_device_cmd *cmd,
+				     struct sk_buff *skb)
 {
-	return 1;
 }
 
 static inline int iwl3945_brightness_to_idx(enum led_brightness brightness)
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 4156deb..febcf76 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -446,9 +446,9 @@ int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id,
 				  u16 len, const void *data);
 int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
 			   const void *data,
-			   int (*callback)(struct iwl_priv *priv,
-					   struct iwl_device_cmd *cmd,
-					   struct sk_buff *skb));
+			   void (*callback)(struct iwl_priv *priv,
+					    struct iwl_device_cmd *cmd,
+					    struct sk_buff *skb));
 
 int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index ce765f7..3ca188a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -163,9 +163,9 @@ struct iwl_cmd_meta {
 	 * invoked for SYNC commands, if it were and its result passed
 	 * through it would be simpler...)
 	 */
-	int (*callback)(struct iwl_priv *priv,
-			struct iwl_device_cmd *cmd,
-			struct sk_buff *skb);
+	void (*callback)(struct iwl_priv *priv,
+			 struct iwl_device_cmd *cmd,
+			 struct sk_buff *skb);
 
 	/* The CMD_SIZE_HUGE flag bit indicates that the command
 	 * structure is stored at the end of the shared queue memory. */
@@ -383,9 +383,9 @@ struct iwl_device_cmd {
 struct iwl_host_cmd {
 	const void *data;
 	struct sk_buff *reply_skb;
-	int (*callback)(struct iwl_priv *priv,
-			struct iwl_device_cmd *cmd,
-			struct sk_buff *skb);
+	void (*callback)(struct iwl_priv *priv,
+			 struct iwl_device_cmd *cmd,
+			 struct sk_buff *skb);
 	u32 flags;
 	u16 len;
 	u8 id;
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index d8a3eac..b82ad15 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -103,23 +103,23 @@ EXPORT_SYMBOL(get_cmd_string);
 
 #define HOST_COMPLETE_TIMEOUT (HZ / 2)
 
-static int iwl_generic_cmd_callback(struct iwl_priv *priv,
-				    struct iwl_device_cmd *cmd,
-				    struct sk_buff *skb)
+static void iwl_generic_cmd_callback(struct iwl_priv *priv,
+				     struct iwl_device_cmd *cmd,
+				     struct sk_buff *skb)
 {
 	struct iwl_rx_packet *pkt = NULL;
 
 	if (!skb) {
 		IWL_ERR(priv, "Error: Response NULL in %s.\n",
 				get_cmd_string(cmd->hdr.cmd));
-		return 1;
+		return;
 	}
 
 	pkt = (struct iwl_rx_packet *)skb->data;
 	if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERR(priv, "Bad return from %s (0x%08X)\n",
 			get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
-		return 1;
+		return;
 	}
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -128,15 +128,12 @@ static int iwl_generic_cmd_callback(struct iwl_priv *priv,
 	case SENSITIVITY_CMD:
 		IWL_DEBUG_HC_DUMP(priv, "back from %s (0x%08X)\n",
 				get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
-				break;
+		break;
 	default:
 		IWL_DEBUG_HC(priv, "back from %s (0x%08X)\n",
 				get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
 	}
 #endif
-
-	/* Let iwl_tx_complete free the response skb */
-	return 1;
 }
 
 static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
@@ -275,9 +272,9 @@ EXPORT_SYMBOL(iwl_send_cmd_pdu);
 
 int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
 			   u8 id, u16 len, const void *data,
-			   int (*callback)(struct iwl_priv *priv,
-					   struct iwl_device_cmd *cmd,
-					   struct sk_buff *skb))
+			   void (*callback)(struct iwl_priv *priv,
+					    struct iwl_device_cmd *cmd,
+					    struct sk_buff *skb))
 {
 	struct iwl_host_cmd cmd = {
 		.id = id,
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 1571ace..79ea5cc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -97,9 +97,9 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
 
-static int iwl_add_sta_callback(struct iwl_priv *priv,
-				struct iwl_device_cmd *cmd,
-				struct sk_buff *skb)
+static void iwl_add_sta_callback(struct iwl_priv *priv,
+				 struct iwl_device_cmd *cmd,
+				 struct sk_buff *skb)
 {
 	struct iwl_rx_packet *res = NULL;
 	struct iwl_addsta_cmd *addsta =
@@ -108,14 +108,14 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
 
 	if (!skb) {
 		IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n");
-		return 1;
+		return;
 	}
 
 	res = (struct iwl_rx_packet *)skb->data;
 	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
 			  res->hdr.flags);
-		return 1;
+		return;
 	}
 
 	switch (res->u.add_sta.status) {
@@ -127,9 +127,6 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
 			     res->u.add_sta.status);
 		break;
 	}
-
-	/* We didn't cache the SKB; let the caller free it */
-	return 1;
 }
 
 int iwl_send_add_sta(struct iwl_priv *priv,
@@ -325,9 +322,9 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
 
-static int iwl_remove_sta_callback(struct iwl_priv *priv,
-				   struct iwl_device_cmd *cmd,
-				   struct sk_buff *skb)
+static void iwl_remove_sta_callback(struct iwl_priv *priv,
+				    struct iwl_device_cmd *cmd,
+				    struct sk_buff *skb)
 {
 	struct iwl_rx_packet *res = NULL;
 	struct iwl_rem_sta_cmd *rm_sta =
@@ -336,14 +333,14 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv,
 
 	if (!skb) {
 		IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n");
-		return 1;
+		return;
 	}
 
 	res = (struct iwl_rx_packet *)skb->data;
 	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
 		res->hdr.flags);
-		return 1;
+		return;
 	}
 
 	switch (res->u.rem_sta.status) {
@@ -354,9 +351,6 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv,
 		IWL_ERR(priv, "REPLY_REMOVE_STA failed\n");
 		break;
 	}
-
-	/* We didn't cache the SKB; let the caller free it */
-	return 1;
 }
 
 static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 51ddbab..e1558db 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -1144,8 +1144,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 	if (meta->flags & CMD_WANT_SKB) {
 		meta->source->reply_skb = rxb->skb;
 		rxb->skb = NULL;
-	} else if (meta->callback && !meta->callback(priv, cmd, rxb->skb))
-		rxb->skb = NULL;
+	} else if (meta->callback)
+		meta->callback(priv, cmd, rxb->skb);
 
 	iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
 
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 08/14] iwlwifi: fix TX queue race
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
                   ` (6 preceding siblings ...)
  2009-07-24 18:13 ` [PATCH 07/14] iwlwifi: remove command callback return value Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  2009-07-24 18:13 ` [PATCH 09/14] iwlwifi: print packet contents in error case Reinette Chatre
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Johannes Berg, Reinette Chatre

From: Johannes Berg <johannes@sipsolutions.net>

I had a problem on 4965 hardware (well, probably other hardware too,
but others don't survive my stress testing right now, unfortunately)
where the driver was sending invalid commands to the device, but no
such thing could be seen from the driver's point of view. I could
reproduce this fairly easily by sending multiple TCP streams with
iperf on different TIDs, though sometimes a single iperf stream was
sufficient. It even happened with a single core, but I have forced
preemption turned on.

The culprit was a queue overrun, where we advanced the queue's write
pointer over the read pointer. After careful analysis I've come to
the conclusion that the cause is a race condition between iwlwifi
and mac80211.

mac80211, of course, checks whether the queue is stopped, before
transmitting a frame. This effectively looks like this:

        lock(queues)
        if (stopped(queue)) {
                unlock(queues)
                return busy;
	}
        unlock(queues)
        ...             <-- this place will be important
			    there is some more code here
        drv_tx(frame)

The driver, on the other hand, can stop and start queues, which does

        lock(queues)
        mark_running/stopped(queue)
        unlock(queues)

	[if marked running: wake up tasklet to send pending frames]

Now, however, once the driver starts the queue, mac80211 can see that
and end up at the marked place above, at which point for some reason the
driver seems to stop the queue again (I don't understand that) and then
we end up transmitting while the queue is actually full.

Now, this shouldn't actually matter much, but for some reason I've seen
it happen multiple times in a row and the queue actually overflows, at
which point the queue bites itself in the tail and things go completely
wrong.

This patch fixes this by just dropping the packet should this have
happened, and making the lock in iwlwifi cover everything so iwlwifi
can't race against itself (dropping the lock there might make it more
likely, but it did seem to happen without that too).

Since we can't hold the lock across drv_tx() above, I see no way to fix
this in mac80211, but I also don't understand why I haven't seen this
before -- maybe I just never stress tested it this badly.

With this patch, the device has survived many minutes of simultanously
sending two iperf streams on different TIDs with combined throughput
of about 60 Mbps.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-tx.c |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index e1558db..5a997f0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -737,8 +737,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 		goto drop_unlock;
 	}
 
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	hdr_len = ieee80211_hdrlen(fc);
 
 	/* Find (or create) index into station table for destination station */
@@ -746,7 +744,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 	if (sta_id == IWL_INVALID_STATION) {
 		IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
 			       hdr->addr1);
-		goto drop;
+		goto drop_unlock;
 	}
 
 	IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
@@ -764,14 +762,17 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 		/* aggregation is on for this <sta,tid> */
 		if (info->flags & IEEE80211_TX_CTL_AMPDU)
 			txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
-		priv->stations[sta_id].tid[tid].tfds_in_queue++;
 	}
 
 	txq = &priv->txq[txq_id];
 	swq_id = txq->swq_id;
 	q = &txq->q;
 
-	spin_lock_irqsave(&priv->lock, flags);
+	if (unlikely(iwl_queue_space(q) < q->high_mark))
+		goto drop_unlock;
+
+	if (ieee80211_is_data_qos(fc))
+		priv->stations[sta_id].tid[tid].tfds_in_queue++;
 
 	/* Set up driver data for this TFD */
 	memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
@@ -917,7 +918,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
 drop_unlock:
 	spin_unlock_irqrestore(&priv->lock, flags);
-drop:
 	return -1;
 }
 EXPORT_SYMBOL(iwl_tx_skb);
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 09/14] iwlwifi: print packet contents in error case
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
                   ` (7 preceding siblings ...)
  2009-07-24 18:13 ` [PATCH 08/14] iwlwifi: fix TX queue race Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  2009-07-24 18:13 ` [PATCH 10/14] iwlwifi: Name fix for MPDU density for TX aggregation Reinette Chatre
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Reinette Chatre

From: Reinette Chatre <reinette.chatre@intel.com>

This data is more useful to debugging that the receive
buffer contents.

Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-tx.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 5a997f0..46983f7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -1132,7 +1132,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 		  txq_id, sequence,
 		  priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr,
 		  priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) {
-		iwl_print_hex_error(priv, rxb, 32);
+		iwl_print_hex_error(priv, pkt, 32);
 		return;
 	}
 
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 10/14] iwlwifi: Name fix for MPDU density for TX aggregation
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
                   ` (8 preceding siblings ...)
  2009-07-24 18:13 ` [PATCH 09/14] iwlwifi: print packet contents in error case Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  2009-07-24 18:13 ` [PATCH 11/14] iwlwifi: fix LED config option Reinette Chatre
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Wey-Yi Guy, Reinette Chatre

From: Wey-Yi Guy <wey-yi.w.guy@intel.com>

Fix incorrect name for HT MPDU Density.
default set to 4 uSec

Reported-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-dev.h |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 3ca188a..facbc3d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -491,8 +491,16 @@ union iwl_ht_rate_supp {
 };
 
 #define CFG_HT_RX_AMPDU_FACTOR_DEF  (0x3)
-#define CFG_HT_MPDU_DENSITY_2USEC   (0x5)
-#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC
+
+/*
+ * Maximal MPDU density for TX aggregation
+ * 4 - 2us density
+ * 5 - 4us density
+ * 6 - 8us density
+ * 7 - 16us density
+ */
+#define CFG_HT_MPDU_DENSITY_4USEC   (0x5)
+#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC
 
 struct iwl_ht_info {
 	/* self configuration data */
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 11/14] iwlwifi: fix LED config option
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
                   ` (9 preceding siblings ...)
  2009-07-24 18:13 ` [PATCH 10/14] iwlwifi: Name fix for MPDU density for TX aggregation Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  2009-07-24 18:13 ` [PATCH 12/14] iwlwifi: debugFs to enable/disable 40MHz channel support Reinette Chatre
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Pavel Machek, Reinette Chatre

From: Pavel Machek <pavel@ucw.cz>

IWLWIFI_LEDS option should certainly have help comment, and should
default to y.

Signed-off-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/Kconfig |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index e092af0..99310c0 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -9,6 +9,9 @@ config IWLWIFI
 config IWLWIFI_LEDS
 	bool "Enable LED support in iwlagn and iwl3945 drivers"
 	depends on IWLWIFI
+	default y
+	---help---
+	  Select this if you want LED support.
 
 config IWLWIFI_SPECTRUM_MEASUREMENT
 	bool "Enable Spectrum Measurement in iwlagn driver"
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 12/14] iwlwifi: debugFs to enable/disable 40MHz channel support
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
                   ` (10 preceding siblings ...)
  2009-07-24 18:13 ` [PATCH 11/14] iwlwifi: fix LED config option Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  2009-07-24 21:40   ` Gábor Stefanik
  2009-07-24 18:13 ` [PATCH 13/14] iwlagn: fix null pointer access during ucode load on 1000 Reinette Chatre
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Wey-Yi Guy, Reinette Chatre

From: Wey-Yi Guy <wey-yi.w.guy@intel.com>

Add debugfs file to enable/disable Fat(40MHz) channel support.
By default, 40MHz is supported if AP can support the function.

By echo "1" to "disable_fat_mode" file, iwlwifi driver will disable the 40MHz
support and only allow 20MHz channel.

Because the information exchange happen during association time,
so enable/disable fat channel only can be performed when it is not
associated with AP.

Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-core.c    |    4 ++
 drivers/net/wireless/iwlwifi/iwl-debug.h   |    1 +
 drivers/net/wireless/iwlwifi/iwl-debugfs.c |   46 ++++++++++++++++++++++++++++
 drivers/net/wireless/iwlwifi/iwl-dev.h     |    1 +
 4 files changed, 52 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 710dd41..edfdbe8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -632,6 +632,10 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
 		if (!sta_ht_inf->ht_supported)
 			return 0;
 	}
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (priv->disable_fat)
+		return 0;
+#endif
 	return iwl_is_channel_extension(priv, priv->band,
 			le16_to_cpu(priv->staging_rxon.channel),
 			iwl_ht_conf->extension_chan_offset);
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 609a681..2e10da3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -88,6 +88,7 @@ struct iwl_debugfs {
 #ifdef CONFIG_IWLWIFI_LEDS
 		struct dentry *file_led;
 #endif
+		struct dentry *file_disable_fat_mode;
 	} dbgfs_data_files;
 	struct dir_rf_files {
 		struct dentry *file_disable_sensitivity;
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 748dc31..03486d5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -653,6 +653,49 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
 	return ret;
 }
 
+static ssize_t iwl_dbgfs_disable_fat_mode_write(struct file *file,
+					 const char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	char buf[8];
+	int buf_size;
+	int fat_mode;
+
+	memset(buf, 0, sizeof(buf));
+	buf_size = min(count, sizeof(buf) -  1);
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+	if (sscanf(buf, "%d", &fat_mode) != 1)
+		return -EFAULT;
+	if (!iwl_is_associated(priv))
+		priv->disable_fat = fat_mode ? true : false;
+	else {
+		IWL_ERR(priv, "Sta associated with AP - "
+			"Change fat mode is not allowed\n");
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_disable_fat_mode_read(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+	char buf[100];
+	int pos = 0;
+	const size_t bufsz = sizeof(buf);
+	ssize_t ret;
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"11n 40Mhz Mode: %s\n",
+			priv->disable_fat ? "Disabled" : "Enabled");
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	return ret;
+}
+
 DEBUGFS_READ_WRITE_FILE_OPS(sram);
 DEBUGFS_WRITE_FILE_OPS(log_event);
 DEBUGFS_READ_FILE_OPS(nvm);
@@ -667,6 +710,7 @@ DEBUGFS_READ_FILE_OPS(qos);
 DEBUGFS_READ_FILE_OPS(led);
 #endif
 DEBUGFS_READ_FILE_OPS(thermal_throttling);
+DEBUGFS_READ_WRITE_FILE_OPS(disable_fat_mode);
 
 /*
  * Create the debugfs files and directories
@@ -708,6 +752,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
 	DEBUGFS_ADD_FILE(led, data);
 #endif
 	DEBUGFS_ADD_FILE(thermal_throttling, data);
+	DEBUGFS_ADD_FILE(disable_fat_mode, data);
 	DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
 	DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
 			 &priv->disable_chain_noise_cal);
@@ -747,6 +792,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
 #endif
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling);
+	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_fat_mode);
 	DEBUGFS_REMOVE(priv->dbgfs->dir_data);
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index facbc3d..6101d12 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1164,6 +1164,7 @@ struct iwl_priv {
 	/* debugging info */
 	u32 framecnt_to_us;
 	atomic_t restrict_refcnt;
+	bool disable_fat;
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 	/* debugfs */
 	struct iwl_debugfs *dbgfs;
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 13/14] iwlagn: fix null pointer access during ucode load on 1000
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
                   ` (11 preceding siblings ...)
  2009-07-24 18:13 ` [PATCH 12/14] iwlwifi: debugFs to enable/disable 40MHz channel support Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  2009-07-24 18:13 ` [PATCH 14/14] iwlagn: fix sparse warning when compiling without debug Reinette Chatre
  2009-07-24 18:13 ` [PATCH v2.6.31] iwlwifi: fix TX queue race Reinette Chatre
  14 siblings, 0 replies; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Reinette Chatre

From: Reinette Chatre <reinette.chatre@intel.com>

Commit "iwlwifi: Handle new firmware file with ucode build number
in header" introduced new ucode header parsing routines, but
neglected to initialize these routines for 1000. The system thus goes
into infinite loop trying to load ucode, failing every time with a null
pointer exception as it tries to parse the header.

Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Acked-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-1000.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 80a2818..5f7c520 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -124,6 +124,7 @@ static struct iwl_lib_ops iwl1000_lib = {
 };
 
 static struct iwl_ops iwl1000_ops = {
+	.ucode = &iwl5000_ucode,
 	.lib = &iwl1000_lib,
 	.hcmd = &iwl5000_hcmd,
 	.utils = &iwl5000_hcmd_utils,
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 14/14] iwlagn: fix sparse warning when compiling without debug
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
                   ` (12 preceding siblings ...)
  2009-07-24 18:13 ` [PATCH 13/14] iwlagn: fix null pointer access during ucode load on 1000 Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  2009-07-24 18:13 ` [PATCH v2.6.31] iwlwifi: fix TX queue race Reinette Chatre
  14 siblings, 0 replies; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Reinette Chatre

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 1167 bytes --]

From: Reinette Chatre <reinette.chatre@intel.com>

C [M]  drivers/net/wireless/iwlwifi/iwl-core.o
drivers/net/wireless/iwlwifi/iwl-core.c:1341: warning:
‘iwl_dump_nic_error_log’ defined but not used

Reported-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-core.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index edfdbe8..b6db955 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1295,7 +1295,6 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
 	IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
 	IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
 }
-#endif
 
 static const char *desc_lookup_text[] = {
 	"OK",
@@ -1500,6 +1499,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv)
 	iwl_print_event_log(priv, 0, next_entry, mode);
 
 }
+#endif
 /**
  * iwl_irq_handle_error - called for HW or SW error interrupt from card
  */
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2.6.31] iwlwifi: fix TX queue race
  2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
                   ` (13 preceding siblings ...)
  2009-07-24 18:13 ` [PATCH 14/14] iwlagn: fix sparse warning when compiling without debug Reinette Chatre
@ 2009-07-24 18:13 ` Reinette Chatre
  14 siblings, 0 replies; 22+ messages in thread
From: Reinette Chatre @ 2009-07-24 18:13 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Johannes Berg, Reinette Chatre

From: Johannes Berg <johannes@sipsolutions.net>

I had a problem on 4965 hardware (well, probably other hardware too,
but others don't survive my stress testing right now, unfortunately)
where the driver was sending invalid commands to the device, but no
such thing could be seen from the driver's point of view. I could
reproduce this fairly easily by sending multiple TCP streams with
iperf on different TIDs, though sometimes a single iperf stream was
sufficient. It even happened with a single core, but I have forced
preemption turned on.

The culprit was a queue overrun, where we advanced the queue's write
pointer over the read pointer. After careful analysis I've come to
the conclusion that the cause is a race condition between iwlwifi
and mac80211.

mac80211, of course, checks whether the queue is stopped, before
transmitting a frame. This effectively looks like this:

        lock(queues)
        if (stopped(queue)) {
                unlock(queues)
                return busy;
	}
        unlock(queues)
        ...             <-- this place will be important
			    there is some more code here
        drv_tx(frame)

The driver, on the other hand, can stop and start queues, which does

        lock(queues)
        mark_running/stopped(queue)
        unlock(queues)

	[if marked running: wake up tasklet to send pending frames]

Now, however, once the driver starts the queue, mac80211 can see that
and end up at the marked place above, at which point for some reason the
driver seems to stop the queue again (I don't understand that) and then
we end up transmitting while the queue is actually full.

Now, this shouldn't actually matter much, but for some reason I've seen
it happen multiple times in a row and the queue actually overflows, at
which point the queue bites itself in the tail and things go completely
wrong.

This patch fixes this by just dropping the packet should this have
happened, and making the lock in iwlwifi cover everything so iwlwifi
can't race against itself (dropping the lock there might make it more
likely, but it did seem to happen without that too).

Since we can't hold the lock across drv_tx() above, I see no way to fix
this in mac80211, but I also don't understand why I haven't seen this
before -- maybe I just never stress tested it this badly.

With this patch, the device has survived many minutes of simultanously
sending two iperf streams on different TIDs with combined throughput
of about 60 Mbps.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-tx.c |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 85ae7a6..82a5f62 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -720,8 +720,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 		goto drop_unlock;
 	}
 
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	hdr_len = ieee80211_hdrlen(fc);
 
 	/* Find (or create) index into station table for destination station */
@@ -729,7 +727,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 	if (sta_id == IWL_INVALID_STATION) {
 		IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
 			       hdr->addr1);
-		goto drop;
+		goto drop_unlock;
 	}
 
 	IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
@@ -750,14 +748,17 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 			txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
 			swq_id = iwl_virtual_agg_queue_num(swq_id, txq_id);
 		}
-		priv->stations[sta_id].tid[tid].tfds_in_queue++;
 	}
 
 	txq = &priv->txq[txq_id];
 	q = &txq->q;
 	txq->swq_id = swq_id;
 
-	spin_lock_irqsave(&priv->lock, flags);
+	if (unlikely(iwl_queue_space(q) < q->high_mark))
+		goto drop_unlock;
+
+	if (ieee80211_is_data_qos(fc))
+		priv->stations[sta_id].tid[tid].tfds_in_queue++;
 
 	/* Set up driver data for this TFD */
 	memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
@@ -901,7 +902,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
 drop_unlock:
 	spin_unlock_irqrestore(&priv->lock, flags);
-drop:
 	return -1;
 }
 EXPORT_SYMBOL(iwl_tx_skb);
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH 12/14] iwlwifi: debugFs to enable/disable 40MHz channel support
  2009-07-24 18:13 ` [PATCH 12/14] iwlwifi: debugFs to enable/disable 40MHz channel support Reinette Chatre
@ 2009-07-24 21:40   ` Gábor Stefanik
  2009-07-25 17:24     ` Guy, Wey-Yi W
  0 siblings, 1 reply; 22+ messages in thread
From: Gábor Stefanik @ 2009-07-24 21:40 UTC (permalink / raw)
  To: Reinette Chatre; +Cc: linville, linux-wireless, ipw3945-devel, Wey-Yi Guy

On Fri, Jul 24, 2009 at 8:13 PM, Reinette
Chatre<reinette.chatre@intel.com> wrote:
> From: Wey-Yi Guy <wey-yi.w.guy@intel.com>
>
> Add debugfs file to enable/disable Fat(40MHz) channel support.
> By default, 40MHz is supported if AP can support the function.
>
> By echo "1" to "disable_fat_mode" file, iwlwifi driver will disable the 40MHz
> support and only allow 20MHz channel.

Please make that disable_ht40. The term "fat channel" is deprecated in
favor of "HT40".

>
> Because the information exchange happen during association time,
> so enable/disable fat channel only can be performed when it is not
> associated with AP.
>
> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
> ---
>  drivers/net/wireless/iwlwifi/iwl-core.c    |    4 ++
>  drivers/net/wireless/iwlwifi/iwl-debug.h   |    1 +
>  drivers/net/wireless/iwlwifi/iwl-debugfs.c |   46 ++++++++++++++++++++++++++++
>  drivers/net/wireless/iwlwifi/iwl-dev.h     |    1 +
>  4 files changed, 52 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
> index 710dd41..edfdbe8 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-core.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-core.c
> @@ -632,6 +632,10 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
>                if (!sta_ht_inf->ht_supported)
>                        return 0;
>        }
> +#ifdef CONFIG_IWLWIFI_DEBUG
> +       if (priv->disable_fat)
> +               return 0;
> +#endif
>        return iwl_is_channel_extension(priv, priv->band,
>                        le16_to_cpu(priv->staging_rxon.channel),
>                        iwl_ht_conf->extension_chan_offset);
> diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
> index 609a681..2e10da3 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-debug.h
> +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
> @@ -88,6 +88,7 @@ struct iwl_debugfs {
>  #ifdef CONFIG_IWLWIFI_LEDS
>                struct dentry *file_led;
>  #endif
> +               struct dentry *file_disable_fat_mode;
>        } dbgfs_data_files;
>        struct dir_rf_files {
>                struct dentry *file_disable_sensitivity;
> diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
> index 748dc31..03486d5 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
> @@ -653,6 +653,49 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
>        return ret;
>  }
>
> +static ssize_t iwl_dbgfs_disable_fat_mode_write(struct file *file,
> +                                        const char __user *user_buf,
> +                                        size_t count, loff_t *ppos)
> +{
> +       struct iwl_priv *priv = file->private_data;
> +       char buf[8];
> +       int buf_size;
> +       int fat_mode;
> +
> +       memset(buf, 0, sizeof(buf));
> +       buf_size = min(count, sizeof(buf) -  1);
> +       if (copy_from_user(buf, user_buf, buf_size))
> +               return -EFAULT;
> +       if (sscanf(buf, "%d", &fat_mode) != 1)
> +               return -EFAULT;
> +       if (!iwl_is_associated(priv))
> +               priv->disable_fat = fat_mode ? true : false;
> +       else {
> +               IWL_ERR(priv, "Sta associated with AP - "
> +                       "Change fat mode is not allowed\n");
> +               return -EINVAL;
> +       }
> +
> +       return count;
> +}
> +
> +static ssize_t iwl_dbgfs_disable_fat_mode_read(struct file *file,
> +                                        char __user *user_buf,
> +                                        size_t count, loff_t *ppos)
> +{
> +       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
> +       char buf[100];
> +       int pos = 0;
> +       const size_t bufsz = sizeof(buf);
> +       ssize_t ret;
> +
> +       pos += scnprintf(buf + pos, bufsz - pos,
> +                       "11n 40Mhz Mode: %s\n",
> +                       priv->disable_fat ? "Disabled" : "Enabled");
> +       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
> +       return ret;
> +}
> +
>  DEBUGFS_READ_WRITE_FILE_OPS(sram);
>  DEBUGFS_WRITE_FILE_OPS(log_event);
>  DEBUGFS_READ_FILE_OPS(nvm);
> @@ -667,6 +710,7 @@ DEBUGFS_READ_FILE_OPS(qos);
>  DEBUGFS_READ_FILE_OPS(led);
>  #endif
>  DEBUGFS_READ_FILE_OPS(thermal_throttling);
> +DEBUGFS_READ_WRITE_FILE_OPS(disable_fat_mode);
>
>  /*
>  * Create the debugfs files and directories
> @@ -708,6 +752,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
>        DEBUGFS_ADD_FILE(led, data);
>  #endif
>        DEBUGFS_ADD_FILE(thermal_throttling, data);
> +       DEBUGFS_ADD_FILE(disable_fat_mode, data);
>        DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
>        DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
>                         &priv->disable_chain_noise_cal);
> @@ -747,6 +792,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
>        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
>  #endif
>        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling);
> +       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_fat_mode);
>        DEBUGFS_REMOVE(priv->dbgfs->dir_data);
>        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
>        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
> diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
> index facbc3d..6101d12 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-dev.h
> +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
> @@ -1164,6 +1164,7 @@ struct iwl_priv {
>        /* debugging info */
>        u32 framecnt_to_us;
>        atomic_t restrict_refcnt;
> +       bool disable_fat;
>  #ifdef CONFIG_IWLWIFI_DEBUGFS
>        /* debugfs */
>        struct iwl_debugfs *dbgfs;
> --
> 1.5.6.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [PATCH 12/14] iwlwifi: debugFs to enable/disable 40MHz channel support
  2009-07-24 21:40   ` Gábor Stefanik
@ 2009-07-25 17:24     ` Guy, Wey-Yi W
  0 siblings, 0 replies; 22+ messages in thread
From: Guy, Wey-Yi W @ 2009-07-25 17:24 UTC (permalink / raw)
  To: Gábor Stefanik, Chatre, Reinette
  Cc: linville, linux-wireless, ipw3945-devel

Sure, I will make the change and re-submit.

Wey-Yi Guy
Intel Corporation
2111 N.E. 25th Avenue  M/S JF3-308                 
Hillsboro OR 97124-5961
USA
Work Phone: 503-264-6023 (OR)
Cell Phone: 503-329-8410
Email: wey-yi.w.guy@intel.com
 

-----Original Message-----
From: Gábor Stefanik [mailto:netrolller.3d@gmail.com] 
Sent: Friday, July 24, 2009 2:41 PM
To: Chatre, Reinette
Cc: linville@tuxdriver.com; linux-wireless@vger.kernel.org; ipw3945-devel@lists.sourceforge.net; Guy, Wey-Yi W
Subject: Re: [PATCH 12/14] iwlwifi: debugFs to enable/disable 40MHz channel support

On Fri, Jul 24, 2009 at 8:13 PM, Reinette
Chatre<reinette.chatre@intel.com> wrote:
> From: Wey-Yi Guy <wey-yi.w.guy@intel.com>
>
> Add debugfs file to enable/disable Fat(40MHz) channel support.
> By default, 40MHz is supported if AP can support the function.
>
> By echo "1" to "disable_fat_mode" file, iwlwifi driver will disable the 40MHz
> support and only allow 20MHz channel.

Please make that disable_ht40. The term "fat channel" is deprecated in
favor of "HT40".

>
> Because the information exchange happen during association time,
> so enable/disable fat channel only can be performed when it is not
> associated with AP.
>
> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
> ---
>  drivers/net/wireless/iwlwifi/iwl-core.c    |    4 ++
>  drivers/net/wireless/iwlwifi/iwl-debug.h   |    1 +
>  drivers/net/wireless/iwlwifi/iwl-debugfs.c |   46 ++++++++++++++++++++++++++++
>  drivers/net/wireless/iwlwifi/iwl-dev.h     |    1 +
>  4 files changed, 52 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
> index 710dd41..edfdbe8 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-core.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-core.c
> @@ -632,6 +632,10 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
>                if (!sta_ht_inf->ht_supported)
>                        return 0;
>        }
> +#ifdef CONFIG_IWLWIFI_DEBUG
> +       if (priv->disable_fat)
> +               return 0;
> +#endif
>        return iwl_is_channel_extension(priv, priv->band,
>                        le16_to_cpu(priv->staging_rxon.channel),
>                        iwl_ht_conf->extension_chan_offset);
> diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
> index 609a681..2e10da3 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-debug.h
> +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
> @@ -88,6 +88,7 @@ struct iwl_debugfs {
>  #ifdef CONFIG_IWLWIFI_LEDS
>                struct dentry *file_led;
>  #endif
> +               struct dentry *file_disable_fat_mode;
>        } dbgfs_data_files;
>        struct dir_rf_files {
>                struct dentry *file_disable_sensitivity;
> diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
> index 748dc31..03486d5 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
> @@ -653,6 +653,49 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
>        return ret;
>  }
>
> +static ssize_t iwl_dbgfs_disable_fat_mode_write(struct file *file,
> +                                        const char __user *user_buf,
> +                                        size_t count, loff_t *ppos)
> +{
> +       struct iwl_priv *priv = file->private_data;
> +       char buf[8];
> +       int buf_size;
> +       int fat_mode;
> +
> +       memset(buf, 0, sizeof(buf));
> +       buf_size = min(count, sizeof(buf) -  1);
> +       if (copy_from_user(buf, user_buf, buf_size))
> +               return -EFAULT;
> +       if (sscanf(buf, "%d", &fat_mode) != 1)
> +               return -EFAULT;
> +       if (!iwl_is_associated(priv))
> +               priv->disable_fat = fat_mode ? true : false;
> +       else {
> +               IWL_ERR(priv, "Sta associated with AP - "
> +                       "Change fat mode is not allowed\n");
> +               return -EINVAL;
> +       }
> +
> +       return count;
> +}
> +
> +static ssize_t iwl_dbgfs_disable_fat_mode_read(struct file *file,
> +                                        char __user *user_buf,
> +                                        size_t count, loff_t *ppos)
> +{
> +       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
> +       char buf[100];
> +       int pos = 0;
> +       const size_t bufsz = sizeof(buf);
> +       ssize_t ret;
> +
> +       pos += scnprintf(buf + pos, bufsz - pos,
> +                       "11n 40Mhz Mode: %s\n",
> +                       priv->disable_fat ? "Disabled" : "Enabled");
> +       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
> +       return ret;
> +}
> +
>  DEBUGFS_READ_WRITE_FILE_OPS(sram);
>  DEBUGFS_WRITE_FILE_OPS(log_event);
>  DEBUGFS_READ_FILE_OPS(nvm);
> @@ -667,6 +710,7 @@ DEBUGFS_READ_FILE_OPS(qos);
>  DEBUGFS_READ_FILE_OPS(led);
>  #endif
>  DEBUGFS_READ_FILE_OPS(thermal_throttling);
> +DEBUGFS_READ_WRITE_FILE_OPS(disable_fat_mode);
>
>  /*
>  * Create the debugfs files and directories
> @@ -708,6 +752,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
>        DEBUGFS_ADD_FILE(led, data);
>  #endif
>        DEBUGFS_ADD_FILE(thermal_throttling, data);
> +       DEBUGFS_ADD_FILE(disable_fat_mode, data);
>        DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
>        DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
>                         &priv->disable_chain_noise_cal);
> @@ -747,6 +792,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
>        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
>  #endif
>        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling);
> +       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_fat_mode);
>        DEBUGFS_REMOVE(priv->dbgfs->dir_data);
>        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
>        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
> diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
> index facbc3d..6101d12 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-dev.h
> +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
> @@ -1164,6 +1164,7 @@ struct iwl_priv {
>        /* debugging info */
>        u32 framecnt_to_us;
>        atomic_t restrict_refcnt;
> +       bool disable_fat;
>  #ifdef CONFIG_IWLWIFI_DEBUGFS
>        /* debugfs */
>        struct iwl_debugfs *dbgfs;
> --
> 1.5.6.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 04/14] iwlwifi: Thermal Throttling Management - part 2
  2009-07-24 18:13 ` [PATCH 04/14] iwlwifi: Thermal Throttling Management - part 2 Reinette Chatre
@ 2009-07-27 22:29   ` Johannes Berg
  2009-07-27 22:46     ` reinette chatre
  0 siblings, 1 reply; 22+ messages in thread
From: Johannes Berg @ 2009-07-27 22:29 UTC (permalink / raw)
  To: Reinette Chatre; +Cc: linville, linux-wireless, ipw3945-devel, Wey-Yi Guy

[-- Attachment #1: Type: text/plain, Size: 659 bytes --]

On Fri, 2009-07-24 at 11:13 -0700, Reinette Chatre wrote:

>  /**
> + * struct iwl_tt_restriction - Thermal Throttling restriction table used
> + *		by advance thermal throttling management
> + *		based on the current thermal throttling state, determine
> + *		number of tx/rx streams; and the status of HT operation
> + * @tx_stream: number of tx stream allowed
> + * @is_ht: ht enable/disable
> + * @rx_stream: number of rx stream allowed
> + */

This kernel-doc, and some others, are really botched btw -- the bit
after 'struct foo - ' really needs to be a single line only, you can put
longer descriptions after the parameters.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 04/14] iwlwifi: Thermal Throttling Management - part 2
  2009-07-27 22:29   ` Johannes Berg
@ 2009-07-27 22:46     ` reinette chatre
  2009-07-28  7:33       ` Johannes Berg
  0 siblings, 1 reply; 22+ messages in thread
From: reinette chatre @ 2009-07-27 22:46 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linville, linux-wireless, ipw3945-devel, Guy, Wey-Yi W

Hi Johannes,

On Mon, 2009-07-27 at 15:29 -0700, Johannes Berg wrote:
> On Fri, 2009-07-24 at 11:13 -0700, Reinette Chatre wrote:
> 
> >  /**
> > + * struct iwl_tt_restriction - Thermal Throttling restriction table used
> > + *		by advance thermal throttling management
> > + *		based on the current thermal throttling state, determine
> > + *		number of tx/rx streams; and the status of HT operation
> > + * @tx_stream: number of tx stream allowed
> > + * @is_ht: ht enable/disable
> > + * @rx_stream: number of rx stream allowed
> > + */
> 
> This kernel-doc, and some others, are really botched btw -- the bit
> after 'struct foo - ' really needs to be a single line only, you can put
> longer descriptions after the parameters.

Sorry for missing this. We are trying to be better with documentation
and need to do more work in this area. This patch is currently in
wireless-testing. I am not sure how to proceed here. If I send a cleanup
patch on top of current wireless-testing it will only make sense to
address other kernel-doc mishaps. As our driver has not been tested
(afaik) to provide meaningful documentation when kernel-doc is used I am
hesitant to take on this right now ... but it is something we have to
address at some point.

Reinette



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 04/14] iwlwifi: Thermal Throttling Management - part 2
  2009-07-27 22:46     ` reinette chatre
@ 2009-07-28  7:33       ` Johannes Berg
  2009-07-28  7:47         ` reinette chatre
  0 siblings, 1 reply; 22+ messages in thread
From: Johannes Berg @ 2009-07-28  7:33 UTC (permalink / raw)
  To: reinette chatre; +Cc: linville, linux-wireless, ipw3945-devel, Guy, Wey-Yi W

[-- Attachment #1: Type: text/plain, Size: 860 bytes --]

On Mon, 2009-07-27 at 15:46 -0700, reinette chatre wrote:

> Sorry for missing this. We are trying to be better with documentation
> and need to do more work in this area. This patch is currently in
> wireless-testing. I am not sure how to proceed here. If I send a cleanup
> patch on top of current wireless-testing it will only make sense to
> address other kernel-doc mishaps. As our driver has not been tested
> (afaik) to provide meaningful documentation when kernel-doc is used I am
> hesitant to take on this right now ... but it is something we have to
> address at some point.

Yeah, I know it's not used, and I'm sure there's more -- I was just
looking at the code trying to rebase a patch and this caught my eye.
It's certainly not too important, but I wanted to point it out anyway if
only to avoid that in the future :)

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 04/14] iwlwifi: Thermal Throttling Management - part 2
  2009-07-28  7:33       ` Johannes Berg
@ 2009-07-28  7:47         ` reinette chatre
  0 siblings, 0 replies; 22+ messages in thread
From: reinette chatre @ 2009-07-28  7:47 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linville, linux-wireless, ipw3945-devel, Guy, Wey-Yi W

On Tue, 2009-07-28 at 00:33 -0700, Johannes Berg wrote:
> On Mon, 2009-07-27 at 15:46 -0700, reinette chatre wrote:
> 
> > Sorry for missing this. We are trying to be better with documentation
> > and need to do more work in this area. This patch is currently in
> > wireless-testing. I am not sure how to proceed here. If I send a cleanup
> > patch on top of current wireless-testing it will only make sense to
> > address other kernel-doc mishaps. As our driver has not been tested
> > (afaik) to provide meaningful documentation when kernel-doc is used I am
> > hesitant to take on this right now ... but it is something we have to
> > address at some point.
> 
> Yeah, I know it's not used, and I'm sure there's more -- I was just
> looking at the code trying to rebase a patch and this caught my eye.
> It's certainly not too important, but I wanted to point it out anyway if
> only to avoid that in the future :)

Point taken. Thank you very much.

Reinette




^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2009-07-28  7:47 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-07-24 18:12 [PATCH 0/14] iwlwifi driver updates 07/24/2009 Reinette Chatre
2009-07-24 18:13 ` [PATCH 01/14] iwlwifi: revert to active table when rate is not valid Reinette Chatre
2009-07-24 18:13 ` [PATCH 02/14] iwlwifi: critical temperature enter/exit condition Reinette Chatre
2009-07-24 18:13 ` [PATCH 03/14] iwlwifi: Thermal Throttling Management - Part 1 Reinette Chatre
2009-07-24 18:13 ` [PATCH 04/14] iwlwifi: Thermal Throttling Management - part 2 Reinette Chatre
2009-07-27 22:29   ` Johannes Berg
2009-07-27 22:46     ` reinette chatre
2009-07-28  7:33       ` Johannes Berg
2009-07-28  7:47         ` reinette chatre
2009-07-24 18:13 ` [PATCH 05/14] iwlwifi: Thermal Throttling debugfs function Reinette Chatre
2009-07-24 18:13 ` [PATCH 06/14] iwlwifi: fix up command sending Reinette Chatre
2009-07-24 18:13 ` [PATCH 07/14] iwlwifi: remove command callback return value Reinette Chatre
2009-07-24 18:13 ` [PATCH 08/14] iwlwifi: fix TX queue race Reinette Chatre
2009-07-24 18:13 ` [PATCH 09/14] iwlwifi: print packet contents in error case Reinette Chatre
2009-07-24 18:13 ` [PATCH 10/14] iwlwifi: Name fix for MPDU density for TX aggregation Reinette Chatre
2009-07-24 18:13 ` [PATCH 11/14] iwlwifi: fix LED config option Reinette Chatre
2009-07-24 18:13 ` [PATCH 12/14] iwlwifi: debugFs to enable/disable 40MHz channel support Reinette Chatre
2009-07-24 21:40   ` Gábor Stefanik
2009-07-25 17:24     ` Guy, Wey-Yi W
2009-07-24 18:13 ` [PATCH 13/14] iwlagn: fix null pointer access during ucode load on 1000 Reinette Chatre
2009-07-24 18:13 ` [PATCH 14/14] iwlagn: fix sparse warning when compiling without debug Reinette Chatre
2009-07-24 18:13 ` [PATCH v2.6.31] iwlwifi: fix TX queue race Reinette Chatre

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).