2010-02-19 06:03:11

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 0/6] iwlwifi updates for 2.6.34

We include more enabling for new 6050 series. The new "force reset" is
strengthened with the addition of per component state so that a reset of
one will not affect the reset of the other, this as well as more
accounting can be monitored with debugfs. We also now allow
serialization of synchronous commands. The rest is cleanup.

These patches are also available from wireless-next-2.6 branch on
git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-2.6.git

Abhijeet Kolekar (1):
iwlwifi: indicate calib version for 6050 series

Reinette Chatre (3):
iwl3945: remove STATUS macros from header
iwlwifi: enable iwl_send_static_wepkey_cmd to sleep
iwlwifi: enable serialization of synchronous commands

Wey-Yi Guy (2):
iwlwifi: separated time check for different type of force reset
iwlwifi: add debugfs to monitor force reset parameters

drivers/net/wireless/iwlwifi/iwl-3945.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-3945.h | 18 ------
drivers/net/wireless/iwlwifi/iwl-6000.c | 79 ++++++++++++++++++++++++++-
drivers/net/wireless/iwlwifi/iwl-agn.c | 7 +++
drivers/net/wireless/iwlwifi/iwl-core.c | 25 +++++----
drivers/net/wireless/iwlwifi/iwl-core.h | 3 +-
drivers/net/wireless/iwlwifi/iwl-csr.h | 2 +-
drivers/net/wireless/iwlwifi/iwl-debugfs.c | 36 +++++++++++--
drivers/net/wireless/iwlwifi/iwl-dev.h | 15 +++++-
drivers/net/wireless/iwlwifi/iwl-hcmd.c | 14 +++---
drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +
drivers/net/wireless/iwlwifi/iwl3945-base.c | 3 +-
13 files changed, 160 insertions(+), 48 deletions(-)



2010-02-19 06:03:13

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 5/6] iwlwifi: separated time check for different type of force reset

From: Wey-Yi Guy <[email protected]>

Use different timing duration check for different type of force reset,
force reset request can come from different source and based on
different reason; one type of reset request should not block other type of
reset request.

Adding structure to keep track of different force reset request.

Signed-off-by: Wey-Yi Guy <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-agn.c | 6 ++++++
drivers/net/wireless/iwlwifi/iwl-core.c | 25 ++++++++++++++-----------
drivers/net/wireless/iwlwifi/iwl-dev.h | 14 +++++++++++++-
3 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 52b6beb..c5b724e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -3378,6 +3378,12 @@ static int iwl_init_drv(struct iwl_priv *priv)
priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
priv->agg_tids_count = 0;

+ /* initialize force reset */
+ priv->force_reset[IWL_RF_RESET].reset_duration =
+ IWL_DELAY_NEXT_FORCE_RF_RESET;
+ priv->force_reset[IWL_FW_RESET].reset_duration =
+ IWL_DELAY_NEXT_FORCE_FW_RELOAD;
+
/* Choose which receivers/antennas to use */
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index bd56827..55252a6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -3357,22 +3357,30 @@ static void iwl_force_rf_reset(struct iwl_priv *priv)
return;
}

-#define IWL_DELAY_NEXT_FORCE_RESET (HZ*3)

int iwl_force_reset(struct iwl_priv *priv, int mode)
{
+ struct iwl_force_reset *force_reset;
+
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return -EINVAL;

- if (priv->last_force_reset_jiffies &&
- time_after(priv->last_force_reset_jiffies +
- IWL_DELAY_NEXT_FORCE_RESET, jiffies)) {
+ if (mode >= IWL_MAX_FORCE_RESET) {
+ IWL_DEBUG_INFO(priv, "invalid reset request.\n");
+ return -EINVAL;
+ }
+ force_reset = &priv->force_reset[mode];
+ force_reset->reset_request_count++;
+ if (force_reset->last_force_reset_jiffies &&
+ time_after(force_reset->last_force_reset_jiffies +
+ force_reset->reset_duration, jiffies)) {
IWL_DEBUG_INFO(priv, "force reset rejected\n");
+ force_reset->reset_reject_count++;
return -EAGAIN;
}
-
+ force_reset->reset_success_count++;
+ force_reset->last_force_reset_jiffies = jiffies;
IWL_DEBUG_INFO(priv, "perform force reset (%d)\n", mode);
-
switch (mode) {
case IWL_RF_RESET:
iwl_force_rf_reset(priv);
@@ -3389,12 +3397,7 @@ int iwl_force_reset(struct iwl_priv *priv, int mode)
clear_bit(STATUS_READY, &priv->status);
queue_work(priv->workqueue, &priv->restart);
break;
- default:
- IWL_DEBUG_INFO(priv, "invalid reset request.\n");
- return -EINVAL;
}
- priv->last_force_reset_jiffies = jiffies;
-
return 0;
}

diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 021c686..7914d65 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1036,9 +1036,21 @@ struct iwl_event_log {
#define IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF (200)
#define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255)

+#define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3)
+#define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5)
+
enum iwl_reset {
IWL_RF_RESET = 0,
IWL_FW_RESET,
+ IWL_MAX_FORCE_RESET,
+};
+
+struct iwl_force_reset {
+ int reset_request_count;
+ int reset_success_count;
+ int reset_reject_count;
+ unsigned long reset_duration;
+ unsigned long last_force_reset_jiffies;
};

struct iwl_priv {
@@ -1076,7 +1088,7 @@ struct iwl_priv {
u8 agg_tids_count;

/* force reset */
- unsigned long last_force_reset_jiffies;
+ struct iwl_force_reset force_reset[IWL_MAX_FORCE_RESET];

/* we allocate array of iwl4965_channel_info for NIC's valid channels.
* Access via channel # using indirect index array */
--
1.6.3.3


2010-02-19 06:03:12

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 4/6] iwlwifi: indicate calib version for 6050 series

From: Abhijeet Kolekar <[email protected]>

Indicate calibration version to uCode

Signed-off-by: Abhijeet Kolekar <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-6000.c | 79 ++++++++++++++++++++++++++++++-
drivers/net/wireless/iwlwifi/iwl-core.h | 1 +
drivers/net/wireless/iwlwifi/iwl-csr.h | 2 +-
3 files changed, 79 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 782e23a..c4844ad 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -70,6 +70,14 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
}

+/* Indicate calibration version to uCode. */
+static void iwl6050_set_calib_version(struct iwl_priv *priv)
+{
+ if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
+ iwl_set_bit(priv, CSR_GP_DRIVER_REG,
+ CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
+}
+
/* NIC configuration for 6000 series */
static void iwl6000_nic_config(struct iwl_priv *priv)
{
@@ -96,6 +104,8 @@ static void iwl6000_nic_config(struct iwl_priv *priv)
CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
}
/* else do nothing, uCode configured */
+ if (priv->cfg->ops->lib->temp_ops.set_calib_version)
+ priv->cfg->ops->lib->temp_ops.set_calib_version(priv);
}

static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
@@ -277,6 +287,71 @@ static const struct iwl_ops iwl6000_ops = {
.led = &iwlagn_led_ops,
};

+static struct iwl_lib_ops iwl6050_lib = {
+ .set_hw_params = iwl6000_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,
+ .dump_nic_event_log = iwl_dump_nic_event_log,
+ .dump_nic_error_log = iwl_dump_nic_error_log,
+ .dump_csr = iwl_dump_csr,
+ .dump_fh = iwl_dump_fh,
+ .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,
+ .set_channel_switch = iwl6000_hw_channel_switch,
+ .apm_ops = {
+ .init = iwl_apm_init,
+ .stop = iwl_apm_stop,
+ .config = iwl6000_nic_config,
+ .set_pwr_src = iwl_set_pwr_src,
+ },
+ .eeprom_ops = {
+ .regulatory_bands = {
+ EEPROM_5000_REG_BAND_1_CHANNELS,
+ EEPROM_5000_REG_BAND_2_CHANNELS,
+ EEPROM_5000_REG_BAND_3_CHANNELS,
+ EEPROM_5000_REG_BAND_4_CHANNELS,
+ EEPROM_5000_REG_BAND_5_CHANNELS,
+ EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
+ EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+ },
+ .verify_signature = iwlcore_eeprom_verify_signature,
+ .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+ .release_semaphore = iwlcore_eeprom_release_semaphore,
+ .calib_version = iwl5000_eeprom_calib_version,
+ .query_addr = iwl5000_eeprom_query_addr,
+ .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
+ },
+ .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,
+ .set_calib_version = iwl6050_set_calib_version,
+ },
+ .add_bcast_station = iwl_add_bcast_station,
+};
+
+static const struct iwl_ops iwl6050_ops = {
+ .ucode = &iwl5000_ucode,
+ .lib = &iwl6050_lib,
+ .hcmd = &iwl5000_hcmd,
+ .utils = &iwl5000_hcmd_utils,
+ .led = &iwlagn_led_ops,
+};
+
/*
* "i": Internal configuration, use internal Power Amplifier
*/
@@ -380,7 +455,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl6000_ops,
+ .ops = &iwl6050_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
@@ -412,7 +487,7 @@ struct iwl_cfg iwl6050_2abg_cfg = {
.ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G,
- .ops = &iwl6000_ops,
+ .ops = &iwl6050_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 6347d4b..3df7933 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -117,6 +117,7 @@ struct iwl_apm_ops {
struct iwl_temp_ops {
void (*temperature)(struct iwl_priv *priv);
void (*set_ct_kill)(struct iwl_priv *priv);
+ void (*set_calib_version)(struct iwl_priv *priv);
};

struct iwl_ucode_ops {
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 1e00720..808b714 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -369,7 +369,7 @@
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_3x3_HYB (0x00000000)
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB (0x00000001)
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002)
-
+#define CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6 (0x00000004)

/* GIO Chicken Bits (PCI Express bus link power management) */
#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
--
1.6.3.3


2010-02-19 06:03:12

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 1/6] iwl3945: remove STATUS macros from header

From: Reinette Chatre <[email protected]>

iwl3945 includes iwl-core.h in which these STATUS flags are already
defined. This also removes a potential confusing definition with iwlcore
using STATUS_MODE_PENDING with value 18 and iwl3945 defining (but not
using) STATUS_CONF_PENDING for value 18.

Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-3945.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-3945.h | 18 ------------------
drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +-
3 files changed, 2 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 5913418..521584b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -45,8 +45,8 @@
#include "iwl-sta.h"
#include "iwl-3945.h"
#include "iwl-eeprom.h"
-#include "iwl-helpers.h"
#include "iwl-core.h"
+#include "iwl-helpers.h"
#include "iwl-led.h"
#include "iwl-3945-led.h"

diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index db4137d..ae94bab 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -171,24 +171,6 @@ struct iwl3945_frame {

#define SCAN_INTERVAL 100

-#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
-#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */
-#define STATUS_INT_ENABLED 2
-#define STATUS_RF_KILL_HW 3
-#define STATUS_INIT 5
-#define STATUS_ALIVE 6
-#define STATUS_READY 7
-#define STATUS_TEMPERATURE 8
-#define STATUS_GEO_CONFIGURED 9
-#define STATUS_EXIT_PENDING 10
-#define STATUS_STATISTICS 12
-#define STATUS_SCANNING 13
-#define STATUS_SCAN_ABORTING 14
-#define STATUS_SCAN_HW 15
-#define STATUS_POWER_PMI 16
-#define STATUS_FW_ERROR 17
-#define STATUS_CONF_PENDING 18
-
#define MAX_TID_COUNT 9

#define IWL_INVALID_RATE 0xFF
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 3df488a..0e5a1ca 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -53,8 +53,8 @@
#include "iwl-commands.h"
#include "iwl-sta.h"
#include "iwl-3945.h"
-#include "iwl-helpers.h"
#include "iwl-core.h"
+#include "iwl-helpers.h"
#include "iwl-dev.h"
#include "iwl-spectrum.h"

--
1.6.3.3


2010-02-19 13:00:10

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/6] iwlwifi: enable iwl_send_static_wepkey_cmd to sleep

Or probably better would be this:

iwlwifi: change WEP key protection to use mutex

Signed-off-by: Johannes Berg <[email protected]>
---

diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 4a616c5..f46e7c6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2841,7 +2841,6 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,

mutex_lock(&priv->mutex);
iwl_scan_cancel_timeout(priv, 100);
- mutex_unlock(&priv->mutex);

/* If we are getting WEP group key and we didn't receive any key mapping
* so far, we are in legacy wep mode (group key only), otherwise we are
@@ -2877,6 +2876,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = -EINVAL;
}

+ mutex_unlock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");

return ret;
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 6ac1199..f978037 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1227,7 +1227,7 @@ struct iwl_priv {
spinlock_t sta_lock;
int num_stations;
struct iwl_station_entry stations[IWL_STATION_COUNT];
- struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
+ struct iwl_wep_key wep_keys[WEP_KEYS_MAX]; /* protected by mutex */
u8 default_wep_key;
u8 key_mapping_key;
unsigned long ucode_key_table;
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index b5f4830..1159d88 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -807,6 +807,8 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
.flags = CMD_SYNC,
};

+ might_sleep();
+
memset(wep_cmd, 0, cmd_size +
(sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));

@@ -842,9 +844,9 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf)
{
int ret;
- unsigned long flags;

- spin_lock_irqsave(&priv->sta_lock, flags);
+ WARN_ON(!mutex_is_locked(&priv->mutex));
+
IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
keyconf->keyidx);

@@ -856,13 +858,12 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
if (iwl_is_rfkill(priv)) {
IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n");
- spin_unlock_irqrestore(&priv->sta_lock, flags);
+ /* but keys in device are clear anyway so return success */
return 0;
}
ret = iwl_send_static_wepkey_cmd(priv, 1);
IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
keyconf->keyidx, ret);
- spin_unlock_irqrestore(&priv->sta_lock, flags);

return ret;
}
@@ -872,7 +873,8 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf)
{
int ret;
- unsigned long flags;
+
+ WARN_ON(!mutex_is_locked(&priv->mutex));

if (keyconf->keylen != WEP_KEY_LEN_128 &&
keyconf->keylen != WEP_KEY_LEN_64) {
@@ -884,12 +886,11 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
keyconf->hw_key_idx = HW_KEY_DEFAULT;
priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;

- spin_lock_irqsave(&priv->sta_lock, flags);
priv->default_wep_key++;

if (test_and_set_bit(keyconf->keyidx, &priv->ucode_key_table))
IWL_ERR(priv, "index %d already used in uCode key table.\n",
- keyconf->keyidx);
+ keyconf->keyidx);

priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
@@ -898,7 +899,6 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
ret = iwl_send_static_wepkey_cmd(priv, 0);
IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n",
keyconf->keylen, keyconf->keyidx, ret);
- spin_unlock_irqrestore(&priv->sta_lock, flags);

return ret;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 6665236..23f1ff2 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -3342,7 +3342,6 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,

mutex_lock(&priv->mutex);
iwl_scan_cancel_timeout(priv, 100);
- mutex_unlock(&priv->mutex);

switch (cmd) {
case SET_KEY:
@@ -3363,6 +3362,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = -EINVAL;
}

+ mutex_unlock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");

return ret;



2010-02-19 17:15:37

by Reinette Chatre

[permalink] [raw]
Subject: Re: [PATCH 2/6] iwlwifi: enable iwl_send_static_wepkey_cmd to sleep

On Fri, 2010-02-19 at 04:59 -0800, Johannes Berg wrote:
> Or probably better would be this:
>
> iwlwifi: change WEP key protection to use mutex
>
> Signed-off-by: Johannes Berg <[email protected]>
> ---

This was a terrible mistake - thank you very much for catching this.
Your solution looks good.

Acked-by: Reinette Chatre <[email protected]>

John, could you please replace "iwlwifi: enable
iwl_send_static_wepkey_cmd to sleep" with "iwlwifi: change WEP key
protection to use mutex" ?

Reinette



2010-02-19 17:31:44

by Reinette Chatre

[permalink] [raw]
Subject: Re: [PATCH 2/6] iwlwifi: enable iwl_send_static_wepkey_cmd to sleep

On Fri, 2010-02-19 at 09:22 -0800, Johannes Berg wrote:
> On Fri, 2010-02-19 at 09:15 -0800, reinette chatre wrote:
>
> > John, could you please replace "iwlwifi: enable
> > iwl_send_static_wepkey_cmd to sleep" with "iwlwifi: change WEP key
> > protection to use mutex" ?
>
> Not replace though, my patch didn't include the ASYNC->SYNC change. And
> it probably wants a better changelog too?

ah - right. Seems like we need to clean up here. John, please drop both
these patches. I'll take them into our repo and submit it later. This is
only needed for future work.

Reinette



2010-02-19 09:13:26

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/6] iwlwifi: enable iwl_send_static_wepkey_cmd to sleep

On Thu, 2010-02-18 at 22:03 -0800, Reinette Chatre wrote:
> From: Reinette Chatre <[email protected]>
>
> iwl_send_static_wepkey_cmd is only called from places that are able to
> sleep. Modify it so that it itself is able to sleep.

Oops, this patch seems wrong (was just working on the wep key restore
stuff):

int iwl_remove_default_wep_key(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf)
...
spin_lock_irqsave(&priv->sta_lock, flags);
...
ret = iwl_send_static_wepkey_cmd(priv, 1);
...
spin_unlock_irqrestore(&priv->sta_lock, flags);

and same in iwl_set_default_wep_key().


How about this in addition? Changes protection from sta_lock to mutex
for wep keys (untested!).

johannes

diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 1d8c940..d0a2e7d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2841,7 +2841,6 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,

mutex_lock(&priv->mutex);
iwl_scan_cancel_timeout(priv, 100);
- mutex_unlock(&priv->mutex);

/* If we are getting WEP group key and we didn't receive any key mapping
* so far, we are in legacy wep mode (group key only), otherwise we are
@@ -2877,6 +2876,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = -EINVAL;
}

+ mutex_unlock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");

return ret;
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 18cf981..e544be9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -806,6 +806,8 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
.flags = CMD_SYNC,
};

+ might_sleep();
+
memset(wep_cmd, 0, cmd_size +
(sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));

@@ -841,27 +843,28 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf)
{
int ret;
- unsigned long flags;

- spin_lock_irqsave(&priv->sta_lock, flags);
+ WARN_ON(!mutex_is_locked(&priv->mutex));
+
IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
keyconf->keyidx);

- if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table))
+ if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table)) {
IWL_ERR(priv, "index %d not used in uCode key table.\n",
- keyconf->keyidx);
+ keyconf->keyidx);
+ return -ENOENT;
+ }

priv->default_wep_key--;
memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
if (iwl_is_rfkill(priv)) {
IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n");
- spin_unlock_irqrestore(&priv->sta_lock, flags);
+ /* but keys in device are clear anyway so return success */
return 0;
}
ret = iwl_send_static_wepkey_cmd(priv, 1);
IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
keyconf->keyidx, ret);
- spin_unlock_irqrestore(&priv->sta_lock, flags);

return ret;
}
@@ -871,7 +874,8 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf)
{
int ret;
- unsigned long flags;
+
+ WARN_ON(!mutex_is_locked(&priv->mutex));

if (keyconf->keylen != WEP_KEY_LEN_128 &&
keyconf->keylen != WEP_KEY_LEN_64) {
@@ -883,12 +887,13 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
keyconf->hw_key_idx = HW_KEY_DEFAULT;
priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;

- spin_lock_irqsave(&priv->sta_lock, flags);
priv->default_wep_key++;

- if (test_and_set_bit(keyconf->keyidx, &priv->ucode_key_table))
+ if (test_and_set_bit(keyconf->keyidx, &priv->ucode_key_table)) {
IWL_ERR(priv, "index %d already used in uCode key table.\n",
keyconf->keyidx);
+ return -EBUSY;
+ }

priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
@@ -897,7 +902,6 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
ret = iwl_send_static_wepkey_cmd(priv, 0);
IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n",
keyconf->keylen, keyconf->keyidx, ret);
- spin_unlock_irqrestore(&priv->sta_lock, flags);

return ret;
}



2010-02-19 06:03:12

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 2/6] iwlwifi: enable iwl_send_static_wepkey_cmd to sleep

From: Reinette Chatre <[email protected]>

iwl_send_static_wepkey_cmd is only called from places that are able to
sleep. Modify it so that it itself is able to sleep.

Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 4a6686f..62aae15 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -549,7 +549,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,
- .flags = CMD_ASYNC,
+ .flags = CMD_SYNC,
};

memset(wep_cmd, 0, cmd_size +
--
1.6.3.3


2010-02-19 06:03:12

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 3/6] iwlwifi: enable serialization of synchronous commands

From: Reinette Chatre <[email protected]>

Until now it was only possible to have one synchronous command running at
any time. If a synchronous command is in progress when a second request
arrives then the second command will fail. Create a new mutex specific for
this purpose to only allow one synchronous command at a time, but enable
other commands to wait instead of fail if a synchronous command is in
progress.

Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-agn.c | 1 +
drivers/net/wireless/iwlwifi/iwl-core.h | 2 +-
drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 --
drivers/net/wireless/iwlwifi/iwl-dev.h | 1 +
drivers/net/wireless/iwlwifi/iwl-hcmd.c | 14 +++++++-------
drivers/net/wireless/iwlwifi/iwl-tx.c | 2 ++
drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 +
7 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 4157c6c..52b6beb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -3364,6 +3364,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
INIT_LIST_HEAD(&priv->free_frames);

mutex_init(&priv->mutex);
+ mutex_init(&priv->sync_cmd_mutex);

/* Clear the driver's (not device's) station table */
iwl_clear_stations_table(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 530fae8..6347d4b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -603,7 +603,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);
/*************** DRIVER STATUS FUNCTIONS *****/

#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
-#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */
+/* 1 is unused (used to be STATUS_HCMD_SYNC_ACTIVE) */
#define STATUS_INT_ENABLED 2
#define STATUS_RF_KILL_HW 3
#define STATUS_CT_KILL 4
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 78298be..7241fda 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -530,8 +530,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,

pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n",
test_bit(STATUS_HCMD_ACTIVE, &priv->status));
- pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_SYNC_ACTIVE: %d\n",
- test_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n",
test_bit(STATUS_INT_ENABLED, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index f81317d..021c686 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1111,6 +1111,7 @@ struct iwl_priv {
spinlock_t hcmd_lock; /* protect hcmd */
spinlock_t reg_lock; /* protect hw register access */
struct mutex mutex;
+ struct mutex sync_cmd_mutex; /* enable serialization of sync commands */

/* basic pci-network driver stuff */
struct pci_dev *pci_dev;
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 86783c2..73681c4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -164,15 +164,13 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
/* A synchronous command can not have a callback set. */
BUG_ON(cmd->callback);

- if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) {
- IWL_ERR(priv,
- "Error sending %s: Already sending a host command\n",
+ IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
get_cmd_string(cmd->id));
- ret = -EBUSY;
- goto out;
- }
+ mutex_lock(&priv->sync_cmd_mutex);

set_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s \n",
+ get_cmd_string(cmd->id));

cmd_idx = iwl_enqueue_hcmd(priv, cmd);
if (cmd_idx < 0) {
@@ -193,6 +191,8 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));

clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n",
+ get_cmd_string(cmd->id));
ret = -ETIMEDOUT;
goto cancel;
}
@@ -237,7 +237,7 @@ fail:
cmd->reply_page = 0;
}
out:
- clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
+ mutex_unlock(&priv->sync_cmd_mutex);
return ret;
}
EXPORT_SYMBOL(iwl_send_cmd_sync);
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index d8c11f9..38655ad 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -1238,6 +1238,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)

if (!(meta->flags & CMD_ASYNC)) {
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n",
+ get_cmd_string(cmd->hdr.cmd));
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 0e5a1ca..54daa38 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -3847,6 +3847,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
INIT_LIST_HEAD(&priv->free_frames);

mutex_init(&priv->mutex);
+ mutex_init(&priv->sync_cmd_mutex);

/* Clear the driver's (not device's) station table */
iwl_clear_stations_table(priv);
--
1.6.3.3


2010-02-19 06:03:13

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 6/6] iwlwifi: add debugfs to monitor force reset parameters

From: Wey-Yi Guy <[email protected]>

Adding debugfs file to monitor the counters and other
information related to "force_reset" request.

Signed-off-by: Wey-Yi Guy <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-debugfs.c | 34 ++++++++++++++++++++++++++-
1 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 7241fda..7bf44f1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -2221,6 +2221,36 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
return count;
}

+static ssize_t iwl_dbgfs_force_reset_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = file->private_data;
+ int i, pos = 0;
+ char buf[300];
+ const size_t bufsz = sizeof(buf);
+ struct iwl_force_reset *force_reset;
+
+ for (i = 0; i < IWL_MAX_FORCE_RESET; i++) {
+ force_reset = &priv->force_reset[i];
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Force reset method %d\n", i);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tnumber of reset request: %d\n",
+ force_reset->reset_request_count);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tnumber of reset request success: %d\n",
+ force_reset->reset_success_count);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tnumber of reset request reject: %d\n",
+ force_reset->reset_reject_count);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\treset duration: %lu\n",
+ force_reset->reset_duration);
+ }
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
static ssize_t iwl_dbgfs_force_reset_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos) {
@@ -2267,7 +2297,7 @@ DEBUGFS_READ_FILE_OPS(fh_reg);
DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
DEBUGFS_WRITE_FILE_OPS(internal_scan);
DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
-DEBUGFS_WRITE_FILE_OPS(force_reset);
+DEBUGFS_READ_WRITE_FILE_OPS(force_reset);

/*
* Create the debugfs files and directories
@@ -2321,7 +2351,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(internal_scan, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR);
+ DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
--
1.6.3.3


2010-02-19 17:22:25

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/6] iwlwifi: enable iwl_send_static_wepkey_cmd to sleep

On Fri, 2010-02-19 at 09:15 -0800, reinette chatre wrote:
> On Fri, 2010-02-19 at 04:59 -0800, Johannes Berg wrote:
> > Or probably better would be this:
> >
> > iwlwifi: change WEP key protection to use mutex
> >
> > Signed-off-by: Johannes Berg <[email protected]>
> > ---
>
> This was a terrible mistake - thank you very much for catching this.
> Your solution looks good.
>
> Acked-by: Reinette Chatre <[email protected]>
>
> John, could you please replace "iwlwifi: enable
> iwl_send_static_wepkey_cmd to sleep" with "iwlwifi: change WEP key
> protection to use mutex" ?

Not replace though, my patch didn't include the ASYNC->SYNC change. And
it probably wants a better changelog too?

johannes