Hi,
Below are 9 patches for 2.6.27. All these fixes have passed our
internal testing/validation. And they affects the iwlwifi driver
only so that won't cause any regression on other components.
Note, although in a patch series, these patches don't have any
dependencies on each other. If you do feel some of them should
not be on this list, please go forward to apply the others. But
I'd suggest you apply them all since they do fix real critical bugs.
Thanks,
-yi
[PATCH 1/9] iwlwifi: W/A for the TSF correction in IBSS
[PATCH 2/9] iwlwifi: fix hidden ssid discovery in passive channels
[PATCH 3/9] iwlwifi: remove false rxon if rx chain changes
[PATCH 4/9] iwlwifi: generic init calibrations framework
[PATCH 5/9] iwlwifi: fix station mimo power save values
[PATCH 6/9] iwlwifi: fix rx_chain computation
[PATCH 7/9] iwlwifi: fix Tx cmd memory allocation failure handling
[PATCH 8/9] iwlwifi: call apm stop on exit
[PATCH 9/9] iwlwifi: fix STATUS_EXIT_PENDING is not set on pci_remove
From: Zhu Yi <[email protected]>
Date: Wed, 3 Sep 2008 11:18:45 +0800
> From: Tomas Winkler <[email protected]>
>
> This patch fixes a critical bug that only the last calibration result
> was applied. On reception of one calibration result all the calibration
> results were freed therefore only last was applied. The patch fixes this
> problem by introducing a generic init calibration framework which allows
> variable number of init calibrations and allows addition new HW.
>
> Signed-off-by: Tomas Winkler <[email protected]>
> Signed-off-by: Emmanuel Grumbach <[email protected]>
> Signed-off-by: Zhu Yi <[email protected]>
This is borderline, I would rather hold off on such a sizable change
for 2.6.27 as I'll have a hard time justifying it.
Hi Tomas,
> >> > This patch fixes a critical bug that only the last calibration result
> >> > was applied. On reception of one calibration result all the calibration
> >> > results were freed therefore only last was applied. The patch fixes this
> >> > problem by introducing a generic init calibration framework which allows
> >> > variable number of init calibrations and allows addition new HW.
> >> >
> >> > Signed-off-by: Tomas Winkler <[email protected]>
> >> > Signed-off-by: Emmanuel Grumbach <[email protected]>
> >> > Signed-off-by: Zhu Yi <[email protected]>
> >>
> >> This is borderline, I would rather hold off on such a sizable change
> >> for 2.6.27 as I'll have a hard time justifying it.
> >
> > do you see any way for fixing (or improving) this with the current code
> > and hold the whole framework change off until the next merge window.
> >
> > Maybe instead of iwl_free_calib_results(priv); just freeing them
> > individually in their case statements.
> > You know the hardware better than I do, but that should just work
> > (judging from the code).
>
> In general it's possible, but we've already tested this fix. Because
> this is sensitive, even if the code looks okay I cannot approve it
> until we run the whole validation cycle and measurements in the lab so
> it will take some time. Last time we broke it code also looked good :)
if I understood Dave correctly, then we either come up with a temporary
fix that is small and simple (even if it is not a long term solution) or
no fix for this issue is going into 2.6.27 at all. The fix that I have
in mind removes one line and adds 6 new ones.
And of course it needs to be tested, but that should be true for
everything that goes into the kernel. I can write the temporary patch
for it, but you guys are the experts with this hardware. So I leave it
up to you.
Regards
Marcel
From: Ron Rindjunsky <[email protected]>
This patch fixes the wrong use MIMO power save values. Our TX was
configured with our MIMO power save values instead of peer's MIMO power
save values, this may affect connectivity. The peer STA/AP may not sense
our traffic at all as it doesn't have all RX chains opened.
Signed-off-by: Ron Rindjunsky <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
Signed-off-by: Zhu Yi <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 3 ++-
drivers/net/wireless/iwlwifi/iwl-agn.c | 2 --
drivers/net/wireless/iwlwifi/iwl-dev.h | 1 -
3 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 754fef5..90a2b6d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -1153,7 +1153,8 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
!sta->ht_info.ht_supported)
return -1;
- if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC)
+ if (((sta->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS) >> 2)
+ == IWL_MIMO_PS_STATIC)
return -1;
/* Need both Tx chains/antennas to support MIMO */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index a5feb0c..34928c8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -586,8 +586,6 @@ static void iwl4965_ht_conf(struct iwl_priv *priv,
iwl_conf->supported_chan_width = 0;
}
- iwl_conf->tx_mimo_ps_mode =
- (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
iwl_conf->control_channel = ht_bss_conf->primary_channel;
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index b00acf4..deec634 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -412,7 +412,6 @@ struct iwl_ht_info {
/* self configuration data */
u8 is_ht;
u8 supported_chan_width;
- u16 tx_mimo_ps_mode;
u8 is_green_field;
u8 sgf; /* HT_SHORT_GI_* short guard interval */
u8 max_amsdu_size;
--
1.5.3.6
From: Zhu Yi <[email protected]>
Date: Wed, 3 Sep 2008 11:18:47 +0800
> From: Tomas Winkler <[email protected]>
>
> This patch fixes rx_chain computation. The code that adjusts number of
> rx chains to number supported by HW was missing. Miss configuration
> causes firmware error. Note: iwlwifi supports HW with up to 3 RX
> chains (2x2, 2x3, 1x2, and 3x3 MIMO). This patch also simplifies the
> whole RX chain computation.
>
> Signed-off-by: Tomas Winkler <[email protected]>
> Signed-off-by: Mohamed Abbas <[email protected]>
> Signed-off-by: Zhu Yi <[email protected]>
Acked-by: David S. Miller <[email protected]>
From: Tomas Winkler <[email protected]>
This patch fixes a critical bug that only the last calibration result
was applied. On reception of one calibration result all the calibration
results were freed therefore only last was applied. The patch fixes this
problem by introducing a generic init calibration framework which allows
variable number of init calibrations and allows addition new HW.
Signed-off-by: Tomas Winkler <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Zhu Yi <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-5000-hw.h | 7 +++
drivers/net/wireless/iwlwifi/iwl-5000.c | 63 ++++------------------------
drivers/net/wireless/iwlwifi/iwl-calib.c | 60 ++++++++++++++++++++++++++
drivers/net/wireless/iwlwifi/iwl-core.c | 19 +--------
drivers/net/wireless/iwlwifi/iwl-core.h | 8 +++-
drivers/net/wireless/iwlwifi/iwl-dev.h | 14 +++----
6 files changed, 90 insertions(+), 81 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
index 17d4f31..c479ee2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
@@ -129,6 +129,13 @@ struct iwl5000_shared {
__le32 padding2;
} __attribute__ ((packed));
+/* calibrations defined for 5000 */
+/* defines the order in which results should be sent to the runtime uCode */
+enum iwl5000_calib {
+ IWL5000_CALIB_LO,
+ IWL5000_CALIB_TX_IQ,
+ IWL5000_CALIB_TX_IQ_PERD,
+};
#endif /* __iwl_5000_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index b08036a..79ff288 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -445,48 +445,6 @@ static int iwl5000_send_Xtal_calib(struct iwl_priv *priv)
sizeof(cal_cmd), &cal_cmd);
}
-static int iwl5000_send_calib_results(struct iwl_priv *priv)
-{
- int ret = 0;
-
- struct iwl_host_cmd hcmd = {
- .id = REPLY_PHY_CALIBRATION_CMD,
- .meta.flags = CMD_SIZE_HUGE,
- };
-
- if (priv->calib_results.lo_res) {
- hcmd.len = priv->calib_results.lo_res_len;
- hcmd.data = priv->calib_results.lo_res;
- ret = iwl_send_cmd_sync(priv, &hcmd);
-
- if (ret)
- goto err;
- }
-
- if (priv->calib_results.tx_iq_res) {
- hcmd.len = priv->calib_results.tx_iq_res_len;
- hcmd.data = priv->calib_results.tx_iq_res;
- ret = iwl_send_cmd_sync(priv, &hcmd);
-
- if (ret)
- goto err;
- }
-
- if (priv->calib_results.tx_iq_perd_res) {
- hcmd.len = priv->calib_results.tx_iq_perd_res_len;
- hcmd.data = priv->calib_results.tx_iq_perd_res;
- ret = iwl_send_cmd_sync(priv, &hcmd);
-
- if (ret)
- goto err;
- }
-
- return 0;
-err:
- IWL_ERROR("Error %d\n", ret);
- return ret;
-}
-
static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
{
struct iwl5000_calib_cfg_cmd calib_cfg_cmd;
@@ -511,33 +469,30 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv,
struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw;
int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK;
-
- iwl_free_calib_results(priv);
+ int index;
/* reduce the size of the length field itself */
len -= 4;
+ /* Define the order in which the results will be sent to the runtime
+ * uCode. iwl_send_calib_results sends them in a row according to their
+ * index. We sort them here */
switch (hdr->op_code) {
case IWL5000_PHY_CALIBRATE_LO_CMD:
- priv->calib_results.lo_res = kzalloc(len, GFP_ATOMIC);
- priv->calib_results.lo_res_len = len;
- memcpy(priv->calib_results.lo_res, pkt->u.raw, len);
+ index = IWL5000_CALIB_LO;
break;
case IWL5000_PHY_CALIBRATE_TX_IQ_CMD:
- priv->calib_results.tx_iq_res = kzalloc(len, GFP_ATOMIC);
- priv->calib_results.tx_iq_res_len = len;
- memcpy(priv->calib_results.tx_iq_res, pkt->u.raw, len);
+ index = IWL5000_CALIB_TX_IQ;
break;
case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD:
- priv->calib_results.tx_iq_perd_res = kzalloc(len, GFP_ATOMIC);
- priv->calib_results.tx_iq_perd_res_len = len;
- memcpy(priv->calib_results.tx_iq_perd_res, pkt->u.raw, len);
+ index = IWL5000_CALIB_TX_IQ_PERD;
break;
default:
IWL_ERROR("Unknown calibration notification %d\n",
hdr->op_code);
return;
}
+ iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
}
static void iwl5000_rx_calib_complete(struct iwl_priv *priv,
@@ -832,7 +787,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
iwl5000_send_Xtal_calib(priv);
if (priv->ucode_type == UCODE_RT)
- iwl5000_send_calib_results(priv);
+ iwl_send_calib_results(priv);
return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index ef49440..35fb4a4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -66,6 +66,66 @@
#include "iwl-core.h"
#include "iwl-calib.h"
+/*****************************************************************************
+ * INIT calibrations framework
+ *****************************************************************************/
+
+ int iwl_send_calib_results(struct iwl_priv *priv)
+{
+ int ret = 0;
+ int i = 0;
+
+ struct iwl_host_cmd hcmd = {
+ .id = REPLY_PHY_CALIBRATION_CMD,
+ .meta.flags = CMD_SIZE_HUGE,
+ };
+
+ for (i = 0; i < IWL_CALIB_MAX; i++)
+ if (priv->calib_results[i].buf) {
+ hcmd.len = priv->calib_results[i].buf_len;
+ hcmd.data = priv->calib_results[i].buf;
+ ret = iwl_send_cmd_sync(priv, &hcmd);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+err:
+ IWL_ERROR("Error %d iteration %d\n", ret, i);
+ return ret;
+}
+EXPORT_SYMBOL(iwl_send_calib_results);
+
+int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len)
+{
+ if (res->buf_len != len) {
+ kfree(res->buf);
+ res->buf = kzalloc(len, GFP_ATOMIC);
+ }
+ if (unlikely(res->buf == NULL))
+ return -ENOMEM;
+
+ res->buf_len = len;
+ memcpy(res->buf, buf, len);
+ return 0;
+}
+EXPORT_SYMBOL(iwl_calib_set);
+
+void iwl_calib_free_results(struct iwl_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < IWL_CALIB_MAX; i++) {
+ kfree(priv->calib_results[i].buf);
+ priv->calib_results[i].buf = NULL;
+ priv->calib_results[i].buf_len = 0;
+ }
+}
+
+/*****************************************************************************
+ * RUNTIME calibrations framework
+ *****************************************************************************/
+
/* "false alarms" are signals that our DSP tries to lock onto,
* but then determines that they are either noise, or transmissions
* from a distant wireless network (also "noise", really) that get
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index c72f725..390fa1d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -935,22 +935,6 @@ err:
}
EXPORT_SYMBOL(iwl_init_drv);
-void iwl_free_calib_results(struct iwl_priv *priv)
-{
- kfree(priv->calib_results.lo_res);
- priv->calib_results.lo_res = NULL;
- priv->calib_results.lo_res_len = 0;
-
- kfree(priv->calib_results.tx_iq_res);
- priv->calib_results.tx_iq_res = NULL;
- priv->calib_results.tx_iq_res_len = 0;
-
- kfree(priv->calib_results.tx_iq_perd_res);
- priv->calib_results.tx_iq_perd_res = NULL;
- priv->calib_results.tx_iq_perd_res_len = 0;
-}
-EXPORT_SYMBOL(iwl_free_calib_results);
-
int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
{
int ret = 0;
@@ -978,10 +962,9 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
}
EXPORT_SYMBOL(iwl_set_tx_power);
-
void iwl_uninit_drv(struct iwl_priv *priv)
{
- iwl_free_calib_results(priv);
+ iwl_calib_free_results(priv);
iwlcore_free_geos(priv);
iwl_free_channel_map(priv);
kfree(priv->scan);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 64f139e..51b36b1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -186,7 +186,6 @@ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
void iwl_hw_detect(struct iwl_priv *priv);
void iwl_clear_stations_table(struct iwl_priv *priv);
-void iwl_free_calib_results(struct iwl_priv *priv);
void iwl_reset_qos(struct iwl_priv *priv);
void iwl_set_rxon_chain(struct iwl_priv *priv);
int iwl_set_rxon_channel(struct iwl_priv *priv,
@@ -291,6 +290,13 @@ int iwl_scan_initiate(struct iwl_priv *priv);
void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
+/*******************************************************************************
+ * Calibrations - implemented in iwl-calib.c
+ ******************************************************************************/
+int iwl_send_calib_results(struct iwl_priv *priv);
+int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len);
+void iwl_calib_free_results(struct iwl_priv *priv);
+
/*****************************************************
* S e n d i n g H o s t C o m m a n d s *
*****************************************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index c19db43..b00acf4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -746,13 +746,10 @@ struct statistics_general_data {
u32 beacon_energy_c;
};
-struct iwl_calib_results {
- void *tx_iq_res;
- void *tx_iq_perd_res;
- void *lo_res;
- u32 tx_iq_res_len;
- u32 tx_iq_perd_res_len;
- u32 lo_res_len;
+/* Opaque calibration results */
+struct iwl_calib_result {
+ void *buf;
+ size_t buf_len;
};
enum ucode_type {
@@ -814,6 +811,7 @@ enum {
#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */
+#define IWL_CALIB_MAX 3
struct iwl_priv {
@@ -858,7 +856,7 @@ struct iwl_priv {
s32 last_temperature;
/* init calibration results */
- struct iwl_calib_results calib_results;
+ struct iwl_calib_result calib_results[IWL_CALIB_MAX];
/* Scan related variables */
unsigned long last_scan_jiffies;
--
1.5.3.6
From: Zhu Yi <[email protected]>
Date: Wed, 3 Sep 2008 11:18:43 +0800
> From: Ron Rindjunsky <[email protected]>
>
> This enables sending of direct probes on passive channels, as long as
> traffic was detected on that channel. This enables connectivity to
> hidden/non broadcasting SSIDs APs on passive channels. Note 5000 HW
> declares all 5.2 spectrum as passive.
>
> Signed-off-by: Cahill Ben <[email protected]>
> Signed-off-by: Tomas Winkler <[email protected]>
> Signed-off-by: Ron Rindjunsky <[email protected]>
> Signed-off-by: Zhu Yi <[email protected]>
Acked-by: David S. Miller <[email protected]>
From: Ron Rindjunsky <[email protected]>
This enables sending of direct probes on passive channels, as long as
traffic was detected on that channel. This enables connectivity to
hidden/non broadcasting SSIDs APs on passive channels. Note 5000 HW
declares all 5.2 spectrum as passive.
Signed-off-by: Cahill Ben <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
Signed-off-by: Ron Rindjunsky <[email protected]>
Signed-off-by: Zhu Yi <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-scan.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 9bb6adb..6c8ac3a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -421,7 +421,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
else
scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
- if ((scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) && n_probes)
+ if (n_probes)
scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
scan_ch->active_dwell = cpu_to_le16(active_dwell);
--
1.5.3.6
On Wed, Sep 3, 2008 at 4:59 PM, Marcel Holtmann
<[email protected]> wrote:
> Hi Tomas,
>
>> >> > This patch fixes a critical bug that only the last calibration result
>> >> > was applied. On reception of one calibration result all the calibration
>> >> > results were freed therefore only last was applied. The patch fixes this
>> >> > problem by introducing a generic init calibration framework which allows
>> >> > variable number of init calibrations and allows addition new HW.
>> >> >
>> >> > Signed-off-by: Tomas Winkler <[email protected]>
>> >> > Signed-off-by: Emmanuel Grumbach <[email protected]>
>> >> > Signed-off-by: Zhu Yi <[email protected]>
>> >>
>> >> This is borderline, I would rather hold off on such a sizable change
>> >> for 2.6.27 as I'll have a hard time justifying it.
>> >
>> > do you see any way for fixing (or improving) this with the current code
>> > and hold the whole framework change off until the next merge window.
>> >
>> > Maybe instead of iwl_free_calib_results(priv); just freeing them
>> > individually in their case statements.
>> > You know the hardware better than I do, but that should just work
>> > (judging from the code).
>>
>> In general it's possible, but we've already tested this fix. Because
>> this is sensitive, even if the code looks okay I cannot approve it
>> until we run the whole validation cycle and measurements in the lab so
>> it will take some time. Last time we broke it code also looked good :)
>
> if I understood Dave correctly, then we either come up with a temporary
> fix that is small and simple (even if it is not a long term solution) or
> no fix for this issue is going into 2.6.27 at all. The fix that I have
> in mind removes one line and adds 6 new ones.
>
> And of course it needs to be tested, but that should be true for
> everything that goes into the kernel. I can write the temporary patch
> for it, but you guys are the experts with this hardware. So I leave it
> up to you.
Writing the fix is not the problem, just to get the cycles from the testing.
Tomas
From: Gregory Greenman <[email protected]>
This patch calls apm stop on exit and suspend. Without this patch
hardware consumes power even after driver is removed or suspended.
Signed-off-by: Gregory Greenman <[email protected]>
Signed-off-by: Mohamed Abbas <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
Signed-off-by: Zhu Yi <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-agn.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 34928c8..4e3d6c7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2187,7 +2187,10 @@ static void __iwl4965_down(struct iwl_priv *priv)
udelay(5);
/* FIXME: apm_ops.suspend(priv) */
- priv->cfg->ops->lib->apm_ops.reset(priv);
+ if (exit_pending || test_bit(STATUS_IN_SUSPEND, &priv->status))
+ priv->cfg->ops->lib->apm_ops.stop(priv);
+ else
+ priv->cfg->ops->lib->apm_ops.reset(priv);
priv->cfg->ops->lib->free_shared_mem(priv);
exit:
--
1.5.3.6
On Wed, Sep 3, 2008 at 11:10 AM, Marcel Holtmann
<[email protected]> wrote:
> Hi Tomas,
>
>> > This patch fixes a critical bug that only the last calibration result
>> > was applied. On reception of one calibration result all the calibration
>> > results were freed therefore only last was applied. The patch fixes this
>> > problem by introducing a generic init calibration framework which allows
>> > variable number of init calibrations and allows addition new HW.
>> >
>> > Signed-off-by: Tomas Winkler <[email protected]>
>> > Signed-off-by: Emmanuel Grumbach <[email protected]>
>> > Signed-off-by: Zhu Yi <[email protected]>
>>
>> This is borderline, I would rather hold off on such a sizable change
>> for 2.6.27 as I'll have a hard time justifying it.
>
> do you see any way for fixing (or improving) this with the current code
> and hold the whole framework change off until the next merge window.
>
> Maybe instead of iwl_free_calib_results(priv); just freeing them
> individually in their case statements.
> You know the hardware better than I do, but that should just work
> (judging from the code).
>
> Regards
>
> Marcel
In general it's possible, but we've already tested this fix. Because
this is sensitive, even if the code looks okay I cannot approve it
until we run the whole validation cycle and measurements in the lab so
it will take some time. Last time we broke it code also looked good :)
Tomas
From: Zhu Yi <[email protected]>
Date: Wed, 3 Sep 2008 11:18:42 +0800
> From: Assaf Krauss <[email protected]>
>
> This patch is a W/A for the TSF sync issue in IBSS merging. HW is not
> capable to sync TSF (it's constantly little behind). This creates
> constant IBSS merging upon reception of each beacon, adding and removing
> station which in turn creates above 50% packet loss and thus dramatically
> degrade the throughput. The W/A simply stops the driver from declaring it
> has a reliable TSF value and thus eliminates IBSS merging.
>
> Signed-off-by: Assaf Krauss <[email protected]>
> Signed-off-by: Tomas Winkler <[email protected]>
> Signed-off-by: Zhu Yi <[email protected]>
Acked-by: David S. Miller <[email protected]>
From: Zhu Yi <[email protected]>
Date: Wed, 3 Sep 2008 11:18:50 +0800
> From: Gregory Greenman <[email protected]>
>
> This patch sets STATUS_EXIT_PENDING on pci_remove. Otherwise
> iwl4965_down may fail to uninitialize the driver.
>
> Signed-off-by: Gregory Greenman <[email protected]>
> Signed-off-by: Mohamed Abbas <[email protected]>
> Signed-off-by: Tomas Winkler <[email protected]>
> Signed-off-by: Zhu Yi <[email protected]>
Acked-by: David S. Miller <[email protected]>
From: Assaf Krauss <[email protected]>
This patch is a W/A for the TSF sync issue in IBSS merging. HW is not
capable to sync TSF (it's constantly little behind). This creates
constant IBSS merging upon reception of each beacon, adding and removing
station which in turn creates above 50% packet loss and thus dramatically
degrade the throughput. The W/A simply stops the driver from declaring it
has a reliable TSF value and thus eliminates IBSS merging.
Signed-off-by: Assaf Krauss <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
Signed-off-by: Zhu Yi <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-rx.c | 5 ++++-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index c0b73c4..2afa1fb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -3588,7 +3588,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
priv->assoc_id = 0;
timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
- priv->timestamp = le64_to_cpu(timestamp) + (priv->beacon_int * 1000);
+ priv->timestamp = le64_to_cpu(timestamp);
IWL_DEBUG_MAC80211("leave\n");
spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index f3f6ea4..e81bfc4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -1173,7 +1173,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
rx_status.antenna = 0;
rx_status.flag = 0;
- rx_status.flag |= RX_FLAG_TSFT;
+
+ /* TSF isn't reliable. In order to allow smooth user experience,
+ * this W/A doesn't propagate it to the mac80211 */
+ /*rx_status.flag |= RX_FLAG_TSFT;*/
if ((unlikely(rx_start->cfg_phy_cnt > 20))) {
IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n",
--
1.5.3.6
From: Tomas Winkler <[email protected]>
This patch fixes rx_chain computation. The code that adjusts number of
rx chains to number supported by HW was missing. Miss configuration
causes firmware error. Note: iwlwifi supports HW with up to 3 RX
chains (2x2, 2x3, 1x2, and 3x3 MIMO). This patch also simplifies the
whole RX chain computation.
Signed-off-by: Tomas Winkler <[email protected]>
Signed-off-by: Mohamed Abbas <[email protected]>
Signed-off-by: Zhu Yi <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-core.c | 77 ++++++++++++++++++------------
1 files changed, 46 insertions(+), 31 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 390fa1d..444e262 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -592,12 +592,11 @@ static void iwlcore_free_geos(struct iwl_priv *priv)
clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
}
-static u8 is_single_rx_stream(struct iwl_priv *priv)
+static bool is_single_rx_stream(struct iwl_priv *priv)
{
return !priv->current_ht_config.is_ht ||
((priv->current_ht_config.supp_mcs_set[1] == 0) &&
- (priv->current_ht_config.supp_mcs_set[2] == 0)) ||
- priv->ps_mode == IWL_MIMO_PS_STATIC;
+ (priv->current_ht_config.supp_mcs_set[2] == 0));
}
static u8 iwl_is_channel_extension(struct iwl_priv *priv,
@@ -704,33 +703,39 @@ EXPORT_SYMBOL(iwl_set_rxon_ht);
* MIMO (dual stream) requires at least 2, but works better with 3.
* This does not determine *which* chains to use, just how many.
*/
-static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv,
- u8 *idle_state, u8 *rx_state)
+static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
{
- u8 is_single = is_single_rx_stream(priv);
- u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1;
+ bool is_single = is_single_rx_stream(priv);
+ bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
/* # of Rx chains to use when expecting MIMO. */
if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
- *rx_state = 2;
+ return 2;
else
- *rx_state = 3;
+ return 3;
+}
+static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
+{
+ int idle_cnt;
+ bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
/* # Rx chains when idling and maybe trying to save power */
switch (priv->ps_mode) {
case IWL_MIMO_PS_STATIC:
case IWL_MIMO_PS_DYNAMIC:
- *idle_state = (is_cam) ? 2 : 1;
+ idle_cnt = (is_cam) ? 2 : 1;
break;
case IWL_MIMO_PS_NONE:
- *idle_state = (is_cam) ? *rx_state : 1;
+ idle_cnt = (is_cam) ? active_cnt : 1;
break;
+ case IWL_MIMO_PS_INVALID:
default:
- *idle_state = 1;
+ IWL_ERROR("invalide mimo ps mode %d\n", priv->ps_mode);
+ WARN_ON(1);
+ idle_cnt = -1;
break;
}
-
- return 0;
+ return idle_cnt;
}
/**
@@ -741,34 +746,44 @@ static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv,
*/
void iwl_set_rxon_chain(struct iwl_priv *priv)
{
- u8 is_single = is_single_rx_stream(priv);
- u8 idle_state, rx_state;
-
- priv->staging_rxon.rx_chain = 0;
- rx_state = idle_state = 3;
+ bool is_single = is_single_rx_stream(priv);
+ bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
+ u8 idle_rx_cnt, active_rx_cnt;
+ u16 rx_chain;
/* Tell uCode which antennas are actually connected.
* Before first association, we assume all antennas are connected.
* Just after first association, iwl_chain_noise_calibration()
* checks which antennas actually *are* connected. */
- priv->staging_rxon.rx_chain |=
- cpu_to_le16(priv->hw_params.valid_rx_ant <<
- RXON_RX_CHAIN_VALID_POS);
+ rx_chain = priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
/* How many receivers should we use? */
- iwlcore_get_rx_chain_counter(priv, &idle_state, &rx_state);
- priv->staging_rxon.rx_chain |=
- cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS);
- priv->staging_rxon.rx_chain |=
- cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS);
-
- if (!is_single && (rx_state >= 2) &&
- !test_bit(STATUS_POWER_PMI, &priv->status))
+ active_rx_cnt = iwl_get_active_rx_chain_count(priv);
+ idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
+
+ /* correct rx chain count accoridng hw settings */
+ if (priv->hw_params.rx_chains_num < active_rx_cnt)
+ active_rx_cnt = priv->hw_params.rx_chains_num;
+
+ if (priv->hw_params.rx_chains_num < idle_rx_cnt)
+ idle_rx_cnt = priv->hw_params.rx_chains_num;
+
+ rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
+ rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS;
+
+ priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain);
+
+ if (!is_single && (active_rx_cnt >= 2) && is_cam)
priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
else
priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
- IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain);
+ IWL_DEBUG_ASSOC("rx_chain=0x%Xi active=%d idle=%d\n",
+ priv->staging_rxon.rx_chain,
+ active_rx_cnt, idle_rx_cnt);
+
+ WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
+ active_rx_cnt < idle_rx_cnt);
}
EXPORT_SYMBOL(iwl_set_rxon_chain);
--
1.5.3.6
From: Zhu Yi <[email protected]>
Date: Wed, 3 Sep 2008 11:18:49 +0800
> From: Gregory Greenman <[email protected]>
>
> This patch calls apm stop on exit and suspend. Without this patch
> hardware consumes power even after driver is removed or suspended.
>
> Signed-off-by: Gregory Greenman <[email protected]>
> Signed-off-by: Mohamed Abbas <[email protected]>
> Signed-off-by: Tomas Winkler <[email protected]>
> Signed-off-by: Zhu Yi <[email protected]>
I'm happy to see those worms get fixed.
Acked-by: David S. Miller <[email protected]>
Hi Tomas,
> > This patch fixes a critical bug that only the last calibration result
> > was applied. On reception of one calibration result all the calibration
> > results were freed therefore only last was applied. The patch fixes this
> > problem by introducing a generic init calibration framework which allows
> > variable number of init calibrations and allows addition new HW.
> >
> > Signed-off-by: Tomas Winkler <[email protected]>
> > Signed-off-by: Emmanuel Grumbach <[email protected]>
> > Signed-off-by: Zhu Yi <[email protected]>
>
> This is borderline, I would rather hold off on such a sizable change
> for 2.6.27 as I'll have a hard time justifying it.
do you see any way for fixing (or improving) this with the current code
and hold the whole framework change off until the next merge window.
Maybe instead of iwl_free_calib_results(priv); just freeing them
individually in their case statements.
You know the hardware better than I do, but that should just work
(judging from the code).
Regards
Marcel
From: Gregory Greenman <[email protected]>
This patch sets STATUS_EXIT_PENDING on pci_remove. Otherwise
iwl4965_down may fail to uninitialize the driver.
Signed-off-by: Gregory Greenman <[email protected]>
Signed-off-by: Mohamed Abbas <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
Signed-off-by: Zhu Yi <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-agn.c | 11 +++++++----
1 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 4e3d6c7..e01f048 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -4372,15 +4372,18 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
iwl_dbgfs_unregister(priv);
sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+ /* ieee80211_unregister_hw call wil cause iwl4965_mac_stop to
+ * to be called and iwl4965_down since we are removing the device
+ * we need to set STATUS_EXIT_PENDING bit.
+ */
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
if (priv->mac80211_registered) {
ieee80211_unregister_hw(priv->hw);
priv->mac80211_registered = 0;
+ } else {
+ iwl4965_down(priv);
}
- set_bit(STATUS_EXIT_PENDING, &priv->status);
-
- iwl4965_down(priv);
-
/* make sure we flush any pending irq or
* tasklet for the driver
*/
--
1.5.3.6
From: Zhu Yi <[email protected]>
Date: Wed, 3 Sep 2008 11:18:46 +0800
> From: Ron Rindjunsky <[email protected]>
>
> This patch fixes the wrong use MIMO power save values. Our TX was
> configured with our MIMO power save values instead of peer's MIMO power
> save values, this may affect connectivity. The peer STA/AP may not sense
> our traffic at all as it doesn't have all RX chains opened.
>
> Signed-off-by: Ron Rindjunsky <[email protected]>
> Signed-off-by: Tomas Winkler <[email protected]>
> Signed-off-by: Zhu Yi <[email protected]>
Acked-by: David S. Miller <[email protected]>
From: Tomas Winkler <[email protected]>
This patch "iwlwifi: do not use GFP_DMA in iwl_tx_queue_init" removes
GFP_DMA from allocation tx command buffers. GFP_DMA allows allocation
only for memory under 16M which causes allocation problems
suspend/resume flows.
Using kmalloc is temporal solution and some consistent/coherent
allocation schema will be more correct. Since iwlwifi hardware
supports 64bit address this solution should work on x86 (32 and
64bit) for now.
This patch fixes memory freeing problem in the previous patch.
Signed-off-by: Tomas Winkler <[email protected]>
Signed-off-by: Ian Schram <[email protected]>
Signed-off-by: Zhu Yi <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-tx.c | 27 +++++++++++++++++----------
1 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index ff879d4..78b1a7a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -402,12 +402,11 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
/**
* iwl_tx_queue_init - Allocate and initialize one tx/cmd queue
*/
-static int iwl_tx_queue_init(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
+static int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
int slots_num, u32 txq_id)
{
int i, len;
- int rc = 0;
+ int ret;
/*
* Alloc buffer array for commands (Tx or other types of commands).
@@ -428,17 +427,14 @@ static int iwl_tx_queue_init(struct iwl_priv *priv,
txq->cmd[i] = kmalloc(len, GFP_KERNEL);
if (!txq->cmd[i])
- return -ENOMEM;
+ goto err;
}
/* Alloc driver data array and TFD circular buffer */
- rc = iwl_tx_queue_alloc(priv, txq, txq_id);
- if (rc) {
- for (i = 0; i < slots_num; i++)
- kfree(txq->cmd[i]);
+ ret = iwl_tx_queue_alloc(priv, txq, txq_id);
+ if (ret)
+ goto err;
- return -ENOMEM;
- }
txq->need_update = 0;
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
@@ -452,6 +448,17 @@ static int iwl_tx_queue_init(struct iwl_priv *priv,
iwl_hw_tx_queue_init(priv, txq);
return 0;
+err:
+ for (i = 0; i < slots_num; i++) {
+ kfree(txq->cmd[i]);
+ txq->cmd[i] = NULL;
+ }
+
+ if (txq_id == IWL_CMD_QUEUE_NUM) {
+ kfree(txq->cmd[slots_num]);
+ txq->cmd[slots_num] = NULL;
+ }
+ return -ENOMEM;
}
/**
* iwl_hw_txq_ctx_free - Free TXQ Context
--
1.5.3.6
From: Zhu Yi <[email protected]>
Date: Wed, 3 Sep 2008 11:18:48 +0800
> From: Tomas Winkler <[email protected]>
>
> This patch "iwlwifi: do not use GFP_DMA in iwl_tx_queue_init" removes
> GFP_DMA from allocation tx command buffers. GFP_DMA allows allocation
> only for memory under 16M which causes allocation problems
> suspend/resume flows.
>
> Using kmalloc is temporal solution and some consistent/coherent
> allocation schema will be more correct. Since iwlwifi hardware
> supports 64bit address this solution should work on x86 (32 and
> 64bit) for now.
>
> This patch fixes memory freeing problem in the previous patch.
>
> Signed-off-by: Tomas Winkler <[email protected]>
> Signed-off-by: Ian Schram <[email protected]>
> Signed-off-by: Zhu Yi <[email protected]>
Acked-by: David S. Miller <[email protected]>
From: Mohamed Abbas <[email protected]>
Rx chain might change during power save transitions but it doesn't
require sending Full-ROXN command to the firmware. Full-RXON requires
reconnection to an AP and thus affects user experience. The patch
avoids the Full-RXON by removing the rx_chain modification check in
iwl_full_rxon_required function.
Signed-off-by: Mohamed Abbas <[email protected]
Signed-off-by: Tomas Winkler <[email protected]>
Signed-off-by: Zhu Yi <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-agn.c | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 2afa1fb..a5feb0c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -181,14 +181,14 @@ static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
}
/**
- * iwl4965_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
+ * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
* @priv: staging_rxon is compared to active_rxon
*
* If the RXON structure is changing enough to require a new tune,
* or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
* a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
*/
-static int iwl4965_full_rxon_required(struct iwl_priv *priv)
+static int iwl_full_rxon_required(struct iwl_priv *priv)
{
/* These items are only settable from the full RXON command */
@@ -207,7 +207,6 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv)
priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
(priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
- (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) ||
(priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
return 1;
@@ -263,7 +262,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
/* If we don't need to send a full RXON, we can use
* iwl4965_rxon_assoc_cmd which is used to reconfigure filter
* and other flags for the current radio configuration. */
- if (!iwl4965_full_rxon_required(priv)) {
+ if (!iwl_full_rxon_required(priv)) {
ret = iwl_send_rxon_assoc(priv);
if (ret) {
IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret);
--
1.5.3.6
From: Zhu Yi <[email protected]>
Date: Wed, 3 Sep 2008 11:18:44 +0800
> From: Mohamed Abbas <[email protected]>
>
> Rx chain might change during power save transitions but it doesn't
> require sending Full-ROXN command to the firmware. Full-RXON requires
> reconnection to an AP and thus affects user experience. The patch
> avoids the Full-RXON by removing the rx_chain modification check in
> iwl_full_rxon_required function.
>
> Signed-off-by: Mohamed Abbas <[email protected]
> Signed-off-by: Tomas Winkler <[email protected]>
> Signed-off-by: Zhu Yi <[email protected]>
Acked-by: David S. Miller <[email protected]>