iwlwifi: Disable QoS when connected to a non-QoS-capable AP (Closes: #578262)

svn path=/dists/sid/linux-2.6/; revision=15758
This commit is contained in:
Ben Hutchings 2010-05-21 23:35:43 +00:00
parent 58976ad6bc
commit 89f42b2e98
4 changed files with 456 additions and 0 deletions

2
debian/changelog vendored
View File

@ -9,6 +9,8 @@ linux-2.6 (2.6.32-14) UNRELEASED; urgency=low
* macvlan: allow multiple driver backends
* Add macvtap driver (Closes: #568755)
* [ia64] Enable SGI SN support and mspec driver (Closes: #582224)
* iwlwifi: Disable QoS when connected to a non-QoS-capable AP
(Closes: #578262)
-- Ben Hutchings <ben@decadent.org.uk> Tue, 18 May 2010 02:13:44 +0100

View File

@ -0,0 +1,355 @@
From 07a6e68c8be45f9b5ea6689c8b247fa15a4fc0d4 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Mon, 29 Mar 2010 12:18:35 +0200
Subject: [PATCH 2/2] iwlwifi: manage QoS by mac stack
We activate/deactivate QoS and setup default queue parameters in iwlwifi
driver. Mac stack do the same, so we do not need repeat that work here.
Stack also will tell when disable QoS, this will fix driver when working
with older APs, that do not have QoS implemented.
Patch make "force = true" in iwl_active_qos() assuming we always want
to do with QoS what mac stack wish.
Patch also remove unused qos_cap bits, do not initialize qos_active = 0,
as we have it initialized to zero by kzalloc.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
[bwh: Adjust context for 2.6.32]
---
drivers/net/wireless/iwlwifi/iwl-agn.c | 9 --
drivers/net/wireless/iwlwifi/iwl-core.c | 147 +++------------------------
drivers/net/wireless/iwlwifi/iwl-core.h | 3 +-
drivers/net/wireless/iwlwifi/iwl-dev.h | 21 ----
drivers/net/wireless/iwlwifi/iwl3945-base.c | 7 --
5 files changed, 17 insertions(+), 170 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 921dc4a..b05f198 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2172,7 +2172,6 @@ void iwl_post_associate(struct iwl_priv *priv)
{
struct ieee80211_conf *conf = NULL;
int ret = 0;
- unsigned long flags;
if (priv->iw_mode == NL80211_IFTYPE_AP) {
IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
@@ -2257,10 +2256,6 @@ void iwl_post_associate(struct iwl_priv *priv)
if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
priv->assoc_station_added = 1;
- spin_lock_irqsave(&priv->lock, flags);
- iwl_activate_qos(priv, 0);
- spin_unlock_irqrestore(&priv->lock, flags);
-
/* the chain noise calibration will enabled PM upon completion
* If chain noise has already been run, then we need to enable
* power management here */
@@ -2384,7 +2379,6 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
void iwl_config_ap(struct iwl_priv *priv)
{
int ret = 0;
- unsigned long flags;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
@@ -2432,9 +2426,6 @@ void iwl_config_ap(struct iwl_priv *priv)
/* restore RXON assoc */
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
iwlcore_commit_rxon(priv);
- spin_lock_irqsave(&priv->lock, flags);
- iwl_activate_qos(priv, 1);
- spin_unlock_irqrestore(&priv->lock, flags);
iwl_rxon_add_station(priv, iwl_bcast_addr, 0);
}
iwl_send_beacon_cmd(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 4a4f7e4..a58e67b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -266,17 +266,13 @@ EXPORT_SYMBOL(iwl_hw_nic_init);
/*
* QoS support
*/
-void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+static void iwl_update_qos(struct iwl_priv *priv)
{
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
priv->qos_data.def_qos_parm.qos_flags = 0;
- if (priv->qos_data.qos_cap.q_AP.queue_request &&
- !priv->qos_data.qos_cap.q_AP.txop_request)
- priv->qos_data.def_qos_parm.qos_flags |=
- QOS_PARAM_FLG_TXOP_TYPE_MSK;
if (priv->qos_data.qos_active)
priv->qos_data.def_qos_parm.qos_flags |=
QOS_PARAM_FLG_UPDATE_EDCA_MSK;
@@ -284,118 +280,14 @@ void iwl_activate_qos(struct iwl_priv *priv, u8 force)
if (priv->current_ht_config.is_ht)
priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
- if (force || iwl_is_associated(priv)) {
- IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
- priv->qos_data.qos_active,
- priv->qos_data.def_qos_parm.qos_flags);
+ IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
+ priv->qos_data.qos_active,
+ priv->qos_data.def_qos_parm.qos_flags);
- iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
- sizeof(struct iwl_qosparam_cmd),
- &priv->qos_data.def_qos_parm, NULL);
- }
+ iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
+ sizeof(struct iwl_qosparam_cmd),
+ &priv->qos_data.def_qos_parm, NULL);
}
-EXPORT_SYMBOL(iwl_activate_qos);
-
-/*
- * AC CWmin CW max AIFSN TXOP Limit TXOP Limit
- * (802.11b) (802.11a/g)
- * AC_BK 15 1023 7 0 0
- * AC_BE 15 1023 3 0 0
- * AC_VI 7 15 2 6.016ms 3.008ms
- * AC_VO 3 7 2 3.264ms 1.504ms
- */
-void iwl_reset_qos(struct iwl_priv *priv)
-{
- u16 cw_min = 15;
- u16 cw_max = 1023;
- u8 aifs = 2;
- bool is_legacy = false;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&priv->lock, flags);
- /* QoS always active in AP and ADHOC mode
- * In STA mode wait for association
- */
- if (priv->iw_mode == NL80211_IFTYPE_ADHOC ||
- priv->iw_mode == NL80211_IFTYPE_AP)
- priv->qos_data.qos_active = 1;
- else
- priv->qos_data.qos_active = 0;
-
- /* check for legacy mode */
- if ((priv->iw_mode == NL80211_IFTYPE_ADHOC &&
- (priv->active_rate & IWL_OFDM_RATES_MASK) == 0) ||
- (priv->iw_mode == NL80211_IFTYPE_STATION &&
- (priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK) == 0)) {
- cw_min = 31;
- is_legacy = 1;
- }
-
- if (priv->qos_data.qos_active)
- aifs = 3;
-
- /* AC_BE */
- priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min);
- priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max);
- priv->qos_data.def_qos_parm.ac[0].aifsn = aifs;
- priv->qos_data.def_qos_parm.ac[0].edca_txop = 0;
- priv->qos_data.def_qos_parm.ac[0].reserved1 = 0;
-
- if (priv->qos_data.qos_active) {
- /* AC_BK */
- i = 1;
- priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min);
- priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max);
- priv->qos_data.def_qos_parm.ac[i].aifsn = 7;
- priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
- priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
-
- /* AC_VI */
- i = 2;
- priv->qos_data.def_qos_parm.ac[i].cw_min =
- cpu_to_le16((cw_min + 1) / 2 - 1);
- priv->qos_data.def_qos_parm.ac[i].cw_max =
- cpu_to_le16(cw_min);
- priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
- if (is_legacy)
- priv->qos_data.def_qos_parm.ac[i].edca_txop =
- cpu_to_le16(6016);
- else
- priv->qos_data.def_qos_parm.ac[i].edca_txop =
- cpu_to_le16(3008);
- priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
-
- /* AC_VO */
- i = 3;
- priv->qos_data.def_qos_parm.ac[i].cw_min =
- cpu_to_le16((cw_min + 1) / 4 - 1);
- priv->qos_data.def_qos_parm.ac[i].cw_max =
- cpu_to_le16((cw_min + 1) / 2 - 1);
- priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
- priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
- if (is_legacy)
- priv->qos_data.def_qos_parm.ac[i].edca_txop =
- cpu_to_le16(3264);
- else
- priv->qos_data.def_qos_parm.ac[i].edca_txop =
- cpu_to_le16(1504);
- } else {
- for (i = 1; i < 4; i++) {
- priv->qos_data.def_qos_parm.ac[i].cw_min =
- cpu_to_le16(cw_min);
- priv->qos_data.def_qos_parm.ac[i].cw_max =
- cpu_to_le16(cw_max);
- priv->qos_data.def_qos_parm.ac[i].aifsn = aifs;
- priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
- priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
- }
- }
- IWL_DEBUG_QOS(priv, "set QoS to default \n");
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-EXPORT_SYMBOL(iwl_reset_qos);
#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
@@ -1503,11 +1395,6 @@ int iwl_init_drv(struct iwl_priv *priv)
iwl_init_scan_params(priv);
- iwl_reset_qos(priv);
-
- priv->qos_data.qos_active = 0;
- priv->qos_data.qos_cap.val = 0;
-
priv->rates_mask = IWL_RATES_MASK;
/* Set the tx_power_user_lmt to the lowest power level
* this value will get overwritten by channel max power avg
@@ -2213,12 +2100,6 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
cpu_to_le16((params->txop * 32));
priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
- priv->qos_data.qos_active = 1;
-
- if (priv->iw_mode == NL80211_IFTYPE_AP)
- iwl_activate_qos(priv, 1);
- else if (priv->assoc_id && iwl_is_associated(priv))
- iwl_activate_qos(priv, 0);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -2452,11 +2333,8 @@ int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
IWL_DEBUG_MAC80211(priv, "leave\n");
spin_unlock_irqrestore(&priv->lock, flags);
- iwl_reset_qos(priv);
-
priv->cfg->ops->lib->post_associate(priv);
-
return 0;
}
EXPORT_SYMBOL(iwl_mac_beacon_update);
@@ -2670,6 +2548,15 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
iwl_set_tx_power(priv, conf->power_level, false);
}
+ if (changed & IEEE80211_CONF_CHANGE_QOS) {
+ bool qos_active = !!(conf->flags & IEEE80211_CONF_QOS);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->qos_data.qos_active = qos_active;
+ iwl_update_qos(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
/* call to ensure that 4965 rx_chain is set properly in monitor mode */
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);
@@ -2744,8 +2631,6 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info));
spin_unlock_irqrestore(&priv->lock, flags);
- iwl_reset_qos(priv);
-
spin_lock_irqsave(&priv->lock, flags);
priv->assoc_id = 0;
priv->assoc_capability = 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 40ec0c1..d5000c7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -266,8 +266,7 @@ struct iwl_cfg {
struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
struct ieee80211_ops *hw_ops);
void iwl_hw_detect(struct iwl_priv *priv);
-void iwl_reset_qos(struct iwl_priv *priv);
-void iwl_activate_qos(struct iwl_priv *priv, u8 force);
+void iwl_activate_qos(struct iwl_priv *priv);
int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params);
void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index cea2ee2..24faad7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -514,30 +514,9 @@ struct iwl_ht_info {
u8 non_GF_STA_present;
};
-union iwl_qos_capabity {
- struct {
- u8 edca_count:4; /* bit 0-3 */
- u8 q_ack:1; /* bit 4 */
- u8 queue_request:1; /* bit 5 */
- u8 txop_request:1; /* bit 6 */
- u8 reserved:1; /* bit 7 */
- } q_AP;
- struct {
- u8 acvo_APSD:1; /* bit 0 */
- u8 acvi_APSD:1; /* bit 1 */
- u8 ac_bk_APSD:1; /* bit 2 */
- u8 ac_be_APSD:1; /* bit 3 */
- u8 q_ack:1; /* bit 4 */
- u8 max_len:2; /* bit 5-6 */
- u8 more_data_ack:1; /* bit 7 */
- } q_STA;
- u8 val;
-};
-
/* QoS structures */
struct iwl_qos_info {
int qos_active;
- union iwl_qos_capabity qos_cap;
struct iwl_qosparam_cmd def_qos_parm;
};
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 619590d..95447ca 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -3091,8 +3091,6 @@ void iwl3945_post_associate(struct iwl_priv *priv)
break;
}
- iwl_activate_qos(priv, 0);
-
/* we have just associated, don't start scan too early */
priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
}
@@ -3805,11 +3803,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
priv->iw_mode = NL80211_IFTYPE_STATION;
- iwl_reset_qos(priv);
-
- priv->qos_data.qos_active = 0;
- priv->qos_data.qos_cap.val = 0;
-
priv->rates_mask = IWL_RATES_MASK;
priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER;
--
1.7.1

View File

@ -0,0 +1,97 @@
From 38c1a8432ffd1796a5fff4070d5c83c3d0ce7c57 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Mon, 29 Mar 2010 12:18:34 +0200
Subject: [PATCH 1/2] mac80211: explicitly disable/enable QoS
Add interface to disable/enable QoS (aka WMM or WME). Currently drivers
enable it explicitly when ->conf_tx method is called, and newer disable.
Disabling is needed for some APs, which do not support QoS, such
we should send QoS frames to them.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
[bwh: Adjust context for 2.6.32]
---
include/net/mac80211.h | 5 +++++
net/mac80211/mlme.c | 9 ++++++++-
net/mac80211/util.c | 5 +++++
3 files changed, 18 insertions(+), 1 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index c39ed07..de904fc 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -572,11 +572,15 @@ struct ieee80211_rx_status {
* may turn the device off as much as possible. Typically, this flag will
* be set when an interface is set UP but not associated or scanning, but
* it can also be unset in that case when monitor interfaces are active.
+ * @IEEE80211_CONF_QOS: Enable 802.11e QoS also know as WMM (Wireless
+ * Multimedia). On some drivers (iwlwifi is one of know) we have
+ * to enable/disable QoS explicitly.
*/
enum ieee80211_conf_flags {
IEEE80211_CONF_RADIOTAP = (1<<0),
IEEE80211_CONF_PS = (1<<1),
IEEE80211_CONF_IDLE = (1<<2),
+ IEEE80211_CONF_QOS = (1<<3),
};
@@ -599,6 +603,7 @@ enum ieee80211_conf_changed {
IEEE80211_CONF_CHANGE_CHANNEL = BIT(6),
IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7),
IEEE80211_CONF_CHANGE_IDLE = BIT(8),
+ IEEE80211_CONF_CHANGE_QOS = BIT(9),
};
/**
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 4a15df1..d3950b7 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -786,6 +786,9 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
int count;
u8 *pos;
+ if (!local->ops->conf_tx)
+ return;
+
if (!(ifmgd->flags & IEEE80211_STA_WMM_ENABLED))
return;
@@ -844,11 +847,15 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
wiphy_name(local->hw.wiphy), queue, aci, acm,
params.aifs, params.cw_min, params.cw_max, params.txop);
#endif
- if (drv_conf_tx(local, queue, &params) && local->ops->conf_tx)
+ if (drv_conf_tx(local, queue, &params))
printk(KERN_DEBUG "%s: failed to set TX queue "
"parameters for queue %d\n",
wiphy_name(local->hw.wiphy), queue);
}
+
+ /* enable WMM or activate new settings */
+ local->hw.conf.flags |= IEEE80211_CONF_QOS;
+ drv_config(local, IEEE80211_CONF_CHANGE_QOS);
}
static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 31b1085..21f11cc 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -791,6 +791,11 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
drv_conf_tx(local, queue, &qparam);
}
+
+ /* after reinitialize QoS TX queues setting to default,
+ * disable QoS at all */
+ local->hw.conf.flags &= ~IEEE80211_CONF_QOS;
+ drv_config(local, IEEE80211_CONF_CHANGE_QOS);
}
void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
--
1.7.1

View File

@ -6,3 +6,5 @@
+ bugfix/all/macvtap-fix-reference-counting.patch
+ bugfix/all/macvtap-rework-object-lifetime-rules.patch
+ features/all/macvtap-add-GSO-csum-offload-support.patch
+ bugfix/all/mac80211-explicitly-disable-enable-QoS.patch
+ bugfix/all/iwlwifi-manage-QoS-by-mac-stack.patch