All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] early HT channel setting
@ 2012-03-28  8:58 Johannes Berg
  2012-03-28  8:58 ` [PATCH 1/4] mac80211: set HT channel before association Johannes Berg
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Johannes Berg @ 2012-03-28  8:58 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

This is the patchset we've discussed earlier, setting
the HT channel on authentication and later changing
only TX control to restrict to 20 MHz (or even non-HT)
as needed/desired.

This provides a better fix for Paul's Korea regulatory
problem (covering one more corner case), makes the code
easier to follow and simplifies hardware programming.

I was holding this until ath9k_htc got fixed, but now I
think it was already broken by Paul's patch and needs  
this patchset to be fixed.

johannes


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

* [PATCH 1/4] mac80211: set HT channel before association
  2012-03-28  8:58 [PATCH 0/4] early HT channel setting Johannes Berg
@ 2012-03-28  8:58 ` Johannes Berg
  2012-03-28  8:58 ` [PATCH 2/4] mac80211: remove channel type argument from rate_update Johannes Berg
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 11+ messages in thread
From: Johannes Berg @ 2012-03-28  8:58 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

From: Johannes Berg <johannes.berg@intel.com>

Changing the channel type during operation is
confusing to some drivers and will be hard to
handle in multi-channel scenarios. Instead of
changing the channel, set it to the right HT
channel before authenticating/associating and
don't change it -- just update the 20/40 MHz
restrictions in rate control as needed when
changed by the AP.

This also fixes a problem that Paul missed in
his fix for the "regulatory makes us deaf"
issue -- when we couldn't use 40 MHz we still
associated saying we were using 40 MHz, which
could in similarly broken APs make us never
even connect successfully.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 Documentation/networking/mac80211-auth-assoc-deauth.txt |   10 
 net/mac80211/ht.c                                       |    9 
 net/mac80211/ieee80211_i.h                              |   10 
 net/mac80211/mlme.c                                     |  226 +++++++---------
 4 files changed, 117 insertions(+), 138 deletions(-)

--- a/net/mac80211/ieee80211_i.h	2012-03-16 14:13:30.000000000 +0100
+++ b/net/mac80211/ieee80211_i.h	2012-03-16 14:14:12.000000000 +0100
@@ -378,6 +378,7 @@ enum ieee80211_sta_flags {
 	IEEE80211_STA_UAPSD_ENABLED	= BIT(7),
 	IEEE80211_STA_NULLFUNC_ACKED	= BIT(8),
 	IEEE80211_STA_RESET_SIGNAL_AVE	= BIT(9),
+	IEEE80211_STA_DISABLE_40MHZ	= BIT(10),
 };
 
 struct ieee80211_mgd_auth_data {
@@ -511,6 +512,8 @@ struct ieee80211_if_managed {
 	int rssi_min_thold, rssi_max_thold;
 	int last_ave_beacon_signal;
 
+	enum nl80211_channel_type tx_chantype;
+
 	struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */
 	struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */
 };
@@ -667,12 +670,6 @@ struct ieee80211_sub_if_data {
 
 	char name[IFNAMSIZ];
 
-	/*
-	 * keep track of whether the HT opmode (stored in
-	 * vif.bss_info.ht_operation_mode) is valid.
-	 */
-	bool ht_opmode_valid;
-
 	/* to detect idle changes */
 	bool old_idle;
 
@@ -1300,7 +1297,6 @@ netdev_tx_t ieee80211_subif_start_xmit(s
 				       struct net_device *dev);
 
 /* HT */
-bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata);
 void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
 				     struct ieee80211_sta_ht_cap *ht_cap);
 void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
--- a/net/mac80211/mlme.c	2012-03-16 14:13:30.000000000 +0100
+++ b/net/mac80211/mlme.c	2012-03-16 14:14:12.000000000 +0100
@@ -171,110 +171,57 @@ static int ecw2cw(int ecw)
 	return (1 << ecw) - 1;
 }
 
-/*
- * ieee80211_enable_ht should be called only after the operating band
- * has been determined as ht configuration depends on the hw's
- * HT abilities for a specific band.
- */
-static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
-			       struct ieee80211_ht_operation *ht_oper,
-			       const u8 *bssid, u16 ap_ht_cap_flags,
-			       bool beacon_htcap_ie)
+static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
+				  struct ieee80211_ht_operation *ht_oper,
+				  const u8 *bssid, bool reconfig)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_supported_band *sband;
 	struct sta_info *sta;
 	u32 changed = 0;
-	int ht_cfreq;
 	u16 ht_opmode;
-	bool enable_ht = true;
-	enum nl80211_channel_type prev_chantype;
-	enum nl80211_channel_type rx_channel_type = NL80211_CHAN_NO_HT;
-	enum nl80211_channel_type tx_channel_type;
+	enum nl80211_channel_type channel_type;
 
 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-	prev_chantype = sdata->vif.bss_conf.channel_type;
-
-
-	ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
-						  sband->band);
-	/* check that channel matches the right operating channel */
-	if (local->hw.conf.channel->center_freq != ht_cfreq) {
-		/* Some APs mess this up, evidently.
-		 * Netgear WNDR3700 sometimes reports 4 higher than
-		 * the actual channel, for instance.
-		 */
-		printk(KERN_DEBUG
-		       "%s: Wrong control channel in association"
-		       " response: configured center-freq: %d"
-		       " ht-cfreq: %d  ht->control_chan: %d"
-		       " band: %d.  Disabling HT.\n",
-		       sdata->name,
-		       local->hw.conf.channel->center_freq,
-		       ht_cfreq, ht_oper->primary_chan,
-		       sband->band);
-		enable_ht = false;
-	}
-
-	if (enable_ht) {
-		rx_channel_type = NL80211_CHAN_HT20;
-
-		if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
-		    !ieee80111_cfg_override_disables_ht40(sdata) &&
-		    (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
-		    (ht_oper->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
-			switch (ht_oper->ht_param &
-					IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
-			case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-				rx_channel_type = NL80211_CHAN_HT40PLUS;
-				break;
-			case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-				rx_channel_type = NL80211_CHAN_HT40MINUS;
-				break;
-			}
-		}
-	}
+	channel_type = local->hw.conf.channel_type;
 
-	tx_channel_type = ieee80211_get_tx_channel_type(local, rx_channel_type);
+	if (WARN_ON_ONCE(channel_type == NL80211_CHAN_NO_HT))
+		return 0;
 
-	if (local->tmp_channel)
-		local->tmp_channel_type = rx_channel_type;
+	channel_type = ieee80211_get_tx_channel_type(local, channel_type);
 
-	if (!ieee80211_set_channel_type(local, sdata, rx_channel_type)) {
-		/* can only fail due to HT40+/- mismatch */
-		rx_channel_type = NL80211_CHAN_HT20;
-		WARN_ON(!ieee80211_set_channel_type(local, sdata,
-						    rx_channel_type));
-	}
+	/* This can change during the lifetime of the BSS */
+	if (!(ht_oper->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
+		channel_type = NL80211_CHAN_HT20;
 
-	if (beacon_htcap_ie && (prev_chantype != rx_channel_type)) {
-		/*
-		 * Whenever the AP announces the HT mode change that can be
-		 * 40MHz intolerant or etc., it would be safer to stop tx
-		 * queues before doing hw config to avoid buffer overflow.
-		 */
-		ieee80211_stop_queues_by_reason(&sdata->local->hw,
+	if (!reconfig || (sdata->u.mgd.tx_chantype != channel_type)) {
+		if (reconfig) {
+			/*
+			 * Whenever the AP announces the HT mode changed
+			 * (e.g. 40 MHz intolerant) stop queues to avoid
+			 * sending out frames while the rate control is
+			 * reconfiguring.
+			 */
+			ieee80211_stop_queues_by_reason(&sdata->local->hw,
 				IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
 
-		/* flush out all packets */
-		synchronize_net();
-
-		drv_flush(local, false);
-	}
+			/* flush out all packets */
+			synchronize_net();
 
-	/* channel_type change automatically detected */
-	ieee80211_hw_config(local, 0);
+			drv_flush(local, false);
+		}
 
-	if (prev_chantype != tx_channel_type) {
 		rcu_read_lock();
 		sta = sta_info_get(sdata, bssid);
 		if (sta)
 			rate_control_rate_update(local, sband, sta,
 						 IEEE80211_RC_HT_CHANGED,
-						 tx_channel_type);
+						 channel_type);
 		rcu_read_unlock();
 
-		if (beacon_htcap_ie)
+		sdata->u.mgd.tx_chantype = channel_type;
+
+		if (reconfig)
 			ieee80211_wake_queues_by_reason(&sdata->local->hw,
 				IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
 	}
@@ -282,12 +229,9 @@ static u32 ieee80211_enable_ht(struct ie
 	ht_opmode = le16_to_cpu(ht_oper->operation_mode);
 
 	/* if bss configuration changed store the new one */
-	if (sdata->ht_opmode_valid != enable_ht ||
-	    sdata->vif.bss_conf.ht_operation_mode != ht_opmode ||
-	    prev_chantype != rx_channel_type) {
+	if (!reconfig || (sdata->vif.bss_conf.ht_operation_mode != ht_opmode)) {
 		changed |= BSS_CHANGED_HT;
 		sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
-		sdata->ht_opmode_valid = enable_ht;
 	}
 
 	return changed;
@@ -350,6 +294,16 @@ static void ieee80211_add_ht_ie(struct i
 		break;
 	}
 
+	/*
+	 * If 40 MHz was disabled associate as though we weren't
+	 * capable of 40 MHz -- some broken APs will never fall
+	 * back to trying to transmit in 20 MHz.
+	 */
+	if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_40MHZ) {
+		cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+		cap &= ~IEEE80211_HT_CAP_SGI_40;
+	}
+
 	/* set SM PS mode properly */
 	cap &= ~IEEE80211_HT_CAP_SM_PS;
 	switch (smps) {
@@ -1427,7 +1381,6 @@ static void ieee80211_set_disassoc(struc
 	sdata->vif.bss_conf.assoc = false;
 
 	/* on the next assoc, re-program HT parameters */
-	sdata->ht_opmode_valid = false;
 	memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
 	memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
 
@@ -1992,7 +1945,6 @@ static bool ieee80211_assoc_success(stru
 	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
 	u32 changed = 0;
 	int err;
-	u16 ap_ht_cap_flags;
 
 	/* AssocResp and ReassocResp have identical structure */
 
@@ -2043,8 +1995,6 @@ static bool ieee80211_assoc_success(stru
 		ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
 				elems.ht_cap_elem, &sta->sta.ht_cap);
 
-	ap_ht_cap_flags = sta->sta.ht_cap.cap;
-
 	rate_control_rate_init(sta);
 
 	if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
@@ -2086,9 +2036,8 @@ static bool ieee80211_assoc_success(stru
 
 	if (elems.ht_operation && elems.wmm_param &&
 	    !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
-		changed |= ieee80211_enable_ht(sdata, elems.ht_operation,
-					       cbss->bssid, ap_ht_cap_flags,
-					       false);
+		changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
+						  cbss->bssid, false);
 
 	/* set AID and assoc capability,
 	 * ieee80211_set_associated() will tell the driver */
@@ -2498,29 +2447,12 @@ static void ieee80211_rx_mgmt_beacon(str
 
 	if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param &&
 	    !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) {
-		struct sta_info *sta;
 		struct ieee80211_supported_band *sband;
-		u16 ap_ht_cap_flags;
-
-		rcu_read_lock();
-
-		sta = sta_info_get(sdata, bssid);
-		if (WARN_ON(!sta)) {
-			rcu_read_unlock();
-			return;
-		}
 
 		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
-		ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
-				elems.ht_cap_elem, &sta->sta.ht_cap);
-
-		ap_ht_cap_flags = sta->sta.ht_cap.cap;
-
-		rcu_read_unlock();
-
-		changed |= ieee80211_enable_ht(sdata, elems.ht_operation,
-					       bssid, ap_ht_cap_flags, true);
+		changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
+						  bssid, true);
 	}
 
 	/* Note: country IE parsing is done for us by cfg80211 */
@@ -3052,6 +2984,11 @@ static int ieee80211_prep_connection(str
 	struct sta_info *sta;
 	bool have_sta = false;
 	int err;
+	int ht_cfreq;
+	enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+	const u8 *ht_oper_ie;
+	const struct ieee80211_ht_operation *ht_oper = NULL;
+	struct ieee80211_supported_band *sband;
 
 	if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data))
 		return -EINVAL;
@@ -3073,17 +3010,76 @@ static int ieee80211_prep_connection(str
 	mutex_unlock(&local->mtx);
 
 	/* switch to the right channel */
+	sband = local->hw.wiphy->bands[cbss->channel->band];
+
+	ifmgd->flags &= ~IEEE80211_STA_DISABLE_40MHZ;
+
+	if (sband->ht_cap.ht_supported) {
+		ht_oper_ie = cfg80211_find_ie(WLAN_EID_HT_OPERATION,
+					      cbss->information_elements,
+					      cbss->len_information_elements);
+		if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper))
+			ht_oper = (void *)(ht_oper_ie + 2);
+	}
+
+	if (ht_oper) {
+		ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
+							  cbss->channel->band);
+		/* check that channel matches the right operating channel */
+		if (cbss->channel->center_freq != ht_cfreq) {
+			/*
+			 * It's possible that some APs are confused here;
+			 * Netgear WNDR3700 sometimes reports 4 higher than
+			 * the actual channel in association responses, but
+			 * since we look at probe response/beacon data here
+			 * it should be OK.
+			 */
+			printk(KERN_DEBUG
+			       "%s: Wrong control channel: center-freq: %d"
+			       " ht-cfreq: %d ht->primary_chan: %d"
+			       " band: %d. Disabling HT.\n",
+			       sdata->name, cbss->channel->center_freq,
+			       ht_cfreq, ht_oper->primary_chan,
+			       cbss->channel->band);
+			ht_oper = NULL;
+		}
+	}
+
+	if (ht_oper) {
+		channel_type = NL80211_CHAN_HT20;
+
+		if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+			switch (ht_oper->ht_param &
+					IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+			case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+				channel_type = NL80211_CHAN_HT40PLUS;
+				break;
+			case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+				channel_type = NL80211_CHAN_HT40MINUS;
+				break;
+			}
+		}
+	}
+
+	if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
+		/* can only fail due to HT40+/- mismatch */
+		channel_type = NL80211_CHAN_HT20;
+		printk(KERN_DEBUG
+		       "%s: disabling 40 MHz due to multi-vif mismatch\n",
+		       sdata->name);
+		ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
+		WARN_ON(!ieee80211_set_channel_type(local, sdata,
+						    channel_type));
+	}
+
 	local->oper_channel = cbss->channel;
-	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+	ieee80211_hw_config(local, 0);
 
 	if (!have_sta) {
-		struct ieee80211_supported_band *sband;
 		u32 rates = 0, basic_rates = 0;
 		bool have_higher_than_11mbit;
 		int min_rate = INT_MAX, min_rate_index = -1;
 
-		sband = sdata->local->hw.wiphy->bands[cbss->channel->band];
-
 		ieee80211_get_rates(sband, bss->supp_rates,
 				    bss->supp_rates_len,
 				    &rates, &basic_rates,
--- a/net/mac80211/ht.c	2012-03-15 19:37:43.000000000 +0100
+++ b/net/mac80211/ht.c	2012-03-16 14:14:12.000000000 +0100
@@ -19,15 +19,6 @@
 #include "ieee80211_i.h"
 #include "rate.h"
 
-bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata)
-{
-	const __le16 flg = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40);
-	if ((sdata->u.mgd.ht_capa_mask.cap_info & flg) &&
-	    !(sdata->u.mgd.ht_capa.cap_info & flg))
-		return true;
-	return false;
-}
-
 static void __check_htcap_disable(struct ieee80211_sub_if_data *sdata,
 				  struct ieee80211_sta_ht_cap *ht_cap,
 				  u16 flag)
--- a/Documentation/networking/mac80211-auth-assoc-deauth.txt	2012-03-15 20:43:13.000000000 +0100
+++ b/Documentation/networking/mac80211-auth-assoc-deauth.txt	2012-03-16 14:14:12.000000000 +0100
@@ -23,7 +23,7 @@ BA session stop & deauth/disassoc frames
 end note
 end
 
-mac80211->driver: config(channel, non-HT)
+mac80211->driver: config(channel, channel type)
 mac80211->driver: bss_info_changed(set BSSID, basic rate bitmap)
 mac80211->driver: sta_state(AP, exists)
 
@@ -51,7 +51,7 @@ note over mac80211,driver: cleanup like
 end
 
 alt not previously authenticated (FT)
-mac80211->driver: config(channel, non-HT)
+mac80211->driver: config(channel, channel type)
 mac80211->driver: bss_info_changed(set BSSID, basic rate bitmap)
 mac80211->driver: sta_state(AP, exists)
 mac80211->driver: sta_state(AP, authenticated)
@@ -67,10 +67,6 @@ end
 
 mac80211->driver: set up QoS parameters
 
-alt is HT channel
-mac80211->driver: config(channel, HT params)
-end
-
 mac80211->driver: bss_info_changed(QoS, HT, associated with AID)
 mac80211->userspace: associated
 
@@ -95,5 +91,5 @@ mac80211->driver: sta_state(AP,exists)
 mac80211->driver: sta_state(AP,not-exists)
 mac80211->driver: turn off powersave
 mac80211->driver: bss_info_changed(clear BSSID, not associated, no QoS, ...)
-mac80211->driver: config(non-HT channel type)
+mac80211->driver: config(channel type to non-HT)
 mac80211->userspace: disconnected



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

* [PATCH 2/4] mac80211: remove channel type argument from rate_update
  2012-03-28  8:58 [PATCH 0/4] early HT channel setting Johannes Berg
  2012-03-28  8:58 ` [PATCH 1/4] mac80211: set HT channel before association Johannes Berg
@ 2012-03-28  8:58 ` Johannes Berg
  2012-03-30  4:37   ` Sujith Manoharan
  2012-03-28  8:58 ` [PATCH 3/4] mac80211: remove queue stop on rate control update Johannes Berg
  2012-03-28  8:58 ` [PATCH 4/4] mac80211: notify driver of rate control updates Johannes Berg
  3 siblings, 1 reply; 11+ messages in thread
From: Johannes Berg @ 2012-03-28  8:58 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

From: Johannes Berg <johannes.berg@intel.com>

The channel type argument to the rate_update()
callback isn't really the correct way to give
the rate control algorithm about the desired
RX bandwidth of the peer.

Remove this argument, and instead update the
STA capabilities with 20/40 appropriately. The
SMPS update done by this callback works in the
same way, so this makes the callback cleaner.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 drivers/net/wireless/ath/ath9k/rc.c |    5 +--
 drivers/net/wireless/rtlwifi/rc.c   |    3 --
 include/net/mac80211.h              |    5 +--
 net/mac80211/chan.c                 |   26 ------------------
 net/mac80211/ieee80211_i.h          |    5 ---
 net/mac80211/mlme.c                 |   51 ++++++++++++++++++++++++------------
 net/mac80211/rate.h                 |    5 +--
 net/mac80211/rc80211_minstrel_ht.c  |   15 ++--------
 net/mac80211/rx.c                   |    7 +---
 net/mac80211/sta_info.h             |    2 +
 10 files changed, 50 insertions(+), 74 deletions(-)

--- a/include/net/mac80211.h	2012-03-26 12:25:00.000000000 +0200
+++ b/include/net/mac80211.h	2012-03-26 12:25:15.000000000 +0200
@@ -3567,9 +3567,8 @@ struct rate_control_ops {
 	void (*rate_init)(void *priv, struct ieee80211_supported_band *sband,
 			  struct ieee80211_sta *sta, void *priv_sta);
 	void (*rate_update)(void *priv, struct ieee80211_supported_band *sband,
-			    struct ieee80211_sta *sta,
-			    void *priv_sta, u32 changed,
-			    enum nl80211_channel_type oper_chan_type);
+			    struct ieee80211_sta *sta, void *priv_sta,
+			    u32 changed);
 	void (*free_sta)(void *priv, struct ieee80211_sta *sta,
 			 void *priv_sta);
 
--- a/drivers/net/wireless/ath/ath9k/rc.c	2012-03-23 17:58:42.000000000 +0100
+++ b/drivers/net/wireless/ath/ath9k/rc.c	2012-03-26 12:25:15.000000000 +0200
@@ -1436,7 +1436,7 @@ static void ath_rate_init(void *priv, st
 
 static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
 			    struct ieee80211_sta *sta, void *priv_sta,
-			    u32 changed, enum nl80211_channel_type oper_chan_type)
+			    u32 changed)
 {
 	struct ath_softc *sc = priv;
 	struct ath_rate_priv *ath_rc_priv = priv_sta;
@@ -1451,8 +1451,7 @@ static void ath_rate_update(void *priv,
 		if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
 			return;
 
-		if (oper_chan_type == NL80211_CHAN_HT40MINUS ||
-		    oper_chan_type == NL80211_CHAN_HT40PLUS)
+		if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
 			oper_cw40 = true;
 
 		if (oper_cw40)
--- a/net/mac80211/rx.c	2012-03-23 17:58:42.000000000 +0100
+++ b/net/mac80211/rx.c	2012-03-26 12:25:15.000000000 +0200
@@ -2269,11 +2269,8 @@ ieee80211_rx_h_action(struct ieee80211_r
 
 			sband = rx->local->hw.wiphy->bands[status->band];
 
-			rate_control_rate_update(
-				local, sband, rx->sta,
-				IEEE80211_RC_SMPS_CHANGED,
-				ieee80211_get_tx_channel_type(
-					local, local->_oper_channel_type));
+			rate_control_rate_update(local, sband, rx->sta,
+						 IEEE80211_RC_SMPS_CHANGED);
 			goto handled;
 		}
 		default:
--- a/net/mac80211/mlme.c	2012-03-26 12:25:14.000000000 +0200
+++ b/net/mac80211/mlme.c	2012-03-26 12:25:15.000000000 +0200
@@ -180,21 +180,38 @@ static u32 ieee80211_config_ht_tx(struct
 	struct sta_info *sta;
 	u32 changed = 0;
 	u16 ht_opmode;
-	enum nl80211_channel_type channel_type;
+	bool disable_40 = false;
 
 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-	channel_type = local->hw.conf.channel_type;
 
-	if (WARN_ON_ONCE(channel_type == NL80211_CHAN_NO_HT))
-		return 0;
-
-	channel_type = ieee80211_get_tx_channel_type(local, channel_type);
+	switch (sdata->vif.bss_conf.channel_type) {
+	case NL80211_CHAN_HT40PLUS:
+		if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40PLUS)
+			disable_40 = true;
+		break;
+	case NL80211_CHAN_HT40MINUS:
+		if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40MINUS)
+			disable_40 = true;
+		break;
+	default:
+		break;
+	}
 
 	/* This can change during the lifetime of the BSS */
 	if (!(ht_oper->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
-		channel_type = NL80211_CHAN_HT20;
+		disable_40 = true;
+
+	mutex_lock(&local->sta_mtx);
+	sta = sta_info_get(sdata, bssid);
 
-	if (!reconfig || (sdata->u.mgd.tx_chantype != channel_type)) {
+	WARN_ON_ONCE(!sta);
+
+	if (sta && !sta->supports_40mhz)
+		disable_40 = true;
+
+	if (sta && (!reconfig ||
+		    (disable_40 != !!(sta->sta.ht_cap.cap &
+					IEEE80211_HT_CAP_SUP_WIDTH_20_40)))) {
 		if (reconfig) {
 			/*
 			 * Whenever the AP announces the HT mode changed
@@ -211,20 +228,19 @@ static u32 ieee80211_config_ht_tx(struct
 			drv_flush(local, false);
 		}
 
-		rcu_read_lock();
-		sta = sta_info_get(sdata, bssid);
-		if (sta)
-			rate_control_rate_update(local, sband, sta,
-						 IEEE80211_RC_HT_CHANGED,
-						 channel_type);
-		rcu_read_unlock();
+		if (disable_40)
+			sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+		else
+			sta->sta.ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 
-		sdata->u.mgd.tx_chantype = channel_type;
+		rate_control_rate_update(local, sband, sta,
+					 IEEE80211_RC_HT_CHANGED);
 
 		if (reconfig)
 			ieee80211_wake_queues_by_reason(&sdata->local->hw,
 				IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
 	}
+	mutex_unlock(&local->sta_mtx);
 
 	ht_opmode = le16_to_cpu(ht_oper->operation_mode);
 
@@ -1995,6 +2011,9 @@ static bool ieee80211_assoc_success(stru
 		ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
 				elems.ht_cap_elem, &sta->sta.ht_cap);
 
+	sta->supports_40mhz =
+		sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
 	rate_control_rate_init(sta);
 
 	if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
--- a/net/mac80211/rate.h	2012-03-23 17:58:42.000000000 +0100
+++ b/net/mac80211/rate.h	2012-03-26 12:25:15.000000000 +0200
@@ -63,8 +63,7 @@ static inline void rate_control_rate_ini
 
 static inline void rate_control_rate_update(struct ieee80211_local *local,
 				    struct ieee80211_supported_band *sband,
-				    struct sta_info *sta, u32 changed,
-				    enum nl80211_channel_type oper_chan_type)
+				    struct sta_info *sta, u32 changed)
 {
 	struct rate_control_ref *ref = local->rate_ctrl;
 	struct ieee80211_sta *ista = &sta->sta;
@@ -72,7 +71,7 @@ static inline void rate_control_rate_upd
 
 	if (ref && ref->ops->rate_update)
 		ref->ops->rate_update(ref->priv, sband, ista,
-				      priv_sta, changed, oper_chan_type);
+				      priv_sta, changed);
 }
 
 static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
--- a/net/mac80211/rc80211_minstrel_ht.c	2012-03-23 17:58:42.000000000 +0100
+++ b/net/mac80211/rc80211_minstrel_ht.c	2012-03-26 12:25:15.000000000 +0200
@@ -686,8 +686,7 @@ minstrel_ht_get_rate(void *priv, struct
 
 static void
 minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
-                        struct ieee80211_sta *sta, void *priv_sta,
-			enum nl80211_channel_type oper_chan_type)
+                        struct ieee80211_sta *sta, void *priv_sta)
 {
 	struct minstrel_priv *mp = priv;
 	struct minstrel_ht_sta_priv *msp = priv_sta;
@@ -735,10 +734,6 @@ minstrel_ht_update_caps(void *priv, stru
 	if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING)
 		mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
 
-	if (oper_chan_type != NL80211_CHAN_HT40MINUS &&
-	    oper_chan_type != NL80211_CHAN_HT40PLUS)
-		sta_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-
 	smps = (sta_cap & IEEE80211_HT_CAP_SM_PS) >>
 		IEEE80211_HT_CAP_SM_PS_SHIFT;
 
@@ -788,17 +783,15 @@ static void
 minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband,
                       struct ieee80211_sta *sta, void *priv_sta)
 {
-	struct minstrel_priv *mp = priv;
-
-	minstrel_ht_update_caps(priv, sband, sta, priv_sta, mp->hw->conf.channel_type);
+	minstrel_ht_update_caps(priv, sband, sta, priv_sta);
 }
 
 static void
 minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband,
                         struct ieee80211_sta *sta, void *priv_sta,
-                        u32 changed, enum nl80211_channel_type oper_chan_type)
+                        u32 changed)
 {
-	minstrel_ht_update_caps(priv, sband, sta, priv_sta, oper_chan_type);
+	minstrel_ht_update_caps(priv, sband, sta, priv_sta);
 }
 
 static void *
--- a/drivers/net/wireless/rtlwifi/rc.c	2012-03-23 17:58:42.000000000 +0100
+++ b/drivers/net/wireless/rtlwifi/rc.c	2012-03-26 12:25:15.000000000 +0200
@@ -225,8 +225,7 @@ static void rtl_rate_init(void *ppriv,
 static void rtl_rate_update(void *ppriv,
 			    struct ieee80211_supported_band *sband,
 			    struct ieee80211_sta *sta, void *priv_sta,
-			    u32 changed,
-			    enum nl80211_channel_type oper_chan_type)
+			    u32 changed)
 {
 }
 
--- a/net/mac80211/chan.c	2012-03-23 17:58:42.000000000 +0100
+++ b/net/mac80211/chan.c	2012-03-26 12:25:15.000000000 +0200
@@ -135,29 +135,3 @@ bool ieee80211_set_channel_type(struct i
 
 	return result;
 }
-
-/*
- * ieee80211_get_tx_channel_type returns the channel type we should
- * use for packet transmission, given the channel capability and
- * whatever regulatory flags we have been given.
- */
-enum nl80211_channel_type ieee80211_get_tx_channel_type(
-				struct ieee80211_local *local,
-				enum nl80211_channel_type channel_type)
-{
-	switch (channel_type) {
-	case NL80211_CHAN_HT40PLUS:
-		if (local->hw.conf.channel->flags &
-				IEEE80211_CHAN_NO_HT40PLUS)
-			return NL80211_CHAN_HT20;
-		break;
-	case NL80211_CHAN_HT40MINUS:
-		if (local->hw.conf.channel->flags &
-				IEEE80211_CHAN_NO_HT40MINUS)
-			return NL80211_CHAN_HT20;
-		break;
-	default:
-		break;
-	}
-	return channel_type;
-}
--- a/net/mac80211/ieee80211_i.h	2012-03-26 12:25:14.000000000 +0200
+++ b/net/mac80211/ieee80211_i.h	2012-03-26 12:25:15.000000000 +0200
@@ -512,8 +512,6 @@ struct ieee80211_if_managed {
 	int rssi_min_thold, rssi_max_thold;
 	int last_ave_beacon_signal;
 
-	enum nl80211_channel_type tx_chantype;
-
 	struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */
 	struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */
 };
@@ -1501,9 +1499,6 @@ bool ieee80211_set_channel_type(struct i
 				enum nl80211_channel_type chantype);
 enum nl80211_channel_type
 ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper);
-enum nl80211_channel_type ieee80211_get_tx_channel_type(
-					struct ieee80211_local *local,
-					enum nl80211_channel_type channel_type);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
--- a/net/mac80211/sta_info.h	2012-03-23 17:58:42.000000000 +0100
+++ b/net/mac80211/sta_info.h	2012-03-26 12:25:15.000000000 +0200
@@ -365,6 +365,8 @@ struct sta_info {
 	unsigned int lost_packets;
 	unsigned int beacon_loss_count;
 
+	bool supports_40mhz;
+
 	/* keep last! */
 	struct ieee80211_sta sta;
 };



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

* [PATCH 3/4] mac80211: remove queue stop on rate control update
  2012-03-28  8:58 [PATCH 0/4] early HT channel setting Johannes Berg
  2012-03-28  8:58 ` [PATCH 1/4] mac80211: set HT channel before association Johannes Berg
  2012-03-28  8:58 ` [PATCH 2/4] mac80211: remove channel type argument from rate_update Johannes Berg
@ 2012-03-28  8:58 ` Johannes Berg
  2012-03-28  8:58 ` [PATCH 4/4] mac80211: notify driver of rate control updates Johannes Berg
  3 siblings, 0 replies; 11+ messages in thread
From: Johannes Berg @ 2012-03-28  8:58 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

From: Johannes Berg <johannes.berg@intel.com>

We currently stop the queue when changing the rate
control between 20/40 MHz in the BSS. This seems to
have been necessary when we actually changed the
channel, but now that we just update the station it
doesn't seem right any more. Remove it.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/ieee80211_i.h |    1 -
 net/mac80211/mlme.c        |   19 -------------------
 2 files changed, 20 deletions(-)

--- a/net/mac80211/ieee80211_i.h	2012-03-16 14:14:19.000000000 +0100
+++ b/net/mac80211/ieee80211_i.h	2012-03-16 14:14:20.000000000 +0100
@@ -757,7 +757,6 @@ enum queue_stop_reason {
 	IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
 	IEEE80211_QUEUE_STOP_REASON_SUSPEND,
 	IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
-	IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE,
 };
 
 #ifdef CONFIG_MAC80211_LEDS
--- a/net/mac80211/mlme.c	2012-03-16 14:14:19.000000000 +0100
+++ b/net/mac80211/mlme.c	2012-03-16 14:14:20.000000000 +0100
@@ -212,21 +212,6 @@ static u32 ieee80211_config_ht_tx(struct
 	if (sta && (!reconfig ||
 		    (disable_40 != !!(sta->sta.ht_cap.cap &
 					IEEE80211_HT_CAP_SUP_WIDTH_20_40)))) {
-		if (reconfig) {
-			/*
-			 * Whenever the AP announces the HT mode changed
-			 * (e.g. 40 MHz intolerant) stop queues to avoid
-			 * sending out frames while the rate control is
-			 * reconfiguring.
-			 */
-			ieee80211_stop_queues_by_reason(&sdata->local->hw,
-				IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
-
-			/* flush out all packets */
-			synchronize_net();
-
-			drv_flush(local, false);
-		}
 
 		if (disable_40)
 			sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
@@ -235,10 +220,6 @@ static u32 ieee80211_config_ht_tx(struct
 
 		rate_control_rate_update(local, sband, sta,
 					 IEEE80211_RC_HT_CHANGED);
-
-		if (reconfig)
-			ieee80211_wake_queues_by_reason(&sdata->local->hw,
-				IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
 	}
 	mutex_unlock(&local->sta_mtx);
 



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

* [PATCH 4/4] mac80211: notify driver of rate control updates
  2012-03-28  8:58 [PATCH 0/4] early HT channel setting Johannes Berg
                   ` (2 preceding siblings ...)
  2012-03-28  8:58 ` [PATCH 3/4] mac80211: remove queue stop on rate control update Johannes Berg
@ 2012-03-28  8:58 ` Johannes Berg
  2012-03-29 19:13   ` Eliad Peller
  2012-03-30  6:43   ` [PATCH 4/4 v2] " Johannes Berg
  3 siblings, 2 replies; 11+ messages in thread
From: Johannes Berg @ 2012-03-28  8:58 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

From: Johannes Berg <johannes.berg@intel.com>

Devices that have internal rate control need to be
notified when the bandwidth or SMPS state changes
just like external rate control algorithms get a
notification now.

Add this notification and clarify the change bits
while at it, the HT_CHANGED bit really meant only
bandwidth changed.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 Documentation/DocBook/80211.tmpl    |    2 -
 drivers/net/wireless/ath/ath9k/rc.c |    2 -
 include/net/mac80211.h              |   37 +++++++++++++++++++++++-------------
 net/mac80211/driver-ops.h           |   17 ++++++++++++++++
 net/mac80211/driver-trace.h         |   28 +++++++++++++++++++++++++++
 net/mac80211/mlme.c                 |    2 -
 net/mac80211/rate.h                 |    2 +
 7 files changed, 74 insertions(+), 16 deletions(-)

--- a/Documentation/DocBook/80211.tmpl	2012-03-16 14:13:10.000000000 +0100
+++ b/Documentation/DocBook/80211.tmpl	2012-03-16 14:25:57.000000000 +0100
@@ -533,7 +533,7 @@ MISSING
 !Finclude/net/mac80211.h ieee80211_start_tx_ba_cb_irqsafe
 !Finclude/net/mac80211.h ieee80211_stop_tx_ba_session
 !Finclude/net/mac80211.h ieee80211_stop_tx_ba_cb_irqsafe
-!Finclude/net/mac80211.h rate_control_changed
+!Finclude/net/mac80211.h ieee80211_rate_control_changed
 !Finclude/net/mac80211.h ieee80211_tx_rate_control
 !Finclude/net/mac80211.h rate_control_send_low
       </chapter>
--- a/include/net/mac80211.h	2012-03-16 14:14:31.000000000 +0100
+++ b/include/net/mac80211.h	2012-03-16 14:36:25.000000000 +0100
@@ -1778,6 +1778,18 @@ enum ieee80211_frame_release_type {
 };
 
 /**
+ * enum ieee80211_rate_control_changed - flags to indicate what changed
+ *
+ * @IEEE80211_RC_BW_CHANGED: The bandwidth that can be used to transmit
+ *	to this station changed.
+ * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed.
+ */
+enum ieee80211_rate_control_changed {
+	IEEE80211_RC_BW_CHANGED		= BIT(0),
+	IEEE80211_RC_SMPS_CHANGED	= BIT(1),
+};
+
+/**
  * struct ieee80211_ops - callbacks from mac80211 to the driver
  *
  * This structure contains various callbacks that the driver may
@@ -1978,6 +1990,14 @@ enum ieee80211_frame_release_type {
  *	up the list of states.
  *	The callback can sleep.
  *
+ * @sta_rc_update: Notifies the driver of changes to the bitrates that can be
+ *	used to transmit to the station. The changes are advertised with bits
+ *	from &enum ieee80211_rate_control_changed and the values are reflected
+ *	in the station data. This callback should only be used when the driver
+ *	uses hardware rate control (%IEEE80211_HW_HAS_RATE_CONTROL) since
+ *	otherwise the rate control algorithm is notified directly.
+ *	Must be atomic.
+ *
  * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
  *	bursting) for a hardware TX queue.
  *	Returns a negative error code on failure.
@@ -2194,6 +2214,10 @@ struct ieee80211_ops {
 			 struct ieee80211_sta *sta,
 			 enum ieee80211_sta_state old_state,
 			 enum ieee80211_sta_state new_state);
+	void (*sta_rc_update)(struct ieee80211_hw *hw,
+			      struct ieee80211_vif *vif,
+			      struct ieee80211_sta *sta,
+			      u32 changed);
 	int (*conf_tx)(struct ieee80211_hw *hw,
 		       struct ieee80211_vif *vif, u16 queue,
 		       const struct ieee80211_tx_queue_params *params);
@@ -3510,19 +3534,6 @@ void ieee80211_send_bar(struct ieee80211
 /* Rate control API */
 
 /**
- * enum rate_control_changed - flags to indicate which parameter changed
- *
- * @IEEE80211_RC_HT_CHANGED: The HT parameters of the operating channel have
- *	changed, rate control algorithm can update its internal state if needed.
- * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed, the rate
- *	control algorithm needs to adjust accordingly.
- */
-enum rate_control_changed {
-	IEEE80211_RC_HT_CHANGED		= BIT(0),
-	IEEE80211_RC_SMPS_CHANGED	= BIT(1),
-};
-
-/**
  * struct ieee80211_tx_rate_control - rate control information for/from RC algo
  *
  * @hw: The hardware the algorithm is invoked for.
--- a/drivers/net/wireless/ath/ath9k/rc.c	2012-03-16 14:14:31.000000000 +0100
+++ b/drivers/net/wireless/ath/ath9k/rc.c	2012-03-16 14:28:34.000000000 +0100
@@ -1447,7 +1447,7 @@ static void ath_rate_update(void *priv,
 
 	/* FIXME: Handle AP mode later when we support CWM */
 
-	if (changed & IEEE80211_RC_HT_CHANGED) {
+	if (changed & IEEE80211_RC_BW_CHANGED) {
 		if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
 			return;
 
--- a/net/mac80211/mlme.c	2012-03-16 14:23:40.000000000 +0100
+++ b/net/mac80211/mlme.c	2012-03-16 14:28:30.000000000 +0100
@@ -219,7 +219,7 @@ static u32 ieee80211_config_ht_tx(struct
 			sta->sta.ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 
 		rate_control_rate_update(local, sband, sta,
-					 IEEE80211_RC_HT_CHANGED);
+					 IEEE80211_RC_BW_CHANGED);
 	}
 	mutex_unlock(&local->sta_mtx);
 
--- a/net/mac80211/driver-trace.h	2012-03-15 20:43:13.000000000 +0100
+++ b/net/mac80211/driver-trace.h	2012-03-16 14:37:24.000000000 +0100
@@ -624,6 +624,34 @@ TRACE_EVENT(drv_sta_state,
 	)
 );
 
+TRACE_EVENT(drv_sta_rc_update,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 struct ieee80211_sta *sta,
+		 u32 changed),
+
+	TP_ARGS(local, sdata, sta, changed),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		STA_ENTRY
+		__field(u32, changed)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		STA_ASSIGN;
+		__entry->changed = changed;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " changed: 0x%x",
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->changed
+	)
+);
+
 TRACE_EVENT(drv_sta_add,
 	TP_PROTO(struct ieee80211_local *local,
 		 struct ieee80211_sub_if_data *sdata,
--- a/net/mac80211/driver-ops.h	2012-03-15 20:43:13.000000000 +0100
+++ b/net/mac80211/driver-ops.h	2012-03-16 14:35:54.000000000 +0100
@@ -474,6 +474,23 @@ int drv_sta_state(struct ieee80211_local
 	return ret;
 }
 
+static inline void drv_sta_rc_update(struct ieee80211_local *local,
+				     struct ieee80211_sub_if_data *sdata,
+				     struct ieee80211_sta *sta, u32 changed)
+{
+	might_sleep();
+
+	sdata = get_bss_sdata(sdata);
+	check_sdata_in_driver(sdata);
+
+	trace_drv_sta_rc_update(local, sdata, sta, changed);
+	if (local->ops->sta_rc_update)
+		local->ops->sta_rc_update(&local->hw, &sdata->vif,
+					  sta, changed);
+
+	trace_drv_return_void(local);
+}
+
 static inline int drv_conf_tx(struct ieee80211_local *local,
 			      struct ieee80211_sub_if_data *sdata, u16 queue,
 			      const struct ieee80211_tx_queue_params *params)
--- a/net/mac80211/rate.h	2012-03-16 14:14:31.000000000 +0100
+++ b/net/mac80211/rate.h	2012-03-16 14:38:20.000000000 +0100
@@ -17,6 +17,7 @@
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
 #include "sta_info.h"
+#include "driver-ops.h"
 
 struct rate_control_ref {
 	struct ieee80211_local *local;
@@ -72,6 +73,7 @@ static inline void rate_control_rate_upd
 	if (ref && ref->ops->rate_update)
 		ref->ops->rate_update(ref->priv, sband, ista,
 				      priv_sta, changed);
+	drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
 }
 
 static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,



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

* Re: [PATCH 4/4] mac80211: notify driver of rate control updates
  2012-03-28  8:58 ` [PATCH 4/4] mac80211: notify driver of rate control updates Johannes Berg
@ 2012-03-29 19:13   ` Eliad Peller
  2012-03-29 19:14     ` Johannes Berg
  2012-03-30  6:43   ` [PATCH 4/4 v2] " Johannes Berg
  1 sibling, 1 reply; 11+ messages in thread
From: Eliad Peller @ 2012-03-29 19:13 UTC (permalink / raw)
  To: Johannes Berg; +Cc: John Linville, linux-wireless

On Wed, Mar 28, 2012 at 10:58 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> Devices that have internal rate control need to be
> notified when the bandwidth or SMPS state changes
> just like external rate control algorithms get a
> notification now.
>
> Add this notification and clarify the change bits
> while at it, the HT_CHANGED bit really meant only
> bandwidth changed.
>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
> ---
[...]

>  *
> + * @sta_rc_update: Notifies the driver of changes to the bitrates that can be
> + *     used to transmit to the station. The changes are advertised with bits
> + *     from &enum ieee80211_rate_control_changed and the values are reflected
> + *     in the station data. This callback should only be used when the driver
> + *     uses hardware rate control (%IEEE80211_HW_HAS_RATE_CONTROL) since
> + *     otherwise the rate control algorithm is notified directly.
> + *     Must be atomic.
> + *
it's either atomic...

> +static inline void drv_sta_rc_update(struct ieee80211_local *local,
> +                                    struct ieee80211_sub_if_data *sdata,
> +                                    struct ieee80211_sta *sta, u32 changed)
> +{
> +       might_sleep();

or might sleep :)

Eliad.

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

* Re: [PATCH 4/4] mac80211: notify driver of rate control updates
  2012-03-29 19:13   ` Eliad Peller
@ 2012-03-29 19:14     ` Johannes Berg
  0 siblings, 0 replies; 11+ messages in thread
From: Johannes Berg @ 2012-03-29 19:14 UTC (permalink / raw)
  To: Eliad Peller; +Cc: John Linville, linux-wireless

On Thu, 2012-03-29 at 21:13 +0200, Eliad Peller wrote:
> >  *
> > + * @sta_rc_update: Notifies the driver of changes to the bitrates that can be
> > + *     used to transmit to the station. The changes are advertised with bits
> > + *     from &enum ieee80211_rate_control_changed and the values are reflected
> > + *     in the station data. This callback should only be used when the driver
> > + *     uses hardware rate control (%IEEE80211_HW_HAS_RATE_CONTROL) since
> > + *     otherwise the rate control algorithm is notified directly.
> > + *     Must be atomic.
> > + *
> it's either atomic...
> 
> > +static inline void drv_sta_rc_update(struct ieee80211_local *local,
> > +                                    struct ieee80211_sub_if_data *sdata,
> > +                                    struct ieee80211_sta *sta, u32 changed)
> > +{
> > +       might_sleep();
> 
> or might sleep :)

Oh wow, it must be atomic since it's potentially in the RX path. I guess
the other path (the more common one) doesn't require atomic. Good catch,
thanks!

johannes


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

* [PATCH 2/4] mac80211: remove channel type argument from rate_update
  2012-03-28  8:58 ` [PATCH 2/4] mac80211: remove channel type argument from rate_update Johannes Berg
@ 2012-03-30  4:37   ` Sujith Manoharan
  2012-03-30  6:46     ` Johannes Berg
  0 siblings, 1 reply; 11+ messages in thread
From: Sujith Manoharan @ 2012-03-30  4:37 UTC (permalink / raw)
  To: Johannes Berg; +Cc: John Linville, linux-wireless

Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
> 
> The channel type argument to the rate_update()
> callback isn't really the correct way to give
> the rate control algorithm about the desired
> RX bandwidth of the peer.
> 
> Remove this argument, and instead update the
> STA capabilities with 20/40 appropriately. The
> SMPS update done by this callback works in the
> same way, so this makes the callback cleaner.

I think that the HT capabilities cannot be changed dynamically.
The HT operating parameters along with ChannelSwitch frames are used to
notify bandwidth changes. Or that is my understanding of 11.14.4.2.

Sujith

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

* [PATCH 4/4 v2] mac80211: notify driver of rate control updates
  2012-03-28  8:58 ` [PATCH 4/4] mac80211: notify driver of rate control updates Johannes Berg
  2012-03-29 19:13   ` Eliad Peller
@ 2012-03-30  6:43   ` Johannes Berg
  1 sibling, 0 replies; 11+ messages in thread
From: Johannes Berg @ 2012-03-30  6:43 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

From: Johannes Berg <johannes.berg@intel.com>

Devices that have internal rate control need to be
notified when the bandwidth or SMPS state changes
just like external rate control algorithms get a
notification now.

Add this notification and clarify the change bits
while at it, the HT_CHANGED bit really meant only
bandwidth changed.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
v2: fix might_sleep() pointed out by Eliad

 Documentation/DocBook/80211.tmpl    |    2 -
 drivers/net/wireless/ath/ath9k/rc.c |    2 -
 include/net/mac80211.h              |   37 +++++++++++++++++++++++-------------
 net/mac80211/driver-ops.h           |   15 ++++++++++++++
 net/mac80211/driver-trace.h         |   28 +++++++++++++++++++++++++++
 net/mac80211/mlme.c                 |    2 -
 net/mac80211/rate.h                 |    2 +
 7 files changed, 72 insertions(+), 16 deletions(-)

--- a/Documentation/DocBook/80211.tmpl	2012-03-29 10:03:59.000000000 +0200
+++ b/Documentation/DocBook/80211.tmpl	2012-03-30 08:40:31.000000000 +0200
@@ -533,7 +533,7 @@ MISSING
 !Finclude/net/mac80211.h ieee80211_start_tx_ba_cb_irqsafe
 !Finclude/net/mac80211.h ieee80211_stop_tx_ba_session
 !Finclude/net/mac80211.h ieee80211_stop_tx_ba_cb_irqsafe
-!Finclude/net/mac80211.h rate_control_changed
+!Finclude/net/mac80211.h ieee80211_rate_control_changed
 !Finclude/net/mac80211.h ieee80211_tx_rate_control
 !Finclude/net/mac80211.h rate_control_send_low
       </chapter>
--- a/include/net/mac80211.h	2012-03-30 08:40:31.000000000 +0200
+++ b/include/net/mac80211.h	2012-03-30 08:42:16.000000000 +0200
@@ -1778,6 +1778,18 @@ enum ieee80211_frame_release_type {
 };
 
 /**
+ * enum ieee80211_rate_control_changed - flags to indicate what changed
+ *
+ * @IEEE80211_RC_BW_CHANGED: The bandwidth that can be used to transmit
+ *	to this station changed.
+ * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed.
+ */
+enum ieee80211_rate_control_changed {
+	IEEE80211_RC_BW_CHANGED		= BIT(0),
+	IEEE80211_RC_SMPS_CHANGED	= BIT(1),
+};
+
+/**
  * struct ieee80211_ops - callbacks from mac80211 to the driver
  *
  * This structure contains various callbacks that the driver may
@@ -1978,6 +1990,14 @@ enum ieee80211_frame_release_type {
  *	up the list of states.
  *	The callback can sleep.
  *
+ * @sta_rc_update: Notifies the driver of changes to the bitrates that can be
+ *	used to transmit to the station. The changes are advertised with bits
+ *	from &enum ieee80211_rate_control_changed and the values are reflected
+ *	in the station data. This callback should only be used when the driver
+ *	uses hardware rate control (%IEEE80211_HW_HAS_RATE_CONTROL) since
+ *	otherwise the rate control algorithm is notified directly.
+ *	Must be atomic.
+ *
  * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
  *	bursting) for a hardware TX queue.
  *	Returns a negative error code on failure.
@@ -2194,6 +2214,10 @@ struct ieee80211_ops {
 			 struct ieee80211_sta *sta,
 			 enum ieee80211_sta_state old_state,
 			 enum ieee80211_sta_state new_state);
+	void (*sta_rc_update)(struct ieee80211_hw *hw,
+			      struct ieee80211_vif *vif,
+			      struct ieee80211_sta *sta,
+			      u32 changed);
 	int (*conf_tx)(struct ieee80211_hw *hw,
 		       struct ieee80211_vif *vif, u16 queue,
 		       const struct ieee80211_tx_queue_params *params);
@@ -3510,19 +3534,6 @@ void ieee80211_send_bar(struct ieee80211
 /* Rate control API */
 
 /**
- * enum rate_control_changed - flags to indicate which parameter changed
- *
- * @IEEE80211_RC_HT_CHANGED: The HT parameters of the operating channel have
- *	changed, rate control algorithm can update its internal state if needed.
- * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed, the rate
- *	control algorithm needs to adjust accordingly.
- */
-enum rate_control_changed {
-	IEEE80211_RC_HT_CHANGED		= BIT(0),
-	IEEE80211_RC_SMPS_CHANGED	= BIT(1),
-};
-
-/**
  * struct ieee80211_tx_rate_control - rate control information for/from RC algo
  *
  * @hw: The hardware the algorithm is invoked for.
--- a/drivers/net/wireless/ath/ath9k/rc.c	2012-03-30 08:40:31.000000000 +0200
+++ b/drivers/net/wireless/ath/ath9k/rc.c	2012-03-30 08:40:31.000000000 +0200
@@ -1447,7 +1447,7 @@ static void ath_rate_update(void *priv,
 
 	/* FIXME: Handle AP mode later when we support CWM */
 
-	if (changed & IEEE80211_RC_HT_CHANGED) {
+	if (changed & IEEE80211_RC_BW_CHANGED) {
 		if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
 			return;
 
--- a/net/mac80211/mlme.c	2012-03-30 08:40:31.000000000 +0200
+++ b/net/mac80211/mlme.c	2012-03-30 08:42:16.000000000 +0200
@@ -219,7 +219,7 @@ static u32 ieee80211_config_ht_tx(struct
 			sta->sta.ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 
 		rate_control_rate_update(local, sband, sta,
-					 IEEE80211_RC_HT_CHANGED);
+					 IEEE80211_RC_BW_CHANGED);
 	}
 	mutex_unlock(&local->sta_mtx);
 
--- a/net/mac80211/driver-trace.h	2012-03-29 10:00:40.000000000 +0200
+++ b/net/mac80211/driver-trace.h	2012-03-30 08:42:16.000000000 +0200
@@ -624,6 +624,34 @@ TRACE_EVENT(drv_sta_state,
 	)
 );
 
+TRACE_EVENT(drv_sta_rc_update,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 struct ieee80211_sta *sta,
+		 u32 changed),
+
+	TP_ARGS(local, sdata, sta, changed),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		STA_ENTRY
+		__field(u32, changed)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		STA_ASSIGN;
+		__entry->changed = changed;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " changed: 0x%x",
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->changed
+	)
+);
+
 TRACE_EVENT(drv_sta_add,
 	TP_PROTO(struct ieee80211_local *local,
 		 struct ieee80211_sub_if_data *sdata,
--- a/net/mac80211/driver-ops.h	2012-03-29 10:00:40.000000000 +0200
+++ b/net/mac80211/driver-ops.h	2012-03-30 08:42:34.000000000 +0200
@@ -474,6 +474,21 @@ int drv_sta_state(struct ieee80211_local
 	return ret;
 }
 
+static inline void drv_sta_rc_update(struct ieee80211_local *local,
+				     struct ieee80211_sub_if_data *sdata,
+				     struct ieee80211_sta *sta, u32 changed)
+{
+	sdata = get_bss_sdata(sdata);
+	check_sdata_in_driver(sdata);
+
+	trace_drv_sta_rc_update(local, sdata, sta, changed);
+	if (local->ops->sta_rc_update)
+		local->ops->sta_rc_update(&local->hw, &sdata->vif,
+					  sta, changed);
+
+	trace_drv_return_void(local);
+}
+
 static inline int drv_conf_tx(struct ieee80211_local *local,
 			      struct ieee80211_sub_if_data *sdata, u16 queue,
 			      const struct ieee80211_tx_queue_params *params)
--- a/net/mac80211/rate.h	2012-03-30 08:40:31.000000000 +0200
+++ b/net/mac80211/rate.h	2012-03-30 08:40:31.000000000 +0200
@@ -17,6 +17,7 @@
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
 #include "sta_info.h"
+#include "driver-ops.h"
 
 struct rate_control_ref {
 	struct ieee80211_local *local;
@@ -72,6 +73,7 @@ static inline void rate_control_rate_upd
 	if (ref && ref->ops->rate_update)
 		ref->ops->rate_update(ref->priv, sband, ista,
 				      priv_sta, changed);
+	drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
 }
 
 static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,



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

* Re: [PATCH 2/4] mac80211: remove channel type argument from rate_update
  2012-03-30  4:37   ` Sujith Manoharan
@ 2012-03-30  6:46     ` Johannes Berg
  2012-03-30  7:12       ` Sujith Manoharan
  0 siblings, 1 reply; 11+ messages in thread
From: Johannes Berg @ 2012-03-30  6:46 UTC (permalink / raw)
  To: Sujith Manoharan; +Cc: John Linville, linux-wireless

On Fri, 2012-03-30 at 10:07 +0530, Sujith Manoharan wrote:
> Johannes Berg wrote:
> > From: Johannes Berg <johannes.berg@intel.com>
> > 
> > The channel type argument to the rate_update()
> > callback isn't really the correct way to give
> > the rate control algorithm about the desired
> > RX bandwidth of the peer.
> > 
> > Remove this argument, and instead update the
> > STA capabilities with 20/40 appropriately. The
> > SMPS update done by this callback works in the
> > same way, so this makes the callback cleaner.
> 
> I think that the HT capabilities cannot be changed dynamically.
> The HT operating parameters along with ChannelSwitch frames are used to
> notify bandwidth changes. Or that is my understanding of 11.14.4.2.

Yes, that's true. However, we use the sta.ht_cap field more of a current
operating set database. For example, we also update it when the station
changes SMPS configuration. Also, we never keep it at just the station's
capabilities -- we always restrict it by our own TX capabilities (so if
for example we aren't 40 MHz capable, we already don't leave 40 MHz in).

Overall, I don't really see a problem with this. I suppose we could
rename the field to make that a bit clearer, but I see little value in
using some other struct or so?

johannes


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

* Re: [PATCH 2/4] mac80211: remove channel type argument from rate_update
  2012-03-30  6:46     ` Johannes Berg
@ 2012-03-30  7:12       ` Sujith Manoharan
  0 siblings, 0 replies; 11+ messages in thread
From: Sujith Manoharan @ 2012-03-30  7:12 UTC (permalink / raw)
  To: Johannes Berg; +Cc: John Linville, linux-wireless

Johannes Berg wrote:
> Yes, that's true. However, we use the sta.ht_cap field more of a current
> operating set database. For example, we also update it when the station
> changes SMPS configuration. Also, we never keep it at just the station's
> capabilities -- we always restrict it by our own TX capabilities (so if
> for example we aren't 40 MHz capable, we already don't leave 40 MHz in).

Ah, that's true.

> Overall, I don't really see a problem with this. I suppose we could
> rename the field to make that a bit clearer, but I see little value in
> using some other struct or so?

Yeah, the current approach seems reasonable enough. Thanks for clarifying.

Sujith

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

end of thread, other threads:[~2012-03-30  7:12 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-28  8:58 [PATCH 0/4] early HT channel setting Johannes Berg
2012-03-28  8:58 ` [PATCH 1/4] mac80211: set HT channel before association Johannes Berg
2012-03-28  8:58 ` [PATCH 2/4] mac80211: remove channel type argument from rate_update Johannes Berg
2012-03-30  4:37   ` Sujith Manoharan
2012-03-30  6:46     ` Johannes Berg
2012-03-30  7:12       ` Sujith Manoharan
2012-03-28  8:58 ` [PATCH 3/4] mac80211: remove queue stop on rate control update Johannes Berg
2012-03-28  8:58 ` [PATCH 4/4] mac80211: notify driver of rate control updates Johannes Berg
2012-03-29 19:13   ` Eliad Peller
2012-03-29 19:14     ` Johannes Berg
2012-03-30  6:43   ` [PATCH 4/4 v2] " Johannes Berg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.