All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 00/21] cfg80211/mac80211: multi-vif csa
@ 2014-03-18 13:53 Michal Kazior
  2014-03-18 13:53 ` [RFC 01/21] mac80211: add support for radar detection for reservations Michal Kazior
                   ` (23 more replies)
  0 siblings, 24 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Hi,

I'm aware this is rather huge. I'm hoping I can
get some early feedback before all other patches
I'm depending on are finally merged into
mac80211-next.

Considering current dependency hell of all related
the patchsets I'm duplicating some of my patches
I've posted on the mailing list here. Hopefully
this is sane enough for reviewing purposes.

The patchset alone is based on:
 * mac80211-next/master
 * VLAN chanctx copy refactor
 * Luca's intf combination patches
 * Luca's chanctx reservation patches

I've skipped the 'cfg80211_stop_iface()' since it
depends on a patch from Johannes that hasn't been
merged yet either.

As some probably suspect I've tested this mostly
with ath10k and iwl/mvm. I've been able to
successfully switch multi-BSS AP and perform
AP-follows-STA.

There's a WARN_ON related to chanctx recalc, but
being aware Zhao has some patches around recalc
stuff I decided to ignore it for now.


Michal Kazior (21):
  mac80211: add support for radar detection for reservations
  cfg80211: allow drivers to iterate over matching combinations
  mac80211: add max channel calculation utility function
  mac80211: prevent chanctx overcommit
  mac80211: track assigned vifs in chanctx
  mac80211: track reserved vifs in chanctx
  mac80211: improve find_chanctx() for reservations
  mac80211: improve chanctx reservation lookup
  mac80211: split ieee80211_new_chanctx()
  mac80211: split ieee80211_free_chanctx()
  mac80211: fix racy usage of chanctx->refcount
  mac80211: compute chanctx refcount on-the-fly
  mac80211: implement multi-vif in-place reservations
  mac80211: fix CSA tx queue locking
  mac80211: split CSA finalize function
  mac80211: make check_combinations() aware of chanctx reservation
  mac80211: use chanctx reservation for AP CSA
  mac80211: use chanctx reservation for STA CSA
  mac80211: ignore cqm during csa
  mac80211: remove old unused channel switching code
  cfg80211: remove channel_switch combination check

 include/net/cfg80211.h     |  27 ++
 include/net/mac80211.h     |  11 +-
 net/mac80211/cfg.c         | 212 +++++++++++----
 net/mac80211/chan.c        | 663 +++++++++++++++++++++++++++++++--------------
 net/mac80211/ieee80211_i.h |  25 +-
 net/mac80211/iface.c       |   9 +
 net/mac80211/mlme.c        | 117 +++++---
 net/mac80211/util.c        |  80 +++++-
 net/wireless/nl80211.c     |  11 -
 net/wireless/util.c        |  44 ++-
 10 files changed, 867 insertions(+), 332 deletions(-)

-- 
1.8.5.3


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

* [RFC 01/21] mac80211: add support for radar detection for reservations
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 02/21] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
                   ` (22 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Initial chanctx reservation code wasn't aware of
radar detection requirements. This is necessary
for chanctx reservations to be used for channel
switching in the future.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c        | 5 ++++-
 net/mac80211/ieee80211_i.h | 4 +++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 74b0df6..a3704d4 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -723,7 +723,8 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
 
 int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 				  const struct cfg80211_chan_def *chandef,
-				  enum ieee80211_chanctx_mode mode)
+				  enum ieee80211_chanctx_mode mode,
+				  bool radar_required)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx_conf *conf;
@@ -764,6 +765,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	new_ctx->refcount++;
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
+	sdata->reserved_radar_required = radar_required;
 out:
 	mutex_unlock(&local->chanctx_mtx);
 	return ret;
@@ -808,6 +810,7 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 	/* unref our reservation */
 	ctx->refcount--;
 	sdata->reserved_chanctx = NULL;
+	sdata->radar_required = sdata->reserved_radar_required;
 
 	if (old_ctx == ctx) {
 		/* This is our own context, just change it */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a32d62d..15556fe 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -759,6 +759,7 @@ struct ieee80211_sub_if_data {
 	/* context reservation -- protected with chanctx_mtx */
 	struct ieee80211_chanctx *reserved_chanctx;
 	struct cfg80211_chan_def reserved_chandef;
+	bool reserved_radar_required;
 
 	/* used to reconfigure hardware SM PS */
 	struct work_struct recalc_smps;
@@ -1776,7 +1777,8 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 int __must_check
 ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 			      const struct cfg80211_chan_def *chandef,
-			      enum ieee80211_chanctx_mode mode);
+			      enum ieee80211_chanctx_mode mode,
+			      bool radar_required);
 int __must_check
 ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 				   u32 *changed);
-- 
1.8.5.3


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

* [RFC 02/21] cfg80211: allow drivers to iterate over matching combinations
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
  2014-03-18 13:53 ` [RFC 01/21] mac80211: add support for radar detection for reservations Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 03/21] mac80211: add max channel calculation utility function Michal Kazior
                   ` (21 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The patch splits cfg80211_check_combinations()
into an iterator function and a simple iteration
user.

This makes it possible for drivers to asses how
many channels can use given iftype setup. This in
turn can be used for future
multi-interface/multi-channel channel switching.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 include/net/cfg80211.h | 27 +++++++++++++++++++++++++++
 net/wireless/util.c    | 44 +++++++++++++++++++++++++++++++++++++-------
 2 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 23a72e2..f3411c9 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4705,6 +4705,33 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
 				const u8 radar_detect,
 				const int iftype_num[NUM_NL80211_IFTYPES]);
 
+/**
+ * cfg80211_iter_combinations - iterate over matching combinations
+ *
+ * @wiphy: the wiphy
+ * @num_different_channels: the number of different channels we want
+ *	to use for verification
+ * @radar_detect: a bitmap where each bit corresponds to a channel
+ *	width where radar detection is needed, as in the definition of
+ *	&struct ieee80211_iface_combination.@radar_detect_widths
+ * @iftype_num: array with the numbers of interfaces of each interface
+ *	type.  The index is the interface type as specified in &enum
+ *	nl80211_iftype.
+ * @iter: function to call for each matching combination
+ * @data: pointer to pass to iter function
+ *
+ * This function can be called by the driver to check what possible
+ * combinations it fits in at a given moment, e.g. for channel switching
+ * purposes.
+ */
+int cfg80211_iter_combinations(struct wiphy *wiphy,
+			       const int num_different_channels,
+			       const u8 radar_detect,
+			       const int iftype_num[NUM_NL80211_IFTYPES],
+			       void (*iter)(const struct ieee80211_iface_combination *c,
+					    void *data),
+			       void *data);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/wireless/util.c b/net/wireless/util.c
index b9deec2..804ba31 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1248,10 +1248,13 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
 	return res;
 }
 
-int cfg80211_check_combinations(struct wiphy *wiphy,
-				const int num_different_channels,
-				const u8 radar_detect,
-				const int iftype_num[NUM_NL80211_IFTYPES])
+int cfg80211_iter_combinations(struct wiphy *wiphy,
+			       const int num_different_channels,
+			       const u8 radar_detect,
+			       const int iftype_num[NUM_NL80211_IFTYPES],
+			       void (*iter)(const struct ieee80211_iface_combination *c,
+					    void *data),
+			       void *data)
 {
 	int i, j, iftype;
 	int num_interfaces = 0;
@@ -1308,13 +1311,40 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
 		/* This combination covered all interface types and
 		 * supported the requested numbers, so we're good.
 		 */
-		kfree(limits);
-		return 0;
+
+		(*iter)(c, data);
  cont:
 		kfree(limits);
 	}
 
-	return -EBUSY;
+	return 0;
+}
+EXPORT_SYMBOL(cfg80211_iter_combinations);
+
+static void
+cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
+			  void *data)
+{
+	int *num = data;
+	(*num)++;
+}
+
+int cfg80211_check_combinations(struct wiphy *wiphy,
+				const int num_different_channels,
+				const u8 radar_detect,
+				const int iftype_num[NUM_NL80211_IFTYPES])
+{
+	int err, num = 0;
+
+	err = cfg80211_iter_combinations(wiphy, num_different_channels,
+					 radar_detect, iftype_num,
+					 cfg80211_iter_sum_ifcombs, &num);
+	if (err)
+		return err;
+	if (num == 0)
+		return -EBUSY;
+
+	return 0;
 }
 EXPORT_SYMBOL(cfg80211_check_combinations);
 
-- 
1.8.5.3


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

* [RFC 03/21] mac80211: add max channel calculation utility function
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
  2014-03-18 13:53 ` [RFC 01/21] mac80211: add support for radar detection for reservations Michal Kazior
  2014-03-18 13:53 ` [RFC 02/21] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 16:17   ` Eliad Peller
  2014-03-18 13:53 ` [RFC 04/21] mac80211: prevent chanctx overcommit Michal Kazior
                   ` (20 subsequent siblings)
  23 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The utility function has no uses yet. It is aimed
at future chanctx reservation management and
channel switching.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/ieee80211_i.h |  1 +
 net/mac80211/util.c        | 43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 15556fe..d4b3fe4 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1823,6 +1823,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 				 const struct cfg80211_chan_def *chandef,
 				 enum ieee80211_chanctx_mode chanmode,
 				 u8 radar_detect);
+int ieee80211_max_num_channels(struct ieee80211_local *local);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 7029a59..2e3e6a3 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2873,3 +2873,46 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 					   num_different_channels,
 					   radar_detect, num);
 }
+
+static void
+ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c,
+			 void *data)
+{
+	u32 *max_num_different_channels = data;
+
+	*max_num_different_channels = max(*max_num_different_channels,
+					  c->num_different_channels);
+}
+
+int ieee80211_max_num_channels(struct ieee80211_local *local)
+{
+	struct ieee80211_sub_if_data *sdata;
+	int num[NUM_NL80211_IFTYPES] = {};
+	struct ieee80211_chanctx *ctx;
+	int num_different_channels = 0;
+	u8 radar_detect = 0;
+	u32 max_num_different_channels = 1;
+	int err;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(ctx, &local->chanctx_list, list) {
+		num_different_channels++;
+
+		if (ctx->conf.radar_enabled)
+			radar_detect |= BIT(ctx->conf.def.width);
+	}
+
+	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+		num[sdata->wdev.iftype]++;
+	}
+
+	err = cfg80211_iter_combinations(local->hw.wiphy,
+					 num_different_channels, radar_detect,
+					 num, ieee80211_iter_max_chans,
+					 &max_num_different_channels);
+	if (err < 0)
+		return err;
+
+	return max_num_different_channels;
+}
-- 
1.8.5.3


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

* [RFC 04/21] mac80211: prevent chanctx overcommit
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (2 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 03/21] mac80211: add max channel calculation utility function Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 16:25   ` Eliad Peller
  2014-03-18 13:53 ` [RFC 05/21] mac80211: track assigned vifs in chanctx Michal Kazior
                   ` (19 subsequent siblings)
  23 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Do not allocate more channel contexts than a
driver is capable for currently matching interface
combination.

This allows the ieee80211_vif_reserve_chanctx() to
act as a guard against breaking interface
combinations.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index a3704d4..c1284f2 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -9,6 +9,25 @@
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
+static int ieee80211_num_chanctx(struct ieee80211_local *local)
+{
+	struct ieee80211_chanctx *ctx;
+	int num = 0;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(ctx, &local->chanctx_list, list)
+		num++;
+
+	return num;
+}
+
+static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
+	return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -752,13 +771,16 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 			 * context, reserve our current context
 			 */
 			new_ctx = curr_ctx;
-		} else {
+		} else if (ieee80211_can_create_new_chanctx(local)) {
 			/* create a new context and reserve it */
 			new_ctx = ieee80211_new_chanctx(local, chandef, mode);
 			if (IS_ERR(new_ctx)) {
 				ret = PTR_ERR(new_ctx);
 				goto out;
 			}
+		} else {
+			ret = -EBUSY;
+			goto out;
 		}
 	}
 
-- 
1.8.5.3


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

* [RFC 05/21] mac80211: track assigned vifs in chanctx
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (3 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 04/21] mac80211: prevent chanctx overcommit Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 06/21] mac80211: track reserved " Michal Kazior
                   ` (18 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

This can be useful.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c        | 4 ++++
 net/mac80211/ieee80211_i.h | 4 ++++
 net/mac80211/iface.c       | 1 +
 3 files changed, 9 insertions(+)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index c1284f2..aca70a6 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -276,6 +276,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 	if (!ctx)
 		return ERR_PTR(-ENOMEM);
 
+	INIT_LIST_HEAD(&ctx->assigned_vifs);
 	ctx->conf.def = *chandef;
 	ctx->conf.rx_chains_static = 1;
 	ctx->conf.rx_chains_dynamic = 1;
@@ -420,6 +421,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 		curr_ctx->refcount--;
 		drv_unassign_vif_chanctx(local, sdata, curr_ctx);
 		conf = NULL;
+		list_del(&sdata->assigned_chanctx_list);
 	}
 
 	if (new_ctx) {
@@ -429,6 +431,8 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 
 		new_ctx->refcount++;
 		conf = &new_ctx->conf;
+		list_add(&sdata->assigned_chanctx_list,
+			 &new_ctx->assigned_vifs);
 	}
 
 out:
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d4b3fe4..6e3d137 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -691,6 +691,8 @@ struct ieee80211_chanctx {
 	struct list_head list;
 	struct rcu_head rcu_head;
 
+	struct list_head assigned_vifs;
+
 	enum ieee80211_chanctx_mode mode;
 	int refcount;
 	bool driver_present;
@@ -756,6 +758,8 @@ struct ieee80211_sub_if_data {
 	bool csa_radar_required;
 	struct cfg80211_chan_def csa_chandef;
 
+	struct list_head assigned_chanctx_list;
+
 	/* context reservation -- protected with chanctx_mtx */
 	struct ieee80211_chanctx *reserved_chanctx;
 	struct cfg80211_chan_def reserved_chandef;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 384f663..3b5b6d3 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1291,6 +1291,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 	INIT_WORK(&sdata->work, ieee80211_iface_work);
 	INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
 	INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
+	INIT_LIST_HEAD(&sdata->assigned_chanctx_list);
 
 	switch (type) {
 	case NL80211_IFTYPE_P2P_GO:
-- 
1.8.5.3


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

* [RFC 06/21] mac80211: track reserved vifs in chanctx
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (4 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 05/21] mac80211: track assigned vifs in chanctx Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 07/21] mac80211: improve find_chanctx() for reservations Michal Kazior
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

This can be useful.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c        | 14 ++++++++++----
 net/mac80211/ieee80211_i.h |  2 ++
 net/mac80211/iface.c       |  1 +
 3 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index aca70a6..525739b 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -277,6 +277,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 		return ERR_PTR(-ENOMEM);
 
 	INIT_LIST_HEAD(&ctx->assigned_vifs);
+	INIT_LIST_HEAD(&ctx->reserved_vifs);
 	ctx->conf.def = *chandef;
 	ctx->conf.rx_chains_static = 1;
 	ctx->conf.rx_chains_dynamic = 1;
@@ -731,16 +732,19 @@ void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 
 int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
 {
+	struct ieee80211_chanctx *ctx = sdata->reserved_chanctx;
+
 	lockdep_assert_held(&sdata->local->chanctx_mtx);
 
-	if (WARN_ON(!sdata->reserved_chanctx))
+	if (WARN_ON(!ctx))
 		return -EINVAL;
 
-	if (--sdata->reserved_chanctx->refcount == 0)
-		ieee80211_free_chanctx(sdata->local, sdata->reserved_chanctx);
-
+	list_del(&sdata->reserved_chanctx_list);
 	sdata->reserved_chanctx = NULL;
 
+	if (--ctx->refcount == 0)
+		ieee80211_free_chanctx(sdata->local, ctx);
+
 	return 0;
 }
 
@@ -788,6 +792,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
+	list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
 	new_ctx->refcount++;
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
@@ -837,6 +842,7 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 	ctx->refcount--;
 	sdata->reserved_chanctx = NULL;
 	sdata->radar_required = sdata->reserved_radar_required;
+	list_del(&sdata->reserved_chanctx_list);
 
 	if (old_ctx == ctx) {
 		/* This is our own context, just change it */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6e3d137..0701631 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -692,6 +692,7 @@ struct ieee80211_chanctx {
 	struct rcu_head rcu_head;
 
 	struct list_head assigned_vifs;
+	struct list_head reserved_vifs;
 
 	enum ieee80211_chanctx_mode mode;
 	int refcount;
@@ -759,6 +760,7 @@ struct ieee80211_sub_if_data {
 	struct cfg80211_chan_def csa_chandef;
 
 	struct list_head assigned_chanctx_list;
+	struct list_head reserved_chanctx_list;
 
 	/* context reservation -- protected with chanctx_mtx */
 	struct ieee80211_chanctx *reserved_chanctx;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 3b5b6d3..d09185b 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1292,6 +1292,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 	INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
 	INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
 	INIT_LIST_HEAD(&sdata->assigned_chanctx_list);
+	INIT_LIST_HEAD(&sdata->reserved_chanctx_list);
 
 	switch (type) {
 	case NL80211_IFTYPE_P2P_GO:
-- 
1.8.5.3


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

* [RFC 07/21] mac80211: improve find_chanctx() for reservations
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (5 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 06/21] mac80211: track reserved " Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 16:42   ` Eliad Peller
  2014-03-18 13:53 ` [RFC 08/21] mac80211: improve chanctx reservation lookup Michal Kazior
                   ` (16 subsequent siblings)
  23 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Relax ieee80211_find_chanctx(). If chanctx
reservation chandef is compatible with
current-future assigned interfaces chandef then
allow it to be used by new interfaces.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 56 +++++++++++++++++++++++++++--------------------------
 1 file changed, 29 insertions(+), 27 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 525739b..08c7653 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -28,6 +28,29 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
 	return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
 }
 
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
+				   struct ieee80211_chanctx *ctx,
+				   const struct cfg80211_chan_def *compat)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs,
+			    reserved_chanctx_list) {
+		if (!compat)
+			compat = &sdata->reserved_chandef;
+
+		compat = cfg80211_chandef_compatible(&sdata->reserved_chandef,
+						     compat);
+		if (!compat)
+			break;
+	}
+
+	return compat;
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -187,27 +210,6 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
 	}
 }
 
-static bool ieee80211_chanctx_is_reserved(struct ieee80211_local *local,
-					  struct ieee80211_chanctx *ctx)
-{
-	struct ieee80211_sub_if_data *sdata;
-	bool ret = false;
-
-	lockdep_assert_held(&local->chanctx_mtx);
-	rcu_read_lock();
-	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-		if (!ieee80211_sdata_running(sdata))
-			continue;
-		if (sdata->reserved_chanctx == ctx) {
-			ret = true;
-			break;
-		}
-	}
-
-	rcu_read_unlock();
-	return ret;
-}
-
 static struct ieee80211_chanctx *
 ieee80211_find_chanctx(struct ieee80211_local *local,
 		       const struct cfg80211_chan_def *chandef,
@@ -223,18 +225,18 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
 	list_for_each_entry(ctx, &local->chanctx_list, list) {
 		const struct cfg80211_chan_def *compat;
 
-		/* We don't support chanctx reservation for multiple
-		 * vifs yet, so don't allow reserved chanctxs to be
-		 * reused.
-		 */
-		if ((ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) ||
-		    ieee80211_chanctx_is_reserved(local, ctx))
+		if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
 			continue;
 
 		compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef);
 		if (!compat)
 			continue;
 
+		compat = ieee80211_chanctx_reserved_chandef(local, ctx,
+							    compat);
+		if (!compat)
+			continue;
+
 		ieee80211_change_chanctx(local, ctx, compat);
 
 		return ctx;
-- 
1.8.5.3


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

* [RFC 08/21] mac80211: improve chanctx reservation lookup
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (6 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 07/21] mac80211: improve find_chanctx() for reservations Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 16:57   ` Eliad Peller
  2014-03-18 13:53 ` [RFC 09/21] mac80211: split ieee80211_new_chanctx() Michal Kazior
                   ` (15 subsequent siblings)
  23 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Use a separate function to look for reservation
chanctx. For multi-interface/channel reservation
search sematics differ slightly.

The new routine allows reservations to be merged
with chanctx that are already reserved by other
interface(s).

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 90 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 08c7653..f6d8610 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -51,6 +51,95 @@ ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
 	return compat;
 }
 
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
+				       struct ieee80211_chanctx *ctx,
+				       const struct cfg80211_chan_def *compat)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->assigned_vifs,
+			    assigned_chanctx_list) {
+		if (rcu_access_pointer(sdata->reserved_chanctx) != NULL)
+			continue;
+
+		if (!compat)
+			compat = &sdata->vif.bss_conf.chandef;
+
+		compat = cfg80211_chandef_compatible(
+				&sdata->vif.bss_conf.chandef, compat);
+		if (!compat)
+			break;
+	}
+
+	return compat;
+}
+
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_combined_chandef(struct ieee80211_local *local,
+				   struct ieee80211_chanctx *ctx,
+				   const struct cfg80211_chan_def *compat)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	compat = ieee80211_chanctx_reserved_chandef(local, ctx, compat);
+	if (!compat)
+		return NULL;
+
+	compat = ieee80211_chanctx_non_reserved_chandef(local, ctx, compat);
+	if (!compat)
+		return NULL;
+
+	return compat;
+}
+
+static bool
+ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local,
+				      struct ieee80211_chanctx *ctx,
+				      const struct cfg80211_chan_def *def)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	if (ieee80211_chanctx_combined_chandef(local, ctx, NULL) &&
+	    ieee80211_chanctx_combined_chandef(local, ctx, def))
+		return true;
+
+	if (!list_empty(&ctx->reserved_vifs) &&
+	    ieee80211_chanctx_reserved_chandef(local, ctx, NULL) &&
+	    ieee80211_chanctx_reserved_chandef(local, ctx, def))
+		return true;
+
+	return false;
+}
+
+static struct ieee80211_chanctx *
+ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
+				   const struct cfg80211_chan_def *chandef,
+				   enum ieee80211_chanctx_mode mode)
+{
+	struct ieee80211_chanctx *ctx;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
+		return NULL;
+
+	list_for_each_entry(ctx, &local->chanctx_list, list) {
+		if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
+			continue;
+
+		if (!ieee80211_chanctx_can_reserve_chandef(local, ctx,
+							   chandef))
+			continue;
+
+		return ctx;
+	}
+
+	return NULL;
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -771,8 +860,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 
 	curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-	/* try to find another context with the chandef we want */
-	new_ctx = ieee80211_find_chanctx(local, chandef, mode);
+	new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
 	if (!new_ctx) {
 		if (curr_ctx->refcount == 1 &&
 		    (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
-- 
1.8.5.3


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

* [RFC 09/21] mac80211: split ieee80211_new_chanctx()
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (7 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 08/21] mac80211: improve chanctx reservation lookup Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 10/21] mac80211: split ieee80211_free_chanctx() Michal Kazior
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The function did a little too much. Split it up so
the code can be easily reused in the future.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 56 ++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 43 insertions(+), 13 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index f6d8610..1982e33 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -353,19 +353,17 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local)
 }
 
 static struct ieee80211_chanctx *
-ieee80211_new_chanctx(struct ieee80211_local *local,
-		      const struct cfg80211_chan_def *chandef,
-		      enum ieee80211_chanctx_mode mode)
+ieee80211_alloc_chanctx(struct ieee80211_local *local,
+			const struct cfg80211_chan_def *chandef,
+			enum ieee80211_chanctx_mode mode)
 {
 	struct ieee80211_chanctx *ctx;
-	u32 changed;
-	int err;
 
 	lockdep_assert_held(&local->chanctx_mtx);
 
 	ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
 	if (!ctx)
-		return ERR_PTR(-ENOMEM);
+		return NULL;
 
 	INIT_LIST_HEAD(&ctx->assigned_vifs);
 	INIT_LIST_HEAD(&ctx->reserved_vifs);
@@ -375,31 +373,63 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 	ctx->mode = mode;
 	ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
 	ieee80211_recalc_chanctx_min_def(local, ctx);
+
+	return ctx;
+}
+
+static int ieee80211_add_chanctx(struct ieee80211_local *local,
+				 struct ieee80211_chanctx *ctx)
+{
+	u32 changed;
+	int err;
+
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
+
 	if (!local->use_chanctx)
 		local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
 
-	/* we hold the mutex to prevent idle from changing */
-	lockdep_assert_held(&local->mtx);
 	/* turn idle off *before* setting channel -- some drivers need that */
 	changed = ieee80211_idle_off(local);
 	if (changed)
 		ieee80211_hw_config(local, changed);
 
 	if (!local->use_chanctx) {
-		local->_oper_chandef = *chandef;
+		local->_oper_chandef = ctx->conf.def;
 		ieee80211_hw_config(local, 0);
 	} else {
 		err = drv_add_chanctx(local, ctx);
 		if (err) {
-			kfree(ctx);
 			ieee80211_recalc_idle(local);
-			return ERR_PTR(err);
+			return err;
 		}
 	}
 
-	/* and keep the mutex held until the new chanctx is on the list */
-	list_add_rcu(&ctx->list, &local->chanctx_list);
+	return 0;
+}
+
+static struct ieee80211_chanctx *
+ieee80211_new_chanctx(struct ieee80211_local *local,
+		      const struct cfg80211_chan_def *chandef,
+		      enum ieee80211_chanctx_mode mode)
+{
+	struct ieee80211_chanctx *ctx;
+	int err;
+
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	ctx = ieee80211_alloc_chanctx(local, chandef, mode);
+	if (!ctx)
+		return ERR_PTR(-ENOMEM);
 
+	err = ieee80211_add_chanctx(local, ctx);
+	if (err) {
+		kfree(ctx);
+		return ERR_PTR(err);
+	}
+
+	list_add_rcu(&ctx->list, &local->chanctx_list);
 	return ctx;
 }
 
-- 
1.8.5.3


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

* [RFC 10/21] mac80211: split ieee80211_free_chanctx()
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (8 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 09/21] mac80211: split ieee80211_new_chanctx() Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 11/21] mac80211: fix racy usage of chanctx->refcount Michal Kazior
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The function did a little too much. Split it up so
the code can be easily reused in the future.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 1982e33..623df6f 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -433,14 +433,11 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 	return ctx;
 }
 
-static void ieee80211_free_chanctx(struct ieee80211_local *local,
-				   struct ieee80211_chanctx *ctx)
+static void ieee80211_del_chanctx(struct ieee80211_local *local,
+				  struct ieee80211_chanctx *ctx)
 {
-	bool check_single_channel = false;
 	lockdep_assert_held(&local->chanctx_mtx);
 
-	WARN_ON_ONCE(ctx->refcount != 0);
-
 	if (!local->use_chanctx) {
 		struct cfg80211_chan_def *chandef = &local->_oper_chandef;
 		chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
@@ -450,8 +447,9 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
 		/* NOTE: Disabling radar is only valid here for
 		 * single channel context. To be sure, check it ...
 		 */
-		if (local->hw.conf.radar_enabled)
-			check_single_channel = true;
+		WARN_ON(local->hw.conf.radar_enabled &&
+			!list_empty(&local->chanctx_list));
+
 		local->hw.conf.radar_enabled = false;
 
 		ieee80211_hw_config(local, 0);
@@ -459,13 +457,19 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
 		drv_remove_chanctx(local, ctx);
 	}
 
-	list_del_rcu(&ctx->list);
-	kfree_rcu(ctx, rcu_head);
+	ieee80211_recalc_idle(local);
+}
 
-	/* throw a warning if this wasn't the only channel context. */
-	WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
+static void ieee80211_free_chanctx(struct ieee80211_local *local,
+				   struct ieee80211_chanctx *ctx)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	ieee80211_recalc_idle(local);
+	WARN_ON_ONCE(ctx->refcount != 0);
+
+	list_del_rcu(&ctx->list);
+	ieee80211_del_chanctx(local, ctx);
+	kfree_rcu(ctx, rcu_head);
 }
 
 static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
-- 
1.8.5.3


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

* [RFC 11/21] mac80211: fix racy usage of chanctx->refcount
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (9 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 10/21] mac80211: split ieee80211_free_chanctx() Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 12/21] mac80211: compute chanctx refcount on-the-fly Michal Kazior
                   ` (12 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Channel context refcount is protected by
chanctx_mtx. Accessing the value without holding
the mutex is racy. RCU section didn't guarantee
anything here.

Theoretically ieee80211_channel_switch() could
fail to see refcount change and read "1" instead
of, e.g. "2". This means mac80211 could accept CSA
even though it shouldn't have.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/cfg.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 137d379..61b62f4 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3225,7 +3225,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx_conf *chanctx_conf;
+	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *chanctx;
 	int err, num_chanctx, changed = 0;
 
@@ -3241,23 +3241,24 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 				       &sdata->vif.bss_conf.chandef))
 		return -EINVAL;
 
-	rcu_read_lock();
-	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
-	if (!chanctx_conf) {
-		rcu_read_unlock();
+	mutex_lock(&local->chanctx_mtx);
+	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+					 lockdep_is_held(&local->chanctx_mtx));
+	if (!conf) {
+		mutex_unlock(&local->chanctx_mtx);
 		return -EBUSY;
 	}
 
 	/* don't handle for multi-VIF cases */
-	chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
+	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
 	if (chanctx->refcount > 1) {
-		rcu_read_unlock();
+		mutex_unlock(&local->chanctx_mtx);
 		return -EBUSY;
 	}
 	num_chanctx = 0;
 	list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
 		num_chanctx++;
-	rcu_read_unlock();
+	mutex_unlock(&local->chanctx_mtx);
 
 	if (num_chanctx > 1)
 		return -EBUSY;
-- 
1.8.5.3


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

* [RFC 12/21] mac80211: compute chanctx refcount on-the-fly
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (10 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 11/21] mac80211: fix racy usage of chanctx->refcount Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 13/21] mac80211: implement multi-vif in-place reservations Michal Kazior
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

It doesn't make much sense to store refcount in
the chanctx structure. One still needs to hold
chanctx_mtx to get the value safely. Besides,
refcount isn't on performance critical paths.

This will make implementing chanctx reservation
refcounting a little easier.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/cfg.c         |  2 +-
 net/mac80211/chan.c        | 59 +++++++++++++++++++++++++++++++++++-----------
 net/mac80211/ieee80211_i.h |  3 ++-
 net/mac80211/mlme.c        |  2 +-
 4 files changed, 49 insertions(+), 17 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 61b62f4..954259d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3251,7 +3251,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 
 	/* don't handle for multi-VIF cases */
 	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
-	if (chanctx->refcount > 1) {
+	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
 		mutex_unlock(&local->chanctx_mtx);
 		return -EBUSY;
 	}
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 623df6f..e99362d 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -9,6 +9,41 @@
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
+static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
+					  struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+	int num = 0;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
+		num++;
+
+	return num;
+}
+
+static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
+					  struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+	int num = 0;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list)
+		num++;
+
+	return num;
+}
+
+int ieee80211_chanctx_refcount(struct ieee80211_local *local,
+			       struct ieee80211_chanctx *ctx)
+{
+	return ieee80211_chanctx_num_assigned(local, ctx) +
+	       ieee80211_chanctx_num_reserved(local, ctx);
+}
+
 static int ieee80211_num_chanctx(struct ieee80211_local *local)
 {
 	struct ieee80211_chanctx *ctx;
@@ -465,7 +500,7 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
 {
 	lockdep_assert_held(&local->chanctx_mtx);
 
-	WARN_ON_ONCE(ctx->refcount != 0);
+	WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
 
 	list_del_rcu(&ctx->list);
 	ieee80211_del_chanctx(local, ctx);
@@ -544,7 +579,6 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 	if (conf) {
 		curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-		curr_ctx->refcount--;
 		drv_unassign_vif_chanctx(local, sdata, curr_ctx);
 		conf = NULL;
 		list_del(&sdata->assigned_chanctx_list);
@@ -555,7 +589,6 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 		if (ret)
 			goto out;
 
-		new_ctx->refcount++;
 		conf = &new_ctx->conf;
 		list_add(&sdata->assigned_chanctx_list,
 			 &new_ctx->assigned_vifs);
@@ -566,14 +599,14 @@ out:
 
 	sdata->vif.bss_conf.idle = !conf;
 
-	if (curr_ctx && curr_ctx->refcount > 0) {
+	if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
 		ieee80211_recalc_chanctx_chantype(local, curr_ctx);
 		ieee80211_recalc_smps_chanctx(local, curr_ctx);
 		ieee80211_recalc_radar_chanctx(local, curr_ctx);
 		ieee80211_recalc_chanctx_min_def(local, curr_ctx);
 	}
 
-	if (new_ctx && new_ctx->refcount > 0) {
+	if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
 		ieee80211_recalc_txpower(sdata);
 		ieee80211_recalc_chanctx_min_def(local, new_ctx);
 	}
@@ -605,7 +638,7 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
 		ieee80211_vif_unreserve_chanctx(sdata);
 
 	ieee80211_assign_vif_chanctx(sdata, NULL);
-	if (ctx->refcount == 0)
+	if (ieee80211_chanctx_refcount(local, ctx) == 0)
 		ieee80211_free_chanctx(local, ctx);
 }
 
@@ -737,7 +770,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 	ret = ieee80211_assign_vif_chanctx(sdata, ctx);
 	if (ret) {
 		/* if assign fails refcount stays the same */
-		if (ctx->refcount == 0)
+		if (ieee80211_chanctx_refcount(local, ctx) == 0)
 			ieee80211_free_chanctx(local, ctx);
 		goto out;
 	}
@@ -761,7 +794,7 @@ static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
 				     IEEE80211_CHAN_DISABLED))
 		return -EINVAL;
 
-	if (ctx->refcount != 1)
+	if (ieee80211_chanctx_refcount(local, ctx) != 1)
 		return -EINVAL;
 
 	if (sdata->vif.bss_conf.chandef.width != chandef->width) {
@@ -867,7 +900,7 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
 	list_del(&sdata->reserved_chanctx_list);
 	sdata->reserved_chanctx = NULL;
 
-	if (--ctx->refcount == 0)
+	if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0)
 		ieee80211_free_chanctx(sdata->local, ctx);
 
 	return 0;
@@ -896,7 +929,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 
 	new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
 	if (!new_ctx) {
-		if (curr_ctx->refcount == 1 &&
+		if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 &&
 		    (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
 			/* if we're the only users of the chanctx and
 			 * the driver supports changing a running
@@ -917,7 +950,6 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	}
 
 	list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
-	new_ctx->refcount++;
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
 	sdata->reserved_radar_required = radar_required;
@@ -963,7 +995,6 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 	sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
 
 	/* unref our reservation */
-	ctx->refcount--;
 	sdata->reserved_chanctx = NULL;
 	sdata->radar_required = sdata->reserved_radar_required;
 	list_del(&sdata->reserved_chanctx_list);
@@ -976,11 +1007,11 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 			goto out;
 	} else {
 		ret = ieee80211_assign_vif_chanctx(sdata, ctx);
-		if (old_ctx->refcount == 0)
+		if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
 			ieee80211_free_chanctx(local, old_ctx);
 		if (ret) {
 			/* if assign fails refcount stays the same */
-			if (ctx->refcount == 0)
+			if (ieee80211_chanctx_refcount(local, ctx) == 0)
 				ieee80211_free_chanctx(local, ctx);
 			goto out;
 		}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 0701631..2de8121 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -695,7 +695,6 @@ struct ieee80211_chanctx {
 	struct list_head reserved_vifs;
 
 	enum ieee80211_chanctx_mode mode;
-	int refcount;
 	bool driver_present;
 
 	struct ieee80211_chanctx_conf conf;
@@ -1802,6 +1801,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 					 bool clear);
+int ieee80211_chanctx_refcount(struct ieee80211_local *local,
+			       struct ieee80211_chanctx *ctx);
 
 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
 				   struct ieee80211_chanctx *chanctx);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 94f0af2..a4d8e99 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1089,7 +1089,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	}
 	chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
 			       struct ieee80211_chanctx, conf);
-	if (chanctx->refcount > 1) {
+	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
 		sdata_info(sdata,
 			   "channel switch with multiple interfaces on the same channel, disconnecting\n");
 		ieee80211_queue_work(&local->hw,
-- 
1.8.5.3


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

* [RFC 13/21] mac80211: implement multi-vif in-place reservations
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (11 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 12/21] mac80211: compute chanctx refcount on-the-fly Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-19 18:35   ` Eliad Peller
  2014-03-18 13:53 ` [RFC 14/21] mac80211: fix CSA tx queue locking Michal Kazior
                   ` (10 subsequent siblings)
  23 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Multi-vif in-place reservations happen when
it's impossible to allocate more chanctx as per
driver combinations.

Such reservations aren't finalized until last
reservation interface calls in to use the
reservation.

This introduces a special hook
ieee80211_vif_chanctx_reservation_complete(). This
is currently an empty stub and will be filled in
by AP/STA CSA code. This is required to implement
2-step CSA finalization.

This also gets rid of driver requirement to be
able to re-program channel of a chanctx.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 include/net/mac80211.h     |   7 --
 net/mac80211/chan.c        | 270 +++++++++++++++++++++++++++++++++------------
 net/mac80211/ieee80211_i.h |   4 +-
 3 files changed, 201 insertions(+), 80 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index b35c608..86faa41 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1553,12 +1553,6 @@ struct ieee80211_tx_control {
  *	for a single active channel while using channel contexts. When support
  *	is not enabled the default action is to disconnect when getting the
  *	CSA frame.
- *
- * @IEEE80211_HW_CHANGE_RUNNING_CHANCTX: The hardware can change a
- *	channel context on-the-fly.  This is needed for channel switch
- *	on single-channel hardware.  It can also be used as an
- *	optimization in certain channel switch cases with
- *	multi-channel.
  */
 enum ieee80211_hw_flags {
 	IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0,
@@ -1590,7 +1584,6 @@ enum ieee80211_hw_flags {
 	IEEE80211_HW_TIMING_BEACON_ONLY			= 1<<26,
 	IEEE80211_HW_SUPPORTS_HT_CCK_RATES		= 1<<27,
 	IEEE80211_HW_CHANCTX_STA_CSA			= 1<<28,
-	IEEE80211_HW_CHANGE_RUNNING_CHANCTX		= 1<<29,
 };
 
 /**
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index e99362d..7cf8970 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -175,6 +175,24 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
 	return NULL;
 }
 
+static bool
+ieee80211_chanctx_all_reserved_vifs_ready(struct ieee80211_local *local,
+					  struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		if (!sdata->reserved_chanctx)
+			continue;
+		if (!sdata->reserved_ready)
+			return false;
+	}
+
+	return true;
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -914,38 +932,24 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *new_ctx, *curr_ctx;
-	int ret = 0;
 
-	mutex_lock(&local->chanctx_mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
 	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf) {
-		ret = -EINVAL;
-		goto out;
-	}
+	if (!conf)
+		return -EINVAL;
 
 	curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
 	new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
 	if (!new_ctx) {
-		if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 &&
-		    (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
-			/* if we're the only users of the chanctx and
-			 * the driver supports changing a running
-			 * context, reserve our current context
-			 */
-			new_ctx = curr_ctx;
-		} else if (ieee80211_can_create_new_chanctx(local)) {
-			/* create a new context and reserve it */
+		if (ieee80211_can_create_new_chanctx(local)) {
 			new_ctx = ieee80211_new_chanctx(local, chandef, mode);
-			if (IS_ERR(new_ctx)) {
-				ret = PTR_ERR(new_ctx);
-				goto out;
-			}
+			if (IS_ERR(new_ctx))
+				return PTR_ERR(new_ctx);
 		} else {
-			ret = -EBUSY;
-			goto out;
+			new_ctx = curr_ctx;
 		}
 	}
 
@@ -953,81 +957,205 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
 	sdata->reserved_radar_required = radar_required;
-out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
+	sdata->reserved_ready = false;
+
+	return 0;
 }
 
-int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
-				       u32 *changed)
+static void
+ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx *ctx;
-	struct ieee80211_chanctx *old_ctx;
-	struct ieee80211_chanctx_conf *conf;
-	int ret;
-	u32 tmp_changed = *changed;
+	/* stub */
+}
 
-	/* TODO: need to recheck if the chandef is usable etc.? */
+static int
+ieee80211_vif_use_reserved_incompat(struct ieee80211_local *local,
+				    struct ieee80211_chanctx *ctx,
+				    const struct cfg80211_chan_def *chandef)
+{
+	struct ieee80211_sub_if_data *sdata, *tmp;
+	struct ieee80211_chanctx *new_ctx;
+	u32 changed = 0;
+	int err;
 
 	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	mutex_lock(&local->chanctx_mtx);
+	if (!ieee80211_chanctx_all_reserved_vifs_ready(local, ctx))
+		return 0;
 
-	ctx = sdata->reserved_chanctx;
-	if (WARN_ON(!ctx)) {
-		ret = -EINVAL;
-		goto out;
+	if (ieee80211_chanctx_num_assigned(local, ctx) !=
+	    ieee80211_chanctx_num_reserved(local, ctx)) {
+		wiphy_info(local->hw.wiphy,
+			   "channel context reservation cannot be finalized because some interfaces aren't switching\n");
+		err = -EBUSY;
+		goto err;
 	}
 
-	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf) {
-		ret = -EINVAL;
-		goto out;
+	new_ctx = ieee80211_alloc_chanctx(local, chandef, ctx->mode);
+	if (!new_ctx) {
+		err = -ENOMEM;
+		goto err;
 	}
 
-	old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		drv_unassign_vif_chanctx(local, sdata, ctx);
+		rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
+	}
 
-	if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
-		tmp_changed |= BSS_CHANGED_BANDWIDTH;
+	list_del_rcu(&ctx->list);
+	ieee80211_del_chanctx(local, ctx);
 
-	sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
+	err = ieee80211_add_chanctx(local, new_ctx);
+	if (err)
+		goto err_revert;
 
-	/* unref our reservation */
-	sdata->reserved_chanctx = NULL;
-	sdata->radar_required = sdata->reserved_radar_required;
-	list_del(&sdata->reserved_chanctx_list);
+	/* don't simply overwrite radar_required in case of failure */
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		bool tmp = sdata->radar_required;
+		sdata->radar_required = sdata->reserved_radar_required;
+		sdata->reserved_radar_required = tmp;
+	}
 
-	if (old_ctx == ctx) {
-		/* This is our own context, just change it */
-		ret = __ieee80211_vif_change_channel(sdata, old_ctx,
-						     &tmp_changed);
-		if (ret)
-			goto out;
-	} else {
-		ret = ieee80211_assign_vif_chanctx(sdata, ctx);
-		if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
-			ieee80211_free_chanctx(local, old_ctx);
-		if (ret) {
-			/* if assign fails refcount stays the same */
-			if (ieee80211_chanctx_refcount(local, ctx) == 0)
-				ieee80211_free_chanctx(local, ctx);
-			goto out;
-		}
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		err = drv_assign_vif_chanctx(local, sdata, ctx);
+		if (err)
+			goto err_unassign;
+	}
 
+	if (sdata->vif.type == NL80211_IFTYPE_AP)
 		__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
-	}
 
-	*changed = tmp_changed;
+	list_add_rcu(&new_ctx->list, &local->chanctx_list);
+	kfree_rcu(ctx, rcu_head);
 
 	ieee80211_recalc_chanctx_chantype(local, ctx);
 	ieee80211_recalc_smps_chanctx(local, ctx);
 	ieee80211_recalc_radar_chanctx(local, ctx);
 	ieee80211_recalc_chanctx_min_def(local, ctx);
+
+	list_for_each_entry_safe(sdata, tmp, &ctx->reserved_vifs,
+				 reserved_chanctx_list) {
+		list_del(&sdata->reserved_chanctx_list);
+		list_move(&sdata->assigned_chanctx_list,
+			  &new_ctx->assigned_vifs);
+		sdata->reserved_chanctx = NULL;
+
+		changed = 0;
+		if (sdata->vif.bss_conf.chandef.width !=
+		    sdata->reserved_chandef.width)
+			changed = BSS_CHANGED_BANDWIDTH;
+
+		sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
+		if (changed)
+			ieee80211_bss_info_change_notify(sdata, changed);
+
+		ieee80211_recalc_txpower(sdata);
+		ieee80211_vif_chanctx_reservation_complete(sdata);
+	}
+
+	return 0;
+
+err_unassign:
+	list_for_each_entry_continue_reverse(sdata, &ctx->reserved_vifs,
+					     reserved_chanctx_list)
+		drv_unassign_vif_chanctx(local, sdata, ctx);
+	ieee80211_del_chanctx(local, new_ctx);
+err_revert:
+	kfree_rcu(new_ctx, rcu_head);
+	WARN_ON(ieee80211_add_chanctx(local, ctx));
+	list_add_rcu(&ctx->list, &local->chanctx_list);
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		sdata->radar_required = sdata->reserved_radar_required;
+		rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
+		WARN_ON(drv_assign_vif_chanctx(local, sdata, ctx));
+	}
+err:
+	list_for_each_entry_safe(sdata, tmp, &ctx->reserved_vifs,
+				 reserved_chanctx_list) {
+		list_del(&sdata->reserved_chanctx_list);
+		sdata->reserved_chanctx = NULL;
+		ieee80211_vif_chanctx_reservation_complete(sdata);
+	}
+	return err;
+}
+
+static int
+ieee80211_vif_use_reserved_compat(struct ieee80211_sub_if_data *sdata,
+				  struct ieee80211_chanctx *old_ctx,
+				  struct ieee80211_chanctx *new_ctx)
+{
+	struct ieee80211_local *local = sdata->local;
+	u32 changed = 0;
+	int err;
+
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_del(&sdata->reserved_chanctx_list);
+	sdata->reserved_chanctx = NULL;
+
+	err = ieee80211_assign_vif_chanctx(sdata, new_ctx);
+	if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
+		ieee80211_free_chanctx(local, old_ctx);
+	if (err) {
+		/* if assign fails refcount stays the same */
+		if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
+			ieee80211_free_chanctx(local, new_ctx);
+		goto out;
+	}
+
+	if (sdata->vif.type == NL80211_IFTYPE_AP)
+		__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
+
+	if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
+		changed = BSS_CHANGED_BANDWIDTH;
+
+	sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
+
+	if (changed)
+		ieee80211_bss_info_change_notify(sdata, changed);
+
 out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
+	ieee80211_vif_chanctx_reservation_complete(sdata);
+	return err;
+}
+
+int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_chanctx *ctx;
+	struct ieee80211_chanctx *old_ctx;
+	struct ieee80211_chanctx_conf *conf;
+	const struct cfg80211_chan_def *chandef;
+
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	ctx = sdata->reserved_chanctx;
+	if (WARN_ON(!ctx))
+		return -EINVAL;
+
+	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+					 lockdep_is_held(&local->chanctx_mtx));
+	if (!conf)
+		return -EINVAL;
+
+	old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
+
+	if (WARN_ON(sdata->reserved_ready))
+		return -EINVAL;
+
+	chandef = ieee80211_chanctx_reserved_chandef(local, ctx, NULL);
+	if (WARN_ON(!chandef))
+		return -EINVAL;
+
+	sdata->reserved_ready = true;
+
+	if (cfg80211_chandef_compatible(&ctx->conf.def, chandef))
+		return ieee80211_vif_use_reserved_compat(sdata, old_ctx, ctx);
+	else
+		return ieee80211_vif_use_reserved_incompat(local, ctx, chandef);
 }
 
 int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 2de8121..3c1033a 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -765,6 +765,7 @@ struct ieee80211_sub_if_data {
 	struct ieee80211_chanctx *reserved_chanctx;
 	struct cfg80211_chan_def reserved_chandef;
 	bool reserved_radar_required;
+	bool reserved_ready;
 
 	/* used to reconfigure hardware SM PS */
 	struct work_struct recalc_smps;
@@ -1785,8 +1786,7 @@ ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 			      enum ieee80211_chanctx_mode mode,
 			      bool radar_required);
 int __must_check
-ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
-				   u32 *changed);
+ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata);
 int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata);
 
 int __must_check
-- 
1.8.5.3


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

* [RFC 14/21] mac80211: fix CSA tx queue locking
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (12 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 13/21] mac80211: implement multi-vif in-place reservations Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 15/21] mac80211: split CSA finalize function Michal Kazior
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

It was possible for tx queues to be stuck locked
if AP CSA finalization failed. In that case
stop_ap nor do_stop woke the queues up. This means
it was impossible to perform tx at all until
driver was reloaded or a successful CSA was
performed later.

It was possible to solve this in a simpler manner
however this is more robust and future proof
(having multi-vif CSA in mind).

New sdata->csa_block_tx is introduced to keep
track of which interfaces requested tx to be
blocked for CSA. This is required because mac80211
locks all tx queues for that purpose. This means
queues must be unlocked only when last tx-blocking
CSA interface is finished.

It is still possible to have tx queues stopped
after CSA failure but as soon as offending
interfaces are stopped from userspace (stop_ap or
ifdown) tx queues are woken up properly.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 include/net/mac80211.h     |  4 ++-
 net/mac80211/cfg.c         | 78 +++++++++++++++++++++++++++++++++++++---------
 net/mac80211/ieee80211_i.h |  2 ++
 net/mac80211/iface.c       |  7 +++++
 net/mac80211/mlme.c        | 30 ++++++++++++------
 5 files changed, 97 insertions(+), 24 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 86faa41..d284411 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1111,7 +1111,9 @@ enum ieee80211_vif_flags {
  * @addr: address of this interface
  * @p2p: indicates whether this AP or STA interface is a p2p
  *	interface, i.e. a GO or p2p-sta respectively
- * @csa_active: marks whether a channel switch is going on
+ * @csa_active: marks whether a channel switch is going on. Internally it is
+ *	write-protected by sdata_lock and local->mtx so holding either is fine
+ *	for read access.
  * @driver_flags: flags/capabilities the driver has for this interface,
  *	these need to be set (or cleared) when the interface is added
  *	or, if supported by the driver, the interface type is changed
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 954259d..4cc4149 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1084,6 +1084,31 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
 	return 0;
 }
 
+bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	lockdep_assert_held(&local->mtx);
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+		if (!ieee80211_sdata_running(sdata))
+			continue;
+
+		if (!sdata->vif.csa_active)
+			continue;
+
+		if (!sdata->csa_block_tx)
+			continue;
+
+		rcu_read_unlock();
+		return true;
+	}
+	rcu_read_unlock();
+
+	return false;
+}
+
 static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1101,7 +1126,14 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
 	old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata);
 
 	/* abort any running channel switch */
+	mutex_lock(&local->mtx);
 	sdata->vif.csa_active = false;
+	if (!ieee80211_csa_needs_block_tx(local))
+		ieee80211_wake_queues_by_reason(&local->hw,
+					IEEE80211_MAX_QUEUE_MAP,
+					IEEE80211_QUEUE_STOP_REASON_CSA);
+	mutex_unlock(&local->mtx);
+
 	kfree(sdata->u.ap.next_beacon);
 	sdata->u.ap.next_beacon = NULL;
 
@@ -3025,11 +3057,10 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
 	int err, changed = 0;
 
 	sdata_assert_lock(sdata);
+	lockdep_assert_held(&local->mtx);
 
-	mutex_lock(&local->mtx);
 	sdata->radar_required = sdata->csa_radar_required;
 	err = ieee80211_vif_change_channel(sdata, &changed);
-	mutex_unlock(&local->mtx);
 	if (WARN_ON(err < 0))
 		return;
 
@@ -3070,10 +3101,6 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
 
 	ieee80211_bss_info_change_notify(sdata, changed);
 
-	ieee80211_wake_queues_by_reason(&sdata->local->hw,
-					IEEE80211_MAX_QUEUE_MAP,
-					IEEE80211_QUEUE_STOP_REASON_CSA);
-
 	cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
 }
 
@@ -3082,8 +3109,11 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
 	struct ieee80211_sub_if_data *sdata =
 		container_of(work, struct ieee80211_sub_if_data,
 			     csa_finalize_work);
+	struct ieee80211_local *local = sdata->local;
 
 	sdata_lock(sdata);
+	mutex_lock(&local->mtx);
+
 	/* AP might have been stopped while waiting for the lock. */
 	if (!sdata->vif.csa_active)
 		goto unlock;
@@ -3092,8 +3122,13 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
 		goto unlock;
 
 	ieee80211_csa_finalize(sdata);
+	if (!ieee80211_csa_needs_block_tx(local))
+		ieee80211_wake_queues_by_reason(&local->hw,
+					IEEE80211_MAX_QUEUE_MAP,
+					IEEE80211_QUEUE_STOP_REASON_CSA);
 
 unlock:
+	mutex_unlock(&local->mtx);
 	sdata_unlock(sdata);
 }
 
@@ -3220,8 +3255,8 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
 	return 0;
 }
 
-int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
-			     struct cfg80211_csa_settings *params)
+int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+			       struct cfg80211_csa_settings *params)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
@@ -3230,6 +3265,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 	int err, num_chanctx, changed = 0;
 
 	sdata_assert_lock(sdata);
+	lockdep_assert_held(&local->mtx);
 
 	if (!list_empty(&local->roc_list) || local->scanning)
 		return -EBUSY;
@@ -3272,15 +3308,15 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 		return err;
 
 	sdata->csa_radar_required = params->radar_required;
-
-	if (params->block_tx)
-		ieee80211_stop_queues_by_reason(&local->hw,
-				IEEE80211_MAX_QUEUE_MAP,
-				IEEE80211_QUEUE_STOP_REASON_CSA);
-
 	sdata->csa_chandef = params->chandef;
+	sdata->csa_block_tx = params->block_tx;
 	sdata->vif.csa_active = true;
 
+	if (sdata->csa_block_tx)
+		ieee80211_wake_queues_by_reason(&local->hw,
+					IEEE80211_MAX_QUEUE_MAP,
+					IEEE80211_QUEUE_STOP_REASON_CSA);
+
 	if (changed) {
 		ieee80211_bss_info_change_notify(sdata, changed);
 		drv_channel_switch_beacon(sdata, &params->chandef);
@@ -3292,6 +3328,20 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 	return 0;
 }
 
+int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+			     struct cfg80211_csa_settings *params)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
+	int err;
+
+	mutex_lock(&local->mtx);
+	err = __ieee80211_channel_switch(wiphy, dev, params);
+	mutex_unlock(&local->mtx);
+
+	return err;
+}
+
 static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 			     struct cfg80211_mgmt_tx_params *params,
 			     u64 *cookie)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3c1033a..82fedd9 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -756,6 +756,7 @@ struct ieee80211_sub_if_data {
 	int csa_counter_offset_beacon;
 	int csa_counter_offset_presp;
 	bool csa_radar_required;
+	bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
 	struct cfg80211_chan_def csa_chandef;
 
 	struct list_head assigned_chanctx_list;
@@ -1472,6 +1473,7 @@ void ieee80211_sw_roc_work(struct work_struct *work);
 void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
 
 /* channel switch handling */
+bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local);
 void ieee80211_csa_finalize_work(struct work_struct *work);
 int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 			     struct cfg80211_csa_settings *params);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index d09185b..1211317 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -838,8 +838,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
 
 	cancel_work_sync(&sdata->recalc_smps);
 	sdata_lock(sdata);
+	mutex_lock(&local->mtx);
 	sdata->vif.csa_active = false;
+	if (!ieee80211_csa_needs_block_tx(local))
+		ieee80211_wake_queues_by_reason(&local->hw,
+					IEEE80211_MAX_QUEUE_MAP,
+					IEEE80211_QUEUE_STOP_REASON_CSA);
+	mutex_unlock(&local->mtx);
 	sdata_unlock(sdata);
+
 	cancel_work_sync(&sdata->csa_finalize_work);
 
 	cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index a4d8e99..f5589c7 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -975,15 +975,18 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 	/* XXX: shouldn't really modify cfg80211-owned data! */
 	ifmgd->associated->channel = sdata->csa_chandef.chan;
 
-	/* XXX: wait for a beacon first? */
-	ieee80211_wake_queues_by_reason(&local->hw,
-					IEEE80211_MAX_QUEUE_MAP,
-					IEEE80211_QUEUE_STOP_REASON_CSA);
-
 	ieee80211_bss_info_change_notify(sdata, changed);
 
  out:
+	mutex_lock(&local->mtx);
 	sdata->vif.csa_active = false;
+	/* XXX: wait for a beacon first? */
+	if (!ieee80211_csa_needs_block_tx(local))
+		ieee80211_wake_queues_by_reason(&local->hw,
+					IEEE80211_MAX_QUEUE_MAP,
+					IEEE80211_QUEUE_STOP_REASON_CSA);
+	mutex_unlock(&local->mtx);
+
 	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
 	sdata_unlock(sdata);
 }
@@ -1100,12 +1103,16 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	mutex_unlock(&local->chanctx_mtx);
 
 	sdata->csa_chandef = csa_ie.chandef;
+
+	mutex_lock(&local->mtx);
 	sdata->vif.csa_active = true;
+	sdata->csa_block_tx = csa_ie.mode;
 
-	if (csa_ie.mode)
+	if (sdata->csa_block_tx)
 		ieee80211_stop_queues_by_reason(&local->hw,
-				IEEE80211_MAX_QUEUE_MAP,
-				IEEE80211_QUEUE_STOP_REASON_CSA);
+					IEEE80211_MAX_QUEUE_MAP,
+					IEEE80211_QUEUE_STOP_REASON_CSA);
+	mutex_unlock(&local->mtx);
 
 	if (local->ops->channel_switch) {
 		/* use driver's channel switch callback */
@@ -2045,6 +2052,7 @@ EXPORT_SYMBOL(ieee80211_ap_probereq_get);
 
 static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
 {
+	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
 
@@ -2058,10 +2066,14 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
 			       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
 			       true, frame_buf);
 	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
+
+	mutex_lock(&local->mtx);
 	sdata->vif.csa_active = false;
-	ieee80211_wake_queues_by_reason(&sdata->local->hw,
+	if (!ieee80211_csa_needs_block_tx(local))
+		ieee80211_wake_queues_by_reason(&local->hw,
 					IEEE80211_MAX_QUEUE_MAP,
 					IEEE80211_QUEUE_STOP_REASON_CSA);
+	mutex_unlock(&local->mtx);
 
 	cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
 			      IEEE80211_DEAUTH_FRAME_LEN);
-- 
1.8.5.3


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

* [RFC 15/21] mac80211: split CSA finalize function
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (13 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 14/21] mac80211: fix CSA tx queue locking Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 16/21] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Improves readability and modularity.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/cfg.c | 61 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 37 insertions(+), 24 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 4cc4149..5f63e1d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3051,25 +3051,11 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif)
 }
 EXPORT_SYMBOL(ieee80211_csa_finish);
 
-static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
+static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata,
+					  u32 *changed)
 {
-	struct ieee80211_local *local = sdata->local;
-	int err, changed = 0;
-
-	sdata_assert_lock(sdata);
-	lockdep_assert_held(&local->mtx);
-
-	sdata->radar_required = sdata->csa_radar_required;
-	err = ieee80211_vif_change_channel(sdata, &changed);
-	if (WARN_ON(err < 0))
-		return;
-
-	if (!local->use_chanctx) {
-		local->_oper_chandef = sdata->csa_chandef;
-		ieee80211_hw_config(local, 0);
-	}
+	int err;
 
-	sdata->vif.csa_active = false;
 	switch (sdata->vif.type) {
 	case NL80211_IFTYPE_AP:
 		err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
@@ -3077,30 +3063,57 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
 		sdata->u.ap.next_beacon = NULL;
 
 		if (err < 0)
-			return;
-		changed |= err;
+			return err;
+		*changed |= err;
 		break;
 	case NL80211_IFTYPE_ADHOC:
 		err = ieee80211_ibss_finish_csa(sdata);
 		if (err < 0)
-			return;
-		changed |= err;
+			return err;
+		*changed |= err;
 		break;
 #ifdef CONFIG_MAC80211_MESH
 	case NL80211_IFTYPE_MESH_POINT:
 		err = ieee80211_mesh_finish_csa(sdata);
 		if (err < 0)
-			return;
-		changed |= err;
+			return err;
+		*changed |= err;
 		break;
 #endif
 	default:
 		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	u32 changed = 0;
+	int err;
+
+	sdata_assert_lock(sdata);
+	lockdep_assert_held(&local->mtx);
+
+	sdata->radar_required = sdata->csa_radar_required;
+	err = ieee80211_vif_change_channel(sdata, &changed);
+	if (WARN_ON(err < 0))
 		return;
+
+	if (!local->use_chanctx) {
+		local->_oper_chandef = sdata->csa_chandef;
+		ieee80211_hw_config(local, 0);
 	}
 
-	ieee80211_bss_info_change_notify(sdata, changed);
+	sdata->vif.csa_active = false;
+
+	err = ieee80211_set_after_csa_beacon(sdata, &changed);
+	if (err)
+		return;
 
+	ieee80211_bss_info_change_notify(sdata, changed);
 	cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
 }
 
-- 
1.8.5.3


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

* [RFC 16/21] mac80211: make check_combinations() aware of chanctx reservation
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (14 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 15/21] mac80211: split CSA finalize function Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 17/21] mac80211: use chanctx reservation for AP CSA Michal Kazior
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The ieee80211_check_combinations() computes
radar_detect accordingly depending on chanctx
reservation status.

This makes it possible to use the function for
channel_switch validation.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/util.c | 37 +++++++++++++++++++++++++++++++++++--
 1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 2e3e6a3..db1411e 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2798,6 +2798,40 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
 	ps->dtim_count = dtim_count;
 }
 
+static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local,
+					 struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_chanctx_conf *conf;
+	u8 radar_detect = 0;
+	bool in_place = false;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		if (sdata->reserved_radar_required)
+			radar_detect |= BIT(sdata->reserved_chandef.width);
+
+		conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+				lockdep_is_held(&local->chanctx_mtx));
+		if (conf == &ctx->conf)
+			in_place = true;
+	}
+
+	/* if chanctx has in-place reservation then consider only the future
+	 * radar_detect. multi-vif reservation is deferred so ignore assigned
+	 * vifs. it is impossible for new vifs to be bound to an in-place
+	 * reserved chanctx so consistency is guranteed */
+	if (in_place)
+		return radar_detect;
+
+	list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
+		if (sdata->radar_required)
+			radar_detect |= BIT(sdata->vif.bss_conf.chandef.width);
+
+	return radar_detect;
+}
+
 int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 				 const struct cfg80211_chan_def *chandef,
 				 enum ieee80211_chanctx_mode chanmode,
@@ -2839,8 +2873,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 		num[iftype] = 1;
 
 	list_for_each_entry(ctx, &local->chanctx_list, list) {
-		if (ctx->conf.radar_enabled)
-			radar_detect |= BIT(ctx->conf.def.width);
+		radar_detect |= ieee80211_chanctx_radar_detect(local, ctx);
 		if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
 			num_different_channels++;
 			continue;
-- 
1.8.5.3


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

* [RFC 17/21] mac80211: use chanctx reservation for AP CSA
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (15 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 16/21] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 18/21] mac80211: use chanctx reservation for STA CSA Michal Kazior
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Channel switch finalization is now 2-step. First
step is when driver calls csa_finish(), the other
is when reservation is actually finalized (which
be defered for in-place reservation).

This implies driver must not call csa_finish()
more than once for each channel_switch request.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/cfg.c  | 77 +++++++++++++++++++++++++++++++++++++----------------
 net/mac80211/chan.c | 11 +++++++-
 2 files changed, 64 insertions(+), 24 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5f63e1d..3979f2f 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3088,7 +3088,7 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata,
 	return 0;
 }
 
-static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
+static int ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_local *local = sdata->local;
 	u32 changed = 0;
@@ -3096,25 +3096,35 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
 
 	sdata_assert_lock(sdata);
 	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->mtx);
 
-	sdata->radar_required = sdata->csa_radar_required;
-	err = ieee80211_vif_change_channel(sdata, &changed);
-	if (WARN_ON(err < 0))
-		return;
+	/* using reservation isn't immediate as it may be deferred until later
+	 * with multi-vif. once reservation is complete it will re-schedule the
+	 * work with no reserved_chanctx so verify chandef to check if it
+	 * completed successfully */
 
-	if (!local->use_chanctx) {
-		local->_oper_chandef = sdata->csa_chandef;
-		ieee80211_hw_config(local, 0);
+	if (sdata->reserved_chanctx) {
+		err = ieee80211_vif_use_reserved_context(sdata);
+		if (err)
+			return err;
+
+		return 0;
 	}
 
+	if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
+					&sdata->csa_chandef))
+		return -EINVAL;
+
 	sdata->vif.csa_active = false;
 
 	err = ieee80211_set_after_csa_beacon(sdata, &changed);
 	if (err)
-		return;
+		return err;
 
 	ieee80211_bss_info_change_notify(sdata, changed);
 	cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
+
+	return 0;
 }
 
 void ieee80211_csa_finalize_work(struct work_struct *work)
@@ -3123,9 +3133,11 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
 		container_of(work, struct ieee80211_sub_if_data,
 			     csa_finalize_work);
 	struct ieee80211_local *local = sdata->local;
+	int err;
 
 	sdata_lock(sdata);
 	mutex_lock(&local->mtx);
+	mutex_lock(&local->chanctx_mtx);
 
 	/* AP might have been stopped while waiting for the lock. */
 	if (!sdata->vif.csa_active)
@@ -3134,13 +3146,20 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
 	if (!ieee80211_sdata_running(sdata))
 		goto unlock;
 
-	ieee80211_csa_finalize(sdata);
+	err = ieee80211_csa_finalize(sdata);
+	if (err) {
+		sdata_info(sdata, "failed to finalize channel switch\n");
+		/* FIXME: disconnect the interface */
+		goto unlock;
+	}
+
 	if (!ieee80211_csa_needs_block_tx(local))
 		ieee80211_wake_queues_by_reason(&local->hw,
 					IEEE80211_MAX_QUEUE_MAP,
 					IEEE80211_QUEUE_STOP_REASON_CSA);
 
 unlock:
+	mutex_unlock(&local->chanctx_mtx);
 	mutex_unlock(&local->mtx);
 	sdata_unlock(sdata);
 }
@@ -3275,7 +3294,7 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *chanctx;
-	int err, num_chanctx, changed = 0;
+	int err, changed = 0;
 
 	sdata_assert_lock(sdata);
 	lockdep_assert_held(&local->mtx);
@@ -3290,6 +3309,10 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 				       &sdata->vif.bss_conf.chandef))
 		return -EINVAL;
 
+	/* don't allow another channel switch if one is already active. */
+	if (sdata->vif.csa_active)
+		return -EBUSY;
+
 	mutex_lock(&local->chanctx_mtx);
 	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 					 lockdep_is_held(&local->chanctx_mtx));
@@ -3298,27 +3321,34 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 		return -EBUSY;
 	}
 
-	/* don't handle for multi-VIF cases */
 	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
-	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
+	if (!chanctx) {
 		mutex_unlock(&local->chanctx_mtx);
 		return -EBUSY;
 	}
-	num_chanctx = 0;
-	list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
-		num_chanctx++;
-	mutex_unlock(&local->chanctx_mtx);
 
-	if (num_chanctx > 1)
-		return -EBUSY;
+	err = ieee80211_vif_reserve_chanctx(sdata, &params->chandef,
+					    chanctx->mode,
+					    params->radar_required);
+	if (err) {
+		mutex_unlock(&local->chanctx_mtx);
+		return err;
+	}
 
-	/* don't allow another channel switch if one is already active. */
-	if (sdata->vif.csa_active)
-		return -EBUSY;
+	/* if reservation is invalid then this will fail */
+	err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0);
+	if (err) {
+		ieee80211_vif_unreserve_chanctx(sdata);
+		mutex_unlock(&local->chanctx_mtx);
+		return err;
+	}
 
 	err = ieee80211_set_csa_beacon(sdata, params, &changed);
-	if (err)
+	if (err) {
+		ieee80211_vif_unreserve_chanctx(sdata);
+		mutex_unlock(&local->chanctx_mtx);
 		return err;
+	}
 
 	sdata->csa_radar_required = params->radar_required;
 	sdata->csa_chandef = params->chandef;
@@ -3338,6 +3368,7 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 		ieee80211_csa_finalize(sdata);
 	}
 
+	mutex_unlock(&local->chanctx_mtx);
 	return 0;
 }
 
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 7cf8970..2959b7f 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -965,7 +965,16 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 static void
 ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
 {
-	/* stub */
+	switch (sdata->vif.type) {
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MESH_POINT:
+		ieee80211_queue_work(&sdata->local->hw,
+				     &sdata->csa_finalize_work);
+		break;
+	default:
+		break;
+	}
 }
 
 static int
-- 
1.8.5.3


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

* [RFC 18/21] mac80211: use chanctx reservation for STA CSA
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (16 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 17/21] mac80211: use chanctx reservation for AP CSA Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 19/21] mac80211: ignore cqm during csa Michal Kazior
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Channel switch finalization is now 2-step. First
step is when driver calls chswitch_done(), the
other is when reservation is actually finalized
(which be defered for in-place reservation).

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c |  4 +++
 net/mac80211/mlme.c | 90 ++++++++++++++++++++++++++++++++---------------------
 2 files changed, 59 insertions(+), 35 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 2959b7f..6f621ba 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -972,6 +972,10 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
 		ieee80211_queue_work(&sdata->local->hw,
 				     &sdata->csa_finalize_work);
 		break;
+	case NL80211_IFTYPE_STATION:
+		ieee80211_queue_work(&sdata->local->hw,
+				     &sdata->u.mgd.chswitch_work);
+		break;
 	default:
 		break;
 	}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index f5589c7..e729da3 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -940,54 +940,66 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 		container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	u32 changed = 0;
 	int ret;
 
 	if (!ieee80211_sdata_running(sdata))
 		return;
 
 	sdata_lock(sdata);
+	mutex_lock(&local->mtx);
+	mutex_lock(&local->chanctx_mtx);
+
 	if (!ifmgd->associated)
+		goto cleanup;
+
+	if (!sdata->vif.csa_active)
+		goto cleanup;
+
+	/* using reservation isn't immediate as it may be deferred until later
+	 * with multi-vif. once reservation is complete it will re-schedule the
+	 * work with no reserved_chanctx so verify chandef to check if it
+	 * completed successfully */
+
+	if (sdata->reserved_chanctx) {
+		ret = ieee80211_vif_use_reserved_context(sdata);
+		if (ret) {
+			sdata_info(sdata,
+				   "failed to use reserved channel context, disconnecting (err=%d)\n",
+				   ret);
+			ieee80211_queue_work(&sdata->local->hw,
+					     &ifmgd->csa_connection_drop_work);
+			goto cleanup;
+		}
+
 		goto out;
+	}
 
-	mutex_lock(&local->mtx);
-	ret = ieee80211_vif_change_channel(sdata, &changed);
-	mutex_unlock(&local->mtx);
-	if (ret) {
+	if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
+					&sdata->csa_chandef)) {
 		sdata_info(sdata,
-			   "vif channel switch failed, disconnecting\n");
+			   "failed to finalize channel switch, disconnecting\n");
 		ieee80211_queue_work(&sdata->local->hw,
 				     &ifmgd->csa_connection_drop_work);
-		goto out;
-	}
-
-	if (!local->use_chanctx) {
-		local->_oper_chandef = sdata->csa_chandef;
-		/* Call "hw_config" only if doing sw channel switch.
-		 * Otherwise update the channel directly
-		 */
-		if (!local->ops->channel_switch)
-			ieee80211_hw_config(local, 0);
-		else
-			local->hw.conf.chandef = local->_oper_chandef;
+		goto cleanup;
 	}
 
 	/* XXX: shouldn't really modify cfg80211-owned data! */
 	ifmgd->associated->channel = sdata->csa_chandef.chan;
 
-	ieee80211_bss_info_change_notify(sdata, changed);
-
- out:
-	mutex_lock(&local->mtx);
+cleanup:
 	sdata->vif.csa_active = false;
+
 	/* XXX: wait for a beacon first? */
 	if (!ieee80211_csa_needs_block_tx(local))
 		ieee80211_wake_queues_by_reason(&local->hw,
 					IEEE80211_MAX_QUEUE_MAP,
 					IEEE80211_QUEUE_STOP_REASON_CSA);
-	mutex_unlock(&local->mtx);
 
 	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
+
+out:
+	mutex_unlock(&local->chanctx_mtx);
+	mutex_unlock(&local->mtx);
 	sdata_unlock(sdata);
 }
 
@@ -1024,6 +1036,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct cfg80211_bss *cbss = ifmgd->associated;
+	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *chanctx;
 	enum ieee80211_band current_band;
 	struct ieee80211_csa_ie csa_ie;
@@ -1068,6 +1081,19 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
 
 	mutex_lock(&local->chanctx_mtx);
+	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+					 lockdep_is_held(&local->chanctx_mtx));
+	if (!conf) {
+		sdata_info(sdata,
+			   "no channel context assigned to vif?, disconnecting\n");
+		ieee80211_queue_work(&local->hw,
+				     &ifmgd->csa_connection_drop_work);
+		mutex_unlock(&local->chanctx_mtx);
+		return;
+	}
+
+	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
+
 	if (local->use_chanctx) {
 		u32 num_chanctx = 0;
 		list_for_each_entry(chanctx, &local->chanctx_list, list)
@@ -1084,17 +1110,12 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
-	if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) {
-		ieee80211_queue_work(&local->hw,
-				     &ifmgd->csa_connection_drop_work);
-		mutex_unlock(&local->chanctx_mtx);
-		return;
-	}
-	chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
-			       struct ieee80211_chanctx, conf);
-	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
+	res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef,
+					    chanctx->mode, false);
+	if (res) {
 		sdata_info(sdata,
-			   "channel switch with multiple interfaces on the same channel, disconnecting\n");
+			   "failed to reserve channel context for channel switch, disconnecting (err=%d)\n",
+			   res);
 		ieee80211_queue_work(&local->hw,
 				     &ifmgd->csa_connection_drop_work);
 		mutex_unlock(&local->chanctx_mtx);
@@ -1102,10 +1123,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	}
 	mutex_unlock(&local->chanctx_mtx);
 
-	sdata->csa_chandef = csa_ie.chandef;
-
 	mutex_lock(&local->mtx);
 	sdata->vif.csa_active = true;
+	sdata->csa_chandef = csa_ie.chandef;
 	sdata->csa_block_tx = csa_ie.mode;
 
 	if (sdata->csa_block_tx)
-- 
1.8.5.3


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

* [RFC 19/21] mac80211: ignore cqm during csa
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (17 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 18/21] mac80211: use chanctx reservation for STA CSA Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 20/21] mac80211: remove old unused channel switching code Michal Kazior
                   ` (4 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

It is not guaranteed that multi-vif channel
switching is tightly synchronized. It makes sense
to ignore cqm (missing beacons, et al) while csa
is progressing and re-check it after it completes.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/mlme.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e729da3..c654a1c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -997,6 +997,9 @@ cleanup:
 
 	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
 
+	ieee80211_sta_reset_beacon_monitor(sdata);
+	ieee80211_sta_reset_conn_monitor(sdata);
+
 out:
 	mutex_unlock(&local->chanctx_mtx);
 	mutex_unlock(&local->mtx);
@@ -3586,6 +3589,9 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
 	if (local->quiescing)
 		return;
 
+	if (sdata->vif.csa_active)
+		return;
+
 	sdata->u.mgd.connection_loss = false;
 	ieee80211_queue_work(&sdata->local->hw,
 			     &sdata->u.mgd.beacon_connection_loss_work);
@@ -3601,6 +3607,9 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data)
 	if (local->quiescing)
 		return;
 
+	if (sdata->vif.csa_active)
+		return;
+
 	ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
 }
 
-- 
1.8.5.3


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

* [RFC 20/21] mac80211: remove old unused channel switching code
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (18 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 19/21] mac80211: ignore cqm during csa Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 13:53 ` [RFC 21/21] cfg80211: remove channel_switch combination check Michal Kazior
                   ` (3 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

ieee80211_vif_change_channel() has no uses
anymore. sdata->csa_radar_required is also removed
because it is no longer used. Instead reservations
take care of tracking whether an interface
requires radar detection or not.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/cfg.c         |  1 -
 net/mac80211/chan.c        | 64 ----------------------------------------------
 net/mac80211/ieee80211_i.h |  5 ----
 3 files changed, 70 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 3979f2f..de48653 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3350,7 +3350,6 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 		return err;
 	}
 
-	sdata->csa_radar_required = params->radar_required;
 	sdata->csa_chandef = params->chandef;
 	sdata->csa_block_tx = params->block_tx;
 	sdata->vif.csa_active = true;
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 6f621ba..2a54dc4 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -800,70 +800,6 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 	return ret;
 }
 
-static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-					  struct ieee80211_chanctx *ctx,
-					  u32 *changed)
-{
-	struct ieee80211_local *local = sdata->local;
-	const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;
-	u32 chanctx_changed = 0;
-
-	if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
-				     IEEE80211_CHAN_DISABLED))
-		return -EINVAL;
-
-	if (ieee80211_chanctx_refcount(local, ctx) != 1)
-		return -EINVAL;
-
-	if (sdata->vif.bss_conf.chandef.width != chandef->width) {
-		chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH;
-		*changed |= BSS_CHANGED_BANDWIDTH;
-	}
-
-	sdata->vif.bss_conf.chandef = *chandef;
-	ctx->conf.def = *chandef;
-
-	chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL;
-	drv_change_chanctx(local, ctx, chanctx_changed);
-
-	ieee80211_recalc_chanctx_chantype(local, ctx);
-	ieee80211_recalc_smps_chanctx(local, ctx);
-	ieee80211_recalc_radar_chanctx(local, ctx);
-	ieee80211_recalc_chanctx_min_def(local, ctx);
-
-	return 0;
-}
-
-int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-				 u32 *changed)
-{
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx_conf *conf;
-	struct ieee80211_chanctx *ctx;
-	int ret;
-
-	lockdep_assert_held(&local->mtx);
-
-	/* should never be called if not performing a channel switch. */
-	if (WARN_ON(!sdata->vif.csa_active))
-		return -EINVAL;
-
-	mutex_lock(&local->chanctx_mtx);
-	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	ctx = container_of(conf, struct ieee80211_chanctx, conf);
-
-	ret = __ieee80211_vif_change_channel(sdata, ctx, changed);
- out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
-}
-
 static void
 __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 				      bool clear)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 82fedd9..3f46c6c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -755,7 +755,6 @@ struct ieee80211_sub_if_data {
 	struct work_struct csa_finalize_work;
 	int csa_counter_offset_beacon;
 	int csa_counter_offset_presp;
-	bool csa_radar_required;
 	bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
 	struct cfg80211_chan_def csa_chandef;
 
@@ -1795,10 +1794,6 @@ int __must_check
 ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
 			       const struct cfg80211_chan_def *chandef,
 			       u32 *changed);
-/* NOTE: only use ieee80211_vif_change_channel() for channel switch */
-int __must_check
-ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-			     u32 *changed);
 void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
-- 
1.8.5.3


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

* [RFC 21/21] cfg80211: remove channel_switch combination check
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (19 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 20/21] mac80211: remove old unused channel switching code Michal Kazior
@ 2014-03-18 13:53 ` Michal Kazior
  2014-03-18 15:52 ` [RFC 00/21] cfg80211/mac80211: multi-vif csa Eliad Peller
                   ` (2 subsequent siblings)
  23 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-18 13:53 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Make the driver responsible for making sure it is
capable of performing the switch. It might as well
accept a request but then disconnect an interface
if some requirements are not met.

In that case userspace should be prepared for an
appropriate event (AP/IBSS/mesh being stopped/left).

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/wireless/nl80211.c | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5465e0e..6b7ded9 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5921,17 +5921,6 @@ skip_beacons:
 		params.radar_required = true;
 	}
 
-	/* TODO: I left this here for now.  With channel switch, the
-	 * verification is a bit more complicated, because we only do
-	 * it later when the channel switch really happens.
-	 */
-	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-					   params.chandef.chan,
-					   CHAN_MODE_SHARED,
-					   radar_detect_width);
-	if (err)
-		return err;
-
 	if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
 		params.block_tx = true;
 
-- 
1.8.5.3


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

* Re: [RFC 00/21] cfg80211/mac80211: multi-vif csa
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (20 preceding siblings ...)
  2014-03-18 13:53 ` [RFC 21/21] cfg80211: remove channel_switch combination check Michal Kazior
@ 2014-03-18 15:52 ` Eliad Peller
  2014-03-19  9:34   ` Luca Coelho
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
  2014-03-21 13:52 ` [PATCH v2 0/7] cfg80211/mac80211: implement multi-vif csa Michal Kazior
  23 siblings, 1 reply; 199+ messages in thread
From: Eliad Peller @ 2014-03-18 15:52 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg

hi,

On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
> I'm aware this is rather huge. I'm hoping I can
> get some early feedback before all other patches
> I'm depending on are finally merged into
> mac80211-next.
>
> Considering current dependency hell of all related
> the patchsets I'm duplicating some of my patches
> I've posted on the mailing list here. Hopefully
> this is sane enough for reviewing purposes.
>
> The patchset alone is based on:
>  * mac80211-next/master
>  * VLAN chanctx copy refactor
>  * Luca's intf combination patches
>  * Luca's chanctx reservation patches
>
it could be nice to have some unified branch somewhere with all these
patchsets. :)
(i tried doing it locally, but encountered merging errors)

Eliad.

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

* Re: [RFC 03/21] mac80211: add max channel calculation utility function
  2014-03-18 13:53 ` [RFC 03/21] mac80211: add max channel calculation utility function Michal Kazior
@ 2014-03-18 16:17   ` Eliad Peller
  2014-03-19  8:32     ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Eliad Peller @ 2014-03-18 16:17 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg

hi,

On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
> The utility function has no uses yet. It is aimed
> at future chanctx reservation management and
> channel switching.
>
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
> ---
[...]

> +int ieee80211_max_num_channels(struct ieee80211_local *local)
> +{
> +       struct ieee80211_sub_if_data *sdata;
> +       int num[NUM_NL80211_IFTYPES] = {};
> +       struct ieee80211_chanctx *ctx;
> +       int num_different_channels = 0;
> +       u8 radar_detect = 0;
> +       u32 max_num_different_channels = 1;
> +       int err;
> +
> +       lockdep_assert_held(&local->chanctx_mtx);
> +
> +       list_for_each_entry(ctx, &local->chanctx_list, list) {
> +               num_different_channels++;
> +
this doesn't seem correct - i think we can have multiple channel
contexts with the same channel (e.g. due to exclusive mode)?

Eliad.

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

* Re: [RFC 04/21] mac80211: prevent chanctx overcommit
  2014-03-18 13:53 ` [RFC 04/21] mac80211: prevent chanctx overcommit Michal Kazior
@ 2014-03-18 16:25   ` Eliad Peller
  0 siblings, 0 replies; 199+ messages in thread
From: Eliad Peller @ 2014-03-18 16:25 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg

On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
> Do not allocate more channel contexts than a
> driver is capable for currently matching interface
> combination.
>
> This allows the ieee80211_vif_reserve_chanctx() to
> act as a guard against breaking interface
> combinations.
>
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
> ---
[...]

> +static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
> +{
> +       lockdep_assert_held(&local->chanctx_mtx);
> +       return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
> +}
the same goes here - num_channels and num_chanctx are two different
things (afaiu).
i don't think you can compare them this way.

Eliad.

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

* Re: [RFC 07/21] mac80211: improve find_chanctx() for reservations
  2014-03-18 13:53 ` [RFC 07/21] mac80211: improve find_chanctx() for reservations Michal Kazior
@ 2014-03-18 16:42   ` Eliad Peller
  2014-03-19  8:34     ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Eliad Peller @ 2014-03-18 16:42 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg

On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
> Relax ieee80211_find_chanctx(). If chanctx
> reservation chandef is compatible with
> current-future assigned interfaces chandef then
> allow it to be used by new interfaces.
>
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
> ---
[...]

> +static const struct cfg80211_chan_def *
> +ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
> +                                  struct ieee80211_chanctx *ctx,
> +                                  const struct cfg80211_chan_def *compat)
> +{
> +       struct ieee80211_sub_if_data *sdata;
> +
> +       lockdep_assert_held(&local->chanctx_mtx);
> +
> +       list_for_each_entry(sdata, &ctx->reserved_vifs,
> +                           reserved_chanctx_list) {
> +               if (!compat)
> +                       compat = &sdata->reserved_chandef;
this check is redundant.

Eliad.

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

* Re: [RFC 08/21] mac80211: improve chanctx reservation lookup
  2014-03-18 13:53 ` [RFC 08/21] mac80211: improve chanctx reservation lookup Michal Kazior
@ 2014-03-18 16:57   ` Eliad Peller
  2014-03-19  8:45     ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Eliad Peller @ 2014-03-18 16:57 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg

On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
> Use a separate function to look for reservation
> chanctx. For multi-interface/channel reservation
> search sematics differ slightly.
>
> The new routine allows reservations to be merged
> with chanctx that are already reserved by other
> interface(s).
>
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
> ---
[...]

> +static const struct cfg80211_chan_def *
> +ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
> +                                      struct ieee80211_chanctx *ctx,
> +                                      const struct cfg80211_chan_def *compat)
> +{
> +       struct ieee80211_sub_if_data *sdata;
> +
> +       lockdep_assert_held(&local->chanctx_mtx);
> +
> +       list_for_each_entry(sdata, &ctx->assigned_vifs,
> +                           assigned_chanctx_list) {
> +               if (rcu_access_pointer(sdata->reserved_chanctx) != NULL)
> +                       continue;
this is not rcu pointer...

> +static const struct cfg80211_chan_def *
> +ieee80211_chanctx_combined_chandef(struct ieee80211_local *local,
> +                                  struct ieee80211_chanctx *ctx,
> +                                  const struct cfg80211_chan_def *compat)
> +{
> +       lockdep_assert_held(&local->chanctx_mtx);
> +
> +       compat = ieee80211_chanctx_reserved_chandef(local, ctx, compat);
> +       if (!compat)
> +               return NULL;
> +
> +       compat = ieee80211_chanctx_non_reserved_chandef(local, ctx, compat);
> +       if (!compat)
> +               return NULL;
> +
> +       return compat;
> +}
> +
> +static bool
> +ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local,
> +                                     struct ieee80211_chanctx *ctx,
> +                                     const struct cfg80211_chan_def *def)
> +{
> +       lockdep_assert_held(&local->chanctx_mtx);
> +
> +       if (ieee80211_chanctx_combined_chandef(local, ctx, NULL) &&
> +           ieee80211_chanctx_combined_chandef(local, ctx, def))
> +               return true;
> +
what's the reason for calling it with NULL?

> +       if (!list_empty(&ctx->reserved_vifs) &&
> +           ieee80211_chanctx_reserved_chandef(local, ctx, NULL) &&
> +           ieee80211_chanctx_reserved_chandef(local, ctx, def))
> +               return true;
and this seems redundant as _combined_chandef() should already check for it?

Eliad.

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

* Re: [RFC 03/21] mac80211: add max channel calculation utility function
  2014-03-18 16:17   ` Eliad Peller
@ 2014-03-19  8:32     ` Michal Kazior
  2014-03-19  8:43       ` Eliad Peller
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-19  8:32 UTC (permalink / raw)
  To: Eliad Peller; +Cc: linux-wireless, Johannes Berg

On 18 March 2014 17:17, Eliad Peller <eliad@wizery.com> wrote:
> hi,
>
> On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
>> The utility function has no uses yet. It is aimed
>> at future chanctx reservation management and
>> channel switching.
>>
>> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
>> ---
> [...]
>
>> +int ieee80211_max_num_channels(struct ieee80211_local *local)
>> +{
>> +       struct ieee80211_sub_if_data *sdata;
>> +       int num[NUM_NL80211_IFTYPES] = {};
>> +       struct ieee80211_chanctx *ctx;
>> +       int num_different_channels = 0;
>> +       u8 radar_detect = 0;
>> +       u32 max_num_different_channels = 1;
>> +       int err;
>> +
>> +       lockdep_assert_held(&local->chanctx_mtx);
>> +
>> +       list_for_each_entry(ctx, &local->chanctx_list, list) {
>> +               num_different_channels++;
>> +
> this doesn't seem correct - i think we can have multiple channel
> contexts with the same channel (e.g. due to exclusive mode)?

Hmm, does it even make sense to consider chanctx mode here?


Michał

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

* Re: [RFC 07/21] mac80211: improve find_chanctx() for reservations
  2014-03-18 16:42   ` Eliad Peller
@ 2014-03-19  8:34     ` Michal Kazior
  2014-03-19  8:47       ` Eliad Peller
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-19  8:34 UTC (permalink / raw)
  To: Eliad Peller; +Cc: linux-wireless, Johannes Berg

On 18 March 2014 17:42, Eliad Peller <eliad@wizery.com> wrote:
> On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
>> Relax ieee80211_find_chanctx(). If chanctx
>> reservation chandef is compatible with
>> current-future assigned interfaces chandef then
>> allow it to be used by new interfaces.
>>
>> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
>> ---
> [...]
>
>> +static const struct cfg80211_chan_def *
>> +ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
>> +                                  struct ieee80211_chanctx *ctx,
>> +                                  const struct cfg80211_chan_def *compat)
>> +{
>> +       struct ieee80211_sub_if_data *sdata;
>> +
>> +       lockdep_assert_held(&local->chanctx_mtx);
>> +
>> +       list_for_each_entry(sdata, &ctx->reserved_vifs,
>> +                           reserved_chanctx_list) {
>> +               if (!compat)
>> +                       compat = &sdata->reserved_chandef;
> this check is redundant.

It isn't. The function can be called with compat == NULL. You don't
want to call cfg80211_chandef_compatible() with a NULL chandef.


Michał

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

* Re: [RFC 03/21] mac80211: add max channel calculation utility function
  2014-03-19  8:32     ` Michal Kazior
@ 2014-03-19  8:43       ` Eliad Peller
  2014-03-19  8:54         ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Eliad Peller @ 2014-03-19  8:43 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg

On Wed, Mar 19, 2014 at 10:32 AM, Michal Kazior <michal.kazior@tieto.com> wrote:
> On 18 March 2014 17:17, Eliad Peller <eliad@wizery.com> wrote:
>> hi,
>>
>> On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
>>> The utility function has no uses yet. It is aimed
>>> at future chanctx reservation management and
>>> channel switching.
>>>
>>> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
>>> ---
>> [...]
>>
>>> +int ieee80211_max_num_channels(struct ieee80211_local *local)
>>> +{
>>> +       struct ieee80211_sub_if_data *sdata;
>>> +       int num[NUM_NL80211_IFTYPES] = {};
>>> +       struct ieee80211_chanctx *ctx;
>>> +       int num_different_channels = 0;
>>> +       u8 radar_detect = 0;
>>> +       u32 max_num_different_channels = 1;
>>> +       int err;
>>> +
>>> +       lockdep_assert_held(&local->chanctx_mtx);
>>> +
>>> +       list_for_each_entry(ctx, &local->chanctx_list, list) {
>>> +               num_different_channels++;
>>> +
>> this doesn't seem correct - i think we can have multiple channel
>> contexts with the same channel (e.g. due to exclusive mode)?
>
> Hmm, does it even make sense to consider chanctx mode here?
>
i don't think you should consider the chancx mode, but keep track of
the used channels.
if you have 2 different channel contexts with the same channel (e.g.
due to exclusive mode), you have to make sure you don't count the same
channel twice. you shouldn't care about the actual reason for it.

Eliad.

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

* Re: [RFC 08/21] mac80211: improve chanctx reservation lookup
  2014-03-18 16:57   ` Eliad Peller
@ 2014-03-19  8:45     ` Michal Kazior
  0 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-19  8:45 UTC (permalink / raw)
  To: Eliad Peller; +Cc: linux-wireless, Johannes Berg

On 18 March 2014 17:57, Eliad Peller <eliad@wizery.com> wrote:
> On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
>> Use a separate function to look for reservation
>> chanctx. For multi-interface/channel reservation
>> search sematics differ slightly.
>>
>> The new routine allows reservations to be merged
>> with chanctx that are already reserved by other
>> interface(s).
>>
>> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
>> ---
> [...]
>
>> +static const struct cfg80211_chan_def *
>> +ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
>> +                                      struct ieee80211_chanctx *ctx,
>> +                                      const struct cfg80211_chan_def *compat)
>> +{
>> +       struct ieee80211_sub_if_data *sdata;
>> +
>> +       lockdep_assert_held(&local->chanctx_mtx);
>> +
>> +       list_for_each_entry(sdata, &ctx->assigned_vifs,
>> +                           assigned_chanctx_list) {
>> +               if (rcu_access_pointer(sdata->reserved_chanctx) != NULL)
>> +                       continue;
> this is not rcu pointer...

Good catch, thanks! I must've missed this while rebasing.


>> +static bool
>> +ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local,
>> +                                     struct ieee80211_chanctx *ctx,
>> +                                     const struct cfg80211_chan_def *def)
>> +{
>> +       lockdep_assert_held(&local->chanctx_mtx);
>> +
>> +       if (ieee80211_chanctx_combined_chandef(local, ctx, NULL) &&
>> +           ieee80211_chanctx_combined_chandef(local, ctx, def))
>> +               return true;
>> +
> what's the reason for calling it with NULL?
>
>> +       if (!list_empty(&ctx->reserved_vifs) &&
>> +           ieee80211_chanctx_reserved_chandef(local, ctx, NULL) &&
>> +           ieee80211_chanctx_reserved_chandef(local, ctx, def))
>> +               return true;
> and this seems redundant as _combined_chandef() should already check for it?

Hmm, good point. I'll get rid of these redundant checks.


Michał

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

* Re: [RFC 07/21] mac80211: improve find_chanctx() for reservations
  2014-03-19  8:34     ` Michal Kazior
@ 2014-03-19  8:47       ` Eliad Peller
  2014-03-19  9:00         ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Eliad Peller @ 2014-03-19  8:47 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg

On Wed, Mar 19, 2014 at 10:34 AM, Michal Kazior <michal.kazior@tieto.com> wrote:
> On 18 March 2014 17:42, Eliad Peller <eliad@wizery.com> wrote:
>> On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
>>> Relax ieee80211_find_chanctx(). If chanctx
>>> reservation chandef is compatible with
>>> current-future assigned interfaces chandef then
>>> allow it to be used by new interfaces.
>>>
>>> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
>>> ---
>> [...]
>>
>>> +static const struct cfg80211_chan_def *
>>> +ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
>>> +                                  struct ieee80211_chanctx *ctx,
>>> +                                  const struct cfg80211_chan_def *compat)
>>> +{
>>> +       struct ieee80211_sub_if_data *sdata;
>>> +
>>> +       lockdep_assert_held(&local->chanctx_mtx);
>>> +
>>> +       list_for_each_entry(sdata, &ctx->reserved_vifs,
>>> +                           reserved_chanctx_list) {
>>> +               if (!compat)
>>> +                       compat = &sdata->reserved_chandef;
>> this check is redundant.
>
> It isn't. The function can be called with compat == NULL. You don't
> want to call cfg80211_chandef_compatible() with a NULL chandef.
>
at least this patch has an explicit check for compat not being NULL
(before calling the function).
since this function checks chandef compatibility with current
reserved chandefs, i don't see why anyone would call it with NULL?

Eliad.

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

* Re: [RFC 03/21] mac80211: add max channel calculation utility function
  2014-03-19  8:43       ` Eliad Peller
@ 2014-03-19  8:54         ` Michal Kazior
  2014-03-19 10:18           ` Eliad Peller
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-19  8:54 UTC (permalink / raw)
  To: Eliad Peller; +Cc: linux-wireless, Johannes Berg

On 19 March 2014 09:43, Eliad Peller <eliad@wizery.com> wrote:
> On Wed, Mar 19, 2014 at 10:32 AM, Michal Kazior <michal.kazior@tieto.com> wrote:
>> On 18 March 2014 17:17, Eliad Peller <eliad@wizery.com> wrote:
>>> hi,
>>>
>>> On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
>>>> The utility function has no uses yet. It is aimed
>>>> at future chanctx reservation management and
>>>> channel switching.
>>>>
>>>> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
>>>> ---
>>> [...]
>>>
>>>> +int ieee80211_max_num_channels(struct ieee80211_local *local)
>>>> +{
>>>> +       struct ieee80211_sub_if_data *sdata;
>>>> +       int num[NUM_NL80211_IFTYPES] = {};
>>>> +       struct ieee80211_chanctx *ctx;
>>>> +       int num_different_channels = 0;
>>>> +       u8 radar_detect = 0;
>>>> +       u32 max_num_different_channels = 1;
>>>> +       int err;
>>>> +
>>>> +       lockdep_assert_held(&local->chanctx_mtx);
>>>> +
>>>> +       list_for_each_entry(ctx, &local->chanctx_list, list) {
>>>> +               num_different_channels++;
>>>> +
>>> this doesn't seem correct - i think we can have multiple channel
>>> contexts with the same channel (e.g. due to exclusive mode)?
>>
>> Hmm, does it even make sense to consider chanctx mode here?
>>
> i don't think you should consider the chancx mode, but keep track of
> the used channels.
> if you have 2 different channel contexts with the same channel (e.g.
> due to exclusive mode), you have to make sure you don't count the same
> channel twice. you shouldn't care about the actual reason for it.

I disagree. There's a reason why we have exclusive chanctx mode.

If you insist on counting compatible chandefs you can lead to
overcommit if your exclusive chanctx bound interface decides to switch
to another channel.


Michał

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

* Re: [RFC 07/21] mac80211: improve find_chanctx() for reservations
  2014-03-19  8:47       ` Eliad Peller
@ 2014-03-19  9:00         ` Michal Kazior
  2014-03-19 10:53           ` Eliad Peller
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-19  9:00 UTC (permalink / raw)
  To: Eliad Peller; +Cc: linux-wireless, Johannes Berg

On 19 March 2014 09:47, Eliad Peller <eliad@wizery.com> wrote:
> On Wed, Mar 19, 2014 at 10:34 AM, Michal Kazior <michal.kazior@tieto.com> wrote:
>> On 18 March 2014 17:42, Eliad Peller <eliad@wizery.com> wrote:
>>> On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
>>>> Relax ieee80211_find_chanctx(). If chanctx
>>>> reservation chandef is compatible with
>>>> current-future assigned interfaces chandef then
>>>> allow it to be used by new interfaces.
>>>>
>>>> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
>>>> ---
>>> [...]
>>>
>>>> +static const struct cfg80211_chan_def *
>>>> +ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
>>>> +                                  struct ieee80211_chanctx *ctx,
>>>> +                                  const struct cfg80211_chan_def *compat)
>>>> +{
>>>> +       struct ieee80211_sub_if_data *sdata;
>>>> +
>>>> +       lockdep_assert_held(&local->chanctx_mtx);
>>>> +
>>>> +       list_for_each_entry(sdata, &ctx->reserved_vifs,
>>>> +                           reserved_chanctx_list) {
>>>> +               if (!compat)
>>>> +                       compat = &sdata->reserved_chandef;
>>> this check is redundant.
>>
>> It isn't. The function can be called with compat == NULL. You don't
>> want to call cfg80211_chandef_compatible() with a NULL chandef.
>>
> at least this patch has an explicit check for compat not being NULL
> (before calling the function).
> since this function checks chandef compatibility with current
> reserved chandefs, i don't see why anyone would call it with NULL?

Fair argument if you treat the patch separately from the whole patchset.

This is later called with NULL (patch: implement multi-vif in-place
reservations).

I could make a if (WARN_ON(!compat)) return NULL; guard condition at
the function start but I prefer the current way as it has wider
appliance for code reuse.


Michał

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

* Re: [RFC 00/21] cfg80211/mac80211: multi-vif csa
  2014-03-18 15:52 ` [RFC 00/21] cfg80211/mac80211: multi-vif csa Eliad Peller
@ 2014-03-19  9:34   ` Luca Coelho
  0 siblings, 0 replies; 199+ messages in thread
From: Luca Coelho @ 2014-03-19  9:34 UTC (permalink / raw)
  To: Eliad Peller; +Cc: Michal Kazior, linux-wireless, Johannes Berg

On Tue, 2014-03-18 at 17:52 +0200, Eliad Peller wrote:
> hi,
> 
> On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
> > I'm aware this is rather huge. I'm hoping I can
> > get some early feedback before all other patches
> > I'm depending on are finally merged into
> > mac80211-next.
> >
> > Considering current dependency hell of all related
> > the patchsets I'm duplicating some of my patches
> > I've posted on the mailing list here. Hopefully
> > this is sane enough for reviewing purposes.
> >
> > The patchset alone is based on:
> >  * mac80211-next/master
> >  * VLAN chanctx copy refactor
> >  * Luca's intf combination patches
> >  * Luca's chanctx reservation patches
> >
> it could be nice to have some unified branch somewhere with all these
> patchsets. :)
> (i tried doing it locally, but encountered merging errors)

I have created a repo in git.kernel.org for us, based on
mac80211-next.git.  There's nothing there yet, but I'll start populating
it with our patches soon.

git://git.kernel.org/pub/scm/linux/kernel/git/luca/mac80211-next-csa.git

--
Cheers,
Luca.


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

* Re: [RFC 03/21] mac80211: add max channel calculation utility function
  2014-03-19  8:54         ` Michal Kazior
@ 2014-03-19 10:18           ` Eliad Peller
  0 siblings, 0 replies; 199+ messages in thread
From: Eliad Peller @ 2014-03-19 10:18 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg

On Wed, Mar 19, 2014 at 10:54 AM, Michal Kazior <michal.kazior@tieto.com> wrote:
> On 19 March 2014 09:43, Eliad Peller <eliad@wizery.com> wrote:
>> On Wed, Mar 19, 2014 at 10:32 AM, Michal Kazior <michal.kazior@tieto.com> wrote:
>>> On 18 March 2014 17:17, Eliad Peller <eliad@wizery.com> wrote:
>>>> hi,
>>>>
>>>> On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
>>>>> The utility function has no uses yet. It is aimed
>>>>> at future chanctx reservation management and
>>>>> channel switching.
>>>>>
>>>>> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
>>>>> ---
>>>> [...]
>>>>
>>>>> +int ieee80211_max_num_channels(struct ieee80211_local *local)
>>>>> +{
>>>>> +       struct ieee80211_sub_if_data *sdata;
>>>>> +       int num[NUM_NL80211_IFTYPES] = {};
>>>>> +       struct ieee80211_chanctx *ctx;
>>>>> +       int num_different_channels = 0;
>>>>> +       u8 radar_detect = 0;
>>>>> +       u32 max_num_different_channels = 1;
>>>>> +       int err;
>>>>> +
>>>>> +       lockdep_assert_held(&local->chanctx_mtx);
>>>>> +
>>>>> +       list_for_each_entry(ctx, &local->chanctx_list, list) {
>>>>> +               num_different_channels++;
>>>>> +
>>>> this doesn't seem correct - i think we can have multiple channel
>>>> contexts with the same channel (e.g. due to exclusive mode)?
>>>
>>> Hmm, does it even make sense to consider chanctx mode here?
>>>
>> i don't think you should consider the chancx mode, but keep track of
>> the used channels.
>> if you have 2 different channel contexts with the same channel (e.g.
>> due to exclusive mode), you have to make sure you don't count the same
>> channel twice. you shouldn't care about the actual reason for it.
>
> I disagree. There's a reason why we have exclusive chanctx mode.
>
> If you insist on counting compatible chandefs you can lead to
> overcommit if your exclusive chanctx bound interface decides to switch
> to another channel.
>
ok. fair point. i guess you're right.

Eliad.

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

* Re: [RFC 07/21] mac80211: improve find_chanctx() for reservations
  2014-03-19  9:00         ` Michal Kazior
@ 2014-03-19 10:53           ` Eliad Peller
  0 siblings, 0 replies; 199+ messages in thread
From: Eliad Peller @ 2014-03-19 10:53 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg

On Wed, Mar 19, 2014 at 11:00 AM, Michal Kazior <michal.kazior@tieto.com> wrote:
> On 19 March 2014 09:47, Eliad Peller <eliad@wizery.com> wrote:
>> On Wed, Mar 19, 2014 at 10:34 AM, Michal Kazior <michal.kazior@tieto.com> wrote:
>>> On 18 March 2014 17:42, Eliad Peller <eliad@wizery.com> wrote:
>>>> On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
>>>>> Relax ieee80211_find_chanctx(). If chanctx
>>>>> reservation chandef is compatible with
>>>>> current-future assigned interfaces chandef then
>>>>> allow it to be used by new interfaces.
>>>>>
>>>>> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
>>>>> ---
>>>> [...]
>>>>
>>>>> +static const struct cfg80211_chan_def *
>>>>> +ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
>>>>> +                                  struct ieee80211_chanctx *ctx,
>>>>> +                                  const struct cfg80211_chan_def *compat)
>>>>> +{
>>>>> +       struct ieee80211_sub_if_data *sdata;
>>>>> +
>>>>> +       lockdep_assert_held(&local->chanctx_mtx);
>>>>> +
>>>>> +       list_for_each_entry(sdata, &ctx->reserved_vifs,
>>>>> +                           reserved_chanctx_list) {
>>>>> +               if (!compat)
>>>>> +                       compat = &sdata->reserved_chandef;
>>>> this check is redundant.
>>>
>>> It isn't. The function can be called with compat == NULL. You don't
>>> want to call cfg80211_chandef_compatible() with a NULL chandef.
>>>
>> at least this patch has an explicit check for compat not being NULL
>> (before calling the function).
>> since this function checks chandef compatibility with current
>> reserved chandefs, i don't see why anyone would call it with NULL?
>
> Fair argument if you treat the patch separately from the whole patchset.
>
> This is later called with NULL (patch: implement multi-vif in-place
> reservations).
>
> I could make a if (WARN_ON(!compat)) return NULL; guard condition at
> the function start but I prefer the current way as it has wider
> appliance for code reuse.
>
ok. i haven't passed through all the patches yet.
if you use it later with NULL there's no reason to change it.

Eliad.

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

* Re: [RFC 13/21] mac80211: implement multi-vif in-place reservations
  2014-03-18 13:53 ` [RFC 13/21] mac80211: implement multi-vif in-place reservations Michal Kazior
@ 2014-03-19 18:35   ` Eliad Peller
  2014-03-20  7:25     ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Eliad Peller @ 2014-03-19 18:35 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg

On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
> Multi-vif in-place reservations happen when
> it's impossible to allocate more chanctx as per
> driver combinations.
>
> Such reservations aren't finalized until last
> reservation interface calls in to use the
> reservation.
>
> This introduces a special hook
> ieee80211_vif_chanctx_reservation_complete(). This
> is currently an empty stub and will be filled in
> by AP/STA CSA code. This is required to implement
> 2-step CSA finalization.
>
> This also gets rid of driver requirement to be
> able to re-program channel of a chanctx.
>
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
> ---
[...]

i started playing with the patches and got some warnings.
they seem to come from:

> +static int
> +ieee80211_vif_use_reserved_incompat(struct ieee80211_local *local,
> +                                   struct ieee80211_chanctx *ctx,
> +                                   const struct cfg80211_chan_def *chandef)
> +{
[...]

> +       new_ctx = ieee80211_alloc_chanctx(local, chandef, ctx->mode);
> +       if (!new_ctx) {
> +               err = -ENOMEM;
> +               goto err;
>         }
>
> -       old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
> +               drv_unassign_vif_chanctx(local, sdata, ctx);
> +               rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
> +       }
>
> -       if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
> -               tmp_changed |= BSS_CHANGED_BANDWIDTH;
> +       list_del_rcu(&ctx->list);
> +       ieee80211_del_chanctx(local, ctx);
>
> -       sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
> +       err = ieee80211_add_chanctx(local, new_ctx);
> +       if (err)
> +               goto err_revert;
>
> -       /* unref our reservation */
> -       sdata->reserved_chanctx = NULL;
> -       sdata->radar_required = sdata->reserved_radar_required;
> -       list_del(&sdata->reserved_chanctx_list);
> +       /* don't simply overwrite radar_required in case of failure */
> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
> +               bool tmp = sdata->radar_required;
> +               sdata->radar_required = sdata->reserved_radar_required;
> +               sdata->reserved_radar_required = tmp;
> +       }
>
> -       if (old_ctx == ctx) {
> -               /* This is our own context, just change it */
> -               ret = __ieee80211_vif_change_channel(sdata, old_ctx,
> -                                                    &tmp_changed);
> -               if (ret)
> -                       goto out;
> -       } else {
> -               ret = ieee80211_assign_vif_chanctx(sdata, ctx);
> -               if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
> -                       ieee80211_free_chanctx(local, old_ctx);
> -               if (ret) {
> -                       /* if assign fails refcount stays the same */
> -                       if (ieee80211_chanctx_refcount(local, ctx) == 0)
> -                               ieee80211_free_chanctx(local, ctx);
> -                       goto out;
> -               }
> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
> +               err = drv_assign_vif_chanctx(local, sdata, ctx);

this should be new_ctx (ctx was already removed from the driver, etc.)

> +               if (err)
> +                       goto err_unassign;
> +       }
>
> +       if (sdata->vif.type == NL80211_IFTYPE_AP)
>                 __ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
> -       }
>
> -       *changed = tmp_changed;
> +       list_add_rcu(&new_ctx->list, &local->chanctx_list);
> +       kfree_rcu(ctx, rcu_head);
>
>         ieee80211_recalc_chanctx_chantype(local, ctx);
>         ieee80211_recalc_smps_chanctx(local, ctx);
>         ieee80211_recalc_radar_chanctx(local, ctx);
>         ieee80211_recalc_chanctx_min_def(local, ctx);

and same here i guess.

all the recalcs have to be moved after setting bss_conf.chandef in the
following loop, as otherwise you it recalcs according to the old
configuration (which is incompatible with the new one).

after these changes the warnings were gone.
i haven't done throughout testing, though.

Eliad.

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

* Re: [RFC 13/21] mac80211: implement multi-vif in-place reservations
  2014-03-19 18:35   ` Eliad Peller
@ 2014-03-20  7:25     ` Michal Kazior
  0 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-20  7:25 UTC (permalink / raw)
  To: Eliad Peller; +Cc: linux-wireless, Johannes Berg

On 19 March 2014 19:35, Eliad Peller <eliad@wizery.com> wrote:
> On Tue, Mar 18, 2014 at 3:53 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
>> Multi-vif in-place reservations happen when
>> it's impossible to allocate more chanctx as per
>> driver combinations.
>>
>> Such reservations aren't finalized until last
>> reservation interface calls in to use the
>> reservation.
>>
>> This introduces a special hook
>> ieee80211_vif_chanctx_reservation_complete(). This
>> is currently an empty stub and will be filled in
>> by AP/STA CSA code. This is required to implement
>> 2-step CSA finalization.
>>
>> This also gets rid of driver requirement to be
>> able to re-program channel of a chanctx.
>>
>> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
>> ---
> [...]
>
> i started playing with the patches and got some warnings.
> they seem to come from:
>
>> +static int
>> +ieee80211_vif_use_reserved_incompat(struct ieee80211_local *local,
>> +                                   struct ieee80211_chanctx *ctx,
>> +                                   const struct cfg80211_chan_def *chandef)
>> +{
> [...]
>
>> +       new_ctx = ieee80211_alloc_chanctx(local, chandef, ctx->mode);
>> +       if (!new_ctx) {
>> +               err = -ENOMEM;
>> +               goto err;
>>         }
>>
>> -       old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
>> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>> +               drv_unassign_vif_chanctx(local, sdata, ctx);
>> +               rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
>> +       }
>>
>> -       if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
>> -               tmp_changed |= BSS_CHANGED_BANDWIDTH;
>> +       list_del_rcu(&ctx->list);
>> +       ieee80211_del_chanctx(local, ctx);
>>
>> -       sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
>> +       err = ieee80211_add_chanctx(local, new_ctx);
>> +       if (err)
>> +               goto err_revert;
>>
>> -       /* unref our reservation */
>> -       sdata->reserved_chanctx = NULL;
>> -       sdata->radar_required = sdata->reserved_radar_required;
>> -       list_del(&sdata->reserved_chanctx_list);
>> +       /* don't simply overwrite radar_required in case of failure */
>> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>> +               bool tmp = sdata->radar_required;
>> +               sdata->radar_required = sdata->reserved_radar_required;
>> +               sdata->reserved_radar_required = tmp;
>> +       }
>>
>> -       if (old_ctx == ctx) {
>> -               /* This is our own context, just change it */
>> -               ret = __ieee80211_vif_change_channel(sdata, old_ctx,
>> -                                                    &tmp_changed);
>> -               if (ret)
>> -                       goto out;
>> -       } else {
>> -               ret = ieee80211_assign_vif_chanctx(sdata, ctx);
>> -               if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
>> -                       ieee80211_free_chanctx(local, old_ctx);
>> -               if (ret) {
>> -                       /* if assign fails refcount stays the same */
>> -                       if (ieee80211_chanctx_refcount(local, ctx) == 0)
>> -                               ieee80211_free_chanctx(local, ctx);
>> -                       goto out;
>> -               }
>> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>> +               err = drv_assign_vif_chanctx(local, sdata, ctx);
>
> this should be new_ctx (ctx was already removed from the driver, etc.)

Good catch, thanks!


>> +               if (err)
>> +                       goto err_unassign;
>> +       }
>>
>> +       if (sdata->vif.type == NL80211_IFTYPE_AP)
>>                 __ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
>> -       }
>>
>> -       *changed = tmp_changed;
>> +       list_add_rcu(&new_ctx->list, &local->chanctx_list);
>> +       kfree_rcu(ctx, rcu_head);
>>
>>         ieee80211_recalc_chanctx_chantype(local, ctx);
>>         ieee80211_recalc_smps_chanctx(local, ctx);
>>         ieee80211_recalc_radar_chanctx(local, ctx);
>>         ieee80211_recalc_chanctx_min_def(local, ctx);
>
> and same here i guess.

Yep. You're right.


> all the recalcs have to be moved after setting bss_conf.chandef in the
> following loop, as otherwise you it recalcs according to the old
> configuration (which is incompatible with the new one).

Thanks for pointing that out. I'll fix that too.


Michał

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

* [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (21 preceding siblings ...)
  2014-03-18 15:52 ` [RFC 00/21] cfg80211/mac80211: multi-vif csa Eliad Peller
@ 2014-03-21 13:47 ` Michal Kazior
  2014-03-21 13:47   ` [PATCH v2 01/13] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
                     ` (13 more replies)
  2014-03-21 13:52 ` [PATCH v2 0/7] cfg80211/mac80211: implement multi-vif csa Michal Kazior
  23 siblings, 14 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Hi,

This is part of my multi-vif csa work. These
patches have been included in my recent big RFC.
I'm trying to split it up a bit.

The patchset incrementally improves chanctx
reservations in order to support multi-vif
reservations and in-place multi-vif reservations
(typically for single-channel hardware, but
multi-channel benefits from this too).

Some of the patches (the refcounting) were also
posted a while ago as a separate small RFC.

This is based on Luca's combination and
reservation patches and my CSA fixes/cleanups.


v2:
 * add changelog for refcounting patches
 * fixes for issues pointed out by Eliad


Michal Kazior (13):
  cfg80211: allow drivers to iterate over matching combinations
  mac80211: add max channel calculation utility function
  mac80211: prevent chanctx overcommit
  mac80211: add support for radar detection for reservations
  mac80211: track assigned vifs in chanctx
  mac80211: track reserved vifs in chanctx
  mac80211: improve find_chanctx() for reservations
  mac80211: improve chanctx reservation lookup
  mac80211: split ieee80211_new_chanctx()
  mac80211: split ieee80211_free_chanctx()
  mac80211: fix racy usage of chanctx->refcount
  mac80211: compute chanctx refcount on-the-fly
  mac80211: implement multi-vif in-place reservations

 include/net/cfg80211.h     |  27 ++
 include/net/mac80211.h     |   7 -
 net/mac80211/cfg.c         |  19 +-
 net/mac80211/chan.c        | 597 ++++++++++++++++++++++++++++++++++-----------
 net/mac80211/ieee80211_i.h |  18 +-
 net/mac80211/iface.c       |   2 +
 net/mac80211/mlme.c        |   2 +-
 net/mac80211/util.c        |  43 ++++
 net/wireless/util.c        |  44 +++-
 9 files changed, 592 insertions(+), 167 deletions(-)

-- 
1.8.5.3


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

* [PATCH v2 01/13] cfg80211: allow drivers to iterate over matching combinations
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
@ 2014-03-21 13:47   ` Michal Kazior
  2014-03-28 13:05     ` Johannes Berg
  2014-03-21 13:47   ` [PATCH v2 02/13] mac80211: add max channel calculation utility function Michal Kazior
                     ` (12 subsequent siblings)
  13 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The patch splits cfg80211_check_combinations()
into an iterator function and a simple iteration
user.

This makes it possible for drivers to asses how
many channels can use given iftype setup. This in
turn can be used for future
multi-interface/multi-channel channel switching.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 include/net/cfg80211.h | 27 +++++++++++++++++++++++++++
 net/wireless/util.c    | 44 +++++++++++++++++++++++++++++++++++++-------
 2 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7f0cbfb..21766b9 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4720,6 +4720,33 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
  */
 void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev);
 
+/**
+ * cfg80211_iter_combinations - iterate over matching combinations
+ *
+ * @wiphy: the wiphy
+ * @num_different_channels: the number of different channels we want
+ *	to use for verification
+ * @radar_detect: a bitmap where each bit corresponds to a channel
+ *	width where radar detection is needed, as in the definition of
+ *	&struct ieee80211_iface_combination.@radar_detect_widths
+ * @iftype_num: array with the numbers of interfaces of each interface
+ *	type.  The index is the interface type as specified in &enum
+ *	nl80211_iftype.
+ * @iter: function to call for each matching combination
+ * @data: pointer to pass to iter function
+ *
+ * This function can be called by the driver to check what possible
+ * combinations it fits in at a given moment, e.g. for channel switching
+ * purposes.
+ */
+int cfg80211_iter_combinations(struct wiphy *wiphy,
+			       const int num_different_channels,
+			       const u8 radar_detect,
+			       const int iftype_num[NUM_NL80211_IFTYPES],
+			       void (*iter)(const struct ieee80211_iface_combination *c,
+					    void *data),
+			       void *data);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 241f0ad..7fa3503 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1252,10 +1252,13 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
 	return res;
 }
 
-int cfg80211_check_combinations(struct wiphy *wiphy,
-				const int num_different_channels,
-				const u8 radar_detect,
-				const int iftype_num[NUM_NL80211_IFTYPES])
+int cfg80211_iter_combinations(struct wiphy *wiphy,
+			       const int num_different_channels,
+			       const u8 radar_detect,
+			       const int iftype_num[NUM_NL80211_IFTYPES],
+			       void (*iter)(const struct ieee80211_iface_combination *c,
+					    void *data),
+			       void *data)
 {
 	int i, j, iftype;
 	int num_interfaces = 0;
@@ -1312,13 +1315,40 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
 		/* This combination covered all interface types and
 		 * supported the requested numbers, so we're good.
 		 */
-		kfree(limits);
-		return 0;
+
+		(*iter)(c, data);
  cont:
 		kfree(limits);
 	}
 
-	return -EBUSY;
+	return 0;
+}
+EXPORT_SYMBOL(cfg80211_iter_combinations);
+
+static void
+cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
+			  void *data)
+{
+	int *num = data;
+	(*num)++;
+}
+
+int cfg80211_check_combinations(struct wiphy *wiphy,
+				const int num_different_channels,
+				const u8 radar_detect,
+				const int iftype_num[NUM_NL80211_IFTYPES])
+{
+	int err, num = 0;
+
+	err = cfg80211_iter_combinations(wiphy, num_different_channels,
+					 radar_detect, iftype_num,
+					 cfg80211_iter_sum_ifcombs, &num);
+	if (err)
+		return err;
+	if (num == 0)
+		return -EBUSY;
+
+	return 0;
 }
 EXPORT_SYMBOL(cfg80211_check_combinations);
 
-- 
1.8.5.3


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

* [PATCH v2 02/13] mac80211: add max channel calculation utility function
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
  2014-03-21 13:47   ` [PATCH v2 01/13] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
@ 2014-03-21 13:47   ` Michal Kazior
  2014-03-21 13:47   ` [PATCH v2 03/13] mac80211: prevent chanctx overcommit Michal Kazior
                     ` (11 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The utility function has no uses yet. It is aimed
at future chanctx reservation management and
channel switching.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/ieee80211_i.h |  1 +
 net/mac80211/util.c        | 43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 02fe9f4..41d9e49 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1830,6 +1830,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 				 const struct cfg80211_chan_def *chandef,
 				 enum ieee80211_chanctx_mode chanmode,
 				 u8 radar_detect);
+int ieee80211_max_num_channels(struct ieee80211_local *local);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 955b043..7233102 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2877,3 +2877,46 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 					   num_different_channels,
 					   radar_detect, num);
 }
+
+static void
+ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c,
+			 void *data)
+{
+	u32 *max_num_different_channels = data;
+
+	*max_num_different_channels = max(*max_num_different_channels,
+					  c->num_different_channels);
+}
+
+int ieee80211_max_num_channels(struct ieee80211_local *local)
+{
+	struct ieee80211_sub_if_data *sdata;
+	int num[NUM_NL80211_IFTYPES] = {};
+	struct ieee80211_chanctx *ctx;
+	int num_different_channels = 0;
+	u8 radar_detect = 0;
+	u32 max_num_different_channels = 1;
+	int err;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(ctx, &local->chanctx_list, list) {
+		num_different_channels++;
+
+		if (ctx->conf.radar_enabled)
+			radar_detect |= BIT(ctx->conf.def.width);
+	}
+
+	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+		num[sdata->wdev.iftype]++;
+	}
+
+	err = cfg80211_iter_combinations(local->hw.wiphy,
+					 num_different_channels, radar_detect,
+					 num, ieee80211_iter_max_chans,
+					 &max_num_different_channels);
+	if (err < 0)
+		return err;
+
+	return max_num_different_channels;
+}
-- 
1.8.5.3


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

* [PATCH v2 03/13] mac80211: prevent chanctx overcommit
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
  2014-03-21 13:47   ` [PATCH v2 01/13] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
  2014-03-21 13:47   ` [PATCH v2 02/13] mac80211: add max channel calculation utility function Michal Kazior
@ 2014-03-21 13:47   ` Michal Kazior
  2014-03-25  7:59     ` Luca Coelho
  2014-03-21 13:47   ` [PATCH v2 04/13] mac80211: add support for radar detection for reservations Michal Kazior
                     ` (10 subsequent siblings)
  13 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Do not allocate more channel contexts than a
driver is capable for currently matching interface
combination.

This allows the ieee80211_vif_reserve_chanctx() to
act as a guard against breaking interface
combinations.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index ee77795..2bf2d01 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -9,6 +9,25 @@
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
+static int ieee80211_num_chanctx(struct ieee80211_local *local)
+{
+	struct ieee80211_chanctx *ctx;
+	int num = 0;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(ctx, &local->chanctx_list, list)
+		num++;
+
+	return num;
+}
+
+static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
+	return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -745,13 +764,16 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 			 * context, reserve our current context
 			 */
 			new_ctx = curr_ctx;
-		} else {
+		} else if (ieee80211_can_create_new_chanctx(local)) {
 			/* create a new context and reserve it */
 			new_ctx = ieee80211_new_chanctx(local, chandef, mode);
 			if (IS_ERR(new_ctx)) {
 				ret = PTR_ERR(new_ctx);
 				goto out;
 			}
+		} else {
+			ret = -EBUSY;
+			goto out;
 		}
 	}
 
-- 
1.8.5.3


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

* [PATCH v2 04/13] mac80211: add support for radar detection for reservations
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                     ` (2 preceding siblings ...)
  2014-03-21 13:47   ` [PATCH v2 03/13] mac80211: prevent chanctx overcommit Michal Kazior
@ 2014-03-21 13:47   ` Michal Kazior
  2014-03-21 13:47   ` [PATCH v2 05/13] mac80211: track assigned vifs in chanctx Michal Kazior
                     ` (9 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Initial chanctx reservation code wasn't aware of
radar detection requirements. This is necessary
for chanctx reservations to be used for channel
switching in the future.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c        | 5 ++++-
 net/mac80211/ieee80211_i.h | 4 +++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 2bf2d01..6b993f9 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -736,7 +736,8 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
 
 int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 				  const struct cfg80211_chan_def *chandef,
-				  enum ieee80211_chanctx_mode mode)
+				  enum ieee80211_chanctx_mode mode,
+				  bool radar_required)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx_conf *conf;
@@ -780,6 +781,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	new_ctx->refcount++;
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
+	sdata->reserved_radar_required = radar_required;
 out:
 	mutex_unlock(&local->chanctx_mtx);
 	return ret;
@@ -824,6 +826,7 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 	/* unref our reservation */
 	ctx->refcount--;
 	sdata->reserved_chanctx = NULL;
+	sdata->radar_required = sdata->reserved_radar_required;
 
 	if (old_ctx == ctx) {
 		/* This is our own context, just change it */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 41d9e49..a96e375 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -760,6 +760,7 @@ struct ieee80211_sub_if_data {
 	/* context reservation -- protected with chanctx_mtx */
 	struct ieee80211_chanctx *reserved_chanctx;
 	struct cfg80211_chan_def reserved_chandef;
+	bool reserved_radar_required;
 
 	/* used to reconfigure hardware SM PS */
 	struct work_struct recalc_smps;
@@ -1785,7 +1786,8 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 int __must_check
 ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 			      const struct cfg80211_chan_def *chandef,
-			      enum ieee80211_chanctx_mode mode);
+			      enum ieee80211_chanctx_mode mode,
+			      bool radar_required);
 int __must_check
 ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 				   u32 *changed);
-- 
1.8.5.3


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

* [PATCH v2 05/13] mac80211: track assigned vifs in chanctx
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                     ` (3 preceding siblings ...)
  2014-03-21 13:47   ` [PATCH v2 04/13] mac80211: add support for radar detection for reservations Michal Kazior
@ 2014-03-21 13:47   ` Michal Kazior
  2014-03-28 13:06     ` Johannes Berg
  2014-03-21 13:47   ` [PATCH v2 06/13] mac80211: track reserved " Michal Kazior
                     ` (8 subsequent siblings)
  13 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

This can be useful.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c        | 4 ++++
 net/mac80211/ieee80211_i.h | 4 ++++
 net/mac80211/iface.c       | 1 +
 3 files changed, 9 insertions(+)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 6b993f9..38d3010 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -270,6 +270,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 	if (!ctx)
 		return ERR_PTR(-ENOMEM);
 
+	INIT_LIST_HEAD(&ctx->assigned_vifs);
 	ctx->conf.def = *chandef;
 	ctx->conf.rx_chains_static = 1;
 	ctx->conf.rx_chains_dynamic = 1;
@@ -414,6 +415,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 		curr_ctx->refcount--;
 		drv_unassign_vif_chanctx(local, sdata, curr_ctx);
 		conf = NULL;
+		list_del(&sdata->assigned_chanctx_list);
 	}
 
 	if (new_ctx) {
@@ -423,6 +425,8 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 
 		new_ctx->refcount++;
 		conf = &new_ctx->conf;
+		list_add(&sdata->assigned_chanctx_list,
+			 &new_ctx->assigned_vifs);
 	}
 
 out:
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a96e375..cd776c1 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -691,6 +691,8 @@ struct ieee80211_chanctx {
 	struct list_head list;
 	struct rcu_head rcu_head;
 
+	struct list_head assigned_vifs;
+
 	enum ieee80211_chanctx_mode mode;
 	int refcount;
 	bool driver_present;
@@ -757,6 +759,8 @@ struct ieee80211_sub_if_data {
 	bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
 	struct cfg80211_chan_def csa_chandef;
 
+	struct list_head assigned_chanctx_list;
+
 	/* context reservation -- protected with chanctx_mtx */
 	struct ieee80211_chanctx *reserved_chanctx;
 	struct cfg80211_chan_def reserved_chandef;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 7ab702a..b130be3 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1296,6 +1296,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 	INIT_WORK(&sdata->work, ieee80211_iface_work);
 	INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
 	INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
+	INIT_LIST_HEAD(&sdata->assigned_chanctx_list);
 
 	switch (type) {
 	case NL80211_IFTYPE_P2P_GO:
-- 
1.8.5.3


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

* [PATCH v2 06/13] mac80211: track reserved vifs in chanctx
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                     ` (4 preceding siblings ...)
  2014-03-21 13:47   ` [PATCH v2 05/13] mac80211: track assigned vifs in chanctx Michal Kazior
@ 2014-03-21 13:47   ` Michal Kazior
  2014-03-28 13:07     ` Johannes Berg
  2014-03-21 13:47   ` [PATCH v2 07/13] mac80211: improve find_chanctx() for reservations Michal Kazior
                     ` (7 subsequent siblings)
  13 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

This can be useful.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c        | 14 ++++++++++----
 net/mac80211/ieee80211_i.h |  2 ++
 net/mac80211/iface.c       |  1 +
 3 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 38d3010..99df19c 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -271,6 +271,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 		return ERR_PTR(-ENOMEM);
 
 	INIT_LIST_HEAD(&ctx->assigned_vifs);
+	INIT_LIST_HEAD(&ctx->reserved_vifs);
 	ctx->conf.def = *chandef;
 	ctx->conf.rx_chains_static = 1;
 	ctx->conf.rx_chains_dynamic = 1;
@@ -725,16 +726,19 @@ void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 
 int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
 {
+	struct ieee80211_chanctx *ctx = sdata->reserved_chanctx;
+
 	lockdep_assert_held(&sdata->local->chanctx_mtx);
 
-	if (WARN_ON(!sdata->reserved_chanctx))
+	if (WARN_ON(!ctx))
 		return -EINVAL;
 
-	if (--sdata->reserved_chanctx->refcount == 0)
-		ieee80211_free_chanctx(sdata->local, sdata->reserved_chanctx);
-
+	list_del(&sdata->reserved_chanctx_list);
 	sdata->reserved_chanctx = NULL;
 
+	if (--ctx->refcount == 0)
+		ieee80211_free_chanctx(sdata->local, ctx);
+
 	return 0;
 }
 
@@ -782,6 +786,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
+	list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
 	new_ctx->refcount++;
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
@@ -831,6 +836,7 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 	ctx->refcount--;
 	sdata->reserved_chanctx = NULL;
 	sdata->radar_required = sdata->reserved_radar_required;
+	list_del(&sdata->reserved_chanctx_list);
 
 	if (old_ctx == ctx) {
 		/* This is our own context, just change it */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index cd776c1..6c5969b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -692,6 +692,7 @@ struct ieee80211_chanctx {
 	struct rcu_head rcu_head;
 
 	struct list_head assigned_vifs;
+	struct list_head reserved_vifs;
 
 	enum ieee80211_chanctx_mode mode;
 	int refcount;
@@ -760,6 +761,7 @@ struct ieee80211_sub_if_data {
 	struct cfg80211_chan_def csa_chandef;
 
 	struct list_head assigned_chanctx_list;
+	struct list_head reserved_chanctx_list;
 
 	/* context reservation -- protected with chanctx_mtx */
 	struct ieee80211_chanctx *reserved_chanctx;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index b130be3..75a852d 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1297,6 +1297,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 	INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
 	INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
 	INIT_LIST_HEAD(&sdata->assigned_chanctx_list);
+	INIT_LIST_HEAD(&sdata->reserved_chanctx_list);
 
 	switch (type) {
 	case NL80211_IFTYPE_P2P_GO:
-- 
1.8.5.3


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

* [PATCH v2 07/13] mac80211: improve find_chanctx() for reservations
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                     ` (5 preceding siblings ...)
  2014-03-21 13:47   ` [PATCH v2 06/13] mac80211: track reserved " Michal Kazior
@ 2014-03-21 13:47   ` Michal Kazior
  2014-03-28 13:08     ` Johannes Berg
  2014-03-21 13:47   ` [PATCH v2 08/13] mac80211: improve chanctx reservation lookup Michal Kazior
                     ` (6 subsequent siblings)
  13 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Relax ieee80211_find_chanctx(). If chanctx
reservation chandef is compatible with
current-future assigned interfaces chandef then
allow it to be used by new interfaces.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 56 +++++++++++++++++++++++++++--------------------------
 1 file changed, 29 insertions(+), 27 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 99df19c..1361788 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -28,6 +28,29 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
 	return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
 }
 
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
+				   struct ieee80211_chanctx *ctx,
+				   const struct cfg80211_chan_def *compat)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs,
+			    reserved_chanctx_list) {
+		if (!compat)
+			compat = &sdata->reserved_chandef;
+
+		compat = cfg80211_chandef_compatible(&sdata->reserved_chandef,
+						     compat);
+		if (!compat)
+			break;
+	}
+
+	return compat;
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -181,27 +204,6 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
 	}
 }
 
-static bool ieee80211_chanctx_is_reserved(struct ieee80211_local *local,
-					  struct ieee80211_chanctx *ctx)
-{
-	struct ieee80211_sub_if_data *sdata;
-	bool ret = false;
-
-	lockdep_assert_held(&local->chanctx_mtx);
-	rcu_read_lock();
-	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-		if (!ieee80211_sdata_running(sdata))
-			continue;
-		if (sdata->reserved_chanctx == ctx) {
-			ret = true;
-			break;
-		}
-	}
-
-	rcu_read_unlock();
-	return ret;
-}
-
 static struct ieee80211_chanctx *
 ieee80211_find_chanctx(struct ieee80211_local *local,
 		       const struct cfg80211_chan_def *chandef,
@@ -217,18 +219,18 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
 	list_for_each_entry(ctx, &local->chanctx_list, list) {
 		const struct cfg80211_chan_def *compat;
 
-		/* We don't support chanctx reservation for multiple
-		 * vifs yet, so don't allow reserved chanctxs to be
-		 * reused.
-		 */
-		if ((ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) ||
-		    ieee80211_chanctx_is_reserved(local, ctx))
+		if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
 			continue;
 
 		compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef);
 		if (!compat)
 			continue;
 
+		compat = ieee80211_chanctx_reserved_chandef(local, ctx,
+							    compat);
+		if (!compat)
+			continue;
+
 		ieee80211_change_chanctx(local, ctx, compat);
 
 		return ctx;
-- 
1.8.5.3


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

* [PATCH v2 08/13] mac80211: improve chanctx reservation lookup
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                     ` (6 preceding siblings ...)
  2014-03-21 13:47   ` [PATCH v2 07/13] mac80211: improve find_chanctx() for reservations Michal Kazior
@ 2014-03-21 13:47   ` Michal Kazior
  2014-03-21 13:47   ` [PATCH v2 09/13] mac80211: split ieee80211_new_chanctx() Michal Kazior
                     ` (5 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Use a separate function to look for reservation
chanctx. For multi-interface/channel reservation
search sematics differ slightly.

The new routine allows reservations to be merged
with chanctx that are already reserved by other
interface(s).

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v2:
 * remove redundant calls to _chandef() [Eliad]
 * dont use rcu_access_pointer() [Eliad]

 net/mac80211/chan.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 88 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 1361788..b82e0c1 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -51,6 +51,93 @@ ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
 	return compat;
 }
 
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
+				       struct ieee80211_chanctx *ctx,
+				       const struct cfg80211_chan_def *compat)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->assigned_vifs,
+			    assigned_chanctx_list) {
+		if (sdata->reserved_chanctx != NULL)
+			continue;
+
+		if (!compat)
+			compat = &sdata->vif.bss_conf.chandef;
+
+		compat = cfg80211_chandef_compatible(
+				&sdata->vif.bss_conf.chandef, compat);
+		if (!compat)
+			break;
+	}
+
+	return compat;
+}
+
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_combined_chandef(struct ieee80211_local *local,
+				   struct ieee80211_chanctx *ctx,
+				   const struct cfg80211_chan_def *compat)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	compat = ieee80211_chanctx_reserved_chandef(local, ctx, compat);
+	if (!compat)
+		return NULL;
+
+	compat = ieee80211_chanctx_non_reserved_chandef(local, ctx, compat);
+	if (!compat)
+		return NULL;
+
+	return compat;
+}
+
+static bool
+ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local,
+				      struct ieee80211_chanctx *ctx,
+				      const struct cfg80211_chan_def *def)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	if (ieee80211_chanctx_combined_chandef(local, ctx, def))
+		return true;
+
+	if (!list_empty(&ctx->reserved_vifs) &&
+	    ieee80211_chanctx_reserved_chandef(local, ctx, def))
+		return true;
+
+	return false;
+}
+
+static struct ieee80211_chanctx *
+ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
+				   const struct cfg80211_chan_def *chandef,
+				   enum ieee80211_chanctx_mode mode)
+{
+	struct ieee80211_chanctx *ctx;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
+		return NULL;
+
+	list_for_each_entry(ctx, &local->chanctx_list, list) {
+		if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
+			continue;
+
+		if (!ieee80211_chanctx_can_reserve_chandef(local, ctx,
+							   chandef))
+			continue;
+
+		return ctx;
+	}
+
+	return NULL;
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -765,8 +852,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 
 	curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-	/* try to find another context with the chandef we want */
-	new_ctx = ieee80211_find_chanctx(local, chandef, mode);
+	new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
 	if (!new_ctx) {
 		if (curr_ctx->refcount == 1 &&
 		    (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
-- 
1.8.5.3


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

* [PATCH v2 09/13] mac80211: split ieee80211_new_chanctx()
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                     ` (7 preceding siblings ...)
  2014-03-21 13:47   ` [PATCH v2 08/13] mac80211: improve chanctx reservation lookup Michal Kazior
@ 2014-03-21 13:47   ` Michal Kazior
  2014-03-21 13:47   ` [PATCH v2 10/13] mac80211: split ieee80211_free_chanctx() Michal Kazior
                     ` (4 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The function did a little too much. Split it up so
the code can be easily reused in the future.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 56 ++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 43 insertions(+), 13 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index b82e0c1..561d7c1 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -345,19 +345,17 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local)
 }
 
 static struct ieee80211_chanctx *
-ieee80211_new_chanctx(struct ieee80211_local *local,
-		      const struct cfg80211_chan_def *chandef,
-		      enum ieee80211_chanctx_mode mode)
+ieee80211_alloc_chanctx(struct ieee80211_local *local,
+			const struct cfg80211_chan_def *chandef,
+			enum ieee80211_chanctx_mode mode)
 {
 	struct ieee80211_chanctx *ctx;
-	u32 changed;
-	int err;
 
 	lockdep_assert_held(&local->chanctx_mtx);
 
 	ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
 	if (!ctx)
-		return ERR_PTR(-ENOMEM);
+		return NULL;
 
 	INIT_LIST_HEAD(&ctx->assigned_vifs);
 	INIT_LIST_HEAD(&ctx->reserved_vifs);
@@ -367,31 +365,63 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 	ctx->mode = mode;
 	ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
 	ieee80211_recalc_chanctx_min_def(local, ctx);
+
+	return ctx;
+}
+
+static int ieee80211_add_chanctx(struct ieee80211_local *local,
+				 struct ieee80211_chanctx *ctx)
+{
+	u32 changed;
+	int err;
+
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
+
 	if (!local->use_chanctx)
 		local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
 
-	/* we hold the mutex to prevent idle from changing */
-	lockdep_assert_held(&local->mtx);
 	/* turn idle off *before* setting channel -- some drivers need that */
 	changed = ieee80211_idle_off(local);
 	if (changed)
 		ieee80211_hw_config(local, changed);
 
 	if (!local->use_chanctx) {
-		local->_oper_chandef = *chandef;
+		local->_oper_chandef = ctx->conf.def;
 		ieee80211_hw_config(local, 0);
 	} else {
 		err = drv_add_chanctx(local, ctx);
 		if (err) {
-			kfree(ctx);
 			ieee80211_recalc_idle(local);
-			return ERR_PTR(err);
+			return err;
 		}
 	}
 
-	/* and keep the mutex held until the new chanctx is on the list */
-	list_add_rcu(&ctx->list, &local->chanctx_list);
+	return 0;
+}
+
+static struct ieee80211_chanctx *
+ieee80211_new_chanctx(struct ieee80211_local *local,
+		      const struct cfg80211_chan_def *chandef,
+		      enum ieee80211_chanctx_mode mode)
+{
+	struct ieee80211_chanctx *ctx;
+	int err;
+
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	ctx = ieee80211_alloc_chanctx(local, chandef, mode);
+	if (!ctx)
+		return ERR_PTR(-ENOMEM);
 
+	err = ieee80211_add_chanctx(local, ctx);
+	if (err) {
+		kfree(ctx);
+		return ERR_PTR(err);
+	}
+
+	list_add_rcu(&ctx->list, &local->chanctx_list);
 	return ctx;
 }
 
-- 
1.8.5.3


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

* [PATCH v2 10/13] mac80211: split ieee80211_free_chanctx()
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                     ` (8 preceding siblings ...)
  2014-03-21 13:47   ` [PATCH v2 09/13] mac80211: split ieee80211_new_chanctx() Michal Kazior
@ 2014-03-21 13:47   ` Michal Kazior
  2014-03-21 13:47   ` [PATCH v2 11/13] mac80211: fix racy usage of chanctx->refcount Michal Kazior
                     ` (3 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The function did a little too much. Split it up so
the code can be easily reused in the future.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 561d7c1..74459a7 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -425,14 +425,11 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 	return ctx;
 }
 
-static void ieee80211_free_chanctx(struct ieee80211_local *local,
-				   struct ieee80211_chanctx *ctx)
+static void ieee80211_del_chanctx(struct ieee80211_local *local,
+				  struct ieee80211_chanctx *ctx)
 {
-	bool check_single_channel = false;
 	lockdep_assert_held(&local->chanctx_mtx);
 
-	WARN_ON_ONCE(ctx->refcount != 0);
-
 	if (!local->use_chanctx) {
 		struct cfg80211_chan_def *chandef = &local->_oper_chandef;
 		chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
@@ -442,8 +439,9 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
 		/* NOTE: Disabling radar is only valid here for
 		 * single channel context. To be sure, check it ...
 		 */
-		if (local->hw.conf.radar_enabled)
-			check_single_channel = true;
+		WARN_ON(local->hw.conf.radar_enabled &&
+			!list_empty(&local->chanctx_list));
+
 		local->hw.conf.radar_enabled = false;
 
 		ieee80211_hw_config(local, 0);
@@ -451,13 +449,19 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
 		drv_remove_chanctx(local, ctx);
 	}
 
-	list_del_rcu(&ctx->list);
-	kfree_rcu(ctx, rcu_head);
+	ieee80211_recalc_idle(local);
+}
 
-	/* throw a warning if this wasn't the only channel context. */
-	WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
+static void ieee80211_free_chanctx(struct ieee80211_local *local,
+				   struct ieee80211_chanctx *ctx)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	ieee80211_recalc_idle(local);
+	WARN_ON_ONCE(ctx->refcount != 0);
+
+	list_del_rcu(&ctx->list);
+	ieee80211_del_chanctx(local, ctx);
+	kfree_rcu(ctx, rcu_head);
 }
 
 static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
-- 
1.8.5.3


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

* [PATCH v2 11/13] mac80211: fix racy usage of chanctx->refcount
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                     ` (9 preceding siblings ...)
  2014-03-21 13:47   ` [PATCH v2 10/13] mac80211: split ieee80211_free_chanctx() Michal Kazior
@ 2014-03-21 13:47   ` Michal Kazior
  2014-03-21 13:47   ` [PATCH v2 12/13] mac80211: compute chanctx refcount on-the-fly Michal Kazior
                     ` (2 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Channel context refcount is protected by
chanctx_mtx. Accessing the value without holding
the mutex is racy. RCU section didn't guarantee
anything here.

Theoretically ieee80211_channel_switch() could
fail to see refcount change and read "1" instead
of, e.g. "2". This means mac80211 could accept CSA
even though it shouldn't have.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v2:
 * use rcu_dereference_protected()

 net/mac80211/cfg.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 64e152d..328c9a3 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3282,7 +3282,7 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx_conf *chanctx_conf;
+	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *chanctx;
 	int err, num_chanctx, changed = 0;
 
@@ -3299,23 +3299,24 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 				       &sdata->vif.bss_conf.chandef))
 		return -EINVAL;
 
-	rcu_read_lock();
-	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
-	if (!chanctx_conf) {
-		rcu_read_unlock();
+	mutex_lock(&local->chanctx_mtx);
+	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+					 lockdep_is_held(&local->chanctx_mtx));
+	if (!conf) {
+		mutex_unlock(&local->chanctx_mtx);
 		return -EBUSY;
 	}
 
 	/* don't handle for multi-VIF cases */
-	chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
+	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
 	if (chanctx->refcount > 1) {
-		rcu_read_unlock();
+		mutex_unlock(&local->chanctx_mtx);
 		return -EBUSY;
 	}
 	num_chanctx = 0;
 	list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
 		num_chanctx++;
-	rcu_read_unlock();
+	mutex_unlock(&local->chanctx_mtx);
 
 	if (num_chanctx > 1)
 		return -EBUSY;
-- 
1.8.5.3


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

* [PATCH v2 12/13] mac80211: compute chanctx refcount on-the-fly
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                     ` (10 preceding siblings ...)
  2014-03-21 13:47   ` [PATCH v2 11/13] mac80211: fix racy usage of chanctx->refcount Michal Kazior
@ 2014-03-21 13:47   ` Michal Kazior
  2014-03-28 13:11     ` Johannes Berg
  2014-03-21 13:47   ` [PATCH v2 13/13] mac80211: implement multi-vif in-place reservations Michal Kazior
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
  13 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

It doesn't make much sense to store refcount in
the chanctx structure. One still needs to hold
chanctx_mtx to get the value safely. Besides,
refcount isn't on performance critical paths.

This will make implementing chanctx reservation
refcounting a little easier.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v2:
 * use assigned/reserved lists instead of
   local->interfaces

 net/mac80211/cfg.c         |  2 +-
 net/mac80211/chan.c        | 59 +++++++++++++++++++++++++++++++++++-----------
 net/mac80211/ieee80211_i.h |  3 ++-
 net/mac80211/mlme.c        |  2 +-
 4 files changed, 49 insertions(+), 17 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 328c9a3..0c68269 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3309,7 +3309,7 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 
 	/* don't handle for multi-VIF cases */
 	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
-	if (chanctx->refcount > 1) {
+	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
 		mutex_unlock(&local->chanctx_mtx);
 		return -EBUSY;
 	}
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 74459a7..9c247e5 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -9,6 +9,41 @@
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
+static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
+					  struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+	int num = 0;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
+		num++;
+
+	return num;
+}
+
+static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
+					  struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+	int num = 0;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list)
+		num++;
+
+	return num;
+}
+
+int ieee80211_chanctx_refcount(struct ieee80211_local *local,
+			       struct ieee80211_chanctx *ctx)
+{
+	return ieee80211_chanctx_num_assigned(local, ctx) +
+	       ieee80211_chanctx_num_reserved(local, ctx);
+}
+
 static int ieee80211_num_chanctx(struct ieee80211_local *local)
 {
 	struct ieee80211_chanctx *ctx;
@@ -457,7 +492,7 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
 {
 	lockdep_assert_held(&local->chanctx_mtx);
 
-	WARN_ON_ONCE(ctx->refcount != 0);
+	WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
 
 	list_del_rcu(&ctx->list);
 	ieee80211_del_chanctx(local, ctx);
@@ -536,7 +571,6 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 	if (conf) {
 		curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-		curr_ctx->refcount--;
 		drv_unassign_vif_chanctx(local, sdata, curr_ctx);
 		conf = NULL;
 		list_del(&sdata->assigned_chanctx_list);
@@ -547,7 +581,6 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 		if (ret)
 			goto out;
 
-		new_ctx->refcount++;
 		conf = &new_ctx->conf;
 		list_add(&sdata->assigned_chanctx_list,
 			 &new_ctx->assigned_vifs);
@@ -558,14 +591,14 @@ out:
 
 	sdata->vif.bss_conf.idle = !conf;
 
-	if (curr_ctx && curr_ctx->refcount > 0) {
+	if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
 		ieee80211_recalc_chanctx_chantype(local, curr_ctx);
 		ieee80211_recalc_smps_chanctx(local, curr_ctx);
 		ieee80211_recalc_radar_chanctx(local, curr_ctx);
 		ieee80211_recalc_chanctx_min_def(local, curr_ctx);
 	}
 
-	if (new_ctx && new_ctx->refcount > 0) {
+	if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
 		ieee80211_recalc_txpower(sdata);
 		ieee80211_recalc_chanctx_min_def(local, new_ctx);
 	}
@@ -597,7 +630,7 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
 		ieee80211_vif_unreserve_chanctx(sdata);
 
 	ieee80211_assign_vif_chanctx(sdata, NULL);
-	if (ctx->refcount == 0)
+	if (ieee80211_chanctx_refcount(local, ctx) == 0)
 		ieee80211_free_chanctx(local, ctx);
 }
 
@@ -729,7 +762,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 	ret = ieee80211_assign_vif_chanctx(sdata, ctx);
 	if (ret) {
 		/* if assign fails refcount stays the same */
-		if (ctx->refcount == 0)
+		if (ieee80211_chanctx_refcount(local, ctx) == 0)
 			ieee80211_free_chanctx(local, ctx);
 		goto out;
 	}
@@ -753,7 +786,7 @@ static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
 				     IEEE80211_CHAN_DISABLED))
 		return -EINVAL;
 
-	if (ctx->refcount != 1)
+	if (ieee80211_chanctx_refcount(local, ctx) != 1)
 		return -EINVAL;
 
 	if (sdata->vif.bss_conf.chandef.width != chandef->width) {
@@ -859,7 +892,7 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
 	list_del(&sdata->reserved_chanctx_list);
 	sdata->reserved_chanctx = NULL;
 
-	if (--ctx->refcount == 0)
+	if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0)
 		ieee80211_free_chanctx(sdata->local, ctx);
 
 	return 0;
@@ -888,7 +921,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 
 	new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
 	if (!new_ctx) {
-		if (curr_ctx->refcount == 1 &&
+		if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 &&
 		    (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
 			/* if we're the only users of the chanctx and
 			 * the driver supports changing a running
@@ -909,7 +942,6 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	}
 
 	list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
-	new_ctx->refcount++;
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
 	sdata->reserved_radar_required = radar_required;
@@ -955,7 +987,6 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 	sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
 
 	/* unref our reservation */
-	ctx->refcount--;
 	sdata->reserved_chanctx = NULL;
 	sdata->radar_required = sdata->reserved_radar_required;
 	list_del(&sdata->reserved_chanctx_list);
@@ -968,11 +999,11 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 			goto out;
 	} else {
 		ret = ieee80211_assign_vif_chanctx(sdata, ctx);
-		if (old_ctx->refcount == 0)
+		if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
 			ieee80211_free_chanctx(local, old_ctx);
 		if (ret) {
 			/* if assign fails refcount stays the same */
-			if (ctx->refcount == 0)
+			if (ieee80211_chanctx_refcount(local, ctx) == 0)
 				ieee80211_free_chanctx(local, ctx);
 			goto out;
 		}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6c5969b..72e8d53 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -695,7 +695,6 @@ struct ieee80211_chanctx {
 	struct list_head reserved_vifs;
 
 	enum ieee80211_chanctx_mode mode;
-	int refcount;
 	bool driver_present;
 
 	struct ieee80211_chanctx_conf conf;
@@ -1811,6 +1810,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 					 bool clear);
+int ieee80211_chanctx_refcount(struct ieee80211_local *local,
+			       struct ieee80211_chanctx *ctx);
 
 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
 				   struct ieee80211_chanctx *chanctx);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 2ca1472..5079454 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1069,7 +1069,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	}
 	chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
 			       struct ieee80211_chanctx, conf);
-	if (chanctx->refcount > 1) {
+	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
 		sdata_info(sdata,
 			   "channel switch with multiple interfaces on the same channel, disconnecting\n");
 		ieee80211_queue_work(&local->hw,
-- 
1.8.5.3


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

* [PATCH v2 13/13] mac80211: implement multi-vif in-place reservations
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                     ` (11 preceding siblings ...)
  2014-03-21 13:47   ` [PATCH v2 12/13] mac80211: compute chanctx refcount on-the-fly Michal Kazior
@ 2014-03-21 13:47   ` Michal Kazior
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Multi-vif in-place reservations happen when
it's impossible to allocate more chanctx as per
driver combinations.

Such reservations aren't finalized until last
reservation interface calls in to use the
reservation.

This introduces a special hook
ieee80211_vif_chanctx_reservation_complete(). This
is currently an empty stub and will be filled in
by AP/STA CSA code. This is required to implement
2-step CSA finalization.

This also gets rid of driver requirement to be
able to re-program channel of a chanctx.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v2:
 * use new_ctx instead of ctx [Eliad]
 * move recalcs after bss_conf is updated [Eliad]

 include/net/mac80211.h     |   7 --
 net/mac80211/chan.c        | 281 +++++++++++++++++++++++++++++++++------------
 net/mac80211/ieee80211_i.h |   4 +-
 3 files changed, 208 insertions(+), 84 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 91e90a2..7ce198c 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1557,12 +1557,6 @@ struct ieee80211_tx_control {
  *	for a single active channel while using channel contexts. When support
  *	is not enabled the default action is to disconnect when getting the
  *	CSA frame.
- *
- * @IEEE80211_HW_CHANGE_RUNNING_CHANCTX: The hardware can change a
- *	channel context on-the-fly.  This is needed for channel switch
- *	on single-channel hardware.  It can also be used as an
- *	optimization in certain channel switch cases with
- *	multi-channel.
  */
 enum ieee80211_hw_flags {
 	IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0,
@@ -1594,7 +1588,6 @@ enum ieee80211_hw_flags {
 	IEEE80211_HW_TIMING_BEACON_ONLY			= 1<<26,
 	IEEE80211_HW_SUPPORTS_HT_CCK_RATES		= 1<<27,
 	IEEE80211_HW_CHANCTX_STA_CSA			= 1<<28,
-	IEEE80211_HW_CHANGE_RUNNING_CHANCTX		= 1<<29,
 };
 
 /**
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 9c247e5..c630501 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -173,6 +173,24 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
 	return NULL;
 }
 
+static bool
+ieee80211_chanctx_all_reserved_vifs_ready(struct ieee80211_local *local,
+					  struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		if (!sdata->reserved_chanctx)
+			continue;
+		if (!sdata->reserved_ready)
+			return false;
+	}
+
+	return true;
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -906,38 +924,24 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *new_ctx, *curr_ctx;
-	int ret = 0;
 
-	mutex_lock(&local->chanctx_mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
 	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf) {
-		ret = -EINVAL;
-		goto out;
-	}
+	if (!conf)
+		return -EINVAL;
 
 	curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
 	new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
 	if (!new_ctx) {
-		if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 &&
-		    (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
-			/* if we're the only users of the chanctx and
-			 * the driver supports changing a running
-			 * context, reserve our current context
-			 */
-			new_ctx = curr_ctx;
-		} else if (ieee80211_can_create_new_chanctx(local)) {
-			/* create a new context and reserve it */
+		if (ieee80211_can_create_new_chanctx(local)) {
 			new_ctx = ieee80211_new_chanctx(local, chandef, mode);
-			if (IS_ERR(new_ctx)) {
-				ret = PTR_ERR(new_ctx);
-				goto out;
-			}
+			if (IS_ERR(new_ctx))
+				return PTR_ERR(new_ctx);
 		} else {
-			ret = -EBUSY;
-			goto out;
+			new_ctx = curr_ctx;
 		}
 	}
 
@@ -945,82 +949,209 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
 	sdata->reserved_radar_required = radar_required;
-out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
+	sdata->reserved_ready = false;
+
+	return 0;
 }
 
-int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
-				       u32 *changed)
+static void
+ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx *ctx;
-	struct ieee80211_chanctx *old_ctx;
-	struct ieee80211_chanctx_conf *conf;
-	int ret;
-	u32 tmp_changed = *changed;
+	/* stub */
+}
 
-	/* TODO: need to recheck if the chandef is usable etc.? */
+static int
+ieee80211_vif_use_reserved_incompat(struct ieee80211_local *local,
+				    struct ieee80211_chanctx *ctx,
+				    const struct cfg80211_chan_def *chandef)
+{
+	struct ieee80211_sub_if_data *sdata, *tmp;
+	struct ieee80211_chanctx *new_ctx;
+	u32 changed = 0;
+	int err;
 
 	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	mutex_lock(&local->chanctx_mtx);
+	if (!ieee80211_chanctx_all_reserved_vifs_ready(local, ctx))
+		return 0;
 
-	ctx = sdata->reserved_chanctx;
-	if (WARN_ON(!ctx)) {
-		ret = -EINVAL;
-		goto out;
+	if (ieee80211_chanctx_num_assigned(local, ctx) !=
+	    ieee80211_chanctx_num_reserved(local, ctx)) {
+		wiphy_info(local->hw.wiphy,
+			   "channel context reservation cannot be finalized because some interfaces aren't switching\n");
+		err = -EBUSY;
+		goto err;
 	}
 
-	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf) {
-		ret = -EINVAL;
+	new_ctx = ieee80211_alloc_chanctx(local, chandef, ctx->mode);
+	if (!new_ctx) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		drv_unassign_vif_chanctx(local, sdata, ctx);
+		rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
+	}
+
+	list_del_rcu(&ctx->list);
+	ieee80211_del_chanctx(local, ctx);
+
+	err = ieee80211_add_chanctx(local, new_ctx);
+	if (err)
+		goto err_revert;
+
+	/* don't simply overwrite radar_required in case of failure */
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		bool tmp = sdata->radar_required;
+		sdata->radar_required = sdata->reserved_radar_required;
+		sdata->reserved_radar_required = tmp;
+	}
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		err = drv_assign_vif_chanctx(local, sdata, new_ctx);
+		if (err)
+			goto err_unassign;
+	}
+
+	if (sdata->vif.type == NL80211_IFTYPE_AP)
+		__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
+
+	list_add_rcu(&new_ctx->list, &local->chanctx_list);
+	kfree_rcu(ctx, rcu_head);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs,
+			    reserved_chanctx_list) {
+		changed = 0;
+		if (sdata->vif.bss_conf.chandef.width !=
+		    sdata->reserved_chandef.width)
+			changed = BSS_CHANGED_BANDWIDTH;
+
+		sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
+		if (changed)
+			ieee80211_bss_info_change_notify(sdata, changed);
+
+		ieee80211_recalc_txpower(sdata);
+	}
+
+	ieee80211_recalc_chanctx_chantype(local, new_ctx);
+	ieee80211_recalc_smps_chanctx(local, new_ctx);
+	ieee80211_recalc_radar_chanctx(local, new_ctx);
+	ieee80211_recalc_chanctx_min_def(local, new_ctx);
+
+	list_for_each_entry_safe(sdata, tmp, &ctx->reserved_vifs,
+				 reserved_chanctx_list) {
+		list_del(&sdata->reserved_chanctx_list);
+		list_move(&sdata->assigned_chanctx_list,
+			  &new_ctx->assigned_vifs);
+		sdata->reserved_chanctx = NULL;
+
+		ieee80211_vif_chanctx_reservation_complete(sdata);
+	}
+
+	return 0;
+
+err_unassign:
+	list_for_each_entry_continue_reverse(sdata, &ctx->reserved_vifs,
+					     reserved_chanctx_list)
+		drv_unassign_vif_chanctx(local, sdata, ctx);
+	ieee80211_del_chanctx(local, new_ctx);
+err_revert:
+	kfree_rcu(new_ctx, rcu_head);
+	WARN_ON(ieee80211_add_chanctx(local, ctx));
+	list_add_rcu(&ctx->list, &local->chanctx_list);
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		sdata->radar_required = sdata->reserved_radar_required;
+		rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
+		WARN_ON(drv_assign_vif_chanctx(local, sdata, ctx));
+	}
+err:
+	list_for_each_entry_safe(sdata, tmp, &ctx->reserved_vifs,
+				 reserved_chanctx_list) {
+		list_del(&sdata->reserved_chanctx_list);
+		sdata->reserved_chanctx = NULL;
+		ieee80211_vif_chanctx_reservation_complete(sdata);
+	}
+	return err;
+}
+
+static int
+ieee80211_vif_use_reserved_compat(struct ieee80211_sub_if_data *sdata,
+				  struct ieee80211_chanctx *old_ctx,
+				  struct ieee80211_chanctx *new_ctx)
+{
+	struct ieee80211_local *local = sdata->local;
+	u32 changed = 0;
+	int err;
+
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_del(&sdata->reserved_chanctx_list);
+	sdata->reserved_chanctx = NULL;
+
+	err = ieee80211_assign_vif_chanctx(sdata, new_ctx);
+	if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
+		ieee80211_free_chanctx(local, old_ctx);
+	if (err) {
+		/* if assign fails refcount stays the same */
+		if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
+			ieee80211_free_chanctx(local, new_ctx);
 		goto out;
 	}
 
-	old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
+	if (sdata->vif.type == NL80211_IFTYPE_AP)
+		__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
 
 	if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
-		tmp_changed |= BSS_CHANGED_BANDWIDTH;
+		changed = BSS_CHANGED_BANDWIDTH;
 
 	sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
 
-	/* unref our reservation */
-	sdata->reserved_chanctx = NULL;
-	sdata->radar_required = sdata->reserved_radar_required;
-	list_del(&sdata->reserved_chanctx_list);
+	if (changed)
+		ieee80211_bss_info_change_notify(sdata, changed);
 
-	if (old_ctx == ctx) {
-		/* This is our own context, just change it */
-		ret = __ieee80211_vif_change_channel(sdata, old_ctx,
-						     &tmp_changed);
-		if (ret)
-			goto out;
-	} else {
-		ret = ieee80211_assign_vif_chanctx(sdata, ctx);
-		if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
-			ieee80211_free_chanctx(local, old_ctx);
-		if (ret) {
-			/* if assign fails refcount stays the same */
-			if (ieee80211_chanctx_refcount(local, ctx) == 0)
-				ieee80211_free_chanctx(local, ctx);
-			goto out;
-		}
+out:
+	ieee80211_vif_chanctx_reservation_complete(sdata);
+	return err;
+}
 
-		if (sdata->vif.type == NL80211_IFTYPE_AP)
-			__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
-	}
+int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_chanctx *ctx;
+	struct ieee80211_chanctx *old_ctx;
+	struct ieee80211_chanctx_conf *conf;
+	const struct cfg80211_chan_def *chandef;
 
-	*changed = tmp_changed;
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	ieee80211_recalc_chanctx_chantype(local, ctx);
-	ieee80211_recalc_smps_chanctx(local, ctx);
-	ieee80211_recalc_radar_chanctx(local, ctx);
-	ieee80211_recalc_chanctx_min_def(local, ctx);
-out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
+	ctx = sdata->reserved_chanctx;
+	if (WARN_ON(!ctx))
+		return -EINVAL;
+
+	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+					 lockdep_is_held(&local->chanctx_mtx));
+	if (!conf)
+		return -EINVAL;
+
+	old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
+
+	if (WARN_ON(sdata->reserved_ready))
+		return -EINVAL;
+
+	chandef = ieee80211_chanctx_reserved_chandef(local, ctx, NULL);
+	if (WARN_ON(!chandef))
+		return -EINVAL;
+
+	sdata->reserved_ready = true;
+
+	if (cfg80211_chandef_compatible(&ctx->conf.def, chandef))
+		return ieee80211_vif_use_reserved_compat(sdata, old_ctx, ctx);
+	else
+		return ieee80211_vif_use_reserved_incompat(local, ctx, chandef);
 }
 
 int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 72e8d53..4394452 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -766,6 +766,7 @@ struct ieee80211_sub_if_data {
 	struct ieee80211_chanctx *reserved_chanctx;
 	struct cfg80211_chan_def reserved_chandef;
 	bool reserved_radar_required;
+	bool reserved_ready;
 
 	/* used to reconfigure hardware SM PS */
 	struct work_struct recalc_smps;
@@ -1794,8 +1795,7 @@ ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 			      enum ieee80211_chanctx_mode mode,
 			      bool radar_required);
 int __must_check
-ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
-				   u32 *changed);
+ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata);
 int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata);
 
 int __must_check
-- 
1.8.5.3


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

* [PATCH v2 0/7] cfg80211/mac80211: implement multi-vif csa
  2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
                   ` (22 preceding siblings ...)
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
@ 2014-03-21 13:52 ` Michal Kazior
  2014-03-21 13:52   ` [PATCH v2 1/7] cfg80211: fix radar_detect combination checking Michal Kazior
                     ` (7 more replies)
  23 siblings, 8 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:52 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Hi,

This is another part of my recent RFC. This is
just the channel switching part.

This is based on my patchset implementing
multi-vif chanctx reservations.


v2:
 * add radar_detect fix patch (wasn't present in
   the big RFC)


Michal Kazior (7):
  cfg80211: fix radar_detect combination checking
  mac80211: make check_combinations() aware of chanctx reservation
  mac80211: use chanctx reservation for AP CSA
  mac80211: use chanctx reservation for STA CSA
  mac80211: ignore cqm during csa
  mac80211: remove old unused channel switching code
  cfg80211: remove channel_switch combination check

 net/mac80211/cfg.c         | 63 +++++++++++++++++++----------
 net/mac80211/chan.c        | 79 +++++++-----------------------------
 net/mac80211/ieee80211_i.h |  5 ---
 net/mac80211/mlme.c        | 99 ++++++++++++++++++++++++++++++----------------
 net/mac80211/util.c        | 37 ++++++++++++++++-
 net/wireless/nl80211.c     | 11 ------
 net/wireless/util.c        |  2 +-
 7 files changed, 156 insertions(+), 140 deletions(-)

-- 
1.8.5.3


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

* [PATCH v2 1/7] cfg80211: fix radar_detect combination checking
  2014-03-21 13:52 ` [PATCH v2 0/7] cfg80211/mac80211: implement multi-vif csa Michal Kazior
@ 2014-03-21 13:52   ` Michal Kazior
  2014-03-28 12:59     ` Johannes Berg
  2014-03-21 13:52   ` [PATCH v2 2/7] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
                     ` (6 subsequent siblings)
  7 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:52 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

All bits from radar_detect must match combination
radar bitmask. Otherwise it is theoretically
possible to lead into an invalid combination
provided a driver reports strange combinations.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v2:
 * patch added

 net/wireless/util.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/wireless/util.c b/net/wireless/util.c
index 7fa3503..b534dc2 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1301,7 +1301,7 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
 			}
 		}
 
-		if (radar_detect && !(c->radar_detect_widths & radar_detect))
+		if (radar_detect != (c->radar_detect_widths & radar_detect))
 			goto cont;
 
 		/* Finally check that all iftypes that we're currently
-- 
1.8.5.3


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

* [PATCH v2 2/7] mac80211: make check_combinations() aware of chanctx reservation
  2014-03-21 13:52 ` [PATCH v2 0/7] cfg80211/mac80211: implement multi-vif csa Michal Kazior
  2014-03-21 13:52   ` [PATCH v2 1/7] cfg80211: fix radar_detect combination checking Michal Kazior
@ 2014-03-21 13:52   ` Michal Kazior
  2014-03-28 13:00     ` Johannes Berg
  2014-03-21 13:52   ` [PATCH v2 3/7] mac80211: use chanctx reservation for AP CSA Michal Kazior
                     ` (5 subsequent siblings)
  7 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:52 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The ieee80211_check_combinations() computes
radar_detect accordingly depending on chanctx
reservation status.

This makes it possible to use the function for
channel_switch validation.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/util.c | 37 +++++++++++++++++++++++++++++++++++--
 1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 7233102..59041d4 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2802,6 +2802,40 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
 	ps->dtim_count = dtim_count;
 }
 
+static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local,
+					 struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_chanctx_conf *conf;
+	u8 radar_detect = 0;
+	bool in_place = false;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		if (sdata->reserved_radar_required)
+			radar_detect |= BIT(sdata->reserved_chandef.width);
+
+		conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+				lockdep_is_held(&local->chanctx_mtx));
+		if (conf == &ctx->conf)
+			in_place = true;
+	}
+
+	/* if chanctx has in-place reservation then consider only the future
+	 * radar_detect. multi-vif reservation is deferred so ignore assigned
+	 * vifs. it is impossible for new vifs to be bound to an in-place
+	 * reserved chanctx so consistency is guranteed */
+	if (in_place)
+		return radar_detect;
+
+	list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
+		if (sdata->radar_required)
+			radar_detect |= BIT(sdata->vif.bss_conf.chandef.width);
+
+	return radar_detect;
+}
+
 int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 				 const struct cfg80211_chan_def *chandef,
 				 enum ieee80211_chanctx_mode chanmode,
@@ -2843,8 +2877,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 		num[iftype] = 1;
 
 	list_for_each_entry(ctx, &local->chanctx_list, list) {
-		if (ctx->conf.radar_enabled)
-			radar_detect |= BIT(ctx->conf.def.width);
+		radar_detect |= ieee80211_chanctx_radar_detect(local, ctx);
 		if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
 			num_different_channels++;
 			continue;
-- 
1.8.5.3


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

* [PATCH v2 3/7] mac80211: use chanctx reservation for AP CSA
  2014-03-21 13:52 ` [PATCH v2 0/7] cfg80211/mac80211: implement multi-vif csa Michal Kazior
  2014-03-21 13:52   ` [PATCH v2 1/7] cfg80211: fix radar_detect combination checking Michal Kazior
  2014-03-21 13:52   ` [PATCH v2 2/7] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
@ 2014-03-21 13:52   ` Michal Kazior
  2014-03-28 13:01     ` Johannes Berg
  2014-03-21 13:52   ` [PATCH v2 4/7] mac80211: use chanctx reservation for STA CSA Michal Kazior
                     ` (4 subsequent siblings)
  7 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:52 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Channel switch finalization is now 2-step. First
step is when driver calls csa_finish(), the other
is when reservation is actually finalized (which
be defered for in-place reservation).

This implies driver must not call csa_finish()
more than once for each channel_switch request.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/cfg.c  | 62 ++++++++++++++++++++++++++++++++++++-----------------
 net/mac80211/chan.c | 11 +++++++++-
 2 files changed, 52 insertions(+), 21 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 0c68269..ba544d3 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3096,17 +3096,25 @@ static int ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
 
 	sdata_assert_lock(sdata);
 	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->mtx);
 
-	sdata->radar_required = sdata->csa_radar_required;
-	err = ieee80211_vif_change_channel(sdata, &changed);
-	if (WARN_ON(err < 0))
-		return err;
+	/* using reservation isn't immediate as it may be deferred until later
+	 * with multi-vif. once reservation is complete it will re-schedule the
+	 * work with no reserved_chanctx so verify chandef to check if it
+	 * completed successfully */
 
-	if (!local->use_chanctx) {
-		local->_oper_chandef = sdata->csa_chandef;
-		ieee80211_hw_config(local, 0);
+	if (sdata->reserved_chanctx) {
+		err = ieee80211_vif_use_reserved_context(sdata);
+		if (err)
+			return err;
+
+		return 0;
 	}
 
+	if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
+					&sdata->csa_chandef))
+		return -EINVAL;
+
 	sdata->vif.csa_active = false;
 
 	err = ieee80211_set_after_csa_beacon(sdata, &changed);
@@ -3129,6 +3137,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
 
 	sdata_lock(sdata);
 	mutex_lock(&local->mtx);
+	mutex_lock(&local->chanctx_mtx);
 
 	/* AP might have been stopped while waiting for the lock. */
 	if (!sdata->vif.csa_active)
@@ -3150,6 +3159,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
 					IEEE80211_QUEUE_STOP_REASON_CSA);
 
 unlock:
+	mutex_unlock(&local->chanctx_mtx);
 	mutex_unlock(&local->mtx);
 	sdata_unlock(sdata);
 }
@@ -3284,7 +3294,7 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *chanctx;
-	int err, num_chanctx, changed = 0;
+	int err, changed = 0;
 
 	sdata_assert_lock(sdata);
 	lockdep_assert_held(&local->mtx);
@@ -3299,6 +3309,10 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 				       &sdata->vif.bss_conf.chandef))
 		return -EINVAL;
 
+	/* don't allow another channel switch if one is already active. */
+	if (sdata->vif.csa_active)
+		return -EBUSY;
+
 	mutex_lock(&local->chanctx_mtx);
 	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 					 lockdep_is_held(&local->chanctx_mtx));
@@ -3307,27 +3321,34 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 		return -EBUSY;
 	}
 
-	/* don't handle for multi-VIF cases */
 	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
-	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
+	if (!chanctx) {
 		mutex_unlock(&local->chanctx_mtx);
 		return -EBUSY;
 	}
-	num_chanctx = 0;
-	list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
-		num_chanctx++;
-	mutex_unlock(&local->chanctx_mtx);
 
-	if (num_chanctx > 1)
-		return -EBUSY;
+	err = ieee80211_vif_reserve_chanctx(sdata, &params->chandef,
+					    chanctx->mode,
+					    params->radar_required);
+	if (err) {
+		mutex_unlock(&local->chanctx_mtx);
+		return err;
+	}
 
-	/* don't allow another channel switch if one is already active. */
-	if (sdata->vif.csa_active)
-		return -EBUSY;
+	/* if reservation is invalid then this will fail */
+	err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0);
+	if (err) {
+		ieee80211_vif_unreserve_chanctx(sdata);
+		mutex_unlock(&local->chanctx_mtx);
+		return err;
+	}
 
 	err = ieee80211_set_csa_beacon(sdata, params, &changed);
-	if (err)
+	if (err) {
+		ieee80211_vif_unreserve_chanctx(sdata);
+		mutex_unlock(&local->chanctx_mtx);
 		return err;
+	}
 
 	sdata->csa_radar_required = params->radar_required;
 	sdata->csa_chandef = params->chandef;
@@ -3347,6 +3368,7 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 		ieee80211_csa_finalize(sdata);
 	}
 
+	mutex_unlock(&local->chanctx_mtx);
 	return 0;
 }
 
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index c630501..c171837 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -957,7 +957,16 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 static void
 ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
 {
-	/* stub */
+	switch (sdata->vif.type) {
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MESH_POINT:
+		ieee80211_queue_work(&sdata->local->hw,
+				     &sdata->csa_finalize_work);
+		break;
+	default:
+		break;
+	}
 }
 
 static int
-- 
1.8.5.3


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

* [PATCH v2 4/7] mac80211: use chanctx reservation for STA CSA
  2014-03-21 13:52 ` [PATCH v2 0/7] cfg80211/mac80211: implement multi-vif csa Michal Kazior
                     ` (2 preceding siblings ...)
  2014-03-21 13:52   ` [PATCH v2 3/7] mac80211: use chanctx reservation for AP CSA Michal Kazior
@ 2014-03-21 13:52   ` Michal Kazior
  2014-03-21 13:52   ` [PATCH v2 5/7] mac80211: ignore cqm during csa Michal Kazior
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:52 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Channel switch finalization is now 2-step. First
step is when driver calls chswitch_done(), the
other is when reservation is actually finalized
(which be defered for in-place reservation).

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c |  4 +++
 net/mac80211/mlme.c | 90 ++++++++++++++++++++++++++++++++---------------------
 2 files changed, 59 insertions(+), 35 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index c171837..faf2a05 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -964,6 +964,10 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
 		ieee80211_queue_work(&sdata->local->hw,
 				     &sdata->csa_finalize_work);
 		break;
+	case NL80211_IFTYPE_STATION:
+		ieee80211_queue_work(&sdata->local->hw,
+				     &sdata->u.mgd.chswitch_work);
+		break;
 	default:
 		break;
 	}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 5079454..a5b23a1 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -917,54 +917,66 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 		container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	u32 changed = 0;
 	int ret;
 
 	if (!ieee80211_sdata_running(sdata))
 		return;
 
 	sdata_lock(sdata);
+	mutex_lock(&local->mtx);
+	mutex_lock(&local->chanctx_mtx);
+
 	if (!ifmgd->associated)
+		goto cleanup;
+
+	if (!sdata->vif.csa_active)
+		goto cleanup;
+
+	/* using reservation isn't immediate as it may be deferred until later
+	 * with multi-vif. once reservation is complete it will re-schedule the
+	 * work with no reserved_chanctx so verify chandef to check if it
+	 * completed successfully */
+
+	if (sdata->reserved_chanctx) {
+		ret = ieee80211_vif_use_reserved_context(sdata);
+		if (ret) {
+			sdata_info(sdata,
+				   "failed to use reserved channel context, disconnecting (err=%d)\n",
+				   ret);
+			ieee80211_queue_work(&sdata->local->hw,
+					     &ifmgd->csa_connection_drop_work);
+			goto cleanup;
+		}
+
 		goto out;
+	}
 
-	mutex_lock(&local->mtx);
-	ret = ieee80211_vif_change_channel(sdata, &changed);
-	mutex_unlock(&local->mtx);
-	if (ret) {
+	if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
+					&sdata->csa_chandef)) {
 		sdata_info(sdata,
-			   "vif channel switch failed, disconnecting\n");
+			   "failed to finalize channel switch, disconnecting\n");
 		ieee80211_queue_work(&sdata->local->hw,
 				     &ifmgd->csa_connection_drop_work);
-		goto out;
-	}
-
-	if (!local->use_chanctx) {
-		local->_oper_chandef = sdata->csa_chandef;
-		/* Call "hw_config" only if doing sw channel switch.
-		 * Otherwise update the channel directly
-		 */
-		if (!local->ops->channel_switch)
-			ieee80211_hw_config(local, 0);
-		else
-			local->hw.conf.chandef = local->_oper_chandef;
+		goto cleanup;
 	}
 
 	/* XXX: shouldn't really modify cfg80211-owned data! */
 	ifmgd->associated->channel = sdata->csa_chandef.chan;
 
-	ieee80211_bss_info_change_notify(sdata, changed);
-
- out:
-	mutex_lock(&local->mtx);
+cleanup:
 	sdata->vif.csa_active = false;
+
 	/* XXX: wait for a beacon first? */
 	if (!ieee80211_csa_needs_block_tx(local))
 		ieee80211_wake_queues_by_reason(&local->hw,
 					IEEE80211_MAX_QUEUE_MAP,
 					IEEE80211_QUEUE_STOP_REASON_CSA);
-	mutex_unlock(&local->mtx);
 
 	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
+
+out:
+	mutex_unlock(&local->chanctx_mtx);
+	mutex_unlock(&local->mtx);
 	sdata_unlock(sdata);
 }
 
@@ -1001,6 +1013,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct cfg80211_bss *cbss = ifmgd->associated;
+	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *chanctx;
 	enum ieee80211_band current_band;
 	struct ieee80211_csa_ie csa_ie;
@@ -1045,6 +1058,19 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
 
 	mutex_lock(&local->chanctx_mtx);
+	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+					 lockdep_is_held(&local->chanctx_mtx));
+	if (!conf) {
+		sdata_info(sdata,
+			   "no channel context assigned to vif?, disconnecting\n");
+		ieee80211_queue_work(&local->hw,
+				     &ifmgd->csa_connection_drop_work);
+		mutex_unlock(&local->chanctx_mtx);
+		return;
+	}
+
+	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
+
 	if (local->use_chanctx) {
 		u32 num_chanctx = 0;
 		list_for_each_entry(chanctx, &local->chanctx_list, list)
@@ -1061,17 +1087,12 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
-	if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) {
-		ieee80211_queue_work(&local->hw,
-				     &ifmgd->csa_connection_drop_work);
-		mutex_unlock(&local->chanctx_mtx);
-		return;
-	}
-	chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
-			       struct ieee80211_chanctx, conf);
-	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
+	res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef,
+					    chanctx->mode, false);
+	if (res) {
 		sdata_info(sdata,
-			   "channel switch with multiple interfaces on the same channel, disconnecting\n");
+			   "failed to reserve channel context for channel switch, disconnecting (err=%d)\n",
+			   res);
 		ieee80211_queue_work(&local->hw,
 				     &ifmgd->csa_connection_drop_work);
 		mutex_unlock(&local->chanctx_mtx);
@@ -1079,10 +1100,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	}
 	mutex_unlock(&local->chanctx_mtx);
 
-	sdata->csa_chandef = csa_ie.chandef;
-
 	mutex_lock(&local->mtx);
 	sdata->vif.csa_active = true;
+	sdata->csa_chandef = csa_ie.chandef;
 	sdata->csa_block_tx = csa_ie.mode;
 
 	if (sdata->csa_block_tx)
-- 
1.8.5.3


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

* [PATCH v2 5/7] mac80211: ignore cqm during csa
  2014-03-21 13:52 ` [PATCH v2 0/7] cfg80211/mac80211: implement multi-vif csa Michal Kazior
                     ` (3 preceding siblings ...)
  2014-03-21 13:52   ` [PATCH v2 4/7] mac80211: use chanctx reservation for STA CSA Michal Kazior
@ 2014-03-21 13:52   ` Michal Kazior
  2014-03-21 13:52   ` [PATCH v2 6/7] mac80211: remove old unused channel switching code Michal Kazior
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:52 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

It is not guaranteed that multi-vif channel
switching is tightly synchronized. It makes sense
to ignore cqm (missing beacons, et al) while csa
is progressing and re-check it after it completes.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/mlme.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index a5b23a1..4304988 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -974,6 +974,9 @@ cleanup:
 
 	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
 
+	ieee80211_sta_reset_beacon_monitor(sdata);
+	ieee80211_sta_reset_conn_monitor(sdata);
+
 out:
 	mutex_unlock(&local->chanctx_mtx);
 	mutex_unlock(&local->mtx);
@@ -3555,6 +3558,9 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
 	if (local->quiescing)
 		return;
 
+	if (sdata->vif.csa_active)
+		return;
+
 	sdata->u.mgd.connection_loss = false;
 	ieee80211_queue_work(&sdata->local->hw,
 			     &sdata->u.mgd.beacon_connection_loss_work);
@@ -3570,6 +3576,9 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data)
 	if (local->quiescing)
 		return;
 
+	if (sdata->vif.csa_active)
+		return;
+
 	ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
 }
 
-- 
1.8.5.3


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

* [PATCH v2 6/7] mac80211: remove old unused channel switching code
  2014-03-21 13:52 ` [PATCH v2 0/7] cfg80211/mac80211: implement multi-vif csa Michal Kazior
                     ` (4 preceding siblings ...)
  2014-03-21 13:52   ` [PATCH v2 5/7] mac80211: ignore cqm during csa Michal Kazior
@ 2014-03-21 13:52   ` Michal Kazior
  2014-03-28 13:03     ` Johannes Berg
  2014-03-21 13:52   ` [PATCH v2 7/7] cfg80211: remove channel_switch combination check Michal Kazior
  2014-03-31 12:04   ` [PATCH v3 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
  7 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:52 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

ieee80211_vif_change_channel() has no uses
anymore. sdata->csa_radar_required is also removed
because it is no longer used. Instead reservations
take care of tracking whether an interface
requires radar detection or not.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/cfg.c         |  1 -
 net/mac80211/chan.c        | 64 ----------------------------------------------
 net/mac80211/ieee80211_i.h |  5 ----
 3 files changed, 70 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index ba544d3..85f04bc 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3350,7 +3350,6 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 		return err;
 	}
 
-	sdata->csa_radar_required = params->radar_required;
 	sdata->csa_chandef = params->chandef;
 	sdata->csa_block_tx = params->block_tx;
 	sdata->vif.csa_active = true;
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index faf2a05..666cb67 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -792,70 +792,6 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 	return ret;
 }
 
-static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-					  struct ieee80211_chanctx *ctx,
-					  u32 *changed)
-{
-	struct ieee80211_local *local = sdata->local;
-	const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;
-	u32 chanctx_changed = 0;
-
-	if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
-				     IEEE80211_CHAN_DISABLED))
-		return -EINVAL;
-
-	if (ieee80211_chanctx_refcount(local, ctx) != 1)
-		return -EINVAL;
-
-	if (sdata->vif.bss_conf.chandef.width != chandef->width) {
-		chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH;
-		*changed |= BSS_CHANGED_BANDWIDTH;
-	}
-
-	sdata->vif.bss_conf.chandef = *chandef;
-	ctx->conf.def = *chandef;
-
-	chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL;
-	drv_change_chanctx(local, ctx, chanctx_changed);
-
-	ieee80211_recalc_chanctx_chantype(local, ctx);
-	ieee80211_recalc_smps_chanctx(local, ctx);
-	ieee80211_recalc_radar_chanctx(local, ctx);
-	ieee80211_recalc_chanctx_min_def(local, ctx);
-
-	return 0;
-}
-
-int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-				 u32 *changed)
-{
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx_conf *conf;
-	struct ieee80211_chanctx *ctx;
-	int ret;
-
-	lockdep_assert_held(&local->mtx);
-
-	/* should never be called if not performing a channel switch. */
-	if (WARN_ON(!sdata->vif.csa_active))
-		return -EINVAL;
-
-	mutex_lock(&local->chanctx_mtx);
-	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	ctx = container_of(conf, struct ieee80211_chanctx, conf);
-
-	ret = __ieee80211_vif_change_channel(sdata, ctx, changed);
- out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
-}
-
 static void
 __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 				      bool clear)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4394452..4892c1d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -755,7 +755,6 @@ struct ieee80211_sub_if_data {
 	struct work_struct csa_finalize_work;
 	int csa_counter_offset_beacon;
 	int csa_counter_offset_presp;
-	bool csa_radar_required;
 	bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
 	struct cfg80211_chan_def csa_chandef;
 
@@ -1802,10 +1801,6 @@ int __must_check
 ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
 			       const struct cfg80211_chan_def *chandef,
 			       u32 *changed);
-/* NOTE: only use ieee80211_vif_change_channel() for channel switch */
-int __must_check
-ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-			     u32 *changed);
 void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
-- 
1.8.5.3


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

* [PATCH v2 7/7] cfg80211: remove channel_switch combination check
  2014-03-21 13:52 ` [PATCH v2 0/7] cfg80211/mac80211: implement multi-vif csa Michal Kazior
                     ` (5 preceding siblings ...)
  2014-03-21 13:52   ` [PATCH v2 6/7] mac80211: remove old unused channel switching code Michal Kazior
@ 2014-03-21 13:52   ` Michal Kazior
  2014-03-31 12:04   ` [PATCH v3 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
  7 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-21 13:52 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Make the driver responsible for making sure it is
capable of performing the switch. It might as well
accept a request but then disconnect an interface
if some requirements are not met.

In that case userspace should be prepared for an
appropriate event (AP/IBSS/mesh being stopped/left).

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/wireless/nl80211.c | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5465e0e..6b7ded9 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5921,17 +5921,6 @@ skip_beacons:
 		params.radar_required = true;
 	}
 
-	/* TODO: I left this here for now.  With channel switch, the
-	 * verification is a bit more complicated, because we only do
-	 * it later when the channel switch really happens.
-	 */
-	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-					   params.chandef.chan,
-					   CHAN_MODE_SHARED,
-					   radar_detect_width);
-	if (err)
-		return err;
-
 	if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
 		params.block_tx = true;
 
-- 
1.8.5.3


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

* Re: [PATCH v2 03/13] mac80211: prevent chanctx overcommit
  2014-03-21 13:47   ` [PATCH v2 03/13] mac80211: prevent chanctx overcommit Michal Kazior
@ 2014-03-25  7:59     ` Luca Coelho
  2014-03-25  8:13       ` Luca Coelho
  2014-03-25  8:37       ` Michal Kazior
  0 siblings, 2 replies; 199+ messages in thread
From: Luca Coelho @ 2014-03-25  7:59 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, johannes

On Fri, 2014-03-21 at 14:47 +0100, Michal Kazior wrote:
> Do not allocate more channel contexts than a
> driver is capable for currently matching interface
> combination.
> 
> This allows the ieee80211_vif_reserve_chanctx() to
> act as a guard against breaking interface
> combinations.
> 
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
> ---

[...]
> @@ -745,13 +764,16 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
>  			 * context, reserve our current context
>  			 */
>  			new_ctx = curr_ctx;
> -		} else {
> +		} else if (ieee80211_can_create_new_chanctx(local)) {
>  			/* create a new context and reserve it */
>  			new_ctx = ieee80211_new_chanctx(local, chandef, mode);
>  			if (IS_ERR(new_ctx)) {
>  				ret = PTR_ERR(new_ctx);
>  				goto out;
>  			}
> +		} else {
> +			ret = -EBUSY;
> +			goto out;

I'm not sure about this whole allowed channels counting thing.  Does it
really matter what is the total number of allowed channels? I think the
actual combinations is what should be checked here.

Let's say the driver supports these combinations:

1. num_different_channels = 2; limits max 2 APs;
2. num_different_channels = 1; limits 1 AP, 1 STA;

Then you're running on a single-channel with 1 AP and 1 STA.  The STA
gets a CSA to move to a new channel.  If you only consider the
max_num_channels you calculated, you will think that it is okay to
switch, but it is not, because you cannot have 1 AP and 1 STA on
different channels.

Or am I missing something?

--
Luca


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

* Re: [PATCH v2 03/13] mac80211: prevent chanctx overcommit
  2014-03-25  7:59     ` Luca Coelho
@ 2014-03-25  8:13       ` Luca Coelho
  2014-03-25  8:37       ` Michal Kazior
  1 sibling, 0 replies; 199+ messages in thread
From: Luca Coelho @ 2014-03-25  8:13 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, johannes

On Tue, 2014-03-25 at 09:59 +0200, Luca Coelho wrote:
> On Fri, 2014-03-21 at 14:47 +0100, Michal Kazior wrote:
> > @@ -745,13 +764,16 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
> >  			 * context, reserve our current context
> >  			 */
> >  			new_ctx = curr_ctx;
> > -		} else {
> > +		} else if (ieee80211_can_create_new_chanctx(local)) {
> >  			/* create a new context and reserve it */
> >  			new_ctx = ieee80211_new_chanctx(local, chandef, mode);
> >  			if (IS_ERR(new_ctx)) {
> >  				ret = PTR_ERR(new_ctx);
> >  				goto out;
> >  			}
> > +		} else {
> > +			ret = -EBUSY;
> > +			goto out;
> 
> I'm not sure about this whole allowed channels counting thing.  Does it
> really matter what is the total number of allowed channels? I think the
> actual combinations is what should be checked here.
> 
> Let's say the driver supports these combinations:
> 
> 1. num_different_channels = 2; limits max 2 APs;
> 2. num_different_channels = 1; limits 1 AP, 1 STA;
> 
> Then you're running on a single-channel with 1 AP and 1 STA.  The STA
> gets a CSA to move to a new channel.  If you only consider the
> max_num_channels you calculated, you will think that it is okay to
> switch, but it is not, because you cannot have 1 AP and 1 STA on
> different channels.
> 
> Or am I missing something?

Hmmm... okay, I guess this is a typical case of "move-or-die" for the
AP.  Basically what we're saying here is that if the driver supports 2
channels in any combination, we can always have 2 channel contexts as
long as one of them is empty.

I'm still not sure this would be valid, for instance, if the driver has
problems with having one STA in a channel and an empty context in
another channel, because we actually try to create that context in the
driver before it's actually used...

--
Luca.


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

* Re: [PATCH v2 03/13] mac80211: prevent chanctx overcommit
  2014-03-25  7:59     ` Luca Coelho
  2014-03-25  8:13       ` Luca Coelho
@ 2014-03-25  8:37       ` Michal Kazior
  2014-03-25  9:45         ` Luca Coelho
  1 sibling, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-25  8:37 UTC (permalink / raw)
  To: Luca Coelho; +Cc: linux-wireless, Johannes Berg

On 25 March 2014 08:59, Luca Coelho <luca@coelho.fi> wrote:
> On Fri, 2014-03-21 at 14:47 +0100, Michal Kazior wrote:
>> Do not allocate more channel contexts than a
>> driver is capable for currently matching interface
>> combination.
>>
>> This allows the ieee80211_vif_reserve_chanctx() to
>> act as a guard against breaking interface
>> combinations.
>>
>> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
>> ---
>
> [...]
>> @@ -745,13 +764,16 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
>>                        * context, reserve our current context
>>                        */
>>                       new_ctx = curr_ctx;
>> -             } else {
>> +             } else if (ieee80211_can_create_new_chanctx(local)) {
>>                       /* create a new context and reserve it */
>>                       new_ctx = ieee80211_new_chanctx(local, chandef, mode);
>>                       if (IS_ERR(new_ctx)) {
>>                               ret = PTR_ERR(new_ctx);
>>                               goto out;
>>                       }
>> +             } else {
>> +                     ret = -EBUSY;
>> +                     goto out;
>
> I'm not sure about this whole allowed channels counting thing.  Does it
> really matter what is the total number of allowed channels? I think the
> actual combinations is what should be checked here.
>
> Let's say the driver supports these combinations:
>
> 1. num_different_channels = 2; limits max 2 APs;
> 2. num_different_channels = 1; limits 1 AP, 1 STA;
>
> Then you're running on a single-channel with 1 AP and 1 STA.  The STA
> gets a CSA to move to a new channel.  If you only consider the
> max_num_channels you calculated, you will think that it is okay to
> switch, but it is not, because you cannot have 1 AP and 1 STA on
> different channels.
>
> Or am I missing something?

Yes. You're missing the fact, that ieee80211_max_num_channels() uses
current iftype set to narrow down matching combinations.

In the above example you provided ieee80211_max_num_channels() returns 1.


Michał

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

* Re: [PATCH v2 03/13] mac80211: prevent chanctx overcommit
  2014-03-25  8:37       ` Michal Kazior
@ 2014-03-25  9:45         ` Luca Coelho
  0 siblings, 0 replies; 199+ messages in thread
From: Luca Coelho @ 2014-03-25  9:45 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg

On Tue, 2014-03-25 at 09:37 +0100, Michal Kazior wrote:
> On 25 March 2014 08:59, Luca Coelho <luca@coelho.fi> wrote:
> > On Fri, 2014-03-21 at 14:47 +0100, Michal Kazior wrote:
> >> Do not allocate more channel contexts than a
> >> driver is capable for currently matching interface
> >> combination.
> >>
> >> This allows the ieee80211_vif_reserve_chanctx() to
> >> act as a guard against breaking interface
> >> combinations.
> >>
> >> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
> >> ---
> >
> > [...]
> >> @@ -745,13 +764,16 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
> >>                        * context, reserve our current context
> >>                        */
> >>                       new_ctx = curr_ctx;
> >> -             } else {
> >> +             } else if (ieee80211_can_create_new_chanctx(local)) {
> >>                       /* create a new context and reserve it */
> >>                       new_ctx = ieee80211_new_chanctx(local, chandef, mode);
> >>                       if (IS_ERR(new_ctx)) {
> >>                               ret = PTR_ERR(new_ctx);
> >>                               goto out;
> >>                       }
> >> +             } else {
> >> +                     ret = -EBUSY;
> >> +                     goto out;
> >
> > I'm not sure about this whole allowed channels counting thing.  Does it
> > really matter what is the total number of allowed channels? I think the
> > actual combinations is what should be checked here.
> >
> > Let's say the driver supports these combinations:
> >
> > 1. num_different_channels = 2; limits max 2 APs;
> > 2. num_different_channels = 1; limits 1 AP, 1 STA;
> >
> > Then you're running on a single-channel with 1 AP and 1 STA.  The STA
> > gets a CSA to move to a new channel.  If you only consider the
> > max_num_channels you calculated, you will think that it is okay to
> > switch, but it is not, because you cannot have 1 AP and 1 STA on
> > different channels.
> >
> > Or am I missing something?
> 
> Yes. You're missing the fact, that ieee80211_max_num_channels() uses
> current iftype set to narrow down matching combinations.

Exactly, that's what I was missing. :)

--
Luca.


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

* Re: [PATCH v2 1/7] cfg80211: fix radar_detect combination checking
  2014-03-21 13:52   ` [PATCH v2 1/7] cfg80211: fix radar_detect combination checking Michal Kazior
@ 2014-03-28 12:59     ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-03-28 12:59 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Fri, 2014-03-21 at 14:52 +0100, Michal Kazior wrote:
> All bits from radar_detect must match combination
> radar bitmask. Otherwise it is theoretically
> possible to lead into an invalid combination
> provided a driver reports strange combinations.

This seemed fairly obvious, applied.

johannes


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

* Re: [PATCH v2 2/7] mac80211: make check_combinations() aware of chanctx reservation
  2014-03-21 13:52   ` [PATCH v2 2/7] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
@ 2014-03-28 13:00     ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-03-28 13:00 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Fri, 2014-03-21 at 14:52 +0100, Michal Kazior wrote:

> +	/* if chanctx has in-place reservation then consider only the future
> +	 * radar_detect. multi-vif reservation is deferred so ignore assigned
> +	 * vifs. it is impossible for new vifs to be bound to an in-place
> +	 * reserved chanctx so consistency is guranteed */

typo, guaranteed; also, */ should be on a new line in both styles

johannes


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

* Re: [PATCH v2 3/7] mac80211: use chanctx reservation for AP CSA
  2014-03-21 13:52   ` [PATCH v2 3/7] mac80211: use chanctx reservation for AP CSA Michal Kazior
@ 2014-03-28 13:01     ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-03-28 13:01 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Fri, 2014-03-21 at 14:52 +0100, Michal Kazior wrote:
> Channel switch finalization is now 2-step. First
> step is when driver calls csa_finish(), the other
> is when reservation is actually finalized (which
> be defered for in-place reservation).
> 
> This implies driver must not call csa_finish()
> more than once for each channel_switch request.
> 
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
> ---
>  net/mac80211/cfg.c  | 62 ++++++++++++++++++++++++++++++++++++-----------------
>  net/mac80211/chan.c | 11 +++++++++-
>  2 files changed, 52 insertions(+), 21 deletions(-)
> 
> diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
> index 0c68269..ba544d3 100644
> --- a/net/mac80211/cfg.c
> +++ b/net/mac80211/cfg.c
> @@ -3096,17 +3096,25 @@ static int ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
>  
>  	sdata_assert_lock(sdata);
>  	lockdep_assert_held(&local->mtx);
> +	lockdep_assert_held(&local->mtx);

duplicate
 
> -	sdata->radar_required = sdata->csa_radar_required;
> -	err = ieee80211_vif_change_channel(sdata, &changed);
> -	if (WARN_ON(err < 0))
> -		return err;
> +	/* using reservation isn't immediate as it may be deferred until later
> +	 * with multi-vif. once reservation is complete it will re-schedule the
> +	 * work with no reserved_chanctx so verify chandef to check if it
> +	 * completed successfully */

style issue here also


> -	if (num_chanctx > 1)
> -		return -EBUSY;
> +	err = ieee80211_vif_reserve_chanctx(sdata, &params->chandef,
> +					    chanctx->mode,
> +					    params->radar_required);
> +	if (err) {
> +		mutex_unlock(&local->chanctx_mtx);
> +		return err;
> +	}
>  
> -	/* don't allow another channel switch if one is already active. */
> -	if (sdata->vif.csa_active)
> -		return -EBUSY;
> +	/* if reservation is invalid then this will fail */
> +	err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0);
> +	if (err) {
> +		ieee80211_vif_unreserve_chanctx(sdata);
> +		mutex_unlock(&local->chanctx_mtx);
> +		return err;
> +	}
>  
>  	err = ieee80211_set_csa_beacon(sdata, params, &changed);
> -	if (err)
> +	if (err) {
> +		ieee80211_vif_unreserve_chanctx(sdata);
> +		mutex_unlock(&local->chanctx_mtx);
>  		return err;
> +	}

All those error cases could be converted to 'goto' instead of
duplicating the unlock/unreserve.

johannes


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

* Re: [PATCH v2 6/7] mac80211: remove old unused channel switching code
  2014-03-21 13:52   ` [PATCH v2 6/7] mac80211: remove old unused channel switching code Michal Kazior
@ 2014-03-28 13:03     ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-03-28 13:03 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Fri, 2014-03-21 at 14:52 +0100, Michal Kazior wrote:
> ieee80211_vif_change_channel() has no uses

users?

> anymore. sdata->csa_radar_required is also removed
> because it is no longer used. Instead reservations
> take care of tracking whether an interface
> requires radar detection or not.

Why not kick it out in the patch that removes the users?

johannes


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

* Re: [PATCH v2 01/13] cfg80211: allow drivers to iterate over matching combinations
  2014-03-21 13:47   ` [PATCH v2 01/13] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
@ 2014-03-28 13:05     ` Johannes Berg
  2014-03-28 13:21       ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-03-28 13:05 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Fri, 2014-03-21 at 14:47 +0100, Michal Kazior wrote:

> +int cfg80211_iter_combinations(struct wiphy *wiphy,
> +			       const int num_different_channels,
> +			       const u8 radar_detect,
> +			       const int iftype_num[NUM_NL80211_IFTYPES],
> +			       void (*iter)(const struct ieee80211_iface_combination *c,
> +					    void *data),
> +			       void *data);

Maybe *iter should have a non-void return value and allow aborting the
loop somehow?

> +static void
> +cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
> +			  void *data)
> +{
> +	int *num = data;
> +	(*num)++;
> +}
> +
> +int cfg80211_check_combinations(struct wiphy *wiphy,
> +				const int num_different_channels,
> +				const u8 radar_detect,
> +				const int iftype_num[NUM_NL80211_IFTYPES])
> +{
> +	int err, num = 0;
> +
> +	err = cfg80211_iter_combinations(wiphy, num_different_channels,
> +					 radar_detect, iftype_num,
> +					 cfg80211_iter_sum_ifcombs, &num);
> +	if (err)
> +		return err;
> +	if (num == 0)
> +		return -EBUSY;
> +
> +	return 0;
>  }

This also seems a bit pointless - why not just have an int instead of
num and set it to -EBUSY outside, and to 0 inside, and then just return
it? You don't need the number of available combinations.

johannes


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

* Re: [PATCH v2 05/13] mac80211: track assigned vifs in chanctx
  2014-03-21 13:47   ` [PATCH v2 05/13] mac80211: track assigned vifs in chanctx Michal Kazior
@ 2014-03-28 13:06     ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-03-28 13:06 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Fri, 2014-03-21 at 14:47 +0100, Michal Kazior wrote:
> This can be useful.

That's a bit terse :)

Can you add a comment for locking?

johannes


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

* Re: [PATCH v2 06/13] mac80211: track reserved vifs in chanctx
  2014-03-21 13:47   ` [PATCH v2 06/13] mac80211: track reserved " Michal Kazior
@ 2014-03-28 13:07     ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-03-28 13:07 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Fri, 2014-03-21 at 14:47 +0100, Michal Kazior wrote:
> This can be useful.

Same comments as on the previous patch, I could hardly even tell the
difference ;)

johannes


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

* Re: [PATCH v2 07/13] mac80211: improve find_chanctx() for reservations
  2014-03-21 13:47   ` [PATCH v2 07/13] mac80211: improve find_chanctx() for reservations Michal Kazior
@ 2014-03-28 13:08     ` Johannes Berg
  2014-03-28 13:32       ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-03-28 13:08 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Fri, 2014-03-21 at 14:47 +0100, Michal Kazior wrote:
> Relax ieee80211_find_chanctx(). If chanctx
> reservation chandef is compatible with
> current-future assigned interfaces chandef then
> allow it to be used by new interfaces.

Err, I don't understand. Could you elaborate?

johannes


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

* Re: [PATCH v2 12/13] mac80211: compute chanctx refcount on-the-fly
  2014-03-21 13:47   ` [PATCH v2 12/13] mac80211: compute chanctx refcount on-the-fly Michal Kazior
@ 2014-03-28 13:11     ` Johannes Berg
  2014-03-28 13:22       ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-03-28 13:11 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Fri, 2014-03-21 at 14:47 +0100, Michal Kazior wrote:
> It doesn't make much sense to store refcount in
> the chanctx structure. One still needs to hold
> chanctx_mtx to get the value safely. Besides,
> refcount isn't on performance critical paths.
> 
> This will make implementing chanctx reservation
> refcounting a little easier.

Why bother with patch 11 then?

johannes


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

* Re: [PATCH v2 01/13] cfg80211: allow drivers to iterate over matching combinations
  2014-03-28 13:05     ` Johannes Berg
@ 2014-03-28 13:21       ` Michal Kazior
  2014-03-28 13:22         ` Johannes Berg
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-28 13:21 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless

On 28 March 2014 14:05, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Fri, 2014-03-21 at 14:47 +0100, Michal Kazior wrote:
>
>> +int cfg80211_iter_combinations(struct wiphy *wiphy,
>> +                            const int num_different_channels,
>> +                            const u8 radar_detect,
>> +                            const int iftype_num[NUM_NL80211_IFTYPES],
>> +                            void (*iter)(const struct ieee80211_iface_combination *c,
>> +                                         void *data),
>> +                            void *data);
>
> Maybe *iter should have a non-void return value and allow aborting the
> loop somehow?

I don't see much of use for that. You can still use *data for that.


>> +static void
>> +cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
>> +                       void *data)
>> +{
>> +     int *num = data;
>> +     (*num)++;
>> +}
>> +
>> +int cfg80211_check_combinations(struct wiphy *wiphy,
>> +                             const int num_different_channels,
>> +                             const u8 radar_detect,
>> +                             const int iftype_num[NUM_NL80211_IFTYPES])
>> +{
>> +     int err, num = 0;
>> +
>> +     err = cfg80211_iter_combinations(wiphy, num_different_channels,
>> +                                      radar_detect, iftype_num,
>> +                                      cfg80211_iter_sum_ifcombs, &num);
>> +     if (err)
>> +             return err;
>> +     if (num == 0)
>> +             return -EBUSY;
>> +
>> +     return 0;
>>  }
>
> This also seems a bit pointless - why not just have an int instead of
> num and set it to -EBUSY outside, and to 0 inside, and then just return
> it? You don't need the number of available combinations.

Hmm.. Well, that works too I guess.


Michał

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

* Re: [PATCH v2 12/13] mac80211: compute chanctx refcount on-the-fly
  2014-03-28 13:11     ` Johannes Berg
@ 2014-03-28 13:22       ` Michal Kazior
  2014-03-28 13:25         ` Johannes Berg
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-28 13:22 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless

On 28 March 2014 14:11, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Fri, 2014-03-21 at 14:47 +0100, Michal Kazior wrote:
>> It doesn't make much sense to store refcount in
>> the chanctx structure. One still needs to hold
>> chanctx_mtx to get the value safely. Besides,
>> refcount isn't on performance critical paths.
>>
>> This will make implementing chanctx reservation
>> refcounting a little easier.
>
> Why bother with patch 11 then?

I try to do one-thing-at-a-time. 11 is a fix, 12 is an enhancement. I
can squash it if you want?


Michał

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

* Re: [PATCH v2 01/13] cfg80211: allow drivers to iterate over matching combinations
  2014-03-28 13:21       ` Michal Kazior
@ 2014-03-28 13:22         ` Johannes Berg
  2014-03-28 13:42           ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-03-28 13:22 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Fri, 2014-03-28 at 14:21 +0100, Michal Kazior wrote:

> >> +int cfg80211_iter_combinations(struct wiphy *wiphy,
> >> +                            const int num_different_channels,
> >> +                            const u8 radar_detect,
> >> +                            const int iftype_num[NUM_NL80211_IFTYPES],
> >> +                            void (*iter)(const struct ieee80211_iface_combination *c,
> >> +                                         void *data),
> >> +                            void *data);
> >
> > Maybe *iter should have a non-void return value and allow aborting the
> > loop somehow?
> 
> I don't see much of use for that. You can still use *data for that.

No, I meant to abort the iteration loop, say when the function returns
true (or false, whichever way you want to look at it). That way you can
stop iteration at the first combination that's sufficient.

johannes


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

* Re: [PATCH v2 12/13] mac80211: compute chanctx refcount on-the-fly
  2014-03-28 13:22       ` Michal Kazior
@ 2014-03-28 13:25         ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-03-28 13:25 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Fri, 2014-03-28 at 14:22 +0100, Michal Kazior wrote:
> On 28 March 2014 14:11, Johannes Berg <johannes@sipsolutions.net> wrote:
> > On Fri, 2014-03-21 at 14:47 +0100, Michal Kazior wrote:
> >> It doesn't make much sense to store refcount in
> >> the chanctx structure. One still needs to hold
> >> chanctx_mtx to get the value safely. Besides,
> >> refcount isn't on performance critical paths.
> >>
> >> This will make implementing chanctx reservation
> >> refcounting a little easier.
> >
> > Why bother with patch 11 then?
> 
> I try to do one-thing-at-a-time. 11 is a fix, 12 is an enhancement. I
> can squash it if you want?

I guess it doesn't really matter, I was just wondering why you were
bothering to fix it up if you're going to remove it :)

johannes


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

* Re: [PATCH v2 07/13] mac80211: improve find_chanctx() for reservations
  2014-03-28 13:08     ` Johannes Berg
@ 2014-03-28 13:32       ` Michal Kazior
  0 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-28 13:32 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless

On 28 March 2014 14:08, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Fri, 2014-03-21 at 14:47 +0100, Michal Kazior wrote:
>> Relax ieee80211_find_chanctx(). If chanctx
>> reservation chandef is compatible with
>> current-future assigned interfaces chandef then
>> allow it to be used by new interfaces.
>
> Err, I don't understand. Could you elaborate?

Yeah. Me too. Apparently I fail at English.

Basically this allows new vifs to be assigned to a chanctx as long as
chanctx's reservation chandefs *and* chanctx's current chandef
(implied by assigned vifs, if any) *and* the new vif chandef are
compatible. chanctx being used for in-place reservation with
conflicting channels are skipped. This also it makes it possible to
assign a vif to a chanctx that has been created for reservation only
(that hasn't been finalized yet) and has no vifs assigned whatsoever.


Michał

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

* Re: [PATCH v2 01/13] cfg80211: allow drivers to iterate over matching combinations
  2014-03-28 13:22         ` Johannes Berg
@ 2014-03-28 13:42           ` Michal Kazior
  2014-03-28 13:49             ` Johannes Berg
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-28 13:42 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless

On 28 March 2014 14:22, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Fri, 2014-03-28 at 14:21 +0100, Michal Kazior wrote:
>
>> >> +int cfg80211_iter_combinations(struct wiphy *wiphy,
>> >> +                            const int num_different_channels,
>> >> +                            const u8 radar_detect,
>> >> +                            const int iftype_num[NUM_NL80211_IFTYPES],
>> >> +                            void (*iter)(const struct ieee80211_iface_combination *c,
>> >> +                                         void *data),
>> >> +                            void *data);
>> >
>> > Maybe *iter should have a non-void return value and allow aborting the
>> > loop somehow?
>>
>> I don't see much of use for that. You can still use *data for that.
>
> No, I meant to abort the iteration loop, say when the function returns
> true (or false, whichever way you want to look at it). That way you can
> stop iteration at the first combination that's sufficient.

I know. It's just that it bothers me - if you use true/false you end
up with "do I use true for continue or break" (and need to put
comments in the code) and having an enum for such a trivial thing
seems silly too. On the other hand using *data to guard *iter is also
silly.

So yeah.


Michał

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

* Re: [PATCH v2 01/13] cfg80211: allow drivers to iterate over matching combinations
  2014-03-28 13:42           ` Michal Kazior
@ 2014-03-28 13:49             ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-03-28 13:49 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Fri, 2014-03-28 at 14:42 +0100, Michal Kazior wrote:
> On 28 March 2014 14:22, Johannes Berg <johannes@sipsolutions.net> wrote:
> > On Fri, 2014-03-28 at 14:21 +0100, Michal Kazior wrote:
> >
> >> >> +int cfg80211_iter_combinations(struct wiphy *wiphy,
> >> >> +                            const int num_different_channels,
> >> >> +                            const u8 radar_detect,
> >> >> +                            const int iftype_num[NUM_NL80211_IFTYPES],
> >> >> +                            void (*iter)(const struct ieee80211_iface_combination *c,
> >> >> +                                         void *data),
> >> >> +                            void *data);
> >> >
> >> > Maybe *iter should have a non-void return value and allow aborting the
> >> > loop somehow?
> >>
> >> I don't see much of use for that. You can still use *data for that.
> >
> > No, I meant to abort the iteration loop, say when the function returns
> > true (or false, whichever way you want to look at it). That way you can
> > stop iteration at the first combination that's sufficient.
> 
> I know. It's just that it bothers me - if you use true/false you end
> up with "do I use true for continue or break" (and need to put
> comments in the code) and having an enum for such a trivial thing
> seems silly too. On the other hand using *data to guard *iter is also
> silly.

Ok, let's leave it. It's not like we have a million combinations and
iterating them is expensive ...

johannes


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

* [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations
  2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                     ` (12 preceding siblings ...)
  2014-03-21 13:47   ` [PATCH v2 13/13] mac80211: implement multi-vif in-place reservations Michal Kazior
@ 2014-03-31 10:39   ` Michal Kazior
  2014-03-31 10:39     ` [PATCH v3 01/13] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
                       ` (14 more replies)
  13 siblings, 15 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 10:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Hi,

This is part of my multi-vif csa work. These
patches have been included in my recent big RFC.
I'm trying to split it up a bit.

The patchset incrementally improves chanctx
reservations in order to support multi-vif
reservations and in-place multi-vif reservations
(typically for single-channel hardware, but
multi-channel benefits from this too).

Some of the patches (the refcounting) were also
posted a while ago as a separate small RFC.

This is rebased on mac80211-next/master and my
CSA fixes/cleanups now.

v2:
 * add changelog for refcounting patches
 * fixes for issues pointed out by Eliad

v3:
 * fix commit messages


Michal Kazior (13):
  cfg80211: allow drivers to iterate over matching combinations
  mac80211: add max channel calculation utility function
  mac80211: prevent chanctx overcommit
  mac80211: add support for radar detection for reservations
  mac80211: track assigned vifs in chanctx
  mac80211: track reserved vifs in chanctx
  mac80211: improve find_chanctx() for reservations
  mac80211: improve chanctx reservation lookup
  mac80211: split ieee80211_new_chanctx()
  mac80211: split ieee80211_free_chanctx()
  mac80211: fix racy usage of chanctx->refcount
  mac80211: compute chanctx refcount on-the-fly
  mac80211: implement multi-vif in-place reservations

 include/net/cfg80211.h     |  27 ++
 include/net/mac80211.h     |   7 -
 net/mac80211/cfg.c         |  19 +-
 net/mac80211/chan.c        | 597 ++++++++++++++++++++++++++++++++++-----------
 net/mac80211/ieee80211_i.h |  18 +-
 net/mac80211/iface.c       |   2 +
 net/mac80211/mlme.c        |   2 +-
 net/mac80211/util.c        |  43 ++++
 net/wireless/util.c        |  44 +++-
 9 files changed, 592 insertions(+), 167 deletions(-)

-- 
1.8.5.3


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

* [PATCH v3 01/13] cfg80211: allow drivers to iterate over matching combinations
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
@ 2014-03-31 10:39     ` Michal Kazior
  2014-03-31 10:39     ` [PATCH v3 02/13] mac80211: add max channel calculation utility function Michal Kazior
                       ` (13 subsequent siblings)
  14 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 10:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The patch splits cfg80211_check_combinations()
into an iterator function and a simple iteration
user.

This makes it possible for drivers to asses how
many channels can use given iftype setup. This in
turn can be used for future
multi-interface/multi-channel channel switching.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 include/net/cfg80211.h | 27 +++++++++++++++++++++++++++
 net/wireless/util.c    | 44 +++++++++++++++++++++++++++++++++++++-------
 2 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b4ea653..af26751 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4730,6 +4730,33 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
 void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev,
 			 gfp_t gfp);
 
+/**
+ * cfg80211_iter_combinations - iterate over matching combinations
+ *
+ * @wiphy: the wiphy
+ * @num_different_channels: the number of different channels we want
+ *	to use for verification
+ * @radar_detect: a bitmap where each bit corresponds to a channel
+ *	width where radar detection is needed, as in the definition of
+ *	&struct ieee80211_iface_combination.@radar_detect_widths
+ * @iftype_num: array with the numbers of interfaces of each interface
+ *	type.  The index is the interface type as specified in &enum
+ *	nl80211_iftype.
+ * @iter: function to call for each matching combination
+ * @data: pointer to pass to iter function
+ *
+ * This function can be called by the driver to check what possible
+ * combinations it fits in at a given moment, e.g. for channel switching
+ * purposes.
+ */
+int cfg80211_iter_combinations(struct wiphy *wiphy,
+			       const int num_different_channels,
+			       const u8 radar_detect,
+			       const int iftype_num[NUM_NL80211_IFTYPES],
+			       void (*iter)(const struct ieee80211_iface_combination *c,
+					    void *data),
+			       void *data);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 31b93b9..f9928f2 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1250,10 +1250,13 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
 	return res;
 }
 
-int cfg80211_check_combinations(struct wiphy *wiphy,
-				const int num_different_channels,
-				const u8 radar_detect,
-				const int iftype_num[NUM_NL80211_IFTYPES])
+int cfg80211_iter_combinations(struct wiphy *wiphy,
+			       const int num_different_channels,
+			       const u8 radar_detect,
+			       const int iftype_num[NUM_NL80211_IFTYPES],
+			       void (*iter)(const struct ieee80211_iface_combination *c,
+					    void *data),
+			       void *data)
 {
 	int i, j, iftype;
 	int num_interfaces = 0;
@@ -1310,13 +1313,40 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
 		/* This combination covered all interface types and
 		 * supported the requested numbers, so we're good.
 		 */
-		kfree(limits);
-		return 0;
+
+		(*iter)(c, data);
  cont:
 		kfree(limits);
 	}
 
-	return -EBUSY;
+	return 0;
+}
+EXPORT_SYMBOL(cfg80211_iter_combinations);
+
+static void
+cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
+			  void *data)
+{
+	int *num = data;
+	(*num)++;
+}
+
+int cfg80211_check_combinations(struct wiphy *wiphy,
+				const int num_different_channels,
+				const u8 radar_detect,
+				const int iftype_num[NUM_NL80211_IFTYPES])
+{
+	int err, num = 0;
+
+	err = cfg80211_iter_combinations(wiphy, num_different_channels,
+					 radar_detect, iftype_num,
+					 cfg80211_iter_sum_ifcombs, &num);
+	if (err)
+		return err;
+	if (num == 0)
+		return -EBUSY;
+
+	return 0;
 }
 EXPORT_SYMBOL(cfg80211_check_combinations);
 
-- 
1.8.5.3


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

* [PATCH v3 02/13] mac80211: add max channel calculation utility function
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
  2014-03-31 10:39     ` [PATCH v3 01/13] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
@ 2014-03-31 10:39     ` Michal Kazior
  2014-04-08 13:23       ` Johannes Berg
  2014-03-31 10:39     ` [PATCH v3 03/13] mac80211: prevent chanctx overcommit Michal Kazior
                       ` (12 subsequent siblings)
  14 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 10:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The utility function has no uses yet. It is aimed
at future chanctx reservation management and
channel switching.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/ieee80211_i.h |  1 +
 net/mac80211/util.c        | 43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 02fe9f4..41d9e49 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1830,6 +1830,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 				 const struct cfg80211_chan_def *chandef,
 				 enum ieee80211_chanctx_mode chanmode,
 				 u8 radar_detect);
+int ieee80211_max_num_channels(struct ieee80211_local *local);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 639bc13..09c4794 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2877,3 +2877,46 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 					   num_different_channels,
 					   radar_detect, num);
 }
+
+static void
+ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c,
+			 void *data)
+{
+	u32 *max_num_different_channels = data;
+
+	*max_num_different_channels = max(*max_num_different_channels,
+					  c->num_different_channels);
+}
+
+int ieee80211_max_num_channels(struct ieee80211_local *local)
+{
+	struct ieee80211_sub_if_data *sdata;
+	int num[NUM_NL80211_IFTYPES] = {};
+	struct ieee80211_chanctx *ctx;
+	int num_different_channels = 0;
+	u8 radar_detect = 0;
+	u32 max_num_different_channels = 1;
+	int err;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(ctx, &local->chanctx_list, list) {
+		num_different_channels++;
+
+		if (ctx->conf.radar_enabled)
+			radar_detect |= BIT(ctx->conf.def.width);
+	}
+
+	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+		num[sdata->wdev.iftype]++;
+	}
+
+	err = cfg80211_iter_combinations(local->hw.wiphy,
+					 num_different_channels, radar_detect,
+					 num, ieee80211_iter_max_chans,
+					 &max_num_different_channels);
+	if (err < 0)
+		return err;
+
+	return max_num_different_channels;
+}
-- 
1.8.5.3


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

* [PATCH v3 03/13] mac80211: prevent chanctx overcommit
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
  2014-03-31 10:39     ` [PATCH v3 01/13] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
  2014-03-31 10:39     ` [PATCH v3 02/13] mac80211: add max channel calculation utility function Michal Kazior
@ 2014-03-31 10:39     ` Michal Kazior
  2014-03-31 10:39     ` [PATCH v3 04/13] mac80211: add support for radar detection for reservations Michal Kazior
                       ` (11 subsequent siblings)
  14 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 10:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Do not allocate more channel contexts than a
driver is capable for currently matching interface
combination.

This allows the ieee80211_vif_reserve_chanctx() to
act as a guard against breaking interface
combinations.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 122033d..90cac10 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -9,6 +9,25 @@
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
+static int ieee80211_num_chanctx(struct ieee80211_local *local)
+{
+	struct ieee80211_chanctx *ctx;
+	int num = 0;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(ctx, &local->chanctx_list, list)
+		num++;
+
+	return num;
+}
+
+static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
+	return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -752,13 +771,16 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 			 * context, reserve our current context
 			 */
 			new_ctx = curr_ctx;
-		} else {
+		} else if (ieee80211_can_create_new_chanctx(local)) {
 			/* create a new context and reserve it */
 			new_ctx = ieee80211_new_chanctx(local, chandef, mode);
 			if (IS_ERR(new_ctx)) {
 				ret = PTR_ERR(new_ctx);
 				goto out;
 			}
+		} else {
+			ret = -EBUSY;
+			goto out;
 		}
 	}
 
-- 
1.8.5.3


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

* [PATCH v3 04/13] mac80211: add support for radar detection for reservations
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                       ` (2 preceding siblings ...)
  2014-03-31 10:39     ` [PATCH v3 03/13] mac80211: prevent chanctx overcommit Michal Kazior
@ 2014-03-31 10:39     ` Michal Kazior
  2014-04-08 13:25       ` Johannes Berg
  2014-03-31 10:39     ` [PATCH v3 05/13] mac80211: track assigned vifs in chanctx Michal Kazior
                       ` (10 subsequent siblings)
  14 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 10:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Initial chanctx reservation code wasn't aware of
radar detection requirements. This is necessary
for chanctx reservations to be used for channel
switching in the future.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c        | 5 ++++-
 net/mac80211/ieee80211_i.h | 4 +++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 90cac10..cc85ad8 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -743,7 +743,8 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
 
 int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 				  const struct cfg80211_chan_def *chandef,
-				  enum ieee80211_chanctx_mode mode)
+				  enum ieee80211_chanctx_mode mode,
+				  bool radar_required)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx_conf *conf;
@@ -787,6 +788,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	new_ctx->refcount++;
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
+	sdata->reserved_radar_required = radar_required;
 out:
 	mutex_unlock(&local->chanctx_mtx);
 	return ret;
@@ -831,6 +833,7 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 	/* unref our reservation */
 	ctx->refcount--;
 	sdata->reserved_chanctx = NULL;
+	sdata->radar_required = sdata->reserved_radar_required;
 
 	if (old_ctx == ctx) {
 		/* This is our own context, just change it */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 41d9e49..a96e375 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -760,6 +760,7 @@ struct ieee80211_sub_if_data {
 	/* context reservation -- protected with chanctx_mtx */
 	struct ieee80211_chanctx *reserved_chanctx;
 	struct cfg80211_chan_def reserved_chandef;
+	bool reserved_radar_required;
 
 	/* used to reconfigure hardware SM PS */
 	struct work_struct recalc_smps;
@@ -1785,7 +1786,8 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 int __must_check
 ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 			      const struct cfg80211_chan_def *chandef,
-			      enum ieee80211_chanctx_mode mode);
+			      enum ieee80211_chanctx_mode mode,
+			      bool radar_required);
 int __must_check
 ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 				   u32 *changed);
-- 
1.8.5.3


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

* [PATCH v3 05/13] mac80211: track assigned vifs in chanctx
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                       ` (3 preceding siblings ...)
  2014-03-31 10:39     ` [PATCH v3 04/13] mac80211: add support for radar detection for reservations Michal Kazior
@ 2014-03-31 10:39     ` Michal Kazior
  2014-03-31 10:39     ` [PATCH v3 06/13] mac80211: track reserved " Michal Kazior
                       ` (9 subsequent siblings)
  14 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 10:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

This can be useful. Provides a more straghtforward
way to iterate over interfaces bound to a given
chanctx and allows tracking chanctx usage
explicitly.

The structure is protected by local->chanctx_mtx.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v3:
 * update commit message [Johannes]
 * add locking information [Johannes]

 net/mac80211/chan.c        | 4 ++++
 net/mac80211/ieee80211_i.h | 4 ++++
 net/mac80211/iface.c       | 1 +
 3 files changed, 9 insertions(+)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index cc85ad8..88aeb40 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -270,6 +270,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 	if (!ctx)
 		return ERR_PTR(-ENOMEM);
 
+	INIT_LIST_HEAD(&ctx->assigned_vifs);
 	ctx->conf.def = *chandef;
 	ctx->conf.rx_chains_static = 1;
 	ctx->conf.rx_chains_dynamic = 1;
@@ -414,6 +415,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 		curr_ctx->refcount--;
 		drv_unassign_vif_chanctx(local, sdata, curr_ctx);
 		conf = NULL;
+		list_del(&sdata->assigned_chanctx_list);
 	}
 
 	if (new_ctx) {
@@ -423,6 +425,8 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 
 		new_ctx->refcount++;
 		conf = &new_ctx->conf;
+		list_add(&sdata->assigned_chanctx_list,
+			 &new_ctx->assigned_vifs);
 	}
 
 out:
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a96e375..d39f32d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -691,6 +691,8 @@ struct ieee80211_chanctx {
 	struct list_head list;
 	struct rcu_head rcu_head;
 
+	struct list_head assigned_vifs;
+
 	enum ieee80211_chanctx_mode mode;
 	int refcount;
 	bool driver_present;
@@ -757,6 +759,8 @@ struct ieee80211_sub_if_data {
 	bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
 	struct cfg80211_chan_def csa_chandef;
 
+	struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */
+
 	/* context reservation -- protected with chanctx_mtx */
 	struct ieee80211_chanctx *reserved_chanctx;
 	struct cfg80211_chan_def reserved_chandef;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 52dccd6..8da4a0d 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1296,6 +1296,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 	INIT_WORK(&sdata->work, ieee80211_iface_work);
 	INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
 	INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
+	INIT_LIST_HEAD(&sdata->assigned_chanctx_list);
 
 	switch (type) {
 	case NL80211_IFTYPE_P2P_GO:
-- 
1.8.5.3


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

* [PATCH v3 06/13] mac80211: track reserved vifs in chanctx
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                       ` (4 preceding siblings ...)
  2014-03-31 10:39     ` [PATCH v3 05/13] mac80211: track assigned vifs in chanctx Michal Kazior
@ 2014-03-31 10:39     ` Michal Kazior
  2014-03-31 10:39     ` [PATCH v3 07/13] mac80211: improve find_chanctx() for reservations Michal Kazior
                       ` (8 subsequent siblings)
  14 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 10:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

This can be useful. Provides a more straghtforward
way to iterate over interfaces taking part in
chanctx reservation and allows tracking chanctx
usage explicitly.

The structure is protected by local->chanctx_mtx.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v3:
 * update commit message [Johannes]
 * add locking information [Johannes]

 net/mac80211/chan.c        | 14 ++++++++++----
 net/mac80211/ieee80211_i.h |  2 ++
 net/mac80211/iface.c       |  1 +
 3 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 88aeb40..ad29e6e 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -271,6 +271,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 		return ERR_PTR(-ENOMEM);
 
 	INIT_LIST_HEAD(&ctx->assigned_vifs);
+	INIT_LIST_HEAD(&ctx->reserved_vifs);
 	ctx->conf.def = *chandef;
 	ctx->conf.rx_chains_static = 1;
 	ctx->conf.rx_chains_dynamic = 1;
@@ -732,16 +733,19 @@ void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 
 int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
 {
+	struct ieee80211_chanctx *ctx = sdata->reserved_chanctx;
+
 	lockdep_assert_held(&sdata->local->chanctx_mtx);
 
-	if (WARN_ON(!sdata->reserved_chanctx))
+	if (WARN_ON(!ctx))
 		return -EINVAL;
 
-	if (--sdata->reserved_chanctx->refcount == 0)
-		ieee80211_free_chanctx(sdata->local, sdata->reserved_chanctx);
-
+	list_del(&sdata->reserved_chanctx_list);
 	sdata->reserved_chanctx = NULL;
 
+	if (--ctx->refcount == 0)
+		ieee80211_free_chanctx(sdata->local, ctx);
+
 	return 0;
 }
 
@@ -789,6 +793,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
+	list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
 	new_ctx->refcount++;
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
@@ -838,6 +843,7 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 	ctx->refcount--;
 	sdata->reserved_chanctx = NULL;
 	sdata->radar_required = sdata->reserved_radar_required;
+	list_del(&sdata->reserved_chanctx_list);
 
 	if (old_ctx == ctx) {
 		/* This is our own context, just change it */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d39f32d..e281bde 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -692,6 +692,7 @@ struct ieee80211_chanctx {
 	struct rcu_head rcu_head;
 
 	struct list_head assigned_vifs;
+	struct list_head reserved_vifs;
 
 	enum ieee80211_chanctx_mode mode;
 	int refcount;
@@ -760,6 +761,7 @@ struct ieee80211_sub_if_data {
 	struct cfg80211_chan_def csa_chandef;
 
 	struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */
+	struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */
 
 	/* context reservation -- protected with chanctx_mtx */
 	struct ieee80211_chanctx *reserved_chanctx;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 8da4a0d..387962d 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1297,6 +1297,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 	INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
 	INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
 	INIT_LIST_HEAD(&sdata->assigned_chanctx_list);
+	INIT_LIST_HEAD(&sdata->reserved_chanctx_list);
 
 	switch (type) {
 	case NL80211_IFTYPE_P2P_GO:
-- 
1.8.5.3


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

* [PATCH v3 07/13] mac80211: improve find_chanctx() for reservations
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                       ` (5 preceding siblings ...)
  2014-03-31 10:39     ` [PATCH v3 06/13] mac80211: track reserved " Michal Kazior
@ 2014-03-31 10:39     ` Michal Kazior
  2014-03-31 10:39     ` [PATCH v3 08/13] mac80211: improve chanctx reservation lookup Michal Kazior
                       ` (7 subsequent siblings)
  14 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 10:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

This allows new vifs to be assigned to a chanctx
as long as chanctx's reservation chandefs (if any)
and chanctx's current chandef (implied by assigned
vifs at the time, if any) and the new vif chandef
are all compatible.

This implies it is impossible to assign a new vif
to an in-place reservation chanctx.

This gives no advantages for single-channel
hardware. It makes sense for multi-channel
hardware only.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v2:
 * remove redundant calls to _chandef() [Eliad]
 * dont use rcu_access_pointer() [Eliad]

v3:
 * fix commit message so it makes more sense [Johannes]

 net/mac80211/chan.c | 56 +++++++++++++++++++++++++++--------------------------
 1 file changed, 29 insertions(+), 27 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index ad29e6e..e14d756 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -28,6 +28,29 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
 	return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
 }
 
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
+				   struct ieee80211_chanctx *ctx,
+				   const struct cfg80211_chan_def *compat)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs,
+			    reserved_chanctx_list) {
+		if (!compat)
+			compat = &sdata->reserved_chandef;
+
+		compat = cfg80211_chandef_compatible(&sdata->reserved_chandef,
+						     compat);
+		if (!compat)
+			break;
+	}
+
+	return compat;
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -181,27 +204,6 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
 	}
 }
 
-static bool ieee80211_chanctx_is_reserved(struct ieee80211_local *local,
-					  struct ieee80211_chanctx *ctx)
-{
-	struct ieee80211_sub_if_data *sdata;
-	bool ret = false;
-
-	lockdep_assert_held(&local->chanctx_mtx);
-	rcu_read_lock();
-	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-		if (!ieee80211_sdata_running(sdata))
-			continue;
-		if (sdata->reserved_chanctx == ctx) {
-			ret = true;
-			break;
-		}
-	}
-
-	rcu_read_unlock();
-	return ret;
-}
-
 static struct ieee80211_chanctx *
 ieee80211_find_chanctx(struct ieee80211_local *local,
 		       const struct cfg80211_chan_def *chandef,
@@ -217,18 +219,18 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
 	list_for_each_entry(ctx, &local->chanctx_list, list) {
 		const struct cfg80211_chan_def *compat;
 
-		/* We don't support chanctx reservation for multiple
-		 * vifs yet, so don't allow reserved chanctxs to be
-		 * reused.
-		 */
-		if ((ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) ||
-		    ieee80211_chanctx_is_reserved(local, ctx))
+		if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
 			continue;
 
 		compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef);
 		if (!compat)
 			continue;
 
+		compat = ieee80211_chanctx_reserved_chandef(local, ctx,
+							    compat);
+		if (!compat)
+			continue;
+
 		ieee80211_change_chanctx(local, ctx, compat);
 
 		return ctx;
-- 
1.8.5.3


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

* [PATCH v3 08/13] mac80211: improve chanctx reservation lookup
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                       ` (6 preceding siblings ...)
  2014-03-31 10:39     ` [PATCH v3 07/13] mac80211: improve find_chanctx() for reservations Michal Kazior
@ 2014-03-31 10:39     ` Michal Kazior
  2014-03-31 10:39     ` [PATCH v3 09/13] mac80211: split ieee80211_new_chanctx() Michal Kazior
                       ` (6 subsequent siblings)
  14 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 10:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Use a separate function to look for reservation
chanctx. For multi-interface/channel reservation
search sematics differ slightly.

The new routine allows reservations to be merged
with chanctx that are already reserved by other
interface(s).

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 88 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index e14d756..a12cc23 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -51,6 +51,93 @@ ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
 	return compat;
 }
 
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
+				       struct ieee80211_chanctx *ctx,
+				       const struct cfg80211_chan_def *compat)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->assigned_vifs,
+			    assigned_chanctx_list) {
+		if (sdata->reserved_chanctx != NULL)
+			continue;
+
+		if (!compat)
+			compat = &sdata->vif.bss_conf.chandef;
+
+		compat = cfg80211_chandef_compatible(
+				&sdata->vif.bss_conf.chandef, compat);
+		if (!compat)
+			break;
+	}
+
+	return compat;
+}
+
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_combined_chandef(struct ieee80211_local *local,
+				   struct ieee80211_chanctx *ctx,
+				   const struct cfg80211_chan_def *compat)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	compat = ieee80211_chanctx_reserved_chandef(local, ctx, compat);
+	if (!compat)
+		return NULL;
+
+	compat = ieee80211_chanctx_non_reserved_chandef(local, ctx, compat);
+	if (!compat)
+		return NULL;
+
+	return compat;
+}
+
+static bool
+ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local,
+				      struct ieee80211_chanctx *ctx,
+				      const struct cfg80211_chan_def *def)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	if (ieee80211_chanctx_combined_chandef(local, ctx, def))
+		return true;
+
+	if (!list_empty(&ctx->reserved_vifs) &&
+	    ieee80211_chanctx_reserved_chandef(local, ctx, def))
+		return true;
+
+	return false;
+}
+
+static struct ieee80211_chanctx *
+ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
+				   const struct cfg80211_chan_def *chandef,
+				   enum ieee80211_chanctx_mode mode)
+{
+	struct ieee80211_chanctx *ctx;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
+		return NULL;
+
+	list_for_each_entry(ctx, &local->chanctx_list, list) {
+		if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
+			continue;
+
+		if (!ieee80211_chanctx_can_reserve_chandef(local, ctx,
+							   chandef))
+			continue;
+
+		return ctx;
+	}
+
+	return NULL;
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -772,8 +859,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 
 	curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-	/* try to find another context with the chandef we want */
-	new_ctx = ieee80211_find_chanctx(local, chandef, mode);
+	new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
 	if (!new_ctx) {
 		if (curr_ctx->refcount == 1 &&
 		    (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
-- 
1.8.5.3


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

* [PATCH v3 09/13] mac80211: split ieee80211_new_chanctx()
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                       ` (7 preceding siblings ...)
  2014-03-31 10:39     ` [PATCH v3 08/13] mac80211: improve chanctx reservation lookup Michal Kazior
@ 2014-03-31 10:39     ` Michal Kazior
  2014-03-31 10:39     ` [PATCH v3 10/13] mac80211: split ieee80211_free_chanctx() Michal Kazior
                       ` (5 subsequent siblings)
  14 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 10:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The function did a little too much. Split it up so
the code can be easily reused in the future.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 56 ++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 43 insertions(+), 13 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index a12cc23..8e207c0 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -345,19 +345,17 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local)
 }
 
 static struct ieee80211_chanctx *
-ieee80211_new_chanctx(struct ieee80211_local *local,
-		      const struct cfg80211_chan_def *chandef,
-		      enum ieee80211_chanctx_mode mode)
+ieee80211_alloc_chanctx(struct ieee80211_local *local,
+			const struct cfg80211_chan_def *chandef,
+			enum ieee80211_chanctx_mode mode)
 {
 	struct ieee80211_chanctx *ctx;
-	u32 changed;
-	int err;
 
 	lockdep_assert_held(&local->chanctx_mtx);
 
 	ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
 	if (!ctx)
-		return ERR_PTR(-ENOMEM);
+		return NULL;
 
 	INIT_LIST_HEAD(&ctx->assigned_vifs);
 	INIT_LIST_HEAD(&ctx->reserved_vifs);
@@ -367,31 +365,63 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 	ctx->mode = mode;
 	ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
 	ieee80211_recalc_chanctx_min_def(local, ctx);
+
+	return ctx;
+}
+
+static int ieee80211_add_chanctx(struct ieee80211_local *local,
+				 struct ieee80211_chanctx *ctx)
+{
+	u32 changed;
+	int err;
+
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
+
 	if (!local->use_chanctx)
 		local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
 
-	/* we hold the mutex to prevent idle from changing */
-	lockdep_assert_held(&local->mtx);
 	/* turn idle off *before* setting channel -- some drivers need that */
 	changed = ieee80211_idle_off(local);
 	if (changed)
 		ieee80211_hw_config(local, changed);
 
 	if (!local->use_chanctx) {
-		local->_oper_chandef = *chandef;
+		local->_oper_chandef = ctx->conf.def;
 		ieee80211_hw_config(local, 0);
 	} else {
 		err = drv_add_chanctx(local, ctx);
 		if (err) {
-			kfree(ctx);
 			ieee80211_recalc_idle(local);
-			return ERR_PTR(err);
+			return err;
 		}
 	}
 
-	/* and keep the mutex held until the new chanctx is on the list */
-	list_add_rcu(&ctx->list, &local->chanctx_list);
+	return 0;
+}
+
+static struct ieee80211_chanctx *
+ieee80211_new_chanctx(struct ieee80211_local *local,
+		      const struct cfg80211_chan_def *chandef,
+		      enum ieee80211_chanctx_mode mode)
+{
+	struct ieee80211_chanctx *ctx;
+	int err;
+
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	ctx = ieee80211_alloc_chanctx(local, chandef, mode);
+	if (!ctx)
+		return ERR_PTR(-ENOMEM);
 
+	err = ieee80211_add_chanctx(local, ctx);
+	if (err) {
+		kfree(ctx);
+		return ERR_PTR(err);
+	}
+
+	list_add_rcu(&ctx->list, &local->chanctx_list);
 	return ctx;
 }
 
-- 
1.8.5.3


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

* [PATCH v3 10/13] mac80211: split ieee80211_free_chanctx()
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                       ` (8 preceding siblings ...)
  2014-03-31 10:39     ` [PATCH v3 09/13] mac80211: split ieee80211_new_chanctx() Michal Kazior
@ 2014-03-31 10:39     ` Michal Kazior
  2014-03-31 10:39     ` [PATCH v3 11/13] mac80211: fix racy usage of chanctx->refcount Michal Kazior
                       ` (4 subsequent siblings)
  14 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 10:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The function did a little too much. Split it up so
the code can be easily reused in the future.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 8e207c0..fc67d4e 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -425,14 +425,11 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 	return ctx;
 }
 
-static void ieee80211_free_chanctx(struct ieee80211_local *local,
-				   struct ieee80211_chanctx *ctx)
+static void ieee80211_del_chanctx(struct ieee80211_local *local,
+				  struct ieee80211_chanctx *ctx)
 {
-	bool check_single_channel = false;
 	lockdep_assert_held(&local->chanctx_mtx);
 
-	WARN_ON_ONCE(ctx->refcount != 0);
-
 	if (!local->use_chanctx) {
 		struct cfg80211_chan_def *chandef = &local->_oper_chandef;
 		chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
@@ -442,8 +439,9 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
 		/* NOTE: Disabling radar is only valid here for
 		 * single channel context. To be sure, check it ...
 		 */
-		if (local->hw.conf.radar_enabled)
-			check_single_channel = true;
+		WARN_ON(local->hw.conf.radar_enabled &&
+			!list_empty(&local->chanctx_list));
+
 		local->hw.conf.radar_enabled = false;
 
 		ieee80211_hw_config(local, 0);
@@ -451,13 +449,19 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
 		drv_remove_chanctx(local, ctx);
 	}
 
-	list_del_rcu(&ctx->list);
-	kfree_rcu(ctx, rcu_head);
+	ieee80211_recalc_idle(local);
+}
 
-	/* throw a warning if this wasn't the only channel context. */
-	WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
+static void ieee80211_free_chanctx(struct ieee80211_local *local,
+				   struct ieee80211_chanctx *ctx)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	ieee80211_recalc_idle(local);
+	WARN_ON_ONCE(ctx->refcount != 0);
+
+	list_del_rcu(&ctx->list);
+	ieee80211_del_chanctx(local, ctx);
+	kfree_rcu(ctx, rcu_head);
 }
 
 static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
-- 
1.8.5.3


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

* [PATCH v3 11/13] mac80211: fix racy usage of chanctx->refcount
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                       ` (9 preceding siblings ...)
  2014-03-31 10:39     ` [PATCH v3 10/13] mac80211: split ieee80211_free_chanctx() Michal Kazior
@ 2014-03-31 10:39     ` Michal Kazior
  2014-03-31 10:39     ` [PATCH v3 12/13] mac80211: compute chanctx refcount on-the-fly Michal Kazior
                       ` (3 subsequent siblings)
  14 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 10:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Channel context refcount is protected by
chanctx_mtx. Accessing the value without holding
the mutex is racy. RCU section didn't guarantee
anything here.

Theoretically ieee80211_channel_switch() could
fail to see refcount change and read "1" instead
of, e.g. "2". This means mac80211 could accept CSA
even though it shouldn't have.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v2:
 * use rcu_dereference_protected() [Eliad/Johannes]

 net/mac80211/cfg.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 821143c..caa351b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3282,7 +3282,7 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx_conf *chanctx_conf;
+	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *chanctx;
 	int err, num_chanctx, changed = 0;
 
@@ -3299,23 +3299,24 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 				       &sdata->vif.bss_conf.chandef))
 		return -EINVAL;
 
-	rcu_read_lock();
-	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
-	if (!chanctx_conf) {
-		rcu_read_unlock();
+	mutex_lock(&local->chanctx_mtx);
+	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+					 lockdep_is_held(&local->chanctx_mtx));
+	if (!conf) {
+		mutex_unlock(&local->chanctx_mtx);
 		return -EBUSY;
 	}
 
 	/* don't handle for multi-VIF cases */
-	chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
+	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
 	if (chanctx->refcount > 1) {
-		rcu_read_unlock();
+		mutex_unlock(&local->chanctx_mtx);
 		return -EBUSY;
 	}
 	num_chanctx = 0;
 	list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
 		num_chanctx++;
-	rcu_read_unlock();
+	mutex_unlock(&local->chanctx_mtx);
 
 	if (num_chanctx > 1)
 		return -EBUSY;
-- 
1.8.5.3


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

* [PATCH v3 12/13] mac80211: compute chanctx refcount on-the-fly
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                       ` (10 preceding siblings ...)
  2014-03-31 10:39     ` [PATCH v3 11/13] mac80211: fix racy usage of chanctx->refcount Michal Kazior
@ 2014-03-31 10:39     ` Michal Kazior
  2014-03-31 10:39     ` [PATCH v3 13/13] mac80211: implement multi-vif in-place reservations Michal Kazior
                       ` (2 subsequent siblings)
  14 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 10:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

It doesn't make much sense to store refcount in
the chanctx structure. One still needs to hold
chanctx_mtx to get the value safely. Besides,
refcount isn't on performance critical paths.

This will make implementing chanctx reservation
refcounting a little easier.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v2:
 * use assigned/reserved lists instead of
   local->interfaces

 net/mac80211/cfg.c         |  2 +-
 net/mac80211/chan.c        | 59 +++++++++++++++++++++++++++++++++++-----------
 net/mac80211/ieee80211_i.h |  3 ++-
 net/mac80211/mlme.c        |  2 +-
 4 files changed, 49 insertions(+), 17 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index caa351b..871830e 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3309,7 +3309,7 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 
 	/* don't handle for multi-VIF cases */
 	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
-	if (chanctx->refcount > 1) {
+	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
 		mutex_unlock(&local->chanctx_mtx);
 		return -EBUSY;
 	}
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index fc67d4e..9d4c04d 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -9,6 +9,41 @@
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
+static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
+					  struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+	int num = 0;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
+		num++;
+
+	return num;
+}
+
+static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
+					  struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+	int num = 0;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list)
+		num++;
+
+	return num;
+}
+
+int ieee80211_chanctx_refcount(struct ieee80211_local *local,
+			       struct ieee80211_chanctx *ctx)
+{
+	return ieee80211_chanctx_num_assigned(local, ctx) +
+	       ieee80211_chanctx_num_reserved(local, ctx);
+}
+
 static int ieee80211_num_chanctx(struct ieee80211_local *local)
 {
 	struct ieee80211_chanctx *ctx;
@@ -457,7 +492,7 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
 {
 	lockdep_assert_held(&local->chanctx_mtx);
 
-	WARN_ON_ONCE(ctx->refcount != 0);
+	WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
 
 	list_del_rcu(&ctx->list);
 	ieee80211_del_chanctx(local, ctx);
@@ -536,7 +571,6 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 	if (conf) {
 		curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-		curr_ctx->refcount--;
 		drv_unassign_vif_chanctx(local, sdata, curr_ctx);
 		conf = NULL;
 		list_del(&sdata->assigned_chanctx_list);
@@ -547,7 +581,6 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 		if (ret)
 			goto out;
 
-		new_ctx->refcount++;
 		conf = &new_ctx->conf;
 		list_add(&sdata->assigned_chanctx_list,
 			 &new_ctx->assigned_vifs);
@@ -558,14 +591,14 @@ out:
 
 	sdata->vif.bss_conf.idle = !conf;
 
-	if (curr_ctx && curr_ctx->refcount > 0) {
+	if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
 		ieee80211_recalc_chanctx_chantype(local, curr_ctx);
 		ieee80211_recalc_smps_chanctx(local, curr_ctx);
 		ieee80211_recalc_radar_chanctx(local, curr_ctx);
 		ieee80211_recalc_chanctx_min_def(local, curr_ctx);
 	}
 
-	if (new_ctx && new_ctx->refcount > 0) {
+	if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
 		ieee80211_recalc_txpower(sdata);
 		ieee80211_recalc_chanctx_min_def(local, new_ctx);
 	}
@@ -597,7 +630,7 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
 		ieee80211_vif_unreserve_chanctx(sdata);
 
 	ieee80211_assign_vif_chanctx(sdata, NULL);
-	if (ctx->refcount == 0)
+	if (ieee80211_chanctx_refcount(local, ctx) == 0)
 		ieee80211_free_chanctx(local, ctx);
 }
 
@@ -736,7 +769,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 	ret = ieee80211_assign_vif_chanctx(sdata, ctx);
 	if (ret) {
 		/* if assign fails refcount stays the same */
-		if (ctx->refcount == 0)
+		if (ieee80211_chanctx_refcount(local, ctx) == 0)
 			ieee80211_free_chanctx(local, ctx);
 		goto out;
 	}
@@ -760,7 +793,7 @@ static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
 				     IEEE80211_CHAN_DISABLED))
 		return -EINVAL;
 
-	if (ctx->refcount != 1)
+	if (ieee80211_chanctx_refcount(local, ctx) != 1)
 		return -EINVAL;
 
 	if (sdata->vif.bss_conf.chandef.width != chandef->width) {
@@ -866,7 +899,7 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
 	list_del(&sdata->reserved_chanctx_list);
 	sdata->reserved_chanctx = NULL;
 
-	if (--ctx->refcount == 0)
+	if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0)
 		ieee80211_free_chanctx(sdata->local, ctx);
 
 	return 0;
@@ -895,7 +928,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 
 	new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
 	if (!new_ctx) {
-		if (curr_ctx->refcount == 1 &&
+		if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 &&
 		    (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
 			/* if we're the only users of the chanctx and
 			 * the driver supports changing a running
@@ -916,7 +949,6 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	}
 
 	list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
-	new_ctx->refcount++;
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
 	sdata->reserved_radar_required = radar_required;
@@ -962,7 +994,6 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 	sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
 
 	/* unref our reservation */
-	ctx->refcount--;
 	sdata->reserved_chanctx = NULL;
 	sdata->radar_required = sdata->reserved_radar_required;
 	list_del(&sdata->reserved_chanctx_list);
@@ -975,11 +1006,11 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 			goto out;
 	} else {
 		ret = ieee80211_assign_vif_chanctx(sdata, ctx);
-		if (old_ctx->refcount == 0)
+		if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
 			ieee80211_free_chanctx(local, old_ctx);
 		if (ret) {
 			/* if assign fails refcount stays the same */
-			if (ctx->refcount == 0)
+			if (ieee80211_chanctx_refcount(local, ctx) == 0)
 				ieee80211_free_chanctx(local, ctx);
 			goto out;
 		}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index e281bde..3dffdb2 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -695,7 +695,6 @@ struct ieee80211_chanctx {
 	struct list_head reserved_vifs;
 
 	enum ieee80211_chanctx_mode mode;
-	int refcount;
 	bool driver_present;
 
 	struct ieee80211_chanctx_conf conf;
@@ -1811,6 +1810,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 					 bool clear);
+int ieee80211_chanctx_refcount(struct ieee80211_local *local,
+			       struct ieee80211_chanctx *ctx);
 
 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
 				   struct ieee80211_chanctx *chanctx);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 5a916bb..b36e73f 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1070,7 +1070,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	}
 	chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
 			       struct ieee80211_chanctx, conf);
-	if (chanctx->refcount > 1) {
+	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
 		sdata_info(sdata,
 			   "channel switch with multiple interfaces on the same channel, disconnecting\n");
 		ieee80211_queue_work(&local->hw,
-- 
1.8.5.3


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

* [PATCH v3 13/13] mac80211: implement multi-vif in-place reservations
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                       ` (11 preceding siblings ...)
  2014-03-31 10:39     ` [PATCH v3 12/13] mac80211: compute chanctx refcount on-the-fly Michal Kazior
@ 2014-03-31 10:39     ` Michal Kazior
  2014-03-31 16:15       ` Eliad Peller
  2014-04-08 13:30     ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Johannes Berg
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
  14 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 10:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Multi-vif in-place reservations happen when
it's impossible to allocate more chanctx as per
driver combinations.

Such reservations aren't finalized until last
reservation interface calls in to use the
reservation.

This introduces a special hook
ieee80211_vif_chanctx_reservation_complete(). This
is currently an empty stub and will be filled in
by AP/STA CSA code. This is required to implement
2-step CSA finalization.

This also gets rid of driver requirement to be
able to re-program channel of a chanctx.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v2:
 * use new_ctx instead of ctx [Eliad]
 * move recalcs after bss_conf is updated [Eliad]

 include/net/mac80211.h     |   7 --
 net/mac80211/chan.c        | 281 +++++++++++++++++++++++++++++++++------------
 net/mac80211/ieee80211_i.h |   4 +-
 3 files changed, 208 insertions(+), 84 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index ea69961..7e3fe90 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1557,12 +1557,6 @@ struct ieee80211_tx_control {
  *	for a single active channel while using channel contexts. When support
  *	is not enabled the default action is to disconnect when getting the
  *	CSA frame.
- *
- * @IEEE80211_HW_CHANGE_RUNNING_CHANCTX: The hardware can change a
- *	channel context on-the-fly.  This is needed for channel switch
- *	on single-channel hardware.  It can also be used as an
- *	optimization in certain channel switch cases with
- *	multi-channel.
  */
 enum ieee80211_hw_flags {
 	IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0,
@@ -1594,7 +1588,6 @@ enum ieee80211_hw_flags {
 	IEEE80211_HW_TIMING_BEACON_ONLY			= 1<<26,
 	IEEE80211_HW_SUPPORTS_HT_CCK_RATES		= 1<<27,
 	IEEE80211_HW_CHANCTX_STA_CSA			= 1<<28,
-	IEEE80211_HW_CHANGE_RUNNING_CHANCTX		= 1<<29,
 };
 
 /**
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 9d4c04d..6870c3c 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -173,6 +173,24 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
 	return NULL;
 }
 
+static bool
+ieee80211_chanctx_all_reserved_vifs_ready(struct ieee80211_local *local,
+					  struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		if (!sdata->reserved_chanctx)
+			continue;
+		if (!sdata->reserved_ready)
+			return false;
+	}
+
+	return true;
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -913,38 +931,24 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *new_ctx, *curr_ctx;
-	int ret = 0;
 
-	mutex_lock(&local->chanctx_mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
 	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf) {
-		ret = -EINVAL;
-		goto out;
-	}
+	if (!conf)
+		return -EINVAL;
 
 	curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
 	new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
 	if (!new_ctx) {
-		if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 &&
-		    (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
-			/* if we're the only users of the chanctx and
-			 * the driver supports changing a running
-			 * context, reserve our current context
-			 */
-			new_ctx = curr_ctx;
-		} else if (ieee80211_can_create_new_chanctx(local)) {
-			/* create a new context and reserve it */
+		if (ieee80211_can_create_new_chanctx(local)) {
 			new_ctx = ieee80211_new_chanctx(local, chandef, mode);
-			if (IS_ERR(new_ctx)) {
-				ret = PTR_ERR(new_ctx);
-				goto out;
-			}
+			if (IS_ERR(new_ctx))
+				return PTR_ERR(new_ctx);
 		} else {
-			ret = -EBUSY;
-			goto out;
+			new_ctx = curr_ctx;
 		}
 	}
 
@@ -952,82 +956,209 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
 	sdata->reserved_radar_required = radar_required;
-out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
+	sdata->reserved_ready = false;
+
+	return 0;
 }
 
-int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
-				       u32 *changed)
+static void
+ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx *ctx;
-	struct ieee80211_chanctx *old_ctx;
-	struct ieee80211_chanctx_conf *conf;
-	int ret;
-	u32 tmp_changed = *changed;
+	/* stub */
+}
 
-	/* TODO: need to recheck if the chandef is usable etc.? */
+static int
+ieee80211_vif_use_reserved_incompat(struct ieee80211_local *local,
+				    struct ieee80211_chanctx *ctx,
+				    const struct cfg80211_chan_def *chandef)
+{
+	struct ieee80211_sub_if_data *sdata, *tmp;
+	struct ieee80211_chanctx *new_ctx;
+	u32 changed = 0;
+	int err;
 
 	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	mutex_lock(&local->chanctx_mtx);
+	if (!ieee80211_chanctx_all_reserved_vifs_ready(local, ctx))
+		return 0;
 
-	ctx = sdata->reserved_chanctx;
-	if (WARN_ON(!ctx)) {
-		ret = -EINVAL;
-		goto out;
+	if (ieee80211_chanctx_num_assigned(local, ctx) !=
+	    ieee80211_chanctx_num_reserved(local, ctx)) {
+		wiphy_info(local->hw.wiphy,
+			   "channel context reservation cannot be finalized because some interfaces aren't switching\n");
+		err = -EBUSY;
+		goto err;
 	}
 
-	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf) {
-		ret = -EINVAL;
+	new_ctx = ieee80211_alloc_chanctx(local, chandef, ctx->mode);
+	if (!new_ctx) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		drv_unassign_vif_chanctx(local, sdata, ctx);
+		rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
+	}
+
+	list_del_rcu(&ctx->list);
+	ieee80211_del_chanctx(local, ctx);
+
+	err = ieee80211_add_chanctx(local, new_ctx);
+	if (err)
+		goto err_revert;
+
+	/* don't simply overwrite radar_required in case of failure */
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		bool tmp = sdata->radar_required;
+		sdata->radar_required = sdata->reserved_radar_required;
+		sdata->reserved_radar_required = tmp;
+	}
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		err = drv_assign_vif_chanctx(local, sdata, new_ctx);
+		if (err)
+			goto err_unassign;
+	}
+
+	if (sdata->vif.type == NL80211_IFTYPE_AP)
+		__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
+
+	list_add_rcu(&new_ctx->list, &local->chanctx_list);
+	kfree_rcu(ctx, rcu_head);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs,
+			    reserved_chanctx_list) {
+		changed = 0;
+		if (sdata->vif.bss_conf.chandef.width !=
+		    sdata->reserved_chandef.width)
+			changed = BSS_CHANGED_BANDWIDTH;
+
+		sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
+		if (changed)
+			ieee80211_bss_info_change_notify(sdata, changed);
+
+		ieee80211_recalc_txpower(sdata);
+	}
+
+	ieee80211_recalc_chanctx_chantype(local, new_ctx);
+	ieee80211_recalc_smps_chanctx(local, new_ctx);
+	ieee80211_recalc_radar_chanctx(local, new_ctx);
+	ieee80211_recalc_chanctx_min_def(local, new_ctx);
+
+	list_for_each_entry_safe(sdata, tmp, &ctx->reserved_vifs,
+				 reserved_chanctx_list) {
+		list_del(&sdata->reserved_chanctx_list);
+		list_move(&sdata->assigned_chanctx_list,
+			  &new_ctx->assigned_vifs);
+		sdata->reserved_chanctx = NULL;
+
+		ieee80211_vif_chanctx_reservation_complete(sdata);
+	}
+
+	return 0;
+
+err_unassign:
+	list_for_each_entry_continue_reverse(sdata, &ctx->reserved_vifs,
+					     reserved_chanctx_list)
+		drv_unassign_vif_chanctx(local, sdata, ctx);
+	ieee80211_del_chanctx(local, new_ctx);
+err_revert:
+	kfree_rcu(new_ctx, rcu_head);
+	WARN_ON(ieee80211_add_chanctx(local, ctx));
+	list_add_rcu(&ctx->list, &local->chanctx_list);
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		sdata->radar_required = sdata->reserved_radar_required;
+		rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
+		WARN_ON(drv_assign_vif_chanctx(local, sdata, ctx));
+	}
+err:
+	list_for_each_entry_safe(sdata, tmp, &ctx->reserved_vifs,
+				 reserved_chanctx_list) {
+		list_del(&sdata->reserved_chanctx_list);
+		sdata->reserved_chanctx = NULL;
+		ieee80211_vif_chanctx_reservation_complete(sdata);
+	}
+	return err;
+}
+
+static int
+ieee80211_vif_use_reserved_compat(struct ieee80211_sub_if_data *sdata,
+				  struct ieee80211_chanctx *old_ctx,
+				  struct ieee80211_chanctx *new_ctx)
+{
+	struct ieee80211_local *local = sdata->local;
+	u32 changed = 0;
+	int err;
+
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_del(&sdata->reserved_chanctx_list);
+	sdata->reserved_chanctx = NULL;
+
+	err = ieee80211_assign_vif_chanctx(sdata, new_ctx);
+	if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
+		ieee80211_free_chanctx(local, old_ctx);
+	if (err) {
+		/* if assign fails refcount stays the same */
+		if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
+			ieee80211_free_chanctx(local, new_ctx);
 		goto out;
 	}
 
-	old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
+	if (sdata->vif.type == NL80211_IFTYPE_AP)
+		__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
 
 	if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
-		tmp_changed |= BSS_CHANGED_BANDWIDTH;
+		changed = BSS_CHANGED_BANDWIDTH;
 
 	sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
 
-	/* unref our reservation */
-	sdata->reserved_chanctx = NULL;
-	sdata->radar_required = sdata->reserved_radar_required;
-	list_del(&sdata->reserved_chanctx_list);
+	if (changed)
+		ieee80211_bss_info_change_notify(sdata, changed);
 
-	if (old_ctx == ctx) {
-		/* This is our own context, just change it */
-		ret = __ieee80211_vif_change_channel(sdata, old_ctx,
-						     &tmp_changed);
-		if (ret)
-			goto out;
-	} else {
-		ret = ieee80211_assign_vif_chanctx(sdata, ctx);
-		if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
-			ieee80211_free_chanctx(local, old_ctx);
-		if (ret) {
-			/* if assign fails refcount stays the same */
-			if (ieee80211_chanctx_refcount(local, ctx) == 0)
-				ieee80211_free_chanctx(local, ctx);
-			goto out;
-		}
+out:
+	ieee80211_vif_chanctx_reservation_complete(sdata);
+	return err;
+}
 
-		if (sdata->vif.type == NL80211_IFTYPE_AP)
-			__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
-	}
+int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_chanctx *ctx;
+	struct ieee80211_chanctx *old_ctx;
+	struct ieee80211_chanctx_conf *conf;
+	const struct cfg80211_chan_def *chandef;
 
-	*changed = tmp_changed;
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	ieee80211_recalc_chanctx_chantype(local, ctx);
-	ieee80211_recalc_smps_chanctx(local, ctx);
-	ieee80211_recalc_radar_chanctx(local, ctx);
-	ieee80211_recalc_chanctx_min_def(local, ctx);
-out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
+	ctx = sdata->reserved_chanctx;
+	if (WARN_ON(!ctx))
+		return -EINVAL;
+
+	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+					 lockdep_is_held(&local->chanctx_mtx));
+	if (!conf)
+		return -EINVAL;
+
+	old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
+
+	if (WARN_ON(sdata->reserved_ready))
+		return -EINVAL;
+
+	chandef = ieee80211_chanctx_reserved_chandef(local, ctx, NULL);
+	if (WARN_ON(!chandef))
+		return -EINVAL;
+
+	sdata->reserved_ready = true;
+
+	if (cfg80211_chandef_compatible(&ctx->conf.def, chandef))
+		return ieee80211_vif_use_reserved_compat(sdata, old_ctx, ctx);
+	else
+		return ieee80211_vif_use_reserved_incompat(local, ctx, chandef);
 }
 
 int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3dffdb2..a941260 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -766,6 +766,7 @@ struct ieee80211_sub_if_data {
 	struct ieee80211_chanctx *reserved_chanctx;
 	struct cfg80211_chan_def reserved_chandef;
 	bool reserved_radar_required;
+	bool reserved_ready;
 
 	/* used to reconfigure hardware SM PS */
 	struct work_struct recalc_smps;
@@ -1794,8 +1795,7 @@ ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 			      enum ieee80211_chanctx_mode mode,
 			      bool radar_required);
 int __must_check
-ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
-				   u32 *changed);
+ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata);
 int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata);
 
 int __must_check
-- 
1.8.5.3


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

* [PATCH v3 0/5] cfg80211/mac80211: implement multi-vif csa
  2014-03-21 13:52 ` [PATCH v2 0/7] cfg80211/mac80211: implement multi-vif csa Michal Kazior
                     ` (6 preceding siblings ...)
  2014-03-21 13:52   ` [PATCH v2 7/7] cfg80211: remove channel_switch combination check Michal Kazior
@ 2014-03-31 12:04   ` Michal Kazior
  2014-03-31 12:04     ` [PATCH v3 1/5] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
                       ` (5 more replies)
  7 siblings, 6 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 12:04 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Hi,

This is another part of my recent RFC. This is
just the channel switching part.

This is based on my patchset implementing
multi-vif chanctx reservations.

This effectively enables multi-vif CSA for
STA/AP/IBSS/mesh.


v2:
 * add radar_detect fix patch (wasn't present in
   the big RFC)

v3:
 * remove radar_detect fix patch (it was
   cherry-picked)
 * squash removal of ieee80211_vif_change_channel() [Johannes]
 * cleanups [Johannes]
 * add resilience for calling ieee80211_csa_finish() and
   ieee80211_chswitch_done() more than once (the
   problem was originally discussed in `ath10k: dont call csa_finish
   more than once`)


Michal Kazior (5):
  mac80211: make check_combinations() aware of chanctx reservation
  mac80211: use chanctx reservation for AP CSA
  mac80211: use chanctx reservation for STA CSA
  mac80211: ignore cqm during csa
  cfg80211: remove channel_switch combination check

 net/mac80211/cfg.c         |  82 ++++++++++++++++++++++++------------
 net/mac80211/chan.c        |  79 ++++++----------------------------
 net/mac80211/ieee80211_i.h |   5 ---
 net/mac80211/mlme.c        | 103 ++++++++++++++++++++++++++++++---------------
 net/mac80211/util.c        |  39 ++++++++++++++++-
 net/wireless/nl80211.c     |  11 -----
 6 files changed, 176 insertions(+), 143 deletions(-)

-- 
1.8.5.3


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

* [PATCH v3 1/5] mac80211: make check_combinations() aware of chanctx reservation
  2014-03-31 12:04   ` [PATCH v3 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
@ 2014-03-31 12:04     ` Michal Kazior
  2014-03-31 12:04     ` [PATCH v3 2/5] mac80211: use chanctx reservation for AP CSA Michal Kazior
                       ` (4 subsequent siblings)
  5 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 12:04 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

The ieee80211_check_combinations() computes
radar_detect accordingly depending on chanctx
reservation status.

This makes it possible to use the function for
channel_switch validation.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v3:
 * fix typo in comment [Johannes]
 * fix comment style [Johannes]

 net/mac80211/util.c | 39 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 09c4794..e9dc90c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2802,6 +2802,42 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
 	ps->dtim_count = dtim_count;
 }
 
+static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local,
+					 struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_chanctx_conf *conf;
+	u8 radar_detect = 0;
+	bool in_place = false;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		if (sdata->reserved_radar_required)
+			radar_detect |= BIT(sdata->reserved_chandef.width);
+
+		conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+				lockdep_is_held(&local->chanctx_mtx));
+		if (conf == &ctx->conf)
+			in_place = true;
+	}
+
+	/*
+	 * if chanctx has in-place reservation then consider only the future
+	 * radar_detect. multi-vif reservation is deferred so ignore assigned
+	 * vifs. it is impossible for new vifs to be bound to an in-place
+	 * reserved chanctx so consistency is guaranteed
+	 */
+	if (in_place)
+		return radar_detect;
+
+	list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
+		if (sdata->radar_required)
+			radar_detect |= BIT(sdata->vif.bss_conf.chandef.width);
+
+	return radar_detect;
+}
+
 int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 				 const struct cfg80211_chan_def *chandef,
 				 enum ieee80211_chanctx_mode chanmode,
@@ -2843,8 +2879,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 		num[iftype] = 1;
 
 	list_for_each_entry(ctx, &local->chanctx_list, list) {
-		if (ctx->conf.radar_enabled)
-			radar_detect |= BIT(ctx->conf.def.width);
+		radar_detect |= ieee80211_chanctx_radar_detect(local, ctx);
 		if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
 			num_different_channels++;
 			continue;
-- 
1.8.5.3


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

* [PATCH v3 2/5] mac80211: use chanctx reservation for AP CSA
  2014-03-31 12:04   ` [PATCH v3 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
  2014-03-31 12:04     ` [PATCH v3 1/5] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
@ 2014-03-31 12:04     ` Michal Kazior
  2014-03-31 13:12       ` Michal Kazior
  2014-03-31 12:04     ` [PATCH v3 3/5] mac80211: use chanctx reservation for STA CSA Michal Kazior
                       ` (3 subsequent siblings)
  5 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 12:04 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Channel switch finalization is now 2-step. First
step is when driver calls csa_finish(), the other
is when reservation is actually finalized (which
be defered for in-place reservation).

Also remove the ieee80211_vif_change_channel()
which isn't used anymore.

It is now safe to call ieee80211_csa_finish() more
then once.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v3:
 * fix lockdep typo s/mtx/chanctx_mtx/ [Johannes]
 * fix comment style [Johannes]
 * use goto for cleaner unlocking/returning [Johannes]
 * squash with ieee80211_vif_change_channel() removal patch [Johannes]
 * fix commit message [Johannes]
 * add resilience for multiple ieee80211_csa_finish() calls

 net/mac80211/cfg.c         | 82 +++++++++++++++++++++++++++++++---------------
 net/mac80211/chan.c        | 75 ++++++------------------------------------
 net/mac80211/ieee80211_i.h |  5 ---
 3 files changed, 65 insertions(+), 97 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 871830e..be9e0c5 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3096,17 +3096,35 @@ static int ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
 
 	sdata_assert_lock(sdata);
 	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	sdata->radar_required = sdata->csa_radar_required;
-	err = ieee80211_vif_change_channel(sdata, &changed);
-	if (WARN_ON(err < 0))
-		return err;
+	/*
+	 * using reservation isn't immediate as it may be deferred until later
+	 * with multi-vif. once reservation is complete it will re-schedule the
+	 * work with no reserved_chanctx so verify chandef to check if it
+	 * completed successfully
+	 */
 
-	if (!local->use_chanctx) {
-		local->_oper_chandef = sdata->csa_chandef;
-		ieee80211_hw_config(local, 0);
+	if (sdata->reserved_chanctx) {
+		/*
+		 * with multi-vif csa driver may call ieee80211_csa_finish()
+		 * many times while waiting for other interfaces to use their
+		 * reservations
+		 */
+		if (sdata->reserved_ready)
+			return 0;
+
+		err = ieee80211_vif_use_reserved_context(sdata);
+		if (err)
+			return err;
+
+		return 0;
 	}
 
+	if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
+					&sdata->csa_chandef))
+		return -EINVAL;
+
 	sdata->vif.csa_active = false;
 
 	err = ieee80211_set_after_csa_beacon(sdata, &changed);
@@ -3134,6 +3152,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
 
 	sdata_lock(sdata);
 	mutex_lock(&local->mtx);
+	mutex_lock(&local->chanctx_mtx);
 
 	/* AP might have been stopped while waiting for the lock. */
 	if (!sdata->vif.csa_active)
@@ -3150,6 +3169,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
 	}
 
 unlock:
+	mutex_unlock(&local->chanctx_mtx);
 	mutex_unlock(&local->mtx);
 	sdata_unlock(sdata);
 }
@@ -3284,7 +3304,7 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *chanctx;
-	int err, num_chanctx, changed = 0;
+	int err, changed = 0;
 
 	sdata_assert_lock(sdata);
 	lockdep_assert_held(&local->mtx);
@@ -3299,37 +3319,43 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 				       &sdata->vif.bss_conf.chandef))
 		return -EINVAL;
 
+	/* don't allow another channel switch if one is already active. */
+	if (sdata->vif.csa_active)
+		return -EBUSY;
+
 	mutex_lock(&local->chanctx_mtx);
 	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 					 lockdep_is_held(&local->chanctx_mtx));
 	if (!conf) {
-		mutex_unlock(&local->chanctx_mtx);
-		return -EBUSY;
+		err = -EBUSY;
+		goto out;
 	}
 
-	/* don't handle for multi-VIF cases */
 	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
-	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
-		mutex_unlock(&local->chanctx_mtx);
-		return -EBUSY;
+	if (!chanctx) {
+		err = -EBUSY;
+		goto out;
 	}
-	num_chanctx = 0;
-	list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
-		num_chanctx++;
-	mutex_unlock(&local->chanctx_mtx);
 
-	if (num_chanctx > 1)
-		return -EBUSY;
+	err = ieee80211_vif_reserve_chanctx(sdata, &params->chandef,
+					    chanctx->mode,
+					    params->radar_required);
+	if (err)
+		goto out;
 
-	/* don't allow another channel switch if one is already active. */
-	if (sdata->vif.csa_active)
-		return -EBUSY;
+	/* if reservation is invalid then this will fail */
+	err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0);
+	if (err) {
+		ieee80211_vif_unreserve_chanctx(sdata);
+		goto out;
+	}
 
 	err = ieee80211_set_csa_beacon(sdata, params, &changed);
-	if (err)
-		return err;
+	if (err) {
+		ieee80211_vif_unreserve_chanctx(sdata);
+		goto out;
+	}
 
-	sdata->csa_radar_required = params->radar_required;
 	sdata->csa_chandef = params->chandef;
 	sdata->csa_block_tx = params->block_tx;
 	sdata->vif.csa_active = true;
@@ -3347,7 +3373,9 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 		ieee80211_csa_finalize(sdata);
 	}
 
-	return 0;
+out:
+	mutex_unlock(&local->chanctx_mtx);
+	return err;
 }
 
 int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 6870c3c..94e06c0 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -799,70 +799,6 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 	return ret;
 }
 
-static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-					  struct ieee80211_chanctx *ctx,
-					  u32 *changed)
-{
-	struct ieee80211_local *local = sdata->local;
-	const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;
-	u32 chanctx_changed = 0;
-
-	if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
-				     IEEE80211_CHAN_DISABLED))
-		return -EINVAL;
-
-	if (ieee80211_chanctx_refcount(local, ctx) != 1)
-		return -EINVAL;
-
-	if (sdata->vif.bss_conf.chandef.width != chandef->width) {
-		chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH;
-		*changed |= BSS_CHANGED_BANDWIDTH;
-	}
-
-	sdata->vif.bss_conf.chandef = *chandef;
-	ctx->conf.def = *chandef;
-
-	chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL;
-	drv_change_chanctx(local, ctx, chanctx_changed);
-
-	ieee80211_recalc_chanctx_chantype(local, ctx);
-	ieee80211_recalc_smps_chanctx(local, ctx);
-	ieee80211_recalc_radar_chanctx(local, ctx);
-	ieee80211_recalc_chanctx_min_def(local, ctx);
-
-	return 0;
-}
-
-int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-				 u32 *changed)
-{
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx_conf *conf;
-	struct ieee80211_chanctx *ctx;
-	int ret;
-
-	lockdep_assert_held(&local->mtx);
-
-	/* should never be called if not performing a channel switch. */
-	if (WARN_ON(!sdata->vif.csa_active))
-		return -EINVAL;
-
-	mutex_lock(&local->chanctx_mtx);
-	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	ctx = container_of(conf, struct ieee80211_chanctx, conf);
-
-	ret = __ieee80211_vif_change_channel(sdata, ctx, changed);
- out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
-}
-
 static void
 __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 				      bool clear)
@@ -964,7 +900,16 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 static void
 ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
 {
-	/* stub */
+	switch (sdata->vif.type) {
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MESH_POINT:
+		ieee80211_queue_work(&sdata->local->hw,
+				     &sdata->csa_finalize_work);
+		break;
+	default:
+		break;
+	}
 }
 
 static int
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a941260..40e0d0d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -755,7 +755,6 @@ struct ieee80211_sub_if_data {
 	struct work_struct csa_finalize_work;
 	int csa_counter_offset_beacon;
 	int csa_counter_offset_presp;
-	bool csa_radar_required;
 	bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
 	struct cfg80211_chan_def csa_chandef;
 
@@ -1802,10 +1801,6 @@ int __must_check
 ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
 			       const struct cfg80211_chan_def *chandef,
 			       u32 *changed);
-/* NOTE: only use ieee80211_vif_change_channel() for channel switch */
-int __must_check
-ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-			     u32 *changed);
 void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
-- 
1.8.5.3


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

* [PATCH v3 3/5] mac80211: use chanctx reservation for STA CSA
  2014-03-31 12:04   ` [PATCH v3 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
  2014-03-31 12:04     ` [PATCH v3 1/5] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
  2014-03-31 12:04     ` [PATCH v3 2/5] mac80211: use chanctx reservation for AP CSA Michal Kazior
@ 2014-03-31 12:04     ` Michal Kazior
  2014-03-31 12:04     ` [PATCH v3 4/5] mac80211: ignore cqm during csa Michal Kazior
                       ` (2 subsequent siblings)
  5 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 12:04 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Channel switch finalization is now 2-step. First
step is when driver calls chswitch_done(), the
other is when reservation is actually finalized
(which be defered for in-place reservation).

It is now safe to call ieee80211_chswitch_done()
more than once.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v3:
 * fix comment style [Johannes]
 * add resilience for multiple ieee80211_chswitch_done() calls

 net/mac80211/chan.c |  4 +++
 net/mac80211/mlme.c | 94 ++++++++++++++++++++++++++++++++++-------------------
 2 files changed, 65 insertions(+), 33 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 94e06c0..d69762f 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -907,6 +907,10 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
 		ieee80211_queue_work(&sdata->local->hw,
 				     &sdata->csa_finalize_work);
 		break;
+	case NL80211_IFTYPE_STATION:
+		ieee80211_queue_work(&sdata->local->hw,
+				     &sdata->u.mgd.chswitch_work);
+		break;
 	default:
 		break;
 	}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index b36e73f..07a4324 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -917,55 +917,75 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 		container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	u32 changed = 0;
 	int ret;
 
 	if (!ieee80211_sdata_running(sdata))
 		return;
 
 	sdata_lock(sdata);
+	mutex_lock(&local->mtx);
+	mutex_lock(&local->chanctx_mtx);
+
 	if (!ifmgd->associated)
 		goto out;
 
-	mutex_lock(&local->mtx);
-	ret = ieee80211_vif_change_channel(sdata, &changed);
-	mutex_unlock(&local->mtx);
-	if (ret) {
+	if (!sdata->vif.csa_active)
+		goto out;
+
+	/*
+	 * using reservation isn't immediate as it may be deferred until later
+	 * with multi-vif. once reservation is complete it will re-schedule the
+	 * work with no reserved_chanctx so verify chandef to check if it
+	 * completed successfully
+	 */
+
+	if (sdata->reserved_chanctx) {
+		/*
+		 * with multi-vif csa driver may call ieee80211_csa_finish()
+		 * many times while waiting for other interfaces to use their
+		 * reservations
+		 */
+		if (sdata->reserved_ready)
+			goto out;
+
+		ret = ieee80211_vif_use_reserved_context(sdata);
+		if (ret) {
+			sdata_info(sdata,
+				   "failed to use reserved channel context, disconnecting (err=%d)\n",
+				   ret);
+			ieee80211_queue_work(&sdata->local->hw,
+					     &ifmgd->csa_connection_drop_work);
+			goto out;
+		}
+
+		goto out;
+	}
+
+	if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
+					&sdata->csa_chandef)) {
 		sdata_info(sdata,
-			   "vif channel switch failed, disconnecting\n");
+			   "failed to finalize channel switch, disconnecting\n");
 		ieee80211_queue_work(&sdata->local->hw,
 				     &ifmgd->csa_connection_drop_work);
 		goto out;
 	}
 
-	if (!local->use_chanctx) {
-		local->_oper_chandef = sdata->csa_chandef;
-		/* Call "hw_config" only if doing sw channel switch.
-		 * Otherwise update the channel directly
-		 */
-		if (!local->ops->channel_switch)
-			ieee80211_hw_config(local, 0);
-		else
-			local->hw.conf.chandef = local->_oper_chandef;
-	}
-
 	/* XXX: shouldn't really modify cfg80211-owned data! */
 	ifmgd->associated->channel = sdata->csa_chandef.chan;
 
-	ieee80211_bss_info_change_notify(sdata, changed);
-
-	mutex_lock(&local->mtx);
 	sdata->vif.csa_active = false;
+
 	/* XXX: wait for a beacon first? */
 	if (!ieee80211_csa_needs_block_tx(local))
 		ieee80211_wake_queues_by_reason(&local->hw,
 					IEEE80211_MAX_QUEUE_MAP,
 					IEEE80211_QUEUE_STOP_REASON_CSA);
-	mutex_unlock(&local->mtx);
 
 	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
 
 out:
+	mutex_unlock(&local->chanctx_mtx);
+	mutex_unlock(&local->mtx);
 	sdata_unlock(sdata);
 }
 
@@ -1002,6 +1022,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct cfg80211_bss *cbss = ifmgd->associated;
+	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *chanctx;
 	enum ieee80211_band current_band;
 	struct ieee80211_csa_ie csa_ie;
@@ -1046,6 +1067,19 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
 
 	mutex_lock(&local->chanctx_mtx);
+	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+					 lockdep_is_held(&local->chanctx_mtx));
+	if (!conf) {
+		sdata_info(sdata,
+			   "no channel context assigned to vif?, disconnecting\n");
+		ieee80211_queue_work(&local->hw,
+				     &ifmgd->csa_connection_drop_work);
+		mutex_unlock(&local->chanctx_mtx);
+		return;
+	}
+
+	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
+
 	if (local->use_chanctx) {
 		u32 num_chanctx = 0;
 		list_for_each_entry(chanctx, &local->chanctx_list, list)
@@ -1062,17 +1096,12 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
-	if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) {
-		ieee80211_queue_work(&local->hw,
-				     &ifmgd->csa_connection_drop_work);
-		mutex_unlock(&local->chanctx_mtx);
-		return;
-	}
-	chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
-			       struct ieee80211_chanctx, conf);
-	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
+	res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef,
+					    chanctx->mode, false);
+	if (res) {
 		sdata_info(sdata,
-			   "channel switch with multiple interfaces on the same channel, disconnecting\n");
+			   "failed to reserve channel context for channel switch, disconnecting (err=%d)\n",
+			   res);
 		ieee80211_queue_work(&local->hw,
 				     &ifmgd->csa_connection_drop_work);
 		mutex_unlock(&local->chanctx_mtx);
@@ -1080,10 +1109,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	}
 	mutex_unlock(&local->chanctx_mtx);
 
-	sdata->csa_chandef = csa_ie.chandef;
-
 	mutex_lock(&local->mtx);
 	sdata->vif.csa_active = true;
+	sdata->csa_chandef = csa_ie.chandef;
 	sdata->csa_block_tx = csa_ie.mode;
 
 	if (sdata->csa_block_tx)
-- 
1.8.5.3


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

* [PATCH v3 4/5] mac80211: ignore cqm during csa
  2014-03-31 12:04   ` [PATCH v3 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
                       ` (2 preceding siblings ...)
  2014-03-31 12:04     ` [PATCH v3 3/5] mac80211: use chanctx reservation for STA CSA Michal Kazior
@ 2014-03-31 12:04     ` Michal Kazior
  2014-03-31 12:04     ` [PATCH v3 5/5] cfg80211: remove channel_switch combination check Michal Kazior
  2014-04-09 13:45     ` [PATCH v4 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
  5 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 12:04 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

It is not guaranteed that multi-vif channel
switching is tightly synchronized. It makes sense
to ignore cqm (missing beacons, et al) while csa
is progressing and re-check it after it completes.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/mlme.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 07a4324..ecf9681 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -983,6 +983,9 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 
 	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
 
+	ieee80211_sta_reset_beacon_monitor(sdata);
+	ieee80211_sta_reset_conn_monitor(sdata);
+
 out:
 	mutex_unlock(&local->chanctx_mtx);
 	mutex_unlock(&local->mtx);
@@ -3570,6 +3573,9 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
 	if (local->quiescing)
 		return;
 
+	if (sdata->vif.csa_active)
+		return;
+
 	sdata->u.mgd.connection_loss = false;
 	ieee80211_queue_work(&sdata->local->hw,
 			     &sdata->u.mgd.beacon_connection_loss_work);
@@ -3585,6 +3591,9 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data)
 	if (local->quiescing)
 		return;
 
+	if (sdata->vif.csa_active)
+		return;
+
 	ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
 }
 
-- 
1.8.5.3


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

* [PATCH v3 5/5] cfg80211: remove channel_switch combination check
  2014-03-31 12:04   ` [PATCH v3 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
                       ` (3 preceding siblings ...)
  2014-03-31 12:04     ` [PATCH v3 4/5] mac80211: ignore cqm during csa Michal Kazior
@ 2014-03-31 12:04     ` Michal Kazior
  2014-04-09 13:45     ` [PATCH v4 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
  5 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 12:04 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Michal Kazior

Make the driver responsible for making sure it is
capable of performing the switch. It might as well
accept a request but then disconnect an interface
if some requirements are not met.

In that case userspace should be prepared for an
appropriate event (AP/IBSS/mesh being stopped/left).

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/wireless/nl80211.c | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 232d15c..84aeb80 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5932,17 +5932,6 @@ skip_beacons:
 		params.radar_required = true;
 	}
 
-	/* TODO: I left this here for now.  With channel switch, the
-	 * verification is a bit more complicated, because we only do
-	 * it later when the channel switch really happens.
-	 */
-	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-					   params.chandef.chan,
-					   CHAN_MODE_SHARED,
-					   radar_detect_width);
-	if (err)
-		return err;
-
 	if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
 		params.block_tx = true;
 
-- 
1.8.5.3


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

* Re: [PATCH v3 2/5] mac80211: use chanctx reservation for AP CSA
  2014-03-31 12:04     ` [PATCH v3 2/5] mac80211: use chanctx reservation for AP CSA Michal Kazior
@ 2014-03-31 13:12       ` Michal Kazior
  0 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-03-31 13:12 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, Michal Kazior

On 31 March 2014 14:04, Michal Kazior <michal.kazior@tieto.com> wrote:
> Channel switch finalization is now 2-step. First
> step is when driver calls csa_finish(), the other
> is when reservation is actually finalized (which
> be defered for in-place reservation).
>
> Also remove the ieee80211_vif_change_channel()
> which isn't used anymore.
>
> It is now safe to call ieee80211_csa_finish() more
> then once.
>
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
> ---
> v3:
>  * fix lockdep typo s/mtx/chanctx_mtx/ [Johannes]
>  * fix comment style [Johannes]
>  * use goto for cleaner unlocking/returning [Johannes]
>  * squash with ieee80211_vif_change_channel() removal patch [Johannes]

Eww, I hastily squashed it too early. It should have been squashed it
onto the following STA CSA patch instead of this one. I'll wait a bit
for more comments before I respin.


Michał

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

* Re: [PATCH v3 13/13] mac80211: implement multi-vif in-place reservations
  2014-03-31 10:39     ` [PATCH v3 13/13] mac80211: implement multi-vif in-place reservations Michal Kazior
@ 2014-03-31 16:15       ` Eliad Peller
  2014-04-01  5:10         ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Eliad Peller @ 2014-03-31 16:15 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg

hi Michal,

On Mon, Mar 31, 2014 at 1:39 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
> Multi-vif in-place reservations happen when
> it's impossible to allocate more chanctx as per
> driver combinations.
>
> Such reservations aren't finalized until last
> reservation interface calls in to use the
> reservation.
>
> This introduces a special hook
> ieee80211_vif_chanctx_reservation_complete(). This
> is currently an empty stub and will be filled in
> by AP/STA CSA code. This is required to implement
> 2-step CSA finalization.
>
> This also gets rid of driver requirement to be
> able to re-program channel of a chanctx.
>
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
> ---
>
[...]

> -       /* TODO: need to recheck if the chandef is usable etc.? */
> +static int
> +ieee80211_vif_use_reserved_incompat(struct ieee80211_local *local,
> +                                   struct ieee80211_chanctx *ctx,
> +                                   const struct cfg80211_chan_def *chandef)
> +{
[...]

> +       new_ctx = ieee80211_alloc_chanctx(local, chandef, ctx->mode);
> +       if (!new_ctx) {
> +               err = -ENOMEM;
> +               goto err;
> +       }
> +
> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
> +               drv_unassign_vif_chanctx(local, sdata, ctx);
> +               rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
> +       }
> +
> +       list_del_rcu(&ctx->list);
> +       ieee80211_del_chanctx(local, ctx);
> +
> +       err = ieee80211_add_chanctx(local, new_ctx);
> +       if (err)
> +               goto err_revert;
> +
> +       /* don't simply overwrite radar_required in case of failure */
> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
> +               bool tmp = sdata->radar_required;
> +               sdata->radar_required = sdata->reserved_radar_required;
> +               sdata->reserved_radar_required = tmp;
> +       }
> +
> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
> +               err = drv_assign_vif_chanctx(local, sdata, new_ctx);
> +               if (err)
> +                       goto err_unassign;
> +       }
> +
better recalc radar before assigning the chanctx. otherwise, you end
up with radar_enabled configuration for non-radar channels -
ieee80211_alloc_chanctx sets radar_enabled if any
sdata->radar_required is true (which is true before the channel
switch).

[...]

> +
> +err_unassign:
> +       list_for_each_entry_continue_reverse(sdata, &ctx->reserved_vifs,
> +                                            reserved_chanctx_list)
> +               drv_unassign_vif_chanctx(local, sdata, ctx);
> +       ieee80211_del_chanctx(local, new_ctx);
> +err_revert:
> +       kfree_rcu(new_ctx, rcu_head);
> +       WARN_ON(ieee80211_add_chanctx(local, ctx));
> +       list_add_rcu(&ctx->list, &local->chanctx_list);
> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
> +               sdata->radar_required = sdata->reserved_radar_required;
> +               rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
> +               WARN_ON(drv_assign_vif_chanctx(local, sdata, ctx));
> +       }
seems like the list_for_each_entry should actually be under err_unassign?

Eliad.

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

* Re: [PATCH v3 13/13] mac80211: implement multi-vif in-place reservations
  2014-03-31 16:15       ` Eliad Peller
@ 2014-04-01  5:10         ` Michal Kazior
  2014-04-01  7:46           ` Eliad Peller
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-04-01  5:10 UTC (permalink / raw)
  To: Eliad Peller; +Cc: linux-wireless, Johannes Berg

On 31 March 2014 18:15, Eliad Peller <eliad@wizery.com> wrote:
> hi Michal,
>
> On Mon, Mar 31, 2014 at 1:39 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
>> Multi-vif in-place reservations happen when
>> it's impossible to allocate more chanctx as per
>> driver combinations.
>>
>> Such reservations aren't finalized until last
>> reservation interface calls in to use the
>> reservation.
>>
>> This introduces a special hook
>> ieee80211_vif_chanctx_reservation_complete(). This
>> is currently an empty stub and will be filled in
>> by AP/STA CSA code. This is required to implement
>> 2-step CSA finalization.
>>
>> This also gets rid of driver requirement to be
>> able to re-program channel of a chanctx.
>>
>> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
>> ---
>>
> [...]
>
>> -       /* TODO: need to recheck if the chandef is usable etc.? */
>> +static int
>> +ieee80211_vif_use_reserved_incompat(struct ieee80211_local *local,
>> +                                   struct ieee80211_chanctx *ctx,
>> +                                   const struct cfg80211_chan_def *chandef)
>> +{
> [...]
>
>> +       new_ctx = ieee80211_alloc_chanctx(local, chandef, ctx->mode);
>> +       if (!new_ctx) {
>> +               err = -ENOMEM;
>> +               goto err;
>> +       }
>> +
>> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>> +               drv_unassign_vif_chanctx(local, sdata, ctx);
>> +               rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
>> +       }
>> +
>> +       list_del_rcu(&ctx->list);
>> +       ieee80211_del_chanctx(local, ctx);
>> +
>> +       err = ieee80211_add_chanctx(local, new_ctx);
>> +       if (err)
>> +               goto err_revert;
>> +
>> +       /* don't simply overwrite radar_required in case of failure */
>> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>> +               bool tmp = sdata->radar_required;
>> +               sdata->radar_required = sdata->reserved_radar_required;
>> +               sdata->reserved_radar_required = tmp;
>> +       }
>> +
>> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>> +               err = drv_assign_vif_chanctx(local, sdata, new_ctx);
>> +               if (err)
>> +                       goto err_unassign;
>> +       }
>> +
> better recalc radar before assigning the chanctx. otherwise, you end
> up with radar_enabled configuration for non-radar channels -
> ieee80211_alloc_chanctx sets radar_enabled if any
> sdata->radar_required is true (which is true before the channel
> switch).

Good point, thanks!


>
> [...]
>
>> +
>> +err_unassign:
>> +       list_for_each_entry_continue_reverse(sdata, &ctx->reserved_vifs,
>> +                                            reserved_chanctx_list)
>> +               drv_unassign_vif_chanctx(local, sdata, ctx);
>> +       ieee80211_del_chanctx(local, new_ctx);
>> +err_revert:
>> +       kfree_rcu(new_ctx, rcu_head);
>> +       WARN_ON(ieee80211_add_chanctx(local, ctx));
>> +       list_add_rcu(&ctx->list, &local->chanctx_list);
>> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>> +               sdata->radar_required = sdata->reserved_radar_required;
>> +               rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
>> +               WARN_ON(drv_assign_vif_chanctx(local, sdata, ctx));
>> +       }
> seems like the list_for_each_entry should actually be under err_unassign?

No. This is correct. The err_unassign is used to bail out if any
drv_assign_vif_chanctx fails mid-way. We want to unassign only those
vif-chanctx we only managed to assign.


Michał

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

* Re: [PATCH v3 13/13] mac80211: implement multi-vif in-place reservations
  2014-04-01  5:10         ` Michal Kazior
@ 2014-04-01  7:46           ` Eliad Peller
  2014-04-01  7:54             ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Eliad Peller @ 2014-04-01  7:46 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg

On Tue, Apr 1, 2014 at 8:10 AM, Michal Kazior <michal.kazior@tieto.com> wrote:
> On 31 March 2014 18:15, Eliad Peller <eliad@wizery.com> wrote:
>> hi Michal,
>>
>> On Mon, Mar 31, 2014 at 1:39 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
>>> Multi-vif in-place reservations happen when
>>> it's impossible to allocate more chanctx as per
>>> driver combinations.
>>>
>>> Such reservations aren't finalized until last
>>> reservation interface calls in to use the
>>> reservation.
>>>
>>> This introduces a special hook
>>> ieee80211_vif_chanctx_reservation_complete(). This
>>> is currently an empty stub and will be filled in
>>> by AP/STA CSA code. This is required to implement
>>> 2-step CSA finalization.
>>>
>>> This also gets rid of driver requirement to be
>>> able to re-program channel of a chanctx.
>>>
>>> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
>>> ---
>>>
>> [...]
>>
>>> -       /* TODO: need to recheck if the chandef is usable etc.? */
>>> +static int
>>> +ieee80211_vif_use_reserved_incompat(struct ieee80211_local *local,
>>> +                                   struct ieee80211_chanctx *ctx,
>>> +                                   const struct cfg80211_chan_def *chandef)
>>> +{
>> [...]
>>
>>> +       new_ctx = ieee80211_alloc_chanctx(local, chandef, ctx->mode);
>>> +       if (!new_ctx) {
>>> +               err = -ENOMEM;
>>> +               goto err;
>>> +       }
>>> +
>>> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>>> +               drv_unassign_vif_chanctx(local, sdata, ctx);
>>> +               rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
>>> +       }
>>> +
>>> +       list_del_rcu(&ctx->list);
>>> +       ieee80211_del_chanctx(local, ctx);
>>> +
>>> +       err = ieee80211_add_chanctx(local, new_ctx);
>>> +       if (err)
>>> +               goto err_revert;
>>> +
>>> +       /* don't simply overwrite radar_required in case of failure */
>>> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>>> +               bool tmp = sdata->radar_required;
>>> +               sdata->radar_required = sdata->reserved_radar_required;
>>> +               sdata->reserved_radar_required = tmp;
>>> +       }
>>> +
>>> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>>> +               err = drv_assign_vif_chanctx(local, sdata, new_ctx);
>>> +               if (err)
>>> +                       goto err_unassign;
>>> +       }
>>> +
>> better recalc radar before assigning the chanctx. otherwise, you end
>> up with radar_enabled configuration for non-radar channels -
>> ieee80211_alloc_chanctx sets radar_enabled if any
>> sdata->radar_required is true (which is true before the channel
>> switch).
>
> Good point, thanks!
>
>
>>
>> [...]
>>
>>> +
>>> +err_unassign:
>>> +       list_for_each_entry_continue_reverse(sdata, &ctx->reserved_vifs,
>>> +                                            reserved_chanctx_list)
>>> +               drv_unassign_vif_chanctx(local, sdata, ctx);
>>> +       ieee80211_del_chanctx(local, new_ctx);
>>> +err_revert:
>>> +       kfree_rcu(new_ctx, rcu_head);
>>> +       WARN_ON(ieee80211_add_chanctx(local, ctx));
>>> +       list_add_rcu(&ctx->list, &local->chanctx_list);
>>> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>>> +               sdata->radar_required = sdata->reserved_radar_required;
>>> +               rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
>>> +               WARN_ON(drv_assign_vif_chanctx(local, sdata, ctx));
>>> +       }
>> seems like the list_for_each_entry should actually be under err_unassign?
>
> No. This is correct. The err_unassign is used to bail out if any
> drv_assign_vif_chanctx fails mid-way. We want to unassign only those
> vif-chanctx we only managed to assign.
>
sure. i failed to explain - i'm referring only to the radar_required
swapping - it seems to happen only later.

Eliad.

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

* Re: [PATCH v3 13/13] mac80211: implement multi-vif in-place reservations
  2014-04-01  7:46           ` Eliad Peller
@ 2014-04-01  7:54             ` Michal Kazior
  2014-04-01  8:10               ` Eliad Peller
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-04-01  7:54 UTC (permalink / raw)
  To: Eliad Peller; +Cc: linux-wireless, Johannes Berg

On 1 April 2014 09:46, Eliad Peller <eliad@wizery.com> wrote:
> On Tue, Apr 1, 2014 at 8:10 AM, Michal Kazior <michal.kazior@tieto.com> wrote:
>> On 31 March 2014 18:15, Eliad Peller <eliad@wizery.com> wrote:
>>> On Mon, Mar 31, 2014 at 1:39 PM, Michal Kazior <michal.kazior@tieto.com> wrote:

[...]

>>>> +err_unassign:
>>>> +       list_for_each_entry_continue_reverse(sdata, &ctx->reserved_vifs,
>>>> +                                            reserved_chanctx_list)
>>>> +               drv_unassign_vif_chanctx(local, sdata, ctx);
>>>> +       ieee80211_del_chanctx(local, new_ctx);
>>>> +err_revert:
>>>> +       kfree_rcu(new_ctx, rcu_head);
>>>> +       WARN_ON(ieee80211_add_chanctx(local, ctx));
>>>> +       list_add_rcu(&ctx->list, &local->chanctx_list);
>>>> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>>>> +               sdata->radar_required = sdata->reserved_radar_required;
>>>> +               rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
>>>> +               WARN_ON(drv_assign_vif_chanctx(local, sdata, ctx));
>>>> +       }
>>> seems like the list_for_each_entry should actually be under err_unassign?
>>
>> No. This is correct. The err_unassign is used to bail out if any
>> drv_assign_vif_chanctx fails mid-way. We want to unassign only those
>> vif-chanctx we only managed to assign.
>>
> sure. i failed to explain - i'm referring only to the radar_required
> swapping - it seems to happen only later.

You mean to split the list_for_each_entry from err_revert into 2
parts: one that reverts the radar_required swapping and the other one
re-assigning vif-chanctx? I'm not really sure if that's necessary? The
`ctx` (old chanctx) should still be configured as it was wrt radar
detection. Or is there something that I'm missing?


Michał

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

* Re: [PATCH v3 13/13] mac80211: implement multi-vif in-place reservations
  2014-04-01  7:54             ` Michal Kazior
@ 2014-04-01  8:10               ` Eliad Peller
  2014-04-01  8:26                 ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Eliad Peller @ 2014-04-01  8:10 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg

On Tue, Apr 1, 2014 at 10:54 AM, Michal Kazior <michal.kazior@tieto.com> wrote:
> On 1 April 2014 09:46, Eliad Peller <eliad@wizery.com> wrote:
>> On Tue, Apr 1, 2014 at 8:10 AM, Michal Kazior <michal.kazior@tieto.com> wrote:
>>> On 31 March 2014 18:15, Eliad Peller <eliad@wizery.com> wrote:
>>>> On Mon, Mar 31, 2014 at 1:39 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
>
> [...]
>
>>>>> +err_unassign:
>>>>> +       list_for_each_entry_continue_reverse(sdata, &ctx->reserved_vifs,
>>>>> +                                            reserved_chanctx_list)
>>>>> +               drv_unassign_vif_chanctx(local, sdata, ctx);
>>>>> +       ieee80211_del_chanctx(local, new_ctx);
>>>>> +err_revert:
>>>>> +       kfree_rcu(new_ctx, rcu_head);
>>>>> +       WARN_ON(ieee80211_add_chanctx(local, ctx));
>>>>> +       list_add_rcu(&ctx->list, &local->chanctx_list);
>>>>> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>>>>> +               sdata->radar_required = sdata->reserved_radar_required;
>>>>> +               rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
>>>>> +               WARN_ON(drv_assign_vif_chanctx(local, sdata, ctx));
>>>>> +       }
>>>> seems like the list_for_each_entry should actually be under err_unassign?
>>>
>>> No. This is correct. The err_unassign is used to bail out if any
>>> drv_assign_vif_chanctx fails mid-way. We want to unassign only those
>>> vif-chanctx we only managed to assign.
>>>
>> sure. i failed to explain - i'm referring only to the radar_required
>> swapping - it seems to happen only later.
>
> You mean to split the list_for_each_entry from err_revert into 2
> parts: one that reverts the radar_required swapping and the other one
> re-assigning vif-chanctx? I'm not really sure if that's necessary? The
> `ctx` (old chanctx) should still be configured as it was wrt radar
> detection. Or is there something that I'm missing?
>
ctx is correct, but sdata->radar_required doesn't seem to derive its
value from it.
i mean that you should either split the list_for_each_entry as you
suggested, or move the radar_enabled swapping loop before the
ieee80211_add_chanctx() call.

Eliad.

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

* Re: [PATCH v3 13/13] mac80211: implement multi-vif in-place reservations
  2014-04-01  8:10               ` Eliad Peller
@ 2014-04-01  8:26                 ` Michal Kazior
  0 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-01  8:26 UTC (permalink / raw)
  To: Eliad Peller; +Cc: linux-wireless, Johannes Berg

On 1 April 2014 10:10, Eliad Peller <eliad@wizery.com> wrote:
> On Tue, Apr 1, 2014 at 10:54 AM, Michal Kazior <michal.kazior@tieto.com> wrote:
>> On 1 April 2014 09:46, Eliad Peller <eliad@wizery.com> wrote:
>>> On Tue, Apr 1, 2014 at 8:10 AM, Michal Kazior <michal.kazior@tieto.com> wrote:
>>>> On 31 March 2014 18:15, Eliad Peller <eliad@wizery.com> wrote:
>>>>> On Mon, Mar 31, 2014 at 1:39 PM, Michal Kazior <michal.kazior@tieto.com> wrote:
>>
>> [...]
>>
>>>>>> +err_unassign:
>>>>>> +       list_for_each_entry_continue_reverse(sdata, &ctx->reserved_vifs,
>>>>>> +                                            reserved_chanctx_list)
>>>>>> +               drv_unassign_vif_chanctx(local, sdata, ctx);
>>>>>> +       ieee80211_del_chanctx(local, new_ctx);
>>>>>> +err_revert:
>>>>>> +       kfree_rcu(new_ctx, rcu_head);
>>>>>> +       WARN_ON(ieee80211_add_chanctx(local, ctx));
>>>>>> +       list_add_rcu(&ctx->list, &local->chanctx_list);
>>>>>> +       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>>>>>> +               sdata->radar_required = sdata->reserved_radar_required;
>>>>>> +               rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
>>>>>> +               WARN_ON(drv_assign_vif_chanctx(local, sdata, ctx));
>>>>>> +       }
>>>>> seems like the list_for_each_entry should actually be under err_unassign?
>>>>
>>>> No. This is correct. The err_unassign is used to bail out if any
>>>> drv_assign_vif_chanctx fails mid-way. We want to unassign only those
>>>> vif-chanctx we only managed to assign.
>>>>
>>> sure. i failed to explain - i'm referring only to the radar_required
>>> swapping - it seems to happen only later.
>>
>> You mean to split the list_for_each_entry from err_revert into 2
>> parts: one that reverts the radar_required swapping and the other one
>> re-assigning vif-chanctx? I'm not really sure if that's necessary? The
>> `ctx` (old chanctx) should still be configured as it was wrt radar
>> detection. Or is there something that I'm missing?
>>
> ctx is correct, but sdata->radar_required doesn't seem to derive its
> value from it.
> i mean that you should either split the list_for_each_entry as you
> suggested, or move the radar_enabled swapping loop before the
> ieee80211_add_chanctx() call.

Yeah. I'll do that. It seems like a good idea regardless if this makes
no difference with current codebase.


Michał

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

* Re: [PATCH v3 02/13] mac80211: add max channel calculation utility function
  2014-03-31 10:39     ` [PATCH v3 02/13] mac80211: add max channel calculation utility function Michal Kazior
@ 2014-04-08 13:23       ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-04-08 13:23 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Mon, 2014-03-31 at 12:39 +0200, Michal Kazior wrote:

> +	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
> +		num[sdata->wdev.iftype]++;
> +	}

Don't really need the braces, I guess.

johannes


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

* Re: [PATCH v3 04/13] mac80211: add support for radar detection for reservations
  2014-03-31 10:39     ` [PATCH v3 04/13] mac80211: add support for radar detection for reservations Michal Kazior
@ 2014-04-08 13:25       ` Johannes Berg
  2014-04-09  7:05         ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-04-08 13:25 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Mon, 2014-03-31 at 12:39 +0200, Michal Kazior wrote:
> Initial chanctx reservation code wasn't aware of
> radar detection requirements. This is necessary
> for chanctx reservations to be used for channel
> switching in the future.

>  int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
>  				  const struct cfg80211_chan_def *chandef,
> -				  enum ieee80211_chanctx_mode mode)
> +				  enum ieee80211_chanctx_mode mode,
> +				  bool radar_required)

Does this not have any callers?

johannes


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

* Re: [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                       ` (12 preceding siblings ...)
  2014-03-31 10:39     ` [PATCH v3 13/13] mac80211: implement multi-vif in-place reservations Michal Kazior
@ 2014-04-08 13:30     ` Johannes Berg
  2014-04-08 14:00       ` Luca Coelho
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
  14 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-04-08 13:30 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Mon, 2014-03-31 at 12:39 +0200, Michal Kazior wrote:
> Hi,
> 
> This is part of my multi-vif csa work. These
> patches have been included in my recent big RFC.
> I'm trying to split it up a bit.
> 
> The patchset incrementally improves chanctx
> reservations in order to support multi-vif
> reservations and in-place multi-vif reservations
> (typically for single-channel hardware, but
> multi-channel benefits from this too).
> 
> Some of the patches (the refcounting) were also
> posted a while ago as a separate small RFC.
> 
> This is rebased on mac80211-next/master and my
> CSA fixes/cleanups now.

I guess this looks fine ... Is Luca planning to pick it up first?

johannes


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

* Re: [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations
  2014-04-08 13:30     ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Johannes Berg
@ 2014-04-08 14:00       ` Luca Coelho
  2014-04-09  7:07         ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Luca Coelho @ 2014-04-08 14:00 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Michal Kazior, linux-wireless

On Tue, 2014-04-08 at 15:30 +0200, Johannes Berg wrote:
> On Mon, 2014-03-31 at 12:39 +0200, Michal Kazior wrote:
> > Hi,
> > 
> > This is part of my multi-vif csa work. These
> > patches have been included in my recent big RFC.
> > I'm trying to split it up a bit.
> > 
> > The patchset incrementally improves chanctx
> > reservations in order to support multi-vif
> > reservations and in-place multi-vif reservations
> > (typically for single-channel hardware, but
> > multi-channel benefits from this too).
> > 
> > Some of the patches (the refcounting) were also
> > posted a while ago as a separate small RFC.
> > 
> > This is rebased on mac80211-next/master and my
> > CSA fixes/cleanups now.
> 
> I guess this looks fine ... Is Luca planning to pick it up first?

I can do that, whichever you prefer.

But Michal is going to resend with some comments by Eliad addressed,
right?

--
Luca.


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

* Re: [PATCH v3 04/13] mac80211: add support for radar detection for reservations
  2014-04-08 13:25       ` Johannes Berg
@ 2014-04-09  7:05         ` Michal Kazior
  0 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09  7:05 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless

On 8 April 2014 15:25, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Mon, 2014-03-31 at 12:39 +0200, Michal Kazior wrote:
>> Initial chanctx reservation code wasn't aware of
>> radar detection requirements. This is necessary
>> for chanctx reservations to be used for channel
>> switching in the future.
>
>>  int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
>>                                 const struct cfg80211_chan_def *chandef,
>> -                               enum ieee80211_chanctx_mode mode)
>> +                               enum ieee80211_chanctx_mode mode,
>> +                               bool radar_required)
>
> Does this not have any callers?

Not yet.


Michał

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

* Re: [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations
  2014-04-08 14:00       ` Luca Coelho
@ 2014-04-09  7:07         ` Michal Kazior
  0 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09  7:07 UTC (permalink / raw)
  To: Luca Coelho; +Cc: Johannes Berg, linux-wireless

On 8 April 2014 16:00, Luca Coelho <luca@coelho.fi> wrote:
> On Tue, 2014-04-08 at 15:30 +0200, Johannes Berg wrote:
>> On Mon, 2014-03-31 at 12:39 +0200, Michal Kazior wrote:
>> > Hi,
>> >
>> > This is part of my multi-vif csa work. These
>> > patches have been included in my recent big RFC.
>> > I'm trying to split it up a bit.
>> >
>> > The patchset incrementally improves chanctx
>> > reservations in order to support multi-vif
>> > reservations and in-place multi-vif reservations
>> > (typically for single-channel hardware, but
>> > multi-channel benefits from this too).
>> >
>> > Some of the patches (the refcounting) were also
>> > posted a while ago as a separate small RFC.
>> >
>> > This is rebased on mac80211-next/master and my
>> > CSA fixes/cleanups now.
>>
>> I guess this looks fine ... Is Luca planning to pick it up first?
>
> I can do that, whichever you prefer.
>
> But Michal is going to resend with some comments by Eliad addressed,
> right?

Yes. I'm planning to re-spin today.


Michał

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

* [PATCH v4 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations
  2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
                       ` (13 preceding siblings ...)
  2014-04-08 13:30     ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Johannes Berg
@ 2014-04-09 13:29     ` Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 01/13] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
                         ` (13 more replies)
  14 siblings, 14 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

Hi,

This is part of my multi-vif csa work. These
patches have been included in my recent big RFC.
I'm trying to split it up a bit.

The patchset incrementally improves chanctx
reservations in order to support multi-vif
reservations and in-place multi-vif reservations
(typically for single-channel hardware, but
multi-channel benefits from this too).

Some of the patches (the refcounting) were also
posted a while ago as a separate small RFC.

This is rebased on mac80211-next/master (the one
rebased today) and my CSA fixes/cleanups now.

v2:
 * add changelog for refcounting patches
 * fixes for issues pointed out by Eliad

v3:
 * fix commit messages

v4:
 * remove unnecessary braces
 * fixes to the in-place reservation code ordering


Michal Kazior (13):
  cfg80211: allow drivers to iterate over matching combinations
  mac80211: add max channel calculation utility function
  mac80211: prevent chanctx overcommit
  mac80211: add support for radar detection for reservations
  mac80211: track assigned vifs in chanctx
  mac80211: track reserved vifs in chanctx
  mac80211: improve find_chanctx() for reservations
  mac80211: improve chanctx reservation lookup
  mac80211: split ieee80211_new_chanctx()
  mac80211: split ieee80211_free_chanctx()
  mac80211: fix racy usage of chanctx->refcount
  mac80211: compute chanctx refcount on-the-fly
  mac80211: implement multi-vif in-place reservations

 include/net/cfg80211.h     |  27 ++
 include/net/mac80211.h     |   7 -
 net/mac80211/cfg.c         |  19 +-
 net/mac80211/chan.c        | 598 ++++++++++++++++++++++++++++++++++-----------
 net/mac80211/ieee80211_i.h |  18 +-
 net/mac80211/iface.c       |   2 +
 net/mac80211/mlme.c        |   2 +-
 net/mac80211/util.c        |  42 ++++
 net/wireless/util.c        |  44 +++-
 9 files changed, 592 insertions(+), 167 deletions(-)

-- 
1.8.5.3


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

* [PATCH v4 01/13] cfg80211: allow drivers to iterate over matching combinations
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
@ 2014-04-09 13:29       ` Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 02/13] mac80211: add max channel calculation utility function Michal Kazior
                         ` (12 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

The patch splits cfg80211_check_combinations()
into an iterator function and a simple iteration
user.

This makes it possible for drivers to asses how
many channels can use given iftype setup. This in
turn can be used for future
multi-interface/multi-channel channel switching.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 include/net/cfg80211.h | 27 +++++++++++++++++++++++++++
 net/wireless/util.c    | 44 +++++++++++++++++++++++++++++++++++++-------
 2 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 6deebc8..0a44a14 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4730,6 +4730,33 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
 void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev,
 			 gfp_t gfp);
 
+/**
+ * cfg80211_iter_combinations - iterate over matching combinations
+ *
+ * @wiphy: the wiphy
+ * @num_different_channels: the number of different channels we want
+ *	to use for verification
+ * @radar_detect: a bitmap where each bit corresponds to a channel
+ *	width where radar detection is needed, as in the definition of
+ *	&struct ieee80211_iface_combination.@radar_detect_widths
+ * @iftype_num: array with the numbers of interfaces of each interface
+ *	type.  The index is the interface type as specified in &enum
+ *	nl80211_iftype.
+ * @iter: function to call for each matching combination
+ * @data: pointer to pass to iter function
+ *
+ * This function can be called by the driver to check what possible
+ * combinations it fits in at a given moment, e.g. for channel switching
+ * purposes.
+ */
+int cfg80211_iter_combinations(struct wiphy *wiphy,
+			       const int num_different_channels,
+			       const u8 radar_detect,
+			       const int iftype_num[NUM_NL80211_IFTYPES],
+			       void (*iter)(const struct ieee80211_iface_combination *c,
+					    void *data),
+			       void *data);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/wireless/util.c b/net/wireless/util.c
index ea4e28d..dbacb4a 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1266,10 +1266,13 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
 	return res;
 }
 
-int cfg80211_check_combinations(struct wiphy *wiphy,
-				const int num_different_channels,
-				const u8 radar_detect,
-				const int iftype_num[NUM_NL80211_IFTYPES])
+int cfg80211_iter_combinations(struct wiphy *wiphy,
+			       const int num_different_channels,
+			       const u8 radar_detect,
+			       const int iftype_num[NUM_NL80211_IFTYPES],
+			       void (*iter)(const struct ieee80211_iface_combination *c,
+					    void *data),
+			       void *data)
 {
 	int i, j, iftype;
 	int num_interfaces = 0;
@@ -1326,13 +1329,40 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
 		/* This combination covered all interface types and
 		 * supported the requested numbers, so we're good.
 		 */
-		kfree(limits);
-		return 0;
+
+		(*iter)(c, data);
  cont:
 		kfree(limits);
 	}
 
-	return -EBUSY;
+	return 0;
+}
+EXPORT_SYMBOL(cfg80211_iter_combinations);
+
+static void
+cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
+			  void *data)
+{
+	int *num = data;
+	(*num)++;
+}
+
+int cfg80211_check_combinations(struct wiphy *wiphy,
+				const int num_different_channels,
+				const u8 radar_detect,
+				const int iftype_num[NUM_NL80211_IFTYPES])
+{
+	int err, num = 0;
+
+	err = cfg80211_iter_combinations(wiphy, num_different_channels,
+					 radar_detect, iftype_num,
+					 cfg80211_iter_sum_ifcombs, &num);
+	if (err)
+		return err;
+	if (num == 0)
+		return -EBUSY;
+
+	return 0;
 }
 EXPORT_SYMBOL(cfg80211_check_combinations);
 
-- 
1.8.5.3


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

* [PATCH v4 02/13] mac80211: add max channel calculation utility function
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 01/13] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
@ 2014-04-09 13:29       ` Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 03/13] mac80211: prevent chanctx overcommit Michal Kazior
                         ` (11 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

The utility function has no uses yet. It is aimed
at future chanctx reservation management and
channel switching.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v4:
 * remove unnecessary braces {} from list_for_each [Johannes]

 net/mac80211/ieee80211_i.h |  1 +
 net/mac80211/util.c        | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6bfeb22..c59f983 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1824,6 +1824,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 				 const struct cfg80211_chan_def *chandef,
 				 enum ieee80211_chanctx_mode chanmode,
 				 u8 radar_detect);
+int ieee80211_max_num_channels(struct ieee80211_local *local);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 5a6cc33..7a376f8 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2873,3 +2873,45 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 					   num_different_channels,
 					   radar_detect, num);
 }
+
+static void
+ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c,
+			 void *data)
+{
+	u32 *max_num_different_channels = data;
+
+	*max_num_different_channels = max(*max_num_different_channels,
+					  c->num_different_channels);
+}
+
+int ieee80211_max_num_channels(struct ieee80211_local *local)
+{
+	struct ieee80211_sub_if_data *sdata;
+	int num[NUM_NL80211_IFTYPES] = {};
+	struct ieee80211_chanctx *ctx;
+	int num_different_channels = 0;
+	u8 radar_detect = 0;
+	u32 max_num_different_channels = 1;
+	int err;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(ctx, &local->chanctx_list, list) {
+		num_different_channels++;
+
+		if (ctx->conf.radar_enabled)
+			radar_detect |= BIT(ctx->conf.def.width);
+	}
+
+	list_for_each_entry_rcu(sdata, &local->interfaces, list)
+		num[sdata->wdev.iftype]++;
+
+	err = cfg80211_iter_combinations(local->hw.wiphy,
+					 num_different_channels, radar_detect,
+					 num, ieee80211_iter_max_chans,
+					 &max_num_different_channels);
+	if (err < 0)
+		return err;
+
+	return max_num_different_channels;
+}
-- 
1.8.5.3


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

* [PATCH v4 03/13] mac80211: prevent chanctx overcommit
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 01/13] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 02/13] mac80211: add max channel calculation utility function Michal Kazior
@ 2014-04-09 13:29       ` Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 04/13] mac80211: add support for radar detection for reservations Michal Kazior
                         ` (10 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

Do not allocate more channel contexts than a
driver is capable for currently matching interface
combination.

This allows the ieee80211_vif_reserve_chanctx() to
act as a guard against breaking interface
combinations.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 57b8ab1..fcb2cd8 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -9,6 +9,25 @@
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
+static int ieee80211_num_chanctx(struct ieee80211_local *local)
+{
+	struct ieee80211_chanctx *ctx;
+	int num = 0;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(ctx, &local->chanctx_list, list)
+		num++;
+
+	return num;
+}
+
+static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
+	return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -751,13 +770,16 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 			 * context, reserve our current context
 			 */
 			new_ctx = curr_ctx;
-		} else {
+		} else if (ieee80211_can_create_new_chanctx(local)) {
 			/* create a new context and reserve it */
 			new_ctx = ieee80211_new_chanctx(local, chandef, mode);
 			if (IS_ERR(new_ctx)) {
 				ret = PTR_ERR(new_ctx);
 				goto out;
 			}
+		} else {
+			ret = -EBUSY;
+			goto out;
 		}
 	}
 
-- 
1.8.5.3


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

* [PATCH v4 04/13] mac80211: add support for radar detection for reservations
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
                         ` (2 preceding siblings ...)
  2014-04-09 13:29       ` [PATCH v4 03/13] mac80211: prevent chanctx overcommit Michal Kazior
@ 2014-04-09 13:29       ` Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 05/13] mac80211: track assigned vifs in chanctx Michal Kazior
                         ` (9 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

Initial chanctx reservation code wasn't aware of
radar detection requirements. This is necessary
for chanctx reservations to be used for channel
switching in the future.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c        | 5 ++++-
 net/mac80211/ieee80211_i.h | 4 +++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index fcb2cd8..4ed229c 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -742,7 +742,8 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
 
 int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 				  const struct cfg80211_chan_def *chandef,
-				  enum ieee80211_chanctx_mode mode)
+				  enum ieee80211_chanctx_mode mode,
+				  bool radar_required)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx_conf *conf;
@@ -786,6 +787,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	new_ctx->refcount++;
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
+	sdata->reserved_radar_required = radar_required;
 out:
 	mutex_unlock(&local->chanctx_mtx);
 	return ret;
@@ -830,6 +832,7 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 	/* unref our reservation */
 	ctx->refcount--;
 	sdata->reserved_chanctx = NULL;
+	sdata->radar_required = sdata->reserved_radar_required;
 
 	if (old_ctx == ctx) {
 		/* This is our own context, just change it */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c59f983..0e85cad 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -760,6 +760,7 @@ struct ieee80211_sub_if_data {
 	/* context reservation -- protected with chanctx_mtx */
 	struct ieee80211_chanctx *reserved_chanctx;
 	struct cfg80211_chan_def reserved_chandef;
+	bool reserved_radar_required;
 
 	/* used to reconfigure hardware SM PS */
 	struct work_struct recalc_smps;
@@ -1779,7 +1780,8 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 int __must_check
 ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 			      const struct cfg80211_chan_def *chandef,
-			      enum ieee80211_chanctx_mode mode);
+			      enum ieee80211_chanctx_mode mode,
+			      bool radar_required);
 int __must_check
 ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 				   u32 *changed);
-- 
1.8.5.3


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

* [PATCH v4 05/13] mac80211: track assigned vifs in chanctx
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
                         ` (3 preceding siblings ...)
  2014-04-09 13:29       ` [PATCH v4 04/13] mac80211: add support for radar detection for reservations Michal Kazior
@ 2014-04-09 13:29       ` Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 06/13] mac80211: track reserved " Michal Kazior
                         ` (8 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

This can be useful. Provides a more straghtforward
way to iterate over interfaces bound to a given
chanctx and allows tracking chanctx usage
explicitly.

The structure is protected by local->chanctx_mtx.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v3:
 * update commit message [Johannes]
 * add locking information [Johannes]

 net/mac80211/chan.c        | 4 ++++
 net/mac80211/ieee80211_i.h | 4 ++++
 net/mac80211/iface.c       | 1 +
 3 files changed, 9 insertions(+)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 4ed229c..504526c 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -276,6 +276,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 	if (!ctx)
 		return ERR_PTR(-ENOMEM);
 
+	INIT_LIST_HEAD(&ctx->assigned_vifs);
 	ctx->conf.def = *chandef;
 	ctx->conf.rx_chains_static = 1;
 	ctx->conf.rx_chains_dynamic = 1;
@@ -420,6 +421,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 		curr_ctx->refcount--;
 		drv_unassign_vif_chanctx(local, sdata, curr_ctx);
 		conf = NULL;
+		list_del(&sdata->assigned_chanctx_list);
 	}
 
 	if (new_ctx) {
@@ -429,6 +431,8 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 
 		new_ctx->refcount++;
 		conf = &new_ctx->conf;
+		list_add(&sdata->assigned_chanctx_list,
+			 &new_ctx->assigned_vifs);
 	}
 
 out:
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 0e85cad..57fed5e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -691,6 +691,8 @@ struct ieee80211_chanctx {
 	struct list_head list;
 	struct rcu_head rcu_head;
 
+	struct list_head assigned_vifs;
+
 	enum ieee80211_chanctx_mode mode;
 	int refcount;
 	bool driver_present;
@@ -757,6 +759,8 @@ struct ieee80211_sub_if_data {
 	bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
 	struct cfg80211_chan_def csa_chandef;
 
+	struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */
+
 	/* context reservation -- protected with chanctx_mtx */
 	struct ieee80211_chanctx *reserved_chanctx;
 	struct cfg80211_chan_def reserved_chandef;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index d6230e2..1479e9f 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1298,6 +1298,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 	INIT_WORK(&sdata->work, ieee80211_iface_work);
 	INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
 	INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
+	INIT_LIST_HEAD(&sdata->assigned_chanctx_list);
 
 	switch (type) {
 	case NL80211_IFTYPE_P2P_GO:
-- 
1.8.5.3


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

* [PATCH v4 06/13] mac80211: track reserved vifs in chanctx
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
                         ` (4 preceding siblings ...)
  2014-04-09 13:29       ` [PATCH v4 05/13] mac80211: track assigned vifs in chanctx Michal Kazior
@ 2014-04-09 13:29       ` Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 07/13] mac80211: improve find_chanctx() for reservations Michal Kazior
                         ` (7 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

This can be useful. Provides a more straghtforward
way to iterate over interfaces taking part in
chanctx reservation and allows tracking chanctx
usage explicitly.

The structure is protected by local->chanctx_mtx.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v3:
 * update commit message [Johannes]
 * add locking information [Johannes]

 net/mac80211/chan.c        | 14 ++++++++++----
 net/mac80211/ieee80211_i.h |  2 ++
 net/mac80211/iface.c       |  1 +
 3 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 504526c..79eac96 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -277,6 +277,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 		return ERR_PTR(-ENOMEM);
 
 	INIT_LIST_HEAD(&ctx->assigned_vifs);
+	INIT_LIST_HEAD(&ctx->reserved_vifs);
 	ctx->conf.def = *chandef;
 	ctx->conf.rx_chains_static = 1;
 	ctx->conf.rx_chains_dynamic = 1;
@@ -731,16 +732,19 @@ void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 
 int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
 {
+	struct ieee80211_chanctx *ctx = sdata->reserved_chanctx;
+
 	lockdep_assert_held(&sdata->local->chanctx_mtx);
 
-	if (WARN_ON(!sdata->reserved_chanctx))
+	if (WARN_ON(!ctx))
 		return -EINVAL;
 
-	if (--sdata->reserved_chanctx->refcount == 0)
-		ieee80211_free_chanctx(sdata->local, sdata->reserved_chanctx);
-
+	list_del(&sdata->reserved_chanctx_list);
 	sdata->reserved_chanctx = NULL;
 
+	if (--ctx->refcount == 0)
+		ieee80211_free_chanctx(sdata->local, ctx);
+
 	return 0;
 }
 
@@ -788,6 +792,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
+	list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
 	new_ctx->refcount++;
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
@@ -837,6 +842,7 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 	ctx->refcount--;
 	sdata->reserved_chanctx = NULL;
 	sdata->radar_required = sdata->reserved_radar_required;
+	list_del(&sdata->reserved_chanctx_list);
 
 	if (old_ctx == ctx) {
 		/* This is our own context, just change it */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 57fed5e..7a60142 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -692,6 +692,7 @@ struct ieee80211_chanctx {
 	struct rcu_head rcu_head;
 
 	struct list_head assigned_vifs;
+	struct list_head reserved_vifs;
 
 	enum ieee80211_chanctx_mode mode;
 	int refcount;
@@ -760,6 +761,7 @@ struct ieee80211_sub_if_data {
 	struct cfg80211_chan_def csa_chandef;
 
 	struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */
+	struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */
 
 	/* context reservation -- protected with chanctx_mtx */
 	struct ieee80211_chanctx *reserved_chanctx;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 1479e9f..13ff2a9 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1299,6 +1299,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 	INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
 	INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
 	INIT_LIST_HEAD(&sdata->assigned_chanctx_list);
+	INIT_LIST_HEAD(&sdata->reserved_chanctx_list);
 
 	switch (type) {
 	case NL80211_IFTYPE_P2P_GO:
-- 
1.8.5.3


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

* [PATCH v4 07/13] mac80211: improve find_chanctx() for reservations
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
                         ` (5 preceding siblings ...)
  2014-04-09 13:29       ` [PATCH v4 06/13] mac80211: track reserved " Michal Kazior
@ 2014-04-09 13:29       ` Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 08/13] mac80211: improve chanctx reservation lookup Michal Kazior
                         ` (6 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

This allows new vifs to be assigned to a chanctx
as long as chanctx's reservation chandefs (if any)
and chanctx's current chandef (implied by assigned
vifs at the time, if any) and the new vif chandef
are all compatible.

This implies it is impossible to assign a new vif
to an in-place reservation chanctx.

This gives no advantages for single-channel
hardware. It makes sense for multi-channel
hardware only.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v2:
 * remove redundant calls to _chandef() [Eliad]
 * dont use rcu_access_pointer() [Eliad]

v3:
 * fix commit message so it makes more sense [Johannes]

 net/mac80211/chan.c | 56 +++++++++++++++++++++++++++--------------------------
 1 file changed, 29 insertions(+), 27 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 79eac96..0dfb04a 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -28,6 +28,29 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
 	return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
 }
 
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
+				   struct ieee80211_chanctx *ctx,
+				   const struct cfg80211_chan_def *compat)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs,
+			    reserved_chanctx_list) {
+		if (!compat)
+			compat = &sdata->reserved_chandef;
+
+		compat = cfg80211_chandef_compatible(&sdata->reserved_chandef,
+						     compat);
+		if (!compat)
+			break;
+	}
+
+	return compat;
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -187,27 +210,6 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
 	}
 }
 
-static bool ieee80211_chanctx_is_reserved(struct ieee80211_local *local,
-					  struct ieee80211_chanctx *ctx)
-{
-	struct ieee80211_sub_if_data *sdata;
-	bool ret = false;
-
-	lockdep_assert_held(&local->chanctx_mtx);
-	rcu_read_lock();
-	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-		if (!ieee80211_sdata_running(sdata))
-			continue;
-		if (sdata->reserved_chanctx == ctx) {
-			ret = true;
-			break;
-		}
-	}
-
-	rcu_read_unlock();
-	return ret;
-}
-
 static struct ieee80211_chanctx *
 ieee80211_find_chanctx(struct ieee80211_local *local,
 		       const struct cfg80211_chan_def *chandef,
@@ -223,18 +225,18 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
 	list_for_each_entry(ctx, &local->chanctx_list, list) {
 		const struct cfg80211_chan_def *compat;
 
-		/* We don't support chanctx reservation for multiple
-		 * vifs yet, so don't allow reserved chanctxs to be
-		 * reused.
-		 */
-		if ((ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) ||
-		    ieee80211_chanctx_is_reserved(local, ctx))
+		if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
 			continue;
 
 		compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef);
 		if (!compat)
 			continue;
 
+		compat = ieee80211_chanctx_reserved_chandef(local, ctx,
+							    compat);
+		if (!compat)
+			continue;
+
 		ieee80211_change_chanctx(local, ctx, compat);
 
 		return ctx;
-- 
1.8.5.3


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

* [PATCH v4 08/13] mac80211: improve chanctx reservation lookup
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
                         ` (6 preceding siblings ...)
  2014-04-09 13:29       ` [PATCH v4 07/13] mac80211: improve find_chanctx() for reservations Michal Kazior
@ 2014-04-09 13:29       ` Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 09/13] mac80211: split ieee80211_new_chanctx() Michal Kazior
                         ` (5 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

Use a separate function to look for reservation
chanctx. For multi-interface/channel reservation
search sematics differ slightly.

The new routine allows reservations to be merged
with chanctx that are already reserved by other
interface(s).

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 88 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 0dfb04a..7303edd 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -51,6 +51,93 @@ ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
 	return compat;
 }
 
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
+				       struct ieee80211_chanctx *ctx,
+				       const struct cfg80211_chan_def *compat)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->assigned_vifs,
+			    assigned_chanctx_list) {
+		if (sdata->reserved_chanctx != NULL)
+			continue;
+
+		if (!compat)
+			compat = &sdata->vif.bss_conf.chandef;
+
+		compat = cfg80211_chandef_compatible(
+				&sdata->vif.bss_conf.chandef, compat);
+		if (!compat)
+			break;
+	}
+
+	return compat;
+}
+
+static const struct cfg80211_chan_def *
+ieee80211_chanctx_combined_chandef(struct ieee80211_local *local,
+				   struct ieee80211_chanctx *ctx,
+				   const struct cfg80211_chan_def *compat)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	compat = ieee80211_chanctx_reserved_chandef(local, ctx, compat);
+	if (!compat)
+		return NULL;
+
+	compat = ieee80211_chanctx_non_reserved_chandef(local, ctx, compat);
+	if (!compat)
+		return NULL;
+
+	return compat;
+}
+
+static bool
+ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local,
+				      struct ieee80211_chanctx *ctx,
+				      const struct cfg80211_chan_def *def)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	if (ieee80211_chanctx_combined_chandef(local, ctx, def))
+		return true;
+
+	if (!list_empty(&ctx->reserved_vifs) &&
+	    ieee80211_chanctx_reserved_chandef(local, ctx, def))
+		return true;
+
+	return false;
+}
+
+static struct ieee80211_chanctx *
+ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
+				   const struct cfg80211_chan_def *chandef,
+				   enum ieee80211_chanctx_mode mode)
+{
+	struct ieee80211_chanctx *ctx;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
+		return NULL;
+
+	list_for_each_entry(ctx, &local->chanctx_list, list) {
+		if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
+			continue;
+
+		if (!ieee80211_chanctx_can_reserve_chandef(local, ctx,
+							   chandef))
+			continue;
+
+		return ctx;
+	}
+
+	return NULL;
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -771,8 +858,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 
 	curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-	/* try to find another context with the chandef we want */
-	new_ctx = ieee80211_find_chanctx(local, chandef, mode);
+	new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
 	if (!new_ctx) {
 		if (curr_ctx->refcount == 1 &&
 		    (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
-- 
1.8.5.3


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

* [PATCH v4 09/13] mac80211: split ieee80211_new_chanctx()
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
                         ` (7 preceding siblings ...)
  2014-04-09 13:29       ` [PATCH v4 08/13] mac80211: improve chanctx reservation lookup Michal Kazior
@ 2014-04-09 13:29       ` Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 10/13] mac80211: split ieee80211_free_chanctx() Michal Kazior
                         ` (4 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

The function did a little too much. Split it up so
the code can be easily reused in the future.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 56 ++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 43 insertions(+), 13 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 7303edd..247133f 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -351,19 +351,17 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local)
 }
 
 static struct ieee80211_chanctx *
-ieee80211_new_chanctx(struct ieee80211_local *local,
-		      const struct cfg80211_chan_def *chandef,
-		      enum ieee80211_chanctx_mode mode)
+ieee80211_alloc_chanctx(struct ieee80211_local *local,
+			const struct cfg80211_chan_def *chandef,
+			enum ieee80211_chanctx_mode mode)
 {
 	struct ieee80211_chanctx *ctx;
-	u32 changed;
-	int err;
 
 	lockdep_assert_held(&local->chanctx_mtx);
 
 	ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
 	if (!ctx)
-		return ERR_PTR(-ENOMEM);
+		return NULL;
 
 	INIT_LIST_HEAD(&ctx->assigned_vifs);
 	INIT_LIST_HEAD(&ctx->reserved_vifs);
@@ -373,31 +371,63 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 	ctx->mode = mode;
 	ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
 	ieee80211_recalc_chanctx_min_def(local, ctx);
+
+	return ctx;
+}
+
+static int ieee80211_add_chanctx(struct ieee80211_local *local,
+				 struct ieee80211_chanctx *ctx)
+{
+	u32 changed;
+	int err;
+
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
+
 	if (!local->use_chanctx)
 		local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
 
-	/* we hold the mutex to prevent idle from changing */
-	lockdep_assert_held(&local->mtx);
 	/* turn idle off *before* setting channel -- some drivers need that */
 	changed = ieee80211_idle_off(local);
 	if (changed)
 		ieee80211_hw_config(local, changed);
 
 	if (!local->use_chanctx) {
-		local->_oper_chandef = *chandef;
+		local->_oper_chandef = ctx->conf.def;
 		ieee80211_hw_config(local, 0);
 	} else {
 		err = drv_add_chanctx(local, ctx);
 		if (err) {
-			kfree(ctx);
 			ieee80211_recalc_idle(local);
-			return ERR_PTR(err);
+			return err;
 		}
 	}
 
-	/* and keep the mutex held until the new chanctx is on the list */
-	list_add_rcu(&ctx->list, &local->chanctx_list);
+	return 0;
+}
+
+static struct ieee80211_chanctx *
+ieee80211_new_chanctx(struct ieee80211_local *local,
+		      const struct cfg80211_chan_def *chandef,
+		      enum ieee80211_chanctx_mode mode)
+{
+	struct ieee80211_chanctx *ctx;
+	int err;
+
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	ctx = ieee80211_alloc_chanctx(local, chandef, mode);
+	if (!ctx)
+		return ERR_PTR(-ENOMEM);
 
+	err = ieee80211_add_chanctx(local, ctx);
+	if (err) {
+		kfree(ctx);
+		return ERR_PTR(err);
+	}
+
+	list_add_rcu(&ctx->list, &local->chanctx_list);
 	return ctx;
 }
 
-- 
1.8.5.3


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

* [PATCH v4 10/13] mac80211: split ieee80211_free_chanctx()
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
                         ` (8 preceding siblings ...)
  2014-04-09 13:29       ` [PATCH v4 09/13] mac80211: split ieee80211_new_chanctx() Michal Kazior
@ 2014-04-09 13:29       ` Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 11/13] mac80211: fix racy usage of chanctx->refcount Michal Kazior
                         ` (3 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

The function did a little too much. Split it up so
the code can be easily reused in the future.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/chan.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 247133f..e4166b3 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -431,14 +431,11 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
 	return ctx;
 }
 
-static void ieee80211_free_chanctx(struct ieee80211_local *local,
-				   struct ieee80211_chanctx *ctx)
+static void ieee80211_del_chanctx(struct ieee80211_local *local,
+				  struct ieee80211_chanctx *ctx)
 {
-	bool check_single_channel = false;
 	lockdep_assert_held(&local->chanctx_mtx);
 
-	WARN_ON_ONCE(ctx->refcount != 0);
-
 	if (!local->use_chanctx) {
 		struct cfg80211_chan_def *chandef = &local->_oper_chandef;
 		chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
@@ -448,8 +445,9 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
 		/* NOTE: Disabling radar is only valid here for
 		 * single channel context. To be sure, check it ...
 		 */
-		if (local->hw.conf.radar_enabled)
-			check_single_channel = true;
+		WARN_ON(local->hw.conf.radar_enabled &&
+			!list_empty(&local->chanctx_list));
+
 		local->hw.conf.radar_enabled = false;
 
 		ieee80211_hw_config(local, 0);
@@ -457,13 +455,19 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
 		drv_remove_chanctx(local, ctx);
 	}
 
-	list_del_rcu(&ctx->list);
-	kfree_rcu(ctx, rcu_head);
+	ieee80211_recalc_idle(local);
+}
 
-	/* throw a warning if this wasn't the only channel context. */
-	WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
+static void ieee80211_free_chanctx(struct ieee80211_local *local,
+				   struct ieee80211_chanctx *ctx)
+{
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	ieee80211_recalc_idle(local);
+	WARN_ON_ONCE(ctx->refcount != 0);
+
+	list_del_rcu(&ctx->list);
+	ieee80211_del_chanctx(local, ctx);
+	kfree_rcu(ctx, rcu_head);
 }
 
 static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
-- 
1.8.5.3


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

* [PATCH v4 11/13] mac80211: fix racy usage of chanctx->refcount
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
                         ` (9 preceding siblings ...)
  2014-04-09 13:29       ` [PATCH v4 10/13] mac80211: split ieee80211_free_chanctx() Michal Kazior
@ 2014-04-09 13:29       ` Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 12/13] mac80211: compute chanctx refcount on-the-fly Michal Kazior
                         ` (2 subsequent siblings)
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

Channel context refcount is protected by
chanctx_mtx. Accessing the value without holding
the mutex is racy. RCU section didn't guarantee
anything here.

Theoretically ieee80211_channel_switch() could
fail to see refcount change and read "1" instead
of, e.g. "2". This means mac80211 could accept CSA
even though it shouldn't have.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v2:
 * use rcu_dereference_protected() [Eliad/Johannes]

 net/mac80211/cfg.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5bd4a81..3bcbf76 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3282,7 +3282,7 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx_conf *chanctx_conf;
+	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *chanctx;
 	int err, num_chanctx, changed = 0;
 
@@ -3299,23 +3299,24 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 				       &sdata->vif.bss_conf.chandef))
 		return -EINVAL;
 
-	rcu_read_lock();
-	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
-	if (!chanctx_conf) {
-		rcu_read_unlock();
+	mutex_lock(&local->chanctx_mtx);
+	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+					 lockdep_is_held(&local->chanctx_mtx));
+	if (!conf) {
+		mutex_unlock(&local->chanctx_mtx);
 		return -EBUSY;
 	}
 
 	/* don't handle for multi-VIF cases */
-	chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
+	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
 	if (chanctx->refcount > 1) {
-		rcu_read_unlock();
+		mutex_unlock(&local->chanctx_mtx);
 		return -EBUSY;
 	}
 	num_chanctx = 0;
 	list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
 		num_chanctx++;
-	rcu_read_unlock();
+	mutex_unlock(&local->chanctx_mtx);
 
 	if (num_chanctx > 1)
 		return -EBUSY;
-- 
1.8.5.3


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

* [PATCH v4 12/13] mac80211: compute chanctx refcount on-the-fly
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
                         ` (10 preceding siblings ...)
  2014-04-09 13:29       ` [PATCH v4 11/13] mac80211: fix racy usage of chanctx->refcount Michal Kazior
@ 2014-04-09 13:29       ` Michal Kazior
  2014-04-09 13:29       ` [PATCH v4 13/13] mac80211: implement multi-vif in-place reservations Michal Kazior
  2014-04-25 15:20       ` [PATCH v4 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Johannes Berg
  13 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

It doesn't make much sense to store refcount in
the chanctx structure. One still needs to hold
chanctx_mtx to get the value safely. Besides,
refcount isn't on performance critical paths.

This will make implementing chanctx reservation
refcounting a little easier.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v2:
 * use assigned/reserved lists instead of
   local->interfaces

 net/mac80211/cfg.c         |  2 +-
 net/mac80211/chan.c        | 59 +++++++++++++++++++++++++++++++++++-----------
 net/mac80211/ieee80211_i.h |  3 ++-
 net/mac80211/mlme.c        |  2 +-
 4 files changed, 49 insertions(+), 17 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 3bcbf76..e7dd809 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3309,7 +3309,7 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 
 	/* don't handle for multi-VIF cases */
 	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
-	if (chanctx->refcount > 1) {
+	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
 		mutex_unlock(&local->chanctx_mtx);
 		return -EBUSY;
 	}
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index e4166b3..d8b1b86 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -9,6 +9,41 @@
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
+static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
+					  struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+	int num = 0;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
+		num++;
+
+	return num;
+}
+
+static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
+					  struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+	int num = 0;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list)
+		num++;
+
+	return num;
+}
+
+int ieee80211_chanctx_refcount(struct ieee80211_local *local,
+			       struct ieee80211_chanctx *ctx)
+{
+	return ieee80211_chanctx_num_assigned(local, ctx) +
+	       ieee80211_chanctx_num_reserved(local, ctx);
+}
+
 static int ieee80211_num_chanctx(struct ieee80211_local *local)
 {
 	struct ieee80211_chanctx *ctx;
@@ -463,7 +498,7 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
 {
 	lockdep_assert_held(&local->chanctx_mtx);
 
-	WARN_ON_ONCE(ctx->refcount != 0);
+	WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
 
 	list_del_rcu(&ctx->list);
 	ieee80211_del_chanctx(local, ctx);
@@ -542,7 +577,6 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 	if (conf) {
 		curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-		curr_ctx->refcount--;
 		drv_unassign_vif_chanctx(local, sdata, curr_ctx);
 		conf = NULL;
 		list_del(&sdata->assigned_chanctx_list);
@@ -553,7 +587,6 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 		if (ret)
 			goto out;
 
-		new_ctx->refcount++;
 		conf = &new_ctx->conf;
 		list_add(&sdata->assigned_chanctx_list,
 			 &new_ctx->assigned_vifs);
@@ -564,14 +597,14 @@ out:
 
 	sdata->vif.bss_conf.idle = !conf;
 
-	if (curr_ctx && curr_ctx->refcount > 0) {
+	if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
 		ieee80211_recalc_chanctx_chantype(local, curr_ctx);
 		ieee80211_recalc_smps_chanctx(local, curr_ctx);
 		ieee80211_recalc_radar_chanctx(local, curr_ctx);
 		ieee80211_recalc_chanctx_min_def(local, curr_ctx);
 	}
 
-	if (new_ctx && new_ctx->refcount > 0) {
+	if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
 		ieee80211_recalc_txpower(sdata);
 		ieee80211_recalc_chanctx_min_def(local, new_ctx);
 	}
@@ -603,7 +636,7 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
 		ieee80211_vif_unreserve_chanctx(sdata);
 
 	ieee80211_assign_vif_chanctx(sdata, NULL);
-	if (ctx->refcount == 0)
+	if (ieee80211_chanctx_refcount(local, ctx) == 0)
 		ieee80211_free_chanctx(local, ctx);
 }
 
@@ -735,7 +768,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 	ret = ieee80211_assign_vif_chanctx(sdata, ctx);
 	if (ret) {
 		/* if assign fails refcount stays the same */
-		if (ctx->refcount == 0)
+		if (ieee80211_chanctx_refcount(local, ctx) == 0)
 			ieee80211_free_chanctx(local, ctx);
 		goto out;
 	}
@@ -759,7 +792,7 @@ static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
 				     IEEE80211_CHAN_DISABLED))
 		return -EINVAL;
 
-	if (ctx->refcount != 1)
+	if (ieee80211_chanctx_refcount(local, ctx) != 1)
 		return -EINVAL;
 
 	if (sdata->vif.bss_conf.chandef.width != chandef->width) {
@@ -865,7 +898,7 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
 	list_del(&sdata->reserved_chanctx_list);
 	sdata->reserved_chanctx = NULL;
 
-	if (--ctx->refcount == 0)
+	if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0)
 		ieee80211_free_chanctx(sdata->local, ctx);
 
 	return 0;
@@ -894,7 +927,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 
 	new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
 	if (!new_ctx) {
-		if (curr_ctx->refcount == 1 &&
+		if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 &&
 		    (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
 			/* if we're the only users of the chanctx and
 			 * the driver supports changing a running
@@ -915,7 +948,6 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	}
 
 	list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
-	new_ctx->refcount++;
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
 	sdata->reserved_radar_required = radar_required;
@@ -961,7 +993,6 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 	sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
 
 	/* unref our reservation */
-	ctx->refcount--;
 	sdata->reserved_chanctx = NULL;
 	sdata->radar_required = sdata->reserved_radar_required;
 	list_del(&sdata->reserved_chanctx_list);
@@ -974,11 +1005,11 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
 			goto out;
 	} else {
 		ret = ieee80211_assign_vif_chanctx(sdata, ctx);
-		if (old_ctx->refcount == 0)
+		if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
 			ieee80211_free_chanctx(local, old_ctx);
 		if (ret) {
 			/* if assign fails refcount stays the same */
-			if (ctx->refcount == 0)
+			if (ieee80211_chanctx_refcount(local, ctx) == 0)
 				ieee80211_free_chanctx(local, ctx);
 			goto out;
 		}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 7a60142..6426e5e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -695,7 +695,6 @@ struct ieee80211_chanctx {
 	struct list_head reserved_vifs;
 
 	enum ieee80211_chanctx_mode mode;
-	int refcount;
 	bool driver_present;
 
 	struct ieee80211_chanctx_conf conf;
@@ -1805,6 +1804,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 					 bool clear);
+int ieee80211_chanctx_refcount(struct ieee80211_local *local,
+			       struct ieee80211_chanctx *ctx);
 
 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
 				   struct ieee80211_chanctx *chanctx);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 8702bc4..0ea337d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1093,7 +1093,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	}
 	chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
 			       struct ieee80211_chanctx, conf);
-	if (chanctx->refcount > 1) {
+	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
 		sdata_info(sdata,
 			   "channel switch with multiple interfaces on the same channel, disconnecting\n");
 		ieee80211_queue_work(&local->hw,
-- 
1.8.5.3


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

* [PATCH v4 13/13] mac80211: implement multi-vif in-place reservations
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
                         ` (11 preceding siblings ...)
  2014-04-09 13:29       ` [PATCH v4 12/13] mac80211: compute chanctx refcount on-the-fly Michal Kazior
@ 2014-04-09 13:29       ` Michal Kazior
  2014-04-28 16:32         ` [v4 " Zhao, Gang
  2014-04-30  9:21         ` [PATCH v5] " Michal Kazior
  2014-04-25 15:20       ` [PATCH v4 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Johannes Berg
  13 siblings, 2 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

Multi-vif in-place reservations happen when
it's impossible to allocate more chanctx as per
driver combinations.

Such reservations aren't finalized until last
reservation interface calls in to use the
reservation.

This introduces a special hook
ieee80211_vif_chanctx_reservation_complete(). This
is currently an empty stub and will be filled in
by AP/STA CSA code. This is required to implement
2-step CSA finalization.

This also gets rid of driver requirement to be
able to re-program channel of a chanctx.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v2:
 * use new_ctx instead of ctx [Eliad]
 * move recalcs after bss_conf is updated [Eliad]

v4:
 * move recalc-radar before vif-chanctx-assign [Eliad]
 * move radar_required swapping before initial add_chanctx() [Eliad]

 include/net/mac80211.h     |   7 --
 net/mac80211/chan.c        | 282 +++++++++++++++++++++++++++++++++------------
 net/mac80211/ieee80211_i.h |   4 +-
 3 files changed, 209 insertions(+), 84 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 2cf9c01..01486dc 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1557,12 +1557,6 @@ struct ieee80211_tx_control {
  *	for a single active channel while using channel contexts. When support
  *	is not enabled the default action is to disconnect when getting the
  *	CSA frame.
- *
- * @IEEE80211_HW_CHANGE_RUNNING_CHANCTX: The hardware can change a
- *	channel context on-the-fly.  This is needed for channel switch
- *	on single-channel hardware.  It can also be used as an
- *	optimization in certain channel switch cases with
- *	multi-channel.
  */
 enum ieee80211_hw_flags {
 	IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0,
@@ -1594,7 +1588,6 @@ enum ieee80211_hw_flags {
 	IEEE80211_HW_TIMING_BEACON_ONLY			= 1<<26,
 	IEEE80211_HW_SUPPORTS_HT_CCK_RATES		= 1<<27,
 	IEEE80211_HW_CHANCTX_STA_CSA			= 1<<28,
-	IEEE80211_HW_CHANGE_RUNNING_CHANCTX		= 1<<29,
 };
 
 /**
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index d8b1b86..cc9e817 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -173,6 +173,24 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
 	return NULL;
 }
 
+static bool
+ieee80211_chanctx_all_reserved_vifs_ready(struct ieee80211_local *local,
+					  struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		if (!sdata->reserved_chanctx)
+			continue;
+		if (!sdata->reserved_ready)
+			return false;
+	}
+
+	return true;
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -912,38 +930,24 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *new_ctx, *curr_ctx;
-	int ret = 0;
 
-	mutex_lock(&local->chanctx_mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
 	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf) {
-		ret = -EINVAL;
-		goto out;
-	}
+	if (!conf)
+		return -EINVAL;
 
 	curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
 	new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
 	if (!new_ctx) {
-		if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 &&
-		    (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
-			/* if we're the only users of the chanctx and
-			 * the driver supports changing a running
-			 * context, reserve our current context
-			 */
-			new_ctx = curr_ctx;
-		} else if (ieee80211_can_create_new_chanctx(local)) {
-			/* create a new context and reserve it */
+		if (ieee80211_can_create_new_chanctx(local)) {
 			new_ctx = ieee80211_new_chanctx(local, chandef, mode);
-			if (IS_ERR(new_ctx)) {
-				ret = PTR_ERR(new_ctx);
-				goto out;
-			}
+			if (IS_ERR(new_ctx))
+				return PTR_ERR(new_ctx);
 		} else {
-			ret = -EBUSY;
-			goto out;
+			new_ctx = curr_ctx;
 		}
 	}
 
@@ -951,82 +955,210 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
 	sdata->reserved_radar_required = radar_required;
-out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
+	sdata->reserved_ready = false;
+
+	return 0;
 }
 
-int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
-				       u32 *changed)
+static void
+ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx *ctx;
-	struct ieee80211_chanctx *old_ctx;
-	struct ieee80211_chanctx_conf *conf;
-	int ret;
-	u32 tmp_changed = *changed;
+	/* stub */
+}
 
-	/* TODO: need to recheck if the chandef is usable etc.? */
+static int
+ieee80211_vif_use_reserved_incompat(struct ieee80211_local *local,
+				    struct ieee80211_chanctx *ctx,
+				    const struct cfg80211_chan_def *chandef)
+{
+	struct ieee80211_sub_if_data *sdata, *tmp;
+	struct ieee80211_chanctx *new_ctx;
+	u32 changed = 0;
+	int err;
 
 	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	mutex_lock(&local->chanctx_mtx);
+	if (!ieee80211_chanctx_all_reserved_vifs_ready(local, ctx))
+		return 0;
 
-	ctx = sdata->reserved_chanctx;
-	if (WARN_ON(!ctx)) {
-		ret = -EINVAL;
-		goto out;
+	if (ieee80211_chanctx_num_assigned(local, ctx) !=
+	    ieee80211_chanctx_num_reserved(local, ctx)) {
+		wiphy_info(local->hw.wiphy,
+			   "channel context reservation cannot be finalized because some interfaces aren't switching\n");
+		err = -EBUSY;
+		goto err;
 	}
 
-	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf) {
-		ret = -EINVAL;
+	new_ctx = ieee80211_alloc_chanctx(local, chandef, ctx->mode);
+	if (!new_ctx) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		drv_unassign_vif_chanctx(local, sdata, ctx);
+		rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
+	}
+
+	list_del_rcu(&ctx->list);
+	ieee80211_del_chanctx(local, ctx);
+
+	/* don't simply overwrite radar_required in case of failure */
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		bool tmp = sdata->radar_required;
+		sdata->radar_required = sdata->reserved_radar_required;
+		sdata->reserved_radar_required = tmp;
+	}
+
+	ieee80211_recalc_radar_chanctx(local, new_ctx);
+
+	err = ieee80211_add_chanctx(local, new_ctx);
+	if (err)
+		goto err_revert;
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		err = drv_assign_vif_chanctx(local, sdata, new_ctx);
+		if (err)
+			goto err_unassign;
+	}
+
+	if (sdata->vif.type == NL80211_IFTYPE_AP)
+		__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
+
+	list_add_rcu(&new_ctx->list, &local->chanctx_list);
+	kfree_rcu(ctx, rcu_head);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs,
+			    reserved_chanctx_list) {
+		changed = 0;
+		if (sdata->vif.bss_conf.chandef.width !=
+		    sdata->reserved_chandef.width)
+			changed = BSS_CHANGED_BANDWIDTH;
+
+		sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
+		if (changed)
+			ieee80211_bss_info_change_notify(sdata, changed);
+
+		ieee80211_recalc_txpower(sdata);
+	}
+
+	ieee80211_recalc_chanctx_chantype(local, new_ctx);
+	ieee80211_recalc_smps_chanctx(local, new_ctx);
+	ieee80211_recalc_chanctx_min_def(local, new_ctx);
+
+	list_for_each_entry_safe(sdata, tmp, &ctx->reserved_vifs,
+				 reserved_chanctx_list) {
+		list_del(&sdata->reserved_chanctx_list);
+		list_move(&sdata->assigned_chanctx_list,
+			  &new_ctx->assigned_vifs);
+		sdata->reserved_chanctx = NULL;
+
+		ieee80211_vif_chanctx_reservation_complete(sdata);
+	}
+
+	return 0;
+
+err_unassign:
+	list_for_each_entry_continue_reverse(sdata, &ctx->reserved_vifs,
+					     reserved_chanctx_list)
+		drv_unassign_vif_chanctx(local, sdata, ctx);
+	ieee80211_del_chanctx(local, new_ctx);
+err_revert:
+	kfree_rcu(new_ctx, rcu_head);
+	WARN_ON(ieee80211_add_chanctx(local, ctx));
+	list_add_rcu(&ctx->list, &local->chanctx_list);
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		sdata->radar_required = sdata->reserved_radar_required;
+		rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
+		WARN_ON(drv_assign_vif_chanctx(local, sdata, ctx));
+	}
+err:
+	list_for_each_entry_safe(sdata, tmp, &ctx->reserved_vifs,
+				 reserved_chanctx_list) {
+		list_del(&sdata->reserved_chanctx_list);
+		sdata->reserved_chanctx = NULL;
+		ieee80211_vif_chanctx_reservation_complete(sdata);
+	}
+	return err;
+}
+
+static int
+ieee80211_vif_use_reserved_compat(struct ieee80211_sub_if_data *sdata,
+				  struct ieee80211_chanctx *old_ctx,
+				  struct ieee80211_chanctx *new_ctx)
+{
+	struct ieee80211_local *local = sdata->local;
+	u32 changed = 0;
+	int err;
+
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_del(&sdata->reserved_chanctx_list);
+	sdata->reserved_chanctx = NULL;
+
+	err = ieee80211_assign_vif_chanctx(sdata, new_ctx);
+	if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
+		ieee80211_free_chanctx(local, old_ctx);
+	if (err) {
+		/* if assign fails refcount stays the same */
+		if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
+			ieee80211_free_chanctx(local, new_ctx);
 		goto out;
 	}
 
-	old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
+	if (sdata->vif.type == NL80211_IFTYPE_AP)
+		__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
 
 	if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
-		tmp_changed |= BSS_CHANGED_BANDWIDTH;
+		changed = BSS_CHANGED_BANDWIDTH;
 
 	sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
 
-	/* unref our reservation */
-	sdata->reserved_chanctx = NULL;
-	sdata->radar_required = sdata->reserved_radar_required;
-	list_del(&sdata->reserved_chanctx_list);
+	if (changed)
+		ieee80211_bss_info_change_notify(sdata, changed);
 
-	if (old_ctx == ctx) {
-		/* This is our own context, just change it */
-		ret = __ieee80211_vif_change_channel(sdata, old_ctx,
-						     &tmp_changed);
-		if (ret)
-			goto out;
-	} else {
-		ret = ieee80211_assign_vif_chanctx(sdata, ctx);
-		if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
-			ieee80211_free_chanctx(local, old_ctx);
-		if (ret) {
-			/* if assign fails refcount stays the same */
-			if (ieee80211_chanctx_refcount(local, ctx) == 0)
-				ieee80211_free_chanctx(local, ctx);
-			goto out;
-		}
+out:
+	ieee80211_vif_chanctx_reservation_complete(sdata);
+	return err;
+}
 
-		if (sdata->vif.type == NL80211_IFTYPE_AP)
-			__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
-	}
+int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_chanctx *ctx;
+	struct ieee80211_chanctx *old_ctx;
+	struct ieee80211_chanctx_conf *conf;
+	const struct cfg80211_chan_def *chandef;
 
-	*changed = tmp_changed;
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	ieee80211_recalc_chanctx_chantype(local, ctx);
-	ieee80211_recalc_smps_chanctx(local, ctx);
-	ieee80211_recalc_radar_chanctx(local, ctx);
-	ieee80211_recalc_chanctx_min_def(local, ctx);
-out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
+	ctx = sdata->reserved_chanctx;
+	if (WARN_ON(!ctx))
+		return -EINVAL;
+
+	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+					 lockdep_is_held(&local->chanctx_mtx));
+	if (!conf)
+		return -EINVAL;
+
+	old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
+
+	if (WARN_ON(sdata->reserved_ready))
+		return -EINVAL;
+
+	chandef = ieee80211_chanctx_reserved_chandef(local, ctx, NULL);
+	if (WARN_ON(!chandef))
+		return -EINVAL;
+
+	sdata->reserved_ready = true;
+
+	if (cfg80211_chandef_compatible(&ctx->conf.def, chandef))
+		return ieee80211_vif_use_reserved_compat(sdata, old_ctx, ctx);
+	else
+		return ieee80211_vif_use_reserved_incompat(local, ctx, chandef);
 }
 
 int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6426e5e..4b8c5fe 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -766,6 +766,7 @@ struct ieee80211_sub_if_data {
 	struct ieee80211_chanctx *reserved_chanctx;
 	struct cfg80211_chan_def reserved_chandef;
 	bool reserved_radar_required;
+	bool reserved_ready;
 
 	/* used to reconfigure hardware SM PS */
 	struct work_struct recalc_smps;
@@ -1788,8 +1789,7 @@ ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 			      enum ieee80211_chanctx_mode mode,
 			      bool radar_required);
 int __must_check
-ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
-				   u32 *changed);
+ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata);
 int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata);
 
 int __must_check
-- 
1.8.5.3


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

* [PATCH v4 0/5] cfg80211/mac80211: implement multi-vif csa
  2014-03-31 12:04   ` [PATCH v3 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
                       ` (4 preceding siblings ...)
  2014-03-31 12:04     ` [PATCH v3 5/5] cfg80211: remove channel_switch combination check Michal Kazior
@ 2014-04-09 13:45     ` Michal Kazior
  2014-04-09 13:45       ` [PATCH v4 1/5] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
                         ` (4 more replies)
  5 siblings, 5 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:45 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

Hi,

This is another part of my recent (originally)
RFC. This is just the channel switching part.

This is based on my patchset implementing
multi-vif chanctx reservations.

This effectively enables multi-vif CSA for
STA/AP/IBSS/mesh (except the fact that channel
switching itself is still hard-disabled in
cfg80211 -- maybe it's about time to re-enable?).


v2:
 * add radar_detect fix patch (wasn't present in
   the big RFC)

v3:
 * remove radar_detect fix patch (it was
   cherry-picked)
 * squash removal of ieee80211_vif_change_channel() [Johannes]
 * cleanups [Johannes]
 * add resilience for calling ieee80211_csa_finish() and
   ieee80211_chswitch_done() more than once (the
   problem was originally discussed in `ath10k: dont call csa_finish
   more than once`)

v4:
 * fix compilation issue between 2/5 and 3/5
   (I had squashed vif_change_channel removal too early)

Michal Kazior (5):
  mac80211: make check_combinations() aware of chanctx reservation
  mac80211: use chanctx reservation for AP CSA
  mac80211: use chanctx reservation for STA CSA
  mac80211: ignore cqm during csa
  cfg80211: remove channel_switch combination check

 net/mac80211/cfg.c         |  82 ++++++++++++++++++++++++------------
 net/mac80211/chan.c        |  79 ++++++----------------------------
 net/mac80211/ieee80211_i.h |   5 ---
 net/mac80211/mlme.c        | 103 ++++++++++++++++++++++++++++++---------------
 net/mac80211/util.c        |  39 ++++++++++++++++-
 net/wireless/nl80211.c     |  11 -----
 6 files changed, 176 insertions(+), 143 deletions(-)

-- 
1.8.5.3


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

* [PATCH v4 1/5] mac80211: make check_combinations() aware of chanctx reservation
  2014-04-09 13:45     ` [PATCH v4 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
@ 2014-04-09 13:45       ` Michal Kazior
  2014-04-09 13:45       ` [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA Michal Kazior
                         ` (3 subsequent siblings)
  4 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:45 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

The ieee80211_check_combinations() computes
radar_detect accordingly depending on chanctx
reservation status.

This makes it possible to use the function for
channel_switch validation.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v3:
 * fix typo in comment [Johannes]
 * fix comment style [Johannes]

 net/mac80211/util.c | 39 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 7a376f8..c296727 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2798,6 +2798,42 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
 	ps->dtim_count = dtim_count;
 }
 
+static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local,
+					 struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_chanctx_conf *conf;
+	u8 radar_detect = 0;
+	bool in_place = false;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		if (sdata->reserved_radar_required)
+			radar_detect |= BIT(sdata->reserved_chandef.width);
+
+		conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+				lockdep_is_held(&local->chanctx_mtx));
+		if (conf == &ctx->conf)
+			in_place = true;
+	}
+
+	/*
+	 * if chanctx has in-place reservation then consider only the future
+	 * radar_detect. multi-vif reservation is deferred so ignore assigned
+	 * vifs. it is impossible for new vifs to be bound to an in-place
+	 * reserved chanctx so consistency is guaranteed
+	 */
+	if (in_place)
+		return radar_detect;
+
+	list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
+		if (sdata->radar_required)
+			radar_detect |= BIT(sdata->vif.bss_conf.chandef.width);
+
+	return radar_detect;
+}
+
 int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 				 const struct cfg80211_chan_def *chandef,
 				 enum ieee80211_chanctx_mode chanmode,
@@ -2839,8 +2875,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
 		num[iftype] = 1;
 
 	list_for_each_entry(ctx, &local->chanctx_list, list) {
-		if (ctx->conf.radar_enabled)
-			radar_detect |= BIT(ctx->conf.def.width);
+		radar_detect |= ieee80211_chanctx_radar_detect(local, ctx);
 		if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
 			num_different_channels++;
 			continue;
-- 
1.8.5.3


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

* [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA
  2014-04-09 13:45     ` [PATCH v4 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
  2014-04-09 13:45       ` [PATCH v4 1/5] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
@ 2014-04-09 13:45       ` Michal Kazior
  2014-05-06 14:42         ` Johannes Berg
  2014-04-09 13:45       ` [PATCH v4 3/5] mac80211: use chanctx reservation for STA CSA Michal Kazior
                         ` (2 subsequent siblings)
  4 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:45 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

Channel switch finalization is now 2-step. First
step is when driver calls csa_finish(), the other
is when reservation is actually finalized (which
be defered for in-place reservation).

It is now safe to call ieee80211_csa_finish() more
then once.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v3:
 * fix lockdep typo s/mtx/chanctx_mtx/ [Johannes]
 * fix comment style [Johannes]
 * use goto for cleaner unlocking/returning [Johannes]
 * squash with ieee80211_vif_change_channel() removal patch [Johannes]
 * fix commit message [Johannes]
 * add resilience for multiple ieee80211_csa_finish() calls

v4:
 * split removal of ieee80211_vif_change_channel()

 net/mac80211/cfg.c  | 82 +++++++++++++++++++++++++++++++++++------------------
 net/mac80211/chan.c | 11 ++++++-
 2 files changed, 65 insertions(+), 28 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index e7dd809..be9e0c5 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3096,17 +3096,35 @@ static int ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
 
 	sdata_assert_lock(sdata);
 	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	sdata->radar_required = sdata->csa_radar_required;
-	err = ieee80211_vif_change_channel(sdata, &changed);
-	if (err < 0)
-		return err;
+	/*
+	 * using reservation isn't immediate as it may be deferred until later
+	 * with multi-vif. once reservation is complete it will re-schedule the
+	 * work with no reserved_chanctx so verify chandef to check if it
+	 * completed successfully
+	 */
 
-	if (!local->use_chanctx) {
-		local->_oper_chandef = sdata->csa_chandef;
-		ieee80211_hw_config(local, 0);
+	if (sdata->reserved_chanctx) {
+		/*
+		 * with multi-vif csa driver may call ieee80211_csa_finish()
+		 * many times while waiting for other interfaces to use their
+		 * reservations
+		 */
+		if (sdata->reserved_ready)
+			return 0;
+
+		err = ieee80211_vif_use_reserved_context(sdata);
+		if (err)
+			return err;
+
+		return 0;
 	}
 
+	if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
+					&sdata->csa_chandef))
+		return -EINVAL;
+
 	sdata->vif.csa_active = false;
 
 	err = ieee80211_set_after_csa_beacon(sdata, &changed);
@@ -3134,6 +3152,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
 
 	sdata_lock(sdata);
 	mutex_lock(&local->mtx);
+	mutex_lock(&local->chanctx_mtx);
 
 	/* AP might have been stopped while waiting for the lock. */
 	if (!sdata->vif.csa_active)
@@ -3150,6 +3169,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
 	}
 
 unlock:
+	mutex_unlock(&local->chanctx_mtx);
 	mutex_unlock(&local->mtx);
 	sdata_unlock(sdata);
 }
@@ -3284,7 +3304,7 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *chanctx;
-	int err, num_chanctx, changed = 0;
+	int err, changed = 0;
 
 	sdata_assert_lock(sdata);
 	lockdep_assert_held(&local->mtx);
@@ -3299,37 +3319,43 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 				       &sdata->vif.bss_conf.chandef))
 		return -EINVAL;
 
+	/* don't allow another channel switch if one is already active. */
+	if (sdata->vif.csa_active)
+		return -EBUSY;
+
 	mutex_lock(&local->chanctx_mtx);
 	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 					 lockdep_is_held(&local->chanctx_mtx));
 	if (!conf) {
-		mutex_unlock(&local->chanctx_mtx);
-		return -EBUSY;
+		err = -EBUSY;
+		goto out;
 	}
 
-	/* don't handle for multi-VIF cases */
 	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
-	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
-		mutex_unlock(&local->chanctx_mtx);
-		return -EBUSY;
+	if (!chanctx) {
+		err = -EBUSY;
+		goto out;
 	}
-	num_chanctx = 0;
-	list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
-		num_chanctx++;
-	mutex_unlock(&local->chanctx_mtx);
 
-	if (num_chanctx > 1)
-		return -EBUSY;
+	err = ieee80211_vif_reserve_chanctx(sdata, &params->chandef,
+					    chanctx->mode,
+					    params->radar_required);
+	if (err)
+		goto out;
 
-	/* don't allow another channel switch if one is already active. */
-	if (sdata->vif.csa_active)
-		return -EBUSY;
+	/* if reservation is invalid then this will fail */
+	err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0);
+	if (err) {
+		ieee80211_vif_unreserve_chanctx(sdata);
+		goto out;
+	}
 
 	err = ieee80211_set_csa_beacon(sdata, params, &changed);
-	if (err)
-		return err;
+	if (err) {
+		ieee80211_vif_unreserve_chanctx(sdata);
+		goto out;
+	}
 
-	sdata->csa_radar_required = params->radar_required;
 	sdata->csa_chandef = params->chandef;
 	sdata->csa_block_tx = params->block_tx;
 	sdata->vif.csa_active = true;
@@ -3347,7 +3373,9 @@ int __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 		ieee80211_csa_finalize(sdata);
 	}
 
-	return 0;
+out:
+	mutex_unlock(&local->chanctx_mtx);
+	return err;
 }
 
 int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index cc9e817..48d3d15 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -963,7 +963,16 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 static void
 ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
 {
-	/* stub */
+	switch (sdata->vif.type) {
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MESH_POINT:
+		ieee80211_queue_work(&sdata->local->hw,
+				     &sdata->csa_finalize_work);
+		break;
+	default:
+		break;
+	}
 }
 
 static int
-- 
1.8.5.3


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

* [PATCH v4 3/5] mac80211: use chanctx reservation for STA CSA
  2014-04-09 13:45     ` [PATCH v4 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
  2014-04-09 13:45       ` [PATCH v4 1/5] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
  2014-04-09 13:45       ` [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA Michal Kazior
@ 2014-04-09 13:45       ` Michal Kazior
  2014-05-06 14:43         ` Johannes Berg
  2014-04-09 13:45       ` [PATCH v4 4/5] mac80211: ignore cqm during csa Michal Kazior
  2014-04-09 13:45       ` [PATCH v4 5/5] cfg80211: remove channel_switch combination check Michal Kazior
  4 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:45 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

Channel switch finalization is now 2-step. First
step is when driver calls chswitch_done(), the
other is when reservation is actually finalized
(which be defered for in-place reservation).

It is now safe to call ieee80211_chswitch_done()
more than once.

Also remove the ieee80211_vif_change_channel()
because it is no longer used.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v3:
 * fix comment style [Johannes]
 * add resilience for multiple ieee80211_chswitch_done() calls

v3:
 * fix lockdep typo s/mtx/chanctx_mtx/ [Johannes]
 * fix comment style [Johannes]
 * use goto for cleaner unlocking/returning [Johannes]
 * squash with ieee80211_vif_change_channel() removal patch [Johannes]
 * fix commit message [Johannes]
 * add resilience for multiple ieee80211_csa_finish() calls

v4:
 * squash with removal of ieee80211_vif_change_channel()

 net/mac80211/chan.c        | 68 ++-------------------------------
 net/mac80211/ieee80211_i.h |  5 ---
 net/mac80211/mlme.c        | 94 ++++++++++++++++++++++++++++++----------------
 3 files changed, 65 insertions(+), 102 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 48d3d15..4c5bcfc 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -798,70 +798,6 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 	return ret;
 }
 
-static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-					  struct ieee80211_chanctx *ctx,
-					  u32 *changed)
-{
-	struct ieee80211_local *local = sdata->local;
-	const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;
-	u32 chanctx_changed = 0;
-
-	if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
-				     IEEE80211_CHAN_DISABLED))
-		return -EINVAL;
-
-	if (ieee80211_chanctx_refcount(local, ctx) != 1)
-		return -EINVAL;
-
-	if (sdata->vif.bss_conf.chandef.width != chandef->width) {
-		chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH;
-		*changed |= BSS_CHANGED_BANDWIDTH;
-	}
-
-	sdata->vif.bss_conf.chandef = *chandef;
-	ctx->conf.def = *chandef;
-
-	chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL;
-	drv_change_chanctx(local, ctx, chanctx_changed);
-
-	ieee80211_recalc_chanctx_chantype(local, ctx);
-	ieee80211_recalc_smps_chanctx(local, ctx);
-	ieee80211_recalc_radar_chanctx(local, ctx);
-	ieee80211_recalc_chanctx_min_def(local, ctx);
-
-	return 0;
-}
-
-int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-				 u32 *changed)
-{
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx_conf *conf;
-	struct ieee80211_chanctx *ctx;
-	int ret;
-
-	lockdep_assert_held(&local->mtx);
-
-	/* should never be called if not performing a channel switch. */
-	if (WARN_ON(!sdata->vif.csa_active))
-		return -EINVAL;
-
-	mutex_lock(&local->chanctx_mtx);
-	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	ctx = container_of(conf, struct ieee80211_chanctx, conf);
-
-	ret = __ieee80211_vif_change_channel(sdata, ctx, changed);
- out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
-}
-
 static void
 __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 				      bool clear)
@@ -970,6 +906,10 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
 		ieee80211_queue_work(&sdata->local->hw,
 				     &sdata->csa_finalize_work);
 		break;
+	case NL80211_IFTYPE_STATION:
+		ieee80211_queue_work(&sdata->local->hw,
+				     &sdata->u.mgd.chswitch_work);
+		break;
 	default:
 		break;
 	}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4b8c5fe..4791f60 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -755,7 +755,6 @@ struct ieee80211_sub_if_data {
 	struct work_struct csa_finalize_work;
 	int csa_counter_offset_beacon;
 	int csa_counter_offset_presp;
-	bool csa_radar_required;
 	bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
 	struct cfg80211_chan_def csa_chandef;
 
@@ -1796,10 +1795,6 @@ int __must_check
 ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
 			       const struct cfg80211_chan_def *chandef,
 			       u32 *changed);
-/* NOTE: only use ieee80211_vif_change_channel() for channel switch */
-int __must_check
-ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-			     u32 *changed);
 void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0ea337d..f87cbf6 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -940,55 +940,75 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 		container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	u32 changed = 0;
 	int ret;
 
 	if (!ieee80211_sdata_running(sdata))
 		return;
 
 	sdata_lock(sdata);
+	mutex_lock(&local->mtx);
+	mutex_lock(&local->chanctx_mtx);
+
 	if (!ifmgd->associated)
 		goto out;
 
-	mutex_lock(&local->mtx);
-	ret = ieee80211_vif_change_channel(sdata, &changed);
-	mutex_unlock(&local->mtx);
-	if (ret) {
+	if (!sdata->vif.csa_active)
+		goto out;
+
+	/*
+	 * using reservation isn't immediate as it may be deferred until later
+	 * with multi-vif. once reservation is complete it will re-schedule the
+	 * work with no reserved_chanctx so verify chandef to check if it
+	 * completed successfully
+	 */
+
+	if (sdata->reserved_chanctx) {
+		/*
+		 * with multi-vif csa driver may call ieee80211_csa_finish()
+		 * many times while waiting for other interfaces to use their
+		 * reservations
+		 */
+		if (sdata->reserved_ready)
+			goto out;
+
+		ret = ieee80211_vif_use_reserved_context(sdata);
+		if (ret) {
+			sdata_info(sdata,
+				   "failed to use reserved channel context, disconnecting (err=%d)\n",
+				   ret);
+			ieee80211_queue_work(&sdata->local->hw,
+					     &ifmgd->csa_connection_drop_work);
+			goto out;
+		}
+
+		goto out;
+	}
+
+	if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
+					&sdata->csa_chandef)) {
 		sdata_info(sdata,
-			   "vif channel switch failed, disconnecting\n");
+			   "failed to finalize channel switch, disconnecting\n");
 		ieee80211_queue_work(&sdata->local->hw,
 				     &ifmgd->csa_connection_drop_work);
 		goto out;
 	}
 
-	if (!local->use_chanctx) {
-		local->_oper_chandef = sdata->csa_chandef;
-		/* Call "hw_config" only if doing sw channel switch.
-		 * Otherwise update the channel directly
-		 */
-		if (!local->ops->channel_switch)
-			ieee80211_hw_config(local, 0);
-		else
-			local->hw.conf.chandef = local->_oper_chandef;
-	}
-
 	/* XXX: shouldn't really modify cfg80211-owned data! */
 	ifmgd->associated->channel = sdata->csa_chandef.chan;
 
-	ieee80211_bss_info_change_notify(sdata, changed);
-
-	mutex_lock(&local->mtx);
 	sdata->vif.csa_active = false;
+
 	/* XXX: wait for a beacon first? */
 	if (!ieee80211_csa_needs_block_tx(local))
 		ieee80211_wake_queues_by_reason(&local->hw,
 					IEEE80211_MAX_QUEUE_MAP,
 					IEEE80211_QUEUE_STOP_REASON_CSA);
-	mutex_unlock(&local->mtx);
 
 	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
 
 out:
+	mutex_unlock(&local->chanctx_mtx);
+	mutex_unlock(&local->mtx);
 	sdata_unlock(sdata);
 }
 
@@ -1025,6 +1045,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct cfg80211_bss *cbss = ifmgd->associated;
+	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *chanctx;
 	enum ieee80211_band current_band;
 	struct ieee80211_csa_ie csa_ie;
@@ -1069,6 +1090,19 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
 
 	mutex_lock(&local->chanctx_mtx);
+	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+					 lockdep_is_held(&local->chanctx_mtx));
+	if (!conf) {
+		sdata_info(sdata,
+			   "no channel context assigned to vif?, disconnecting\n");
+		ieee80211_queue_work(&local->hw,
+				     &ifmgd->csa_connection_drop_work);
+		mutex_unlock(&local->chanctx_mtx);
+		return;
+	}
+
+	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
+
 	if (local->use_chanctx) {
 		u32 num_chanctx = 0;
 		list_for_each_entry(chanctx, &local->chanctx_list, list)
@@ -1085,17 +1119,12 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
-	if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) {
-		ieee80211_queue_work(&local->hw,
-				     &ifmgd->csa_connection_drop_work);
-		mutex_unlock(&local->chanctx_mtx);
-		return;
-	}
-	chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
-			       struct ieee80211_chanctx, conf);
-	if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
+	res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef,
+					    chanctx->mode, false);
+	if (res) {
 		sdata_info(sdata,
-			   "channel switch with multiple interfaces on the same channel, disconnecting\n");
+			   "failed to reserve channel context for channel switch, disconnecting (err=%d)\n",
+			   res);
 		ieee80211_queue_work(&local->hw,
 				     &ifmgd->csa_connection_drop_work);
 		mutex_unlock(&local->chanctx_mtx);
@@ -1103,10 +1132,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	}
 	mutex_unlock(&local->chanctx_mtx);
 
-	sdata->csa_chandef = csa_ie.chandef;
-
 	mutex_lock(&local->mtx);
 	sdata->vif.csa_active = true;
+	sdata->csa_chandef = csa_ie.chandef;
 	sdata->csa_block_tx = csa_ie.mode;
 
 	if (sdata->csa_block_tx)
-- 
1.8.5.3


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

* [PATCH v4 4/5] mac80211: ignore cqm during csa
  2014-04-09 13:45     ` [PATCH v4 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
                         ` (2 preceding siblings ...)
  2014-04-09 13:45       ` [PATCH v4 3/5] mac80211: use chanctx reservation for STA CSA Michal Kazior
@ 2014-04-09 13:45       ` Michal Kazior
  2014-05-06 14:45         ` Johannes Berg
  2014-04-09 13:45       ` [PATCH v4 5/5] cfg80211: remove channel_switch combination check Michal Kazior
  4 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:45 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

It is not guaranteed that multi-vif channel
switching is tightly synchronized. It makes sense
to ignore cqm (missing beacons, et al) while csa
is progressing and re-check it after it completes.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/mlme.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index f87cbf6..417db18 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1006,6 +1006,9 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 
 	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
 
+	ieee80211_sta_reset_beacon_monitor(sdata);
+	ieee80211_sta_reset_conn_monitor(sdata);
+
 out:
 	mutex_unlock(&local->chanctx_mtx);
 	mutex_unlock(&local->mtx);
@@ -3593,6 +3596,9 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
 	if (local->quiescing)
 		return;
 
+	if (sdata->vif.csa_active)
+		return;
+
 	sdata->u.mgd.connection_loss = false;
 	ieee80211_queue_work(&sdata->local->hw,
 			     &sdata->u.mgd.beacon_connection_loss_work);
@@ -3608,6 +3614,9 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data)
 	if (local->quiescing)
 		return;
 
+	if (sdata->vif.csa_active)
+		return;
+
 	ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
 }
 
-- 
1.8.5.3


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

* [PATCH v4 5/5] cfg80211: remove channel_switch combination check
  2014-04-09 13:45     ` [PATCH v4 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
                         ` (3 preceding siblings ...)
  2014-04-09 13:45       ` [PATCH v4 4/5] mac80211: ignore cqm during csa Michal Kazior
@ 2014-04-09 13:45       ` Michal Kazior
  2014-05-06 14:45         ` Johannes Berg
  4 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-04-09 13:45 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

Make the driver responsible for making sure it is
capable of performing the switch. It might as well
accept a request but then disconnect an interface
if some requirements are not met.

In that case userspace should be prepared for an
appropriate event (AP/IBSS/mesh being stopped/left).

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/wireless/nl80211.c | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 232d15c..84aeb80 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5932,17 +5932,6 @@ skip_beacons:
 		params.radar_required = true;
 	}
 
-	/* TODO: I left this here for now.  With channel switch, the
-	 * verification is a bit more complicated, because we only do
-	 * it later when the channel switch really happens.
-	 */
-	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-					   params.chandef.chan,
-					   CHAN_MODE_SHARED,
-					   radar_detect_width);
-	if (err)
-		return err;
-
 	if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
 		params.block_tx = true;
 
-- 
1.8.5.3


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

* Re: [PATCH v4 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations
  2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
                         ` (12 preceding siblings ...)
  2014-04-09 13:29       ` [PATCH v4 13/13] mac80211: implement multi-vif in-place reservations Michal Kazior
@ 2014-04-25 15:20       ` Johannes Berg
  2014-04-28  6:16         ` Michal Kazior
  13 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-04-25 15:20 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, luca

Hi,

> The patchset incrementally improves chanctx
> reservations in order to support multi-vif
> reservations and in-place multi-vif reservations
> (typically for single-channel hardware, but
> multi-channel benefits from this too).

I've applied the first 12 patches, i.e. all but patch 13. As far as
patch 13 is concerned, I (a) need more time to review it, and (b) would
like to understand better how you intend to use it.

I also don't really like the "stub" thing. :)

Maybe it would also make sense to insert the "recalc" refactoring
somewhere around here?

johannes


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

* Re: [PATCH v4 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations
  2014-04-25 15:20       ` [PATCH v4 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Johannes Berg
@ 2014-04-28  6:16         ` Michal Kazior
  0 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-04-28  6:16 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Luca Coelho

On 25 April 2014 17:20, Johannes Berg <johannes@sipsolutions.net> wrote:
> Hi,
>
>> The patchset incrementally improves chanctx
>> reservations in order to support multi-vif
>> reservations and in-place multi-vif reservations
>> (typically for single-channel hardware, but
>> multi-channel benefits from this too).
>
> I've applied the first 12 patches, i.e. all but patch 13. As far as
> patch 13 is concerned, I (a) need more time to review it, and (b) would
> like to understand better how you intend to use it.

Sure.


> I also don't really like the "stub" thing. :)

I agree that it's not the most beautiful thing to have but I wanted to
make my intention clear how conflicting channel reservation/switching
is going to be handled (AP and CSA channel switching patches come
later). I can remove the stub and just introduce the hook in one of
the channel switching patches or I can change the comment to something
more meaningful if that makes any more sense to you.


> Maybe it would also make sense to insert the "recalc" refactoring
> somewhere around here?

Do you mean Zhao Gang's recalc refactoring patches? Patch 13 stills
interacts with some recalc code and might produce minor conflicts.


Michał

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

* Re: [v4 13/13] mac80211: implement multi-vif in-place reservations
  2014-04-09 13:29       ` [PATCH v4 13/13] mac80211: implement multi-vif in-place reservations Michal Kazior
@ 2014-04-28 16:32         ` Zhao, Gang
  2014-04-29  6:10           ` Michal Kazior
  2014-04-30  9:21         ` [PATCH v5] " Michal Kazior
  1 sibling, 1 reply; 199+ messages in thread
From: Zhao, Gang @ 2014-04-28 16:32 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, johannes

Hi Michal,

+	kfree_rcu(ctx, rcu_head);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs,
+			    reserved_chanctx_list) {

I'm not very familiar with rcu, but this doesn't seems right ?

I noticed it when rebasing my recalc refactoring code on your patches. :-)

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

* Re: [v4 13/13] mac80211: implement multi-vif in-place reservations
  2014-04-28 16:32         ` [v4 " Zhao, Gang
@ 2014-04-29  6:10           ` Michal Kazior
  2014-04-29 19:44             ` Johannes Berg
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-04-29  6:10 UTC (permalink / raw)
  To: Zhao, Gang; +Cc: linux-wireless, Johannes Berg

On 28 April 2014 18:32, Zhao, Gang <gamerh2o@gmail.com> wrote:
> Hi Michal,
>
> +       kfree_rcu(ctx, rcu_head);
> +
> +       list_for_each_entry(sdata, &ctx->reserved_vifs,
> +                           reserved_chanctx_list) {
>
> I'm not very familiar with rcu, but this doesn't seems right ?
>
> I noticed it when rebasing my recalc refactoring code on your patches. :-)

Great catch, thanks! kfree_rcu() should be called just before the return 0.


Michał

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

* Re: [v4 13/13] mac80211: implement multi-vif in-place reservations
  2014-04-29  6:10           ` Michal Kazior
@ 2014-04-29 19:44             ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-04-29 19:44 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Zhao, Gang, linux-wireless

On Tue, 2014-04-29 at 08:10 +0200, Michal Kazior wrote:
> On 28 April 2014 18:32, Zhao, Gang <gamerh2o@gmail.com> wrote:
> > Hi Michal,
> >
> > +       kfree_rcu(ctx, rcu_head);
> > +
> > +       list_for_each_entry(sdata, &ctx->reserved_vifs,
> > +                           reserved_chanctx_list) {
> >
> > I'm not very familiar with rcu, but this doesn't seems right ?
> >
> > I noticed it when rebasing my recalc refactoring code on your patches. :-)
> 
> Great catch, thanks! kfree_rcu() should be called just before the return 0.

Care to send a patch?

johannes


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

* [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-04-09 13:29       ` [PATCH v4 13/13] mac80211: implement multi-vif in-place reservations Michal Kazior
  2014-04-28 16:32         ` [v4 " Zhao, Gang
@ 2014-04-30  9:21         ` Michal Kazior
  2014-05-06 10:41           ` Johannes Berg
  1 sibling, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-04-30  9:21 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, luca, Michal Kazior

Multi-vif in-place reservations happen when
it's impossible to allocate more chanctx as per
driver combinations.

Such reservations aren't finalized until last
reservation interface calls in to use the
reservation.

This introduces a special hook
ieee80211_vif_chanctx_reservation_complete(). This
is currently an empty stub and will be filled in
by AP/STA CSA code. This is required to implement
2-step CSA finalization.

This also gets rid of driver requirement to be
able to re-program channel of a chanctx.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
v2:
 * use new_ctx instead of ctx [Eliad]
 * move recalcs after bss_conf is updated [Eliad]

v4:
 * move recalc-radar before vif-chanctx-assign [Eliad]
 * move radar_required swapping before initial add_chanctx() [Eliad]

v5:
 * move kfree_rcu() [Zhao Gang]


This was originally PATCH [13/13] of my
`cfg80211/mac80211: implement multi-vif chanctx
reservations`.


 include/net/mac80211.h     |   7 --
 net/mac80211/chan.c        | 282 +++++++++++++++++++++++++++++++++------------
 net/mac80211/ieee80211_i.h |   4 +-
 3 files changed, 209 insertions(+), 84 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 451c1bf..9f2422d 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1559,12 +1559,6 @@ struct ieee80211_tx_control {
  *	for a single active channel while using channel contexts. When support
  *	is not enabled the default action is to disconnect when getting the
  *	CSA frame.
- *
- * @IEEE80211_HW_CHANGE_RUNNING_CHANCTX: The hardware can change a
- *	channel context on-the-fly.  This is needed for channel switch
- *	on single-channel hardware.  It can also be used as an
- *	optimization in certain channel switch cases with
- *	multi-channel.
  */
 enum ieee80211_hw_flags {
 	IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0,
@@ -1596,7 +1590,6 @@ enum ieee80211_hw_flags {
 	IEEE80211_HW_TIMING_BEACON_ONLY			= 1<<26,
 	IEEE80211_HW_SUPPORTS_HT_CCK_RATES		= 1<<27,
 	IEEE80211_HW_CHANCTX_STA_CSA			= 1<<28,
-	IEEE80211_HW_CHANGE_RUNNING_CHANCTX		= 1<<29,
 };
 
 /**
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index d8b1b86..859c7ba 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -173,6 +173,24 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
 	return NULL;
 }
 
+static bool
+ieee80211_chanctx_all_reserved_vifs_ready(struct ieee80211_local *local,
+					  struct ieee80211_chanctx *ctx)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		if (!sdata->reserved_chanctx)
+			continue;
+		if (!sdata->reserved_ready)
+			return false;
+	}
+
+	return true;
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
 	switch (sta->bandwidth) {
@@ -912,38 +930,24 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *new_ctx, *curr_ctx;
-	int ret = 0;
 
-	mutex_lock(&local->chanctx_mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
 	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf) {
-		ret = -EINVAL;
-		goto out;
-	}
+	if (!conf)
+		return -EINVAL;
 
 	curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
 	new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
 	if (!new_ctx) {
-		if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 &&
-		    (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
-			/* if we're the only users of the chanctx and
-			 * the driver supports changing a running
-			 * context, reserve our current context
-			 */
-			new_ctx = curr_ctx;
-		} else if (ieee80211_can_create_new_chanctx(local)) {
-			/* create a new context and reserve it */
+		if (ieee80211_can_create_new_chanctx(local)) {
 			new_ctx = ieee80211_new_chanctx(local, chandef, mode);
-			if (IS_ERR(new_ctx)) {
-				ret = PTR_ERR(new_ctx);
-				goto out;
-			}
+			if (IS_ERR(new_ctx))
+				return PTR_ERR(new_ctx);
 		} else {
-			ret = -EBUSY;
-			goto out;
+			new_ctx = curr_ctx;
 		}
 	}
 
@@ -951,82 +955,210 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 	sdata->reserved_chanctx = new_ctx;
 	sdata->reserved_chandef = *chandef;
 	sdata->reserved_radar_required = radar_required;
-out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
+	sdata->reserved_ready = false;
+
+	return 0;
 }
 
-int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
-				       u32 *changed)
+static void
+ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx *ctx;
-	struct ieee80211_chanctx *old_ctx;
-	struct ieee80211_chanctx_conf *conf;
-	int ret;
-	u32 tmp_changed = *changed;
+	/* stub */
+}
 
-	/* TODO: need to recheck if the chandef is usable etc.? */
+static int
+ieee80211_vif_use_reserved_incompat(struct ieee80211_local *local,
+				    struct ieee80211_chanctx *ctx,
+				    const struct cfg80211_chan_def *chandef)
+{
+	struct ieee80211_sub_if_data *sdata, *tmp;
+	struct ieee80211_chanctx *new_ctx;
+	u32 changed = 0;
+	int err;
 
 	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	mutex_lock(&local->chanctx_mtx);
+	if (!ieee80211_chanctx_all_reserved_vifs_ready(local, ctx))
+		return 0;
 
-	ctx = sdata->reserved_chanctx;
-	if (WARN_ON(!ctx)) {
-		ret = -EINVAL;
-		goto out;
+	if (ieee80211_chanctx_num_assigned(local, ctx) !=
+	    ieee80211_chanctx_num_reserved(local, ctx)) {
+		wiphy_info(local->hw.wiphy,
+			   "channel context reservation cannot be finalized because some interfaces aren't switching\n");
+		err = -EBUSY;
+		goto err;
 	}
 
-	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf) {
-		ret = -EINVAL;
+	new_ctx = ieee80211_alloc_chanctx(local, chandef, ctx->mode);
+	if (!new_ctx) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		drv_unassign_vif_chanctx(local, sdata, ctx);
+		rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
+	}
+
+	list_del_rcu(&ctx->list);
+	ieee80211_del_chanctx(local, ctx);
+
+	/* don't simply overwrite radar_required in case of failure */
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		bool tmp = sdata->radar_required;
+		sdata->radar_required = sdata->reserved_radar_required;
+		sdata->reserved_radar_required = tmp;
+	}
+
+	ieee80211_recalc_radar_chanctx(local, new_ctx);
+
+	err = ieee80211_add_chanctx(local, new_ctx);
+	if (err)
+		goto err_revert;
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		err = drv_assign_vif_chanctx(local, sdata, new_ctx);
+		if (err)
+			goto err_unassign;
+	}
+
+	if (sdata->vif.type == NL80211_IFTYPE_AP)
+		__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
+
+	list_add_rcu(&new_ctx->list, &local->chanctx_list);
+
+	list_for_each_entry(sdata, &ctx->reserved_vifs,
+			    reserved_chanctx_list) {
+		changed = 0;
+		if (sdata->vif.bss_conf.chandef.width !=
+		    sdata->reserved_chandef.width)
+			changed = BSS_CHANGED_BANDWIDTH;
+
+		sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
+		if (changed)
+			ieee80211_bss_info_change_notify(sdata, changed);
+
+		ieee80211_recalc_txpower(sdata);
+	}
+
+	ieee80211_recalc_chanctx_chantype(local, new_ctx);
+	ieee80211_recalc_smps_chanctx(local, new_ctx);
+	ieee80211_recalc_chanctx_min_def(local, new_ctx);
+
+	list_for_each_entry_safe(sdata, tmp, &ctx->reserved_vifs,
+				 reserved_chanctx_list) {
+		list_del(&sdata->reserved_chanctx_list);
+		list_move(&sdata->assigned_chanctx_list,
+			  &new_ctx->assigned_vifs);
+		sdata->reserved_chanctx = NULL;
+
+		ieee80211_vif_chanctx_reservation_complete(sdata);
+	}
+
+	kfree_rcu(ctx, rcu_head);
+	return 0;
+
+err_unassign:
+	list_for_each_entry_continue_reverse(sdata, &ctx->reserved_vifs,
+					     reserved_chanctx_list)
+		drv_unassign_vif_chanctx(local, sdata, ctx);
+	ieee80211_del_chanctx(local, new_ctx);
+err_revert:
+	kfree_rcu(new_ctx, rcu_head);
+	WARN_ON(ieee80211_add_chanctx(local, ctx));
+	list_add_rcu(&ctx->list, &local->chanctx_list);
+	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
+		sdata->radar_required = sdata->reserved_radar_required;
+		rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
+		WARN_ON(drv_assign_vif_chanctx(local, sdata, ctx));
+	}
+err:
+	list_for_each_entry_safe(sdata, tmp, &ctx->reserved_vifs,
+				 reserved_chanctx_list) {
+		list_del(&sdata->reserved_chanctx_list);
+		sdata->reserved_chanctx = NULL;
+		ieee80211_vif_chanctx_reservation_complete(sdata);
+	}
+	return err;
+}
+
+static int
+ieee80211_vif_use_reserved_compat(struct ieee80211_sub_if_data *sdata,
+				  struct ieee80211_chanctx *old_ctx,
+				  struct ieee80211_chanctx *new_ctx)
+{
+	struct ieee80211_local *local = sdata->local;
+	u32 changed = 0;
+	int err;
+
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	list_del(&sdata->reserved_chanctx_list);
+	sdata->reserved_chanctx = NULL;
+
+	err = ieee80211_assign_vif_chanctx(sdata, new_ctx);
+	if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
+		ieee80211_free_chanctx(local, old_ctx);
+	if (err) {
+		/* if assign fails refcount stays the same */
+		if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
+			ieee80211_free_chanctx(local, new_ctx);
 		goto out;
 	}
 
-	old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
+	if (sdata->vif.type == NL80211_IFTYPE_AP)
+		__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
 
 	if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
-		tmp_changed |= BSS_CHANGED_BANDWIDTH;
+		changed = BSS_CHANGED_BANDWIDTH;
 
 	sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
 
-	/* unref our reservation */
-	sdata->reserved_chanctx = NULL;
-	sdata->radar_required = sdata->reserved_radar_required;
-	list_del(&sdata->reserved_chanctx_list);
+	if (changed)
+		ieee80211_bss_info_change_notify(sdata, changed);
 
-	if (old_ctx == ctx) {
-		/* This is our own context, just change it */
-		ret = __ieee80211_vif_change_channel(sdata, old_ctx,
-						     &tmp_changed);
-		if (ret)
-			goto out;
-	} else {
-		ret = ieee80211_assign_vif_chanctx(sdata, ctx);
-		if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
-			ieee80211_free_chanctx(local, old_ctx);
-		if (ret) {
-			/* if assign fails refcount stays the same */
-			if (ieee80211_chanctx_refcount(local, ctx) == 0)
-				ieee80211_free_chanctx(local, ctx);
-			goto out;
-		}
+out:
+	ieee80211_vif_chanctx_reservation_complete(sdata);
+	return err;
+}
 
-		if (sdata->vif.type == NL80211_IFTYPE_AP)
-			__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
-	}
+int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_chanctx *ctx;
+	struct ieee80211_chanctx *old_ctx;
+	struct ieee80211_chanctx_conf *conf;
+	const struct cfg80211_chan_def *chandef;
 
-	*changed = tmp_changed;
+	lockdep_assert_held(&local->mtx);
+	lockdep_assert_held(&local->chanctx_mtx);
 
-	ieee80211_recalc_chanctx_chantype(local, ctx);
-	ieee80211_recalc_smps_chanctx(local, ctx);
-	ieee80211_recalc_radar_chanctx(local, ctx);
-	ieee80211_recalc_chanctx_min_def(local, ctx);
-out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
+	ctx = sdata->reserved_chanctx;
+	if (WARN_ON(!ctx))
+		return -EINVAL;
+
+	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+					 lockdep_is_held(&local->chanctx_mtx));
+	if (!conf)
+		return -EINVAL;
+
+	old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
+
+	if (WARN_ON(sdata->reserved_ready))
+		return -EINVAL;
+
+	chandef = ieee80211_chanctx_reserved_chandef(local, ctx, NULL);
+	if (WARN_ON(!chandef))
+		return -EINVAL;
+
+	sdata->reserved_ready = true;
+
+	if (cfg80211_chandef_compatible(&ctx->conf.def, chandef))
+		return ieee80211_vif_use_reserved_compat(sdata, old_ctx, ctx);
+	else
+		return ieee80211_vif_use_reserved_incompat(local, ctx, chandef);
 }
 
 int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index b455f62..340645b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -765,6 +765,7 @@ struct ieee80211_sub_if_data {
 	struct ieee80211_chanctx *reserved_chanctx;
 	struct cfg80211_chan_def reserved_chandef;
 	bool reserved_radar_required;
+	bool reserved_ready;
 
 	/* used to reconfigure hardware SM PS */
 	struct work_struct recalc_smps;
@@ -1786,8 +1787,7 @@ ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 			      enum ieee80211_chanctx_mode mode,
 			      bool radar_required);
 int __must_check
-ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
-				   u32 *changed);
+ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata);
 int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata);
 
 int __must_check
-- 
1.8.5.3


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-04-30  9:21         ` [PATCH v5] " Michal Kazior
@ 2014-05-06 10:41           ` Johannes Berg
  2014-05-06 12:47             ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-06 10:41 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, luca, Simon Wunderlich

Hi Michal, all,

So I finally got around to discussing this with Luca and getting a
better understanding of what we have right now and where we're going to
this. Unfortunately (for you :) ) I don't think we're quite on the right
track between what we have and what you (and others) are doing here and
what we'll want.

>  	IEEE80211_HW_CHANCTX_STA_CSA			= 1<<28,
> -	IEEE80211_HW_CHANGE_RUNNING_CHANCTX		= 1<<29,

Right now we have this, along with WIPHY_FLAG_HAS_CHANNEL_SWITCH (which
we still turn off upstream though)

> +	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
> +		drv_unassign_vif_chanctx(local, sdata, ctx);
> +		rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
> +	}
> +
> +	list_del_rcu(&ctx->list);
> +	ieee80211_del_chanctx(local, ctx);
> +
> +	/* don't simply overwrite radar_required in case of failure */
> +	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
> +		bool tmp = sdata->radar_required;
> +		sdata->radar_required = sdata->reserved_radar_required;
> +		sdata->reserved_radar_required = tmp;
> +	}
> +
> +	ieee80211_recalc_radar_chanctx(local, new_ctx);
> +
> +	err = ieee80211_add_chanctx(local, new_ctx);
> +	if (err)
> +		goto err_revert;
> +
> +	list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
> +		err = drv_assign_vif_chanctx(local, sdata, new_ctx);
> +		if (err)
> +			goto err_unassign;
> +	}

I think this is problematic in terms of the channel context API, as is
the "unassign while in use" case of ieee80211_vif_use_reserved_context()
through the call of ieee80211_assign_vif_chanctx() (unassign is inside
of that.)

Without those APIs, we have perfect ordering between using the channel
context and having the interface active (interfaces have to be idle
while no channel context is assigned). The logic here breaks this, which
could cause issues.

In fact, drivers now will have to rely on out-of-band information (e.g.
vif->csa_active) to detect that this is not a "real" unassign, but
rather a temporary one, and then rely on getting the new assignment
immediately.

Going back to this out-of-band information is not only ugly in the
driver, but also makes the API less predictable IMHO. It also doesn't
allow for drivers that have the ability to change a channel context on
the fly - in which case none of this add/remove stuff would really be
needed.

Luca and I discussed this and came up with this suggested new API:

/**
 * enum ieee80211_chanctx_switch_mode - channel context switch mode
 * @CHANCTX_SWMODE_REASSIGN_VIF: Both old and new contexts already exist
 *	(and may continue to exist), but the virtual interface needs to
 *	be switched from one to the other
 * @CHANCTX_SWMODE_SWAP_CONTEXTS: The old context exists but will stop
to
 *	exist with this call, the new context doesn't exist but will be
 *	active after this call, the virtual interface switches from the
 *	old to the new (note that the driver may of course implement this
 *	as an on-the-fly chandef switch of the existing hardware context,
 *	but the mac80211 pointer for the old context will cease to exist
 *	and only the new one will later be used for changes/removal.)
 */
enum ieee80211_chanctx_switch_mode {
	CHANCTX_SWMODE_REASSIGN_VIF,
	CHANCTX_SWMODE_SWAP_CONTEXTS,
};

	(*switch_vif_chanctx)(struct ieee80211_hw *hw,
			    struct ieee80211_vif *vif,
			    struct ieee80211_chanctx_conf *old_ctx,
			    struct ieee80211_chanctx_conf *new_ctx,
			    enum ieee80211_chanctx_switch_mode mode);



Separately, I think due to the complexities involved in the driver
implementation we'll probably need a bitmap indicating which interface
types are supported (this is not something we do today, and this would
be broken in iwlwifi for sure.)

As a result, I'm going to drop this patch, which likely also means your
other 5-patch series won't apply?

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-06 10:41           ` Johannes Berg
@ 2014-05-06 12:47             ` Michal Kazior
  2014-05-06 14:05               ` Johannes Berg
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-06 12:47 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Luca Coelho, Simon Wunderlich

On 6 May 2014 12:41, Johannes Berg <johannes@sipsolutions.net> wrote:
> Hi Michal, all,
>
> So I finally got around to discussing this with Luca and getting a
> better understanding of what we have right now and where we're going to
> this. Unfortunately (for you :) ) I don't think we're quite on the right
> track between what we have and what you (and others) are doing here and
> what we'll want.

Yay! :-)


>
>>       IEEE80211_HW_CHANCTX_STA_CSA                    = 1<<28,
>> -     IEEE80211_HW_CHANGE_RUNNING_CHANCTX             = 1<<29,
>
> Right now we have this, along with WIPHY_FLAG_HAS_CHANNEL_SWITCH (which
> we still turn off upstream though)
>
>> +     list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>> +             drv_unassign_vif_chanctx(local, sdata, ctx);
>> +             rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
>> +     }
>> +
>> +     list_del_rcu(&ctx->list);
>> +     ieee80211_del_chanctx(local, ctx);
>> +
>> +     /* don't simply overwrite radar_required in case of failure */
>> +     list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>> +             bool tmp = sdata->radar_required;
>> +             sdata->radar_required = sdata->reserved_radar_required;
>> +             sdata->reserved_radar_required = tmp;
>> +     }
>> +
>> +     ieee80211_recalc_radar_chanctx(local, new_ctx);
>> +
>> +     err = ieee80211_add_chanctx(local, new_ctx);
>> +     if (err)
>> +             goto err_revert;
>> +
>> +     list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) {
>> +             err = drv_assign_vif_chanctx(local, sdata, new_ctx);
>> +             if (err)
>> +                     goto err_unassign;
>> +     }
>
> I think this is problematic in terms of the channel context API, as is
> the "unassign while in use" case of ieee80211_vif_use_reserved_context()
> through the call of ieee80211_assign_vif_chanctx() (unassign is inside
> of that.)
>
> Without those APIs, we have perfect ordering between using the channel
> context and having the interface active (interfaces have to be idle
> while no channel context is assigned). The logic here breaks this, which
> could cause issues.
>
> In fact, drivers now will have to rely on out-of-band information (e.g.
> vif->csa_active) to detect that this is not a "real" unassign, but
> rather a temporary one, and then rely on getting the new assignment
> immediately.
>
> Going back to this out-of-band information is not only ugly in the
> driver, but also makes the API less predictable IMHO. It also doesn't
> allow for drivers that have the ability to change a channel context on
> the fly - in which case none of this add/remove stuff would really be
> needed.
>
> Luca and I discussed this and came up with this suggested new API:
>
> /**
>  * enum ieee80211_chanctx_switch_mode - channel context switch mode
>  * @CHANCTX_SWMODE_REASSIGN_VIF: Both old and new contexts already exist
>  *      (and may continue to exist), but the virtual interface needs to
>  *      be switched from one to the other
>  * @CHANCTX_SWMODE_SWAP_CONTEXTS: The old context exists but will stop
> to
>  *      exist with this call, the new context doesn't exist but will be
>  *      active after this call, the virtual interface switches from the
>  *      old to the new (note that the driver may of course implement this
>  *      as an on-the-fly chandef switch of the existing hardware context,
>  *      but the mac80211 pointer for the old context will cease to exist
>  *      and only the new one will later be used for changes/removal.)
>  */
> enum ieee80211_chanctx_switch_mode {
>         CHANCTX_SWMODE_REASSIGN_VIF,
>         CHANCTX_SWMODE_SWAP_CONTEXTS,
> };
>
>         (*switch_vif_chanctx)(struct ieee80211_hw *hw,
>                             struct ieee80211_vif *vif,
>                             struct ieee80211_chanctx_conf *old_ctx,
>                             struct ieee80211_chanctx_conf *new_ctx,
>                             enum ieee80211_chanctx_switch_mode mode);

So.. is my understanding correct that my patch itself stands with the
exception of the hunk you cited that would need to be reworked to use
the new suggested API instead of the unassign/assign trickery?

If I consider non-chanctx drivers we would need to do:
  if (!local->chanctx) { del_chanctx(); add_chanctx(); } else {
switch_vif_chanctx(); }

Btw. Do you intend the new switch_vif_chanctx() to take over
unassign_vif_chanctx() too?


> Separately, I think due to the complexities involved in the driver
> implementation we'll probably need a bitmap indicating which interface
> types are supported (this is not something we do today, and this would
> be broken in iwlwifi for sure.)

Care to elaborate?


> As a result, I'm going to drop this patch, which likely also means your
> other 5-patch series won't apply?

Yeah (although it's probably possible to transplant part of the patch
so the other 5 can apply).


Michał

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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-06 12:47             ` Michal Kazior
@ 2014-05-06 14:05               ` Johannes Berg
  2014-05-07  6:05                 ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-06 14:05 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Luca Coelho, Simon Wunderlich

On Tue, 2014-05-06 at 14:47 +0200, Michal Kazior wrote:

> > So I finally got around to discussing this with Luca and getting a
> > better understanding of what we have right now and where we're going to
> > this. Unfortunately (for you :) ) I don't think we're quite on the right
> > track between what we have and what you (and others) are doing here and
> > what we'll want.
> 
> Yay! :-)

I'm guessing you're excited I finally looked at it - not that I said it
wasn't what I wanted ;-)

Sorry about that though - I'll try to be better, now that I understand
CSA. It was exactly what I was afraid of, that I'd actually have to go
sit down for a day to understand it first :-)

> So.. is my understanding correct that my patch itself stands with the
> exception of the hunk you cited that would need to be reworked to use
> the new suggested API instead of the unassign/assign trickery?

Yes. The rest of your patch is pretty small though :)

> If I consider non-chanctx drivers we would need to do:
>   if (!local->chanctx) { del_chanctx(); add_chanctx(); } else {
> switch_vif_chanctx(); }

Not sure - we still need to do the right book-keeping inside mac80211 to
remove/add the chanctx around (after) the new driver operation, that
might in itself do enough. Depends on how the code is structured, I
guess. But yeah, something will probably be needed.

> Btw. Do you intend the new switch_vif_chanctx() to take over
> unassign_vif_chanctx() too?

It has to, yeah. There are two cases for the new op - the ones you
called "use_reserved_incompat" and "use_reserved_compat".

For the former, our driver will behave as though you'd called

 unassign_vif_chanctx(vif, old)
 delete_chanctx(old)
 add_chanctx(new)
 assign_vif_chanctx(vif, new)

[though other drivers may behave differently]

For the latter, drivers will behave as though you'd called

 unassign_vif_chanctx(vif, old)
 assign_vif_chanctx(vif, new)

[but depending on how the driver operates it'll be able to do this in a
single atomic step, similar to how mac80211 never goes through NULL in
either of these cases for the vif chanctx pointer]


> > Separately, I think due to the complexities involved in the driver
> > implementation we'll probably need a bitmap indicating which interface
> > types are supported (this is not something we do today, and this would
> > be broken in iwlwifi for sure.)
> 
> Care to elaborate?

It's a separate issue really - but sure: the iwlwifi firmware API will
likely not allow doing such trickery in the IBSS case, so we should have
a bitmap of supported interface types (e.g. BIT(NL80211_IFTYPE_STATION)
| ...) for the channel switch operation.

> > As a result, I'm going to drop this patch, which likely also means your
> > other 5-patch series won't apply?
> 
> Yeah (although it's probably possible to transplant part of the patch
> so the other 5 can apply).

I'll review the others now.

johannes


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

* Re: [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA
  2014-04-09 13:45       ` [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA Michal Kazior
@ 2014-05-06 14:42         ` Johannes Berg
  2014-05-07  7:25           ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-06 14:42 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, luca

On Wed, 2014-04-09 at 15:45 +0200, Michal Kazior wrote:
> Channel switch finalization is now 2-step. First
> step is when driver calls csa_finish(), the other
> is when reservation is actually finalized (which
> be defered for in-place reservation).

"which be defered"? should that be "can be"?

> +	if (sdata->reserved_chanctx) {
> +		/*
> +		 * with multi-vif csa driver may call ieee80211_csa_finish()
> +		 * many times while waiting for other interfaces to use their
> +		 * reservations
> +		 */
> +		if (sdata->reserved_ready)
> +			return 0;
> +
> +		err = ieee80211_vif_use_reserved_context(sdata);
> +		if (err)
> +			return err;
> +
> +		return 0;
>  	}
>  
> +	if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
> +					&sdata->csa_chandef))
> +		return -EINVAL;
> +
>  	sdata->vif.csa_active = false;

Should csa_active really stay true in the reserved_chanctx case?
Wouldn't that leave it beaconing, with potentially suddenly negative
(due to underflow) CSA counter, or something?

johannes


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

* Re: [PATCH v4 3/5] mac80211: use chanctx reservation for STA CSA
  2014-04-09 13:45       ` [PATCH v4 3/5] mac80211: use chanctx reservation for STA CSA Michal Kazior
@ 2014-05-06 14:43         ` Johannes Berg
  2014-05-07  7:35           ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-06 14:43 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, luca

On Wed, 2014-04-09 at 15:45 +0200, Michal Kazior wrote:
> Channel switch finalization is now 2-step. First
> step is when driver calls chswitch_done(), the
> other is when reservation is actually finalized
> (which be defered for in-place reservation).
> 
> It is now safe to call ieee80211_chswitch_done()
> more than once.
> 
> Also remove the ieee80211_vif_change_channel()
> because it is no longer used.

A lot of this looks really duplicated from the previous patch - since I
just merged the fixes is there really a need to go through the work etc.
and have this different, instead of going through cfg80211 for the
disconnect?

johannes


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

* Re: [PATCH v4 4/5] mac80211: ignore cqm during csa
  2014-04-09 13:45       ` [PATCH v4 4/5] mac80211: ignore cqm during csa Michal Kazior
@ 2014-05-06 14:45         ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-05-06 14:45 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, luca

On Wed, 2014-04-09 at 15:45 +0200, Michal Kazior wrote:
> It is not guaranteed that multi-vif channel
> switching is tightly synchronized. It makes sense
> to ignore cqm (missing beacons, et al) while csa
> is progressing and re-check it after it completes.

Makes sense, applied.

johannes


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

* Re: [PATCH v4 5/5] cfg80211: remove channel_switch combination check
  2014-04-09 13:45       ` [PATCH v4 5/5] cfg80211: remove channel_switch combination check Michal Kazior
@ 2014-05-06 14:45         ` Johannes Berg
  2014-05-07  7:40           ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-06 14:45 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, luca

On Wed, 2014-04-09 at 15:45 +0200, Michal Kazior wrote:
> Make the driver responsible for making sure it is
> capable of performing the switch. It might as well
> accept a request but then disconnect an interface
> if some requirements are not met.
> 
> In that case userspace should be prepared for an
> appropriate event (AP/IBSS/mesh being stopped/left).

Also makes sense, but I'm not sure if this relies on any previous
patches, so I won't apply it for now.

The other three I don't think will apply anyway though.

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-06 14:05               ` Johannes Berg
@ 2014-05-07  6:05                 ` Michal Kazior
  2014-05-07  8:07                   ` Johannes Berg
  2014-05-07  9:27                   ` Luca Coelho
  0 siblings, 2 replies; 199+ messages in thread
From: Michal Kazior @ 2014-05-07  6:05 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Luca Coelho, Simon Wunderlich

On 6 May 2014 16:05, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Tue, 2014-05-06 at 14:47 +0200, Michal Kazior wrote:
[...]
>> If I consider non-chanctx drivers we would need to do:
>>   if (!local->chanctx) { del_chanctx(); add_chanctx(); } else {
>> switch_vif_chanctx(); }
>
> Not sure - we still need to do the right book-keeping inside mac80211 to
> remove/add the chanctx around (after) the new driver operation, that
> might in itself do enough. Depends on how the code is structured, I
> guess. But yeah, something will probably be needed.
>
>> Btw. Do you intend the new switch_vif_chanctx() to take over
>> unassign_vif_chanctx() too?
>
> It has to, yeah. There are two cases for the new op - the ones you
> called "use_reserved_incompat" and "use_reserved_compat".
>
> For the former, our driver will behave as though you'd called
>
>  unassign_vif_chanctx(vif, old)
>  delete_chanctx(old)
>  add_chanctx(new)
>  assign_vif_chanctx(vif, new)
>
> [though other drivers may behave differently]
>
> For the latter, drivers will behave as though you'd called
>
>  unassign_vif_chanctx(vif, old)
>  assign_vif_chanctx(vif, new)
>
> [but depending on how the driver operates it'll be able to do this in a
> single atomic step, similar to how mac80211 never goes through NULL in
> either of these cases for the vif chanctx pointer]

Hmm... Now that I think about the atomic swap - it actually becomes a
little bit of an issue in some cases.

For one you might need to overcommit number of chanctx since swapping
requires both chanctx (old and new) to exist but that's the least of
the eproblem. If you have more than one interface you end up with
temporarily breaking interface combinations from driver point of view
while switching (first swap breaks it, last swap fixes it). Driver
won't know whether given swap is first/last unless we somehow pass it
through the switch_vif_chanctx(). IOW we actually need a "chanctx
transaction" (sort of a start-stop) that can batch up a couple of
chanctx switches for different vifs as an atomic op.


>> > Separately, I think due to the complexities involved in the driver
>> > implementation we'll probably need a bitmap indicating which interface
>> > types are supported (this is not something we do today, and this would
>> > be broken in iwlwifi for sure.)
>>
>> Care to elaborate?
>
> It's a separate issue really - but sure: the iwlwifi firmware API will
> likely not allow doing such trickery in the IBSS case, so we should have
> a bitmap of supported interface types (e.g. BIT(NL80211_IFTYPE_STATION)
> | ...) for the channel switch operation.

Ah, I get it now. Thanks.


Michał

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

* Re: [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA
  2014-05-06 14:42         ` Johannes Berg
@ 2014-05-07  7:25           ` Michal Kazior
  2014-05-07  8:05             ` Johannes Berg
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-07  7:25 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Luca Coelho

On 6 May 2014 16:42, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-04-09 at 15:45 +0200, Michal Kazior wrote:
>> Channel switch finalization is now 2-step. First
>> step is when driver calls csa_finish(), the other
>> is when reservation is actually finalized (which
>> be defered for in-place reservation).
>
> "which be defered"? should that be "can be"?

Oh, you're right.


>> +     if (sdata->reserved_chanctx) {
>> +             /*
>> +              * with multi-vif csa driver may call ieee80211_csa_finish()
>> +              * many times while waiting for other interfaces to use their
>> +              * reservations
>> +              */
>> +             if (sdata->reserved_ready)
>> +                     return 0;
>> +
>> +             err = ieee80211_vif_use_reserved_context(sdata);
>> +             if (err)
>> +                     return err;
>> +
>> +             return 0;
>>       }
>>
>> +     if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
>> +                                     &sdata->csa_chandef))
>> +             return -EINVAL;
>> +
>>       sdata->vif.csa_active = false;
>
> Should csa_active really stay true in the reserved_chanctx case?
> Wouldn't that leave it beaconing, with potentially suddenly negative
> (due to underflow) CSA counter, or something?

Hmm.. I think drivers should check ieee80211_csa_is_complete() before
calling to ieee80211_beacon_get(). At least that's what ath9k and
ath10k effectively do now. Hwsim might complain though but this should
be changed for multi-vif CSA. You may need to wait for other vifs to
finish CS (the incompat case) so you shouldn't call
ieee80211_beacon_get() after you get last CSA beacon on a given AP
vif.

Btw. shouldn't csa_active be protected/synchronized between CPUs
somehow? I think it's possible now to get inconsistencies and hit
WARN_ONs due to that.


Michał

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

* Re: [PATCH v4 3/5] mac80211: use chanctx reservation for STA CSA
  2014-05-06 14:43         ` Johannes Berg
@ 2014-05-07  7:35           ` Michal Kazior
  2014-05-07  8:03             ` Johannes Berg
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-07  7:35 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Luca Coelho

On 6 May 2014 16:43, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-04-09 at 15:45 +0200, Michal Kazior wrote:
>> Channel switch finalization is now 2-step. First
>> step is when driver calls chswitch_done(), the
>> other is when reservation is actually finalized
>> (which be defered for in-place reservation).
>>
>> It is now safe to call ieee80211_chswitch_done()
>> more than once.
>>
>> Also remove the ieee80211_vif_change_channel()
>> because it is no longer used.
>
> A lot of this looks really duplicated from the previous patch - since I
> just merged the fixes is there really a need to go through the work etc.
> and have this different, instead of going through cfg80211 for the
> disconnect?

I'm not really sure what duplication you refer to? There were already
a couple of uses of csa_connection_drop_work so I used it too. It
might make sense now to use cfg80211_stop_iface() instead but I'd
argue it's better to do that as a follow up patch.


Michał

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

* Re: [PATCH v4 5/5] cfg80211: remove channel_switch combination check
  2014-05-06 14:45         ` Johannes Berg
@ 2014-05-07  7:40           ` Michal Kazior
  0 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-05-07  7:40 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Luca Coelho

On 6 May 2014 16:45, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-04-09 at 15:45 +0200, Michal Kazior wrote:
>> Make the driver responsible for making sure it is
>> capable of performing the switch. It might as well
>> accept a request but then disconnect an interface
>> if some requirements are not met.
>>
>> In that case userspace should be prepared for an
>> appropriate event (AP/IBSS/mesh being stopped/left).
>
> Also makes sense, but I'm not sure if this relies on any previous
> patches, so I won't apply it for now.
>
> The other three I don't think will apply anyway though.

Chanctx reservations provide implicit combination verification so it
doesn't make sense to apply this patch until reservations are used for
AP CSA.


Michał

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

* Re: [PATCH v4 3/5] mac80211: use chanctx reservation for STA CSA
  2014-05-07  7:35           ` Michal Kazior
@ 2014-05-07  8:03             ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-05-07  8:03 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Luca Coelho

On Wed, 2014-05-07 at 09:35 +0200, Michal Kazior wrote:

> >> Also remove the ieee80211_vif_change_channel()
> >> because it is no longer used.
> >
> > A lot of this looks really duplicated from the previous patch - since I
> > just merged the fixes is there really a need to go through the work etc.
> > and have this different, instead of going through cfg80211 for the
> > disconnect?
> 
> I'm not really sure what duplication you refer to? There were already
> a couple of uses of csa_connection_drop_work so I used it too. 

Yeah, never mind, I think I misinterpreted your patch.

> It
> might make sense now to use cfg80211_stop_iface() instead but I'd
> argue it's better to do that as a follow up patch.

Ok.

johannes


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

* Re: [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA
  2014-05-07  7:25           ` Michal Kazior
@ 2014-05-07  8:05             ` Johannes Berg
  2014-05-07  9:05               ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-07  8:05 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Luca Coelho

On Wed, 2014-05-07 at 09:25 +0200, Michal Kazior wrote:

> > Should csa_active really stay true in the reserved_chanctx case?
> > Wouldn't that leave it beaconing, with potentially suddenly negative
> > (due to underflow) CSA counter, or something?
> 
> Hmm.. I think drivers should check ieee80211_csa_is_complete() before
> calling to ieee80211_beacon_get(). At least that's what ath9k and
> ath10k effectively do now. Hwsim might complain though but this should
> be changed for multi-vif CSA. You may need to wait for other vifs to
> finish CS (the incompat case) so you shouldn't call
> ieee80211_beacon_get() after you get last CSA beacon on a given AP
> vif.

I don't think that works for all drivers - only drivers that actually
generate and tx each beacon - but other drivers just update a template.
We actually have some pending patches to make that work correctly for
the CSA counters, but I'm not really sure what you want to happen in the
case that one is switching while the other hasn't yet? Should it stop
beaconing? Seems like clients would give up the switch then, no?

> Btw. shouldn't csa_active be protected/synchronized between CPUs
> somehow? I think it's possible now to get inconsistencies and hit
> WARN_ONs due to that.

I suppose it should then, I didn't write it :)

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07  6:05                 ` Michal Kazior
@ 2014-05-07  8:07                   ` Johannes Berg
  2014-05-07  8:51                     ` Michal Kazior
  2014-05-07  9:40                     ` Luca Coelho
  2014-05-07  9:27                   ` Luca Coelho
  1 sibling, 2 replies; 199+ messages in thread
From: Johannes Berg @ 2014-05-07  8:07 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Luca Coelho, Simon Wunderlich

On Wed, 2014-05-07 at 08:05 +0200, Michal Kazior wrote:

> Hmm... Now that I think about the atomic swap - it actually becomes a
> little bit of an issue in some cases.
> 
> For one you might need to overcommit number of chanctx since swapping
> requires both chanctx (old and new) to exist but that's the least of
> the eproblem. If you have more than one interface you end up with
> temporarily breaking interface combinations from driver point of view
> while switching (first swap breaks it, last swap fixes it). Driver
> won't know whether given swap is first/last unless we somehow pass it
> through the switch_vif_chanctx(). IOW we actually need a "chanctx
> transaction" (sort of a start-stop) that can batch up a couple of
> chanctx switches for different vifs as an atomic op.

Hmmm. Don't you already have that problem? Or you don't because you'd do

for_each_affected_vif: unassign
del chanctx [optional depending on reservation]
add chanctx [ditto]
for_each_affected_vif: assign

right now?

I suppose a sort of transaction API, if designed the right way, would
also work somehow - Luca?

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07  8:07                   ` Johannes Berg
@ 2014-05-07  8:51                     ` Michal Kazior
  2014-05-07  9:41                       ` Luca Coelho
  2014-05-07  9:40                     ` Luca Coelho
  1 sibling, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-07  8:51 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Luca Coelho, Simon Wunderlich

On 7 May 2014 10:07, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-05-07 at 08:05 +0200, Michal Kazior wrote:
>
>> Hmm... Now that I think about the atomic swap - it actually becomes a
>> little bit of an issue in some cases.
>>
>> For one you might need to overcommit number of chanctx since swapping
>> requires both chanctx (old and new) to exist but that's the least of
>> the eproblem. If you have more than one interface you end up with
>> temporarily breaking interface combinations from driver point of view
>> while switching (first swap breaks it, last swap fixes it). Driver
>> won't know whether given swap is first/last unless we somehow pass it
>> through the switch_vif_chanctx(). IOW we actually need a "chanctx
>> transaction" (sort of a start-stop) that can batch up a couple of
>> chanctx switches for different vifs as an atomic op.
>
> Hmmm. Don't you already have that problem? Or you don't because you'd do
>
> for_each_affected_vif: unassign
> del chanctx [optional depending on reservation]
> add chanctx [ditto]
> for_each_affected_vif: assign
>
> right now?

Correct - this is how my patch deals with this problem. This was also
the reason why I split the new_chanctx() into alloc_chanctx() and
add_chanctx().


Michał

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

* Re: [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA
  2014-05-07  8:05             ` Johannes Berg
@ 2014-05-07  9:05               ` Michal Kazior
  2014-05-07  9:06                 ` Michal Kazior
  2014-05-07  9:07                 ` Johannes Berg
  0 siblings, 2 replies; 199+ messages in thread
From: Michal Kazior @ 2014-05-07  9:05 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Luca Coelho

On 7 May 2014 10:05, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-05-07 at 09:25 +0200, Michal Kazior wrote:
>
>> > Should csa_active really stay true in the reserved_chanctx case?
>> > Wouldn't that leave it beaconing, with potentially suddenly negative
>> > (due to underflow) CSA counter, or something?
>>
>> Hmm.. I think drivers should check ieee80211_csa_is_complete() before
>> calling to ieee80211_beacon_get(). At least that's what ath9k and
>> ath10k effectively do now. Hwsim might complain though but this should
>> be changed for multi-vif CSA. You may need to wait for other vifs to
>> finish CS (the incompat case) so you shouldn't call
>> ieee80211_beacon_get() after you get last CSA beacon on a given AP
>> vif.
>
> I don't think that works for all drivers - only drivers that actually
> generate and tx each beacon - but other drivers just update a template.
> We actually have some pending patches to make that work correctly for
> the CSA counters, but I'm not really sure what you want to happen in the
> case that one is switching while the other hasn't yet? Should it stop
> beaconing? Seems like clients would give up the switch then, no?

Ah, I completely forgot about the template-based approach.

But I don't think any beacons should be sent after cs_count=1 on the
old channel either way. Thus, I would expect template-based drivers to
stop beaconing after cs_count=1. cs_count=0 is a separate case as it
means "i can disappear at any time now" and is a special case, not
what happens after reaching cs_count=1 if I remember correctly.

Clients should expect next beacon to appear on the new channel after
seeing beacon with cs_count=1. In that case regular cqm for clients
should apply.

Real-world multi-vif CSA will probably be off by up to 1 or 2 beacon
intervals between vifs which should be disruptive for clients I guess.


Michał

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

* Re: [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA
  2014-05-07  9:05               ` Michal Kazior
@ 2014-05-07  9:06                 ` Michal Kazior
  2014-05-07  9:07                 ` Johannes Berg
  1 sibling, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-05-07  9:06 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Luca Coelho

On 7 May 2014 11:05, Michal Kazior <michal.kazior@tieto.com> wrote:
[...]
> Real-world multi-vif CSA will probably be off by up to 1 or 2 beacon
> intervals between vifs which should be disruptive for clients I guess.

shouldn't (eh, proofreading)


Michał

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

* Re: [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA
  2014-05-07  9:05               ` Michal Kazior
  2014-05-07  9:06                 ` Michal Kazior
@ 2014-05-07  9:07                 ` Johannes Berg
  2014-05-07  9:41                   ` Michal Kazior
  1 sibling, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-07  9:07 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Luca Coelho

On Wed, 2014-05-07 at 11:05 +0200, Michal Kazior wrote:

> > I don't think that works for all drivers - only drivers that actually
> > generate and tx each beacon - but other drivers just update a template.
> > We actually have some pending patches to make that work correctly for
> > the CSA counters, but I'm not really sure what you want to happen in the
> > case that one is switching while the other hasn't yet? Should it stop
> > beaconing? Seems like clients would give up the switch then, no?
> 
> Ah, I completely forgot about the template-based approach.
> 
> But I don't think any beacons should be sent after cs_count=1 on the
> old channel either way. Thus, I would expect template-based drivers to
> stop beaconing after cs_count=1. cs_count=0 is a separate case as it
> means "i can disappear at any time now" and is a special case, not
> what happens after reaching cs_count=1 if I remember correctly.

I'm not really sure how this would work though - drivers that have
firmware generating beacons don't generally seem to be in a position to
just stop that aspect and continue operating otherwise, with active
clients and all that. It seems to me this might be really difficult to
implement.

> Clients should expect next beacon to appear on the new channel after
> seeing beacon with cs_count=1. In that case regular cqm for clients
> should apply.
> 
> Real-world multi-vif CSA will probably be off by up to 1 or 2 beacon
> intervals between vifs which should be disruptive for clients I guess.

"not be disruptive"?

Remind me why we're doing this - didn't you originally have something in
mind that was forcing them all to be synchronized with the switch?

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07  6:05                 ` Michal Kazior
  2014-05-07  8:07                   ` Johannes Berg
@ 2014-05-07  9:27                   ` Luca Coelho
  2014-05-07 11:09                     ` Johannes Berg
  1 sibling, 1 reply; 199+ messages in thread
From: Luca Coelho @ 2014-05-07  9:27 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Johannes Berg, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 08:05 +0200, Michal Kazior wrote:
> On 6 May 2014 16:05, Johannes Berg <johannes@sipsolutions.net> wrote:
> > On Tue, 2014-05-06 at 14:47 +0200, Michal Kazior wrote:
> >> > Separately, I think due to the complexities involved in the driver
> >> > implementation we'll probably need a bitmap indicating which interface
> >> > types are supported (this is not something we do today, and this would
> >> > be broken in iwlwifi for sure.)
> >>
> >> Care to elaborate?
> >
> > It's a separate issue really - but sure: the iwlwifi firmware API will
> > likely not allow doing such trickery in the IBSS case, so we should have
> > a bitmap of supported interface types (e.g. BIT(NL80211_IFTYPE_STATION)
> > | ...) for the channel switch operation.
> 
> Ah, I get it now. Thanks.

I guess this should be done when the actual support for AP, STATION and
so on is added? For example, add the station flag with the "mac80211:
use chanctx reservation for STA CSA" patch and so on...

--
Luca.


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07  8:07                   ` Johannes Berg
  2014-05-07  8:51                     ` Michal Kazior
@ 2014-05-07  9:40                     ` Luca Coelho
  2014-05-07 10:02                       ` Michal Kazior
  1 sibling, 1 reply; 199+ messages in thread
From: Luca Coelho @ 2014-05-07  9:40 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Michal Kazior, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 10:07 +0200, Johannes Berg wrote:
> On Wed, 2014-05-07 at 08:05 +0200, Michal Kazior wrote:
> 
> > Hmm... Now that I think about the atomic swap - it actually becomes a
> > little bit of an issue in some cases.
> > 
> > For one you might need to overcommit number of chanctx since swapping
> > requires both chanctx (old and new) to exist but that's the least of
> > the eproblem. If you have more than one interface you end up with
> > temporarily breaking interface combinations from driver point of view
> > while switching (first swap breaks it, last swap fixes it). Driver
> > won't know whether given swap is first/last unless we somehow pass it
> > through the switch_vif_chanctx(). IOW we actually need a "chanctx
> > transaction" (sort of a start-stop) that can batch up a couple of
> > chanctx switches for different vifs as an atomic op.
> 
> Hmmm. Don't you already have that problem? Or you don't because you'd do
> 
> for_each_affected_vif: unassign
> del chanctx [optional depending on reservation]
> add chanctx [ditto]
> for_each_affected_vif: assign
> 
> right now?
> 
> I suppose a sort of transaction API, if designed the right way, would
> also work somehow - Luca?

Yeah, I think this is a good idea.  If we have an atomic transaction API
towards the driver, we can solve the problems of switching several vifs
at once.

--
Luca.


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07  8:51                     ` Michal Kazior
@ 2014-05-07  9:41                       ` Luca Coelho
  0 siblings, 0 replies; 199+ messages in thread
From: Luca Coelho @ 2014-05-07  9:41 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Johannes Berg, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 10:51 +0200, Michal Kazior wrote:
> On 7 May 2014 10:07, Johannes Berg <johannes@sipsolutions.net> wrote:
> > On Wed, 2014-05-07 at 08:05 +0200, Michal Kazior wrote:
> >
> >> Hmm... Now that I think about the atomic swap - it actually becomes a
> >> little bit of an issue in some cases.
> >>
> >> For one you might need to overcommit number of chanctx since swapping
> >> requires both chanctx (old and new) to exist but that's the least of
> >> the eproblem. If you have more than one interface you end up with
> >> temporarily breaking interface combinations from driver point of view
> >> while switching (first swap breaks it, last swap fixes it). Driver
> >> won't know whether given swap is first/last unless we somehow pass it
> >> through the switch_vif_chanctx(). IOW we actually need a "chanctx
> >> transaction" (sort of a start-stop) that can batch up a couple of
> >> chanctx switches for different vifs as an atomic op.
> >
> > Hmmm. Don't you already have that problem? Or you don't because you'd do
> >
> > for_each_affected_vif: unassign
> > del chanctx [optional depending on reservation]
> > add chanctx [ditto]
> > for_each_affected_vif: assign
> >
> > right now?
> 
> Correct - this is how my patch deals with this problem. This was also
> the reason why I split the new_chanctx() into alloc_chanctx() and
> add_chanctx().

Right, I had forgotten the overcommit thing...

--
Luca.


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

* Re: [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA
  2014-05-07  9:07                 ` Johannes Berg
@ 2014-05-07  9:41                   ` Michal Kazior
  2014-05-07 11:17                     ` Johannes Berg
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-07  9:41 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Luca Coelho

On 7 May 2014 11:07, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-05-07 at 11:05 +0200, Michal Kazior wrote:
>
>> > I don't think that works for all drivers - only drivers that actually
>> > generate and tx each beacon - but other drivers just update a template.
>> > We actually have some pending patches to make that work correctly for
>> > the CSA counters, but I'm not really sure what you want to happen in the
>> > case that one is switching while the other hasn't yet? Should it stop
>> > beaconing? Seems like clients would give up the switch then, no?
>>
>> Ah, I completely forgot about the template-based approach.
>>
>> But I don't think any beacons should be sent after cs_count=1 on the
>> old channel either way. Thus, I would expect template-based drivers to
>> stop beaconing after cs_count=1. cs_count=0 is a separate case as it
>> means "i can disappear at any time now" and is a special case, not
>> what happens after reaching cs_count=1 if I remember correctly.
>
> I'm not really sure how this would work though - drivers that have
> firmware generating beacons don't generally seem to be in a position to
> just stop that aspect and continue operating otherwise, with active
> clients and all that. It seems to me this might be really difficult to
> implement.

Yeah. This seems like a problem for template drivers. But on the other
hand if they are capable of handling CSA IE counter they should
understand CSA, shouldn't they?


>> Clients should expect next beacon to appear on the new channel after
>> seeing beacon with cs_count=1. In that case regular cqm for clients
>> should apply.
>>
>> Real-world multi-vif CSA will probably be off by up to 1 or 2 beacon
>> intervals between vifs which should be disruptive for clients I guess.
>
> "not be disruptive"?

Yeah. Typo.


> Remind me why we're doing this - didn't you originally have something in
> mind that was forcing them all to be synchronized with the switch?

No, not really.

With per-vif CSA requests you can end up submitting requests between
vif TBTTs, no? Having an atomic "switch vif1,vif2,vif3 to chanX" could
help - although currently ieee80211_beacon_get() isn't really
synchronized well so you still hit the problem.

And how do you expect to deal with multi-vif with APs with different
beacon intervals? Those inherently can't be tightly synchronized. The
same goes for AP+STA if you start AP first (with the other way around
you could, in theory, match STA's AP TBTT with your own).


Michał

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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07  9:40                     ` Luca Coelho
@ 2014-05-07 10:02                       ` Michal Kazior
  2014-05-07 10:16                         ` Luca Coelho
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-07 10:02 UTC (permalink / raw)
  To: Luca Coelho; +Cc: Johannes Berg, linux-wireless, Simon Wunderlich

On 7 May 2014 11:40, Luca Coelho <luca@coelho.fi> wrote:
> On Wed, 2014-05-07 at 10:07 +0200, Johannes Berg wrote:
>> On Wed, 2014-05-07 at 08:05 +0200, Michal Kazior wrote:
>>
>> > Hmm... Now that I think about the atomic swap - it actually becomes a
>> > little bit of an issue in some cases.
>> >
>> > For one you might need to overcommit number of chanctx since swapping
>> > requires both chanctx (old and new) to exist but that's the least of
>> > the eproblem. If you have more than one interface you end up with
>> > temporarily breaking interface combinations from driver point of view
>> > while switching (first swap breaks it, last swap fixes it). Driver
>> > won't know whether given swap is first/last unless we somehow pass it
>> > through the switch_vif_chanctx(). IOW we actually need a "chanctx
>> > transaction" (sort of a start-stop) that can batch up a couple of
>> > chanctx switches for different vifs as an atomic op.
>>
>> Hmmm. Don't you already have that problem? Or you don't because you'd do
>>
>> for_each_affected_vif: unassign
>> del chanctx [optional depending on reservation]
>> add chanctx [ditto]
>> for_each_affected_vif: assign
>>
>> right now?
>>
>> I suppose a sort of transaction API, if designed the right way, would
>> also work somehow - Luca?
>
> Yeah, I think this is a good idea.  If we have an atomic transaction API
> towards the driver, we can solve the problems of switching several vifs
> at once.

Hmm.. I assume all chanctx calls would be subject to the transaction
API, i.e. add_chanctx/remove_chanctx/switch_vif_chanctx/change_chanctx.
Then all calls except begin/commit would return void - I guess this
could make handling errors a little saner.

Another approach would be to merge all separate chanctx ops into a
single one. This would have the benefit of providing driver all
information in one place and possibly making it easier to handle
errors internally (due to single function flow instead of having stuff
all over the place). But I imagine this could become a little
ambiguous in some parameter combinations. Any thoughts?


Michał

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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 10:02                       ` Michal Kazior
@ 2014-05-07 10:16                         ` Luca Coelho
  2014-05-07 10:38                           ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Luca Coelho @ 2014-05-07 10:16 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Johannes Berg, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 12:02 +0200, Michal Kazior wrote:
> On 7 May 2014 11:40, Luca Coelho <luca@coelho.fi> wrote:
> > On Wed, 2014-05-07 at 10:07 +0200, Johannes Berg wrote:
> >> On Wed, 2014-05-07 at 08:05 +0200, Michal Kazior wrote:
> >>
> >> > Hmm... Now that I think about the atomic swap - it actually becomes a
> >> > little bit of an issue in some cases.
> >> >
> >> > For one you might need to overcommit number of chanctx since swapping
> >> > requires both chanctx (old and new) to exist but that's the least of
> >> > the eproblem. If you have more than one interface you end up with
> >> > temporarily breaking interface combinations from driver point of view
> >> > while switching (first swap breaks it, last swap fixes it). Driver
> >> > won't know whether given swap is first/last unless we somehow pass it
> >> > through the switch_vif_chanctx(). IOW we actually need a "chanctx
> >> > transaction" (sort of a start-stop) that can batch up a couple of
> >> > chanctx switches for different vifs as an atomic op.
> >>
> >> Hmmm. Don't you already have that problem? Or you don't because you'd do
> >>
> >> for_each_affected_vif: unassign
> >> del chanctx [optional depending on reservation]
> >> add chanctx [ditto]
> >> for_each_affected_vif: assign
> >>
> >> right now?
> >>
> >> I suppose a sort of transaction API, if designed the right way, would
> >> also work somehow - Luca?
> >
> > Yeah, I think this is a good idea.  If we have an atomic transaction API
> > towards the driver, we can solve the problems of switching several vifs
> > at once.
> 
> Hmm.. I assume all chanctx calls would be subject to the transaction
> API, i.e. add_chanctx/remove_chanctx/switch_vif_chanctx/change_chanctx.
> Then all calls except begin/commit would return void - I guess this
> could make handling errors a little saner.
> 
> Another approach would be to merge all separate chanctx ops into a
> single one. This would have the benefit of providing driver all
> information in one place and possibly making it easier to handle
> errors internally (due to single function flow instead of having stuff
> all over the place). But I imagine this could become a little
> ambiguous in some parameter combinations. Any thoughts?

I think the latter is a better option.  Instead of having multiple calls
and requiring the driver to save all the new information until it's
committed (as would be the case with the first approach), the driver
would have all the information it needs at once.

Maybe you could have a single function call with an array of
transactions?

--
Luca.


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 10:16                         ` Luca Coelho
@ 2014-05-07 10:38                           ` Michal Kazior
  2014-05-07 11:09                             ` Johannes Berg
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-07 10:38 UTC (permalink / raw)
  To: Luca Coelho; +Cc: Johannes Berg, linux-wireless, Simon Wunderlich

On 7 May 2014 12:16, Luca Coelho <luca@coelho.fi> wrote:
> On Wed, 2014-05-07 at 12:02 +0200, Michal Kazior wrote:
>> On 7 May 2014 11:40, Luca Coelho <luca@coelho.fi> wrote:
>> > On Wed, 2014-05-07 at 10:07 +0200, Johannes Berg wrote:
>> >> On Wed, 2014-05-07 at 08:05 +0200, Michal Kazior wrote:
>> >>
>> >> > Hmm... Now that I think about the atomic swap - it actually becomes a
>> >> > little bit of an issue in some cases.
>> >> >
>> >> > For one you might need to overcommit number of chanctx since swapping
>> >> > requires both chanctx (old and new) to exist but that's the least of
>> >> > the eproblem. If you have more than one interface you end up with
>> >> > temporarily breaking interface combinations from driver point of view
>> >> > while switching (first swap breaks it, last swap fixes it). Driver
>> >> > won't know whether given swap is first/last unless we somehow pass it
>> >> > through the switch_vif_chanctx(). IOW we actually need a "chanctx
>> >> > transaction" (sort of a start-stop) that can batch up a couple of
>> >> > chanctx switches for different vifs as an atomic op.
>> >>
>> >> Hmmm. Don't you already have that problem? Or you don't because you'd do
>> >>
>> >> for_each_affected_vif: unassign
>> >> del chanctx [optional depending on reservation]
>> >> add chanctx [ditto]
>> >> for_each_affected_vif: assign
>> >>
>> >> right now?
>> >>
>> >> I suppose a sort of transaction API, if designed the right way, would
>> >> also work somehow - Luca?
>> >
>> > Yeah, I think this is a good idea.  If we have an atomic transaction API
>> > towards the driver, we can solve the problems of switching several vifs
>> > at once.
>>
>> Hmm.. I assume all chanctx calls would be subject to the transaction
>> API, i.e. add_chanctx/remove_chanctx/switch_vif_chanctx/change_chanctx.
>> Then all calls except begin/commit would return void - I guess this
>> could make handling errors a little saner.
>>
>> Another approach would be to merge all separate chanctx ops into a
>> single one. This would have the benefit of providing driver all
>> information in one place and possibly making it easier to handle
>> errors internally (due to single function flow instead of having stuff
>> all over the place). But I imagine this could become a little
>> ambiguous in some parameter combinations. Any thoughts?
>
> I think the latter is a better option.  Instead of having multiple calls
> and requiring the driver to save all the new information until it's
> committed (as would be the case with the first approach), the driver
> would have all the information it needs at once.
>
> Maybe you could have a single function call with an array of
> transactions?

Hmm..

I was actually thinking of just providing the bare minimum to fulfill
requirements for the CSA case: int foo(*hw, **vifs, n_vifs, *oldctx,
*newctx, flags).

Having an array of transactions passed through a single call seems
more robust and cleaner. Naiive drivers might just iterate over each
entry while more complex drivers might examine the whole request and
detect chanctx swapping.


Michał

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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 10:38                           ` Michal Kazior
@ 2014-05-07 11:09                             ` Johannes Berg
  2014-05-07 11:19                               ` Michal Kazior
  2014-05-07 11:48                               ` Luca Coelho
  0 siblings, 2 replies; 199+ messages in thread
From: Johannes Berg @ 2014-05-07 11:09 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 12:38 +0200, Michal Kazior wrote:

> I was actually thinking of just providing the bare minimum to fulfill
> requirements for the CSA case: int foo(*hw, **vifs, n_vifs, *oldctx,
> *newctx, flags).
> 
> Having an array of transactions passed through a single call seems
> more robust and cleaner. Naiive drivers might just iterate over each
> entry while more complex drivers might examine the whole request and
> detect chanctx swapping.

Not sure what you mean by "detect chanctx swapping" - the flags would
indicate that anyway, no? In any case, I like this better than a more
general transaction API I think, it's easier for the driver
implementation and clearer as to what needs to be done/supported.

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07  9:27                   ` Luca Coelho
@ 2014-05-07 11:09                     ` Johannes Berg
  2014-05-07 11:24                       ` Luca Coelho
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-07 11:09 UTC (permalink / raw)
  To: Luca Coelho; +Cc: Michal Kazior, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 12:27 +0300, Luca Coelho wrote:

> > > It's a separate issue really - but sure: the iwlwifi firmware API will
> > > likely not allow doing such trickery in the IBSS case, so we should have
> > > a bitmap of supported interface types (e.g. BIT(NL80211_IFTYPE_STATION)
> > > | ...) for the channel switch operation.
> > 
> > Ah, I get it now. Thanks.
> 
> I guess this should be done when the actual support for AP, STATION and
> so on is added? For example, add the station flag with the "mac80211:
> use chanctx reservation for STA CSA" patch and so on...

I don't know if we really want separate flags, rather than maybe a new
field with an interface types supported bitmap?

johannes


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

* Re: [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA
  2014-05-07  9:41                   ` Michal Kazior
@ 2014-05-07 11:17                     ` Johannes Berg
  2014-05-07 11:43                       ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-07 11:17 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Luca Coelho

On Wed, 2014-05-07 at 11:41 +0200, Michal Kazior wrote:

> > I'm not really sure how this would work though - drivers that have
> > firmware generating beacons don't generally seem to be in a position to
> > just stop that aspect and continue operating otherwise, with active
> > clients and all that. It seems to me this might be really difficult to
> > implement.
> 
> Yeah. This seems like a problem for template drivers. But on the other
> hand if they are capable of handling CSA IE counter they should
> understand CSA, shouldn't they?

Yeah but that doesn't mean they can simply stop beaconing for "extended"
periods of time.

> > Remind me why we're doing this - didn't you originally have something in
> > mind that was forcing them all to be synchronized with the switch?
> 
> No, not really.
> 
> With per-vif CSA requests you can end up submitting requests between
> vif TBTTs, no? Having an atomic "switch vif1,vif2,vif3 to chanX" could
> help - although currently ieee80211_beacon_get() isn't really
> synchronized well so you still hit the problem.
> 
> And how do you expect to deal with multi-vif with APs with different
> beacon intervals? Those inherently can't be tightly synchronized. The
> same goes for AP+STA if you start AP first (with the other way around
> you could, in theory, match STA's AP TBTT with your own).

I'm not really sure all of these are cases that we need to consider
though?

Multi-BSS I totally see, but if you're trying to do that with different
beacon intervals you're probably in a world of pain already - not sure
we should support that to start with...

AP/GO-follows-STA I can also see, due to regulatory and concurrent
BSS/P2P usage.

As for those other cases, are they really relevant?

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 11:09                             ` Johannes Berg
@ 2014-05-07 11:19                               ` Michal Kazior
  2014-05-07 11:54                                 ` Johannes Berg
  2014-05-07 11:48                               ` Luca Coelho
  1 sibling, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-07 11:19 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On 7 May 2014 13:09, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-05-07 at 12:38 +0200, Michal Kazior wrote:
>
>> I was actually thinking of just providing the bare minimum to fulfill
>> requirements for the CSA case: int foo(*hw, **vifs, n_vifs, *oldctx,
>> *newctx, flags).
>>
>> Having an array of transactions passed through a single call seems
>> more robust and cleaner. Naiive drivers might just iterate over each
>> entry while more complex drivers might examine the whole request and
>> detect chanctx swapping.
>
> Not sure what you mean by "detect chanctx swapping" - the flags would
> indicate that anyway, no? In any case, I like this better than a more
> general transaction API I think, it's easier for the driver
> implementation and clearer as to what needs to be done/supported.

You could submit a transaction sequence:
 - new chanctx2
 - switch vif1 chanctx1->chanctx2
 - switch vif2 chanctx1->chanctx2
 - remove chanctx1

Driver could infer this is a channel switch and depending on it's
capabilities/limitations perform some extra actions or just map it to
internal commands 1:1.


Michał

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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 11:09                     ` Johannes Berg
@ 2014-05-07 11:24                       ` Luca Coelho
  0 siblings, 0 replies; 199+ messages in thread
From: Luca Coelho @ 2014-05-07 11:24 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Michal Kazior, linux-wireless, Simon Wunderlich

On May 7, 2014 2:09:54 PM EEST, Johannes Berg <johannes@sipsolutions.net> wrote:
>On Wed, 2014-05-07 at 12:27 +0300, Luca Coelho wrote:
>
>> > > It's a separate issue really - but sure: the iwlwifi firmware API
>will
>> > > likely not allow doing such trickery in the IBSS case, so we
>should have
>> > > a bitmap of supported interface types (e.g.
>BIT(NL80211_IFTYPE_STATION)
>> > > | ...) for the channel switch operation.
>> > 
>> > Ah, I get it now. Thanks.
>> 
>> I guess this should be done when the actual support for AP, STATION
>and
>> so on is added? For example, add the station flag with the "mac80211:
>> use chanctx reservation for STA CSA" patch and so on...
>
>I don't know if we really want separate flags, rather than maybe a new
>field with an interface types supported bitmap?

Yes, that's what I had in mind too (as we discussed offline). I meant STA, AP etc. flags in this new bitmask, not in the existing HW_CONF stuff.

--
Luca.



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

* Re: [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA
  2014-05-07 11:17                     ` Johannes Berg
@ 2014-05-07 11:43                       ` Michal Kazior
  2014-05-07 11:50                         ` Johannes Berg
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-07 11:43 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Luca Coelho

On 7 May 2014 13:17, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-05-07 at 11:41 +0200, Michal Kazior wrote:
>
>> > I'm not really sure how this would work though - drivers that have
>> > firmware generating beacons don't generally seem to be in a position to
>> > just stop that aspect and continue operating otherwise, with active
>> > clients and all that. It seems to me this might be really difficult to
>> > implement.
>>
>> Yeah. This seems like a problem for template drivers. But on the other
>> hand if they are capable of handling CSA IE counter they should
>> understand CSA, shouldn't they?
>
> Yeah but that doesn't mean they can simply stop beaconing for "extended"
> periods of time.

We can't really guarantee how long we'll need to stop beaconing for.

Assume: AP+STA. Start AP CSA bcn_int=100ms, cs_count=5. While CSA
progresses STA receives cs_count=100 (with bcn_int=100ms).

This is all theory and in practice you won't get cs_count that big and
the lag greater shouldn't be greater than 5 or 6 beacon intervals. Is
that an "extended" period of time? I don't know. Should we even worry
about this? I don't think so.


>> > Remind me why we're doing this - didn't you originally have something in
>> > mind that was forcing them all to be synchronized with the switch?
>>
>> No, not really.
>>
>> With per-vif CSA requests you can end up submitting requests between
>> vif TBTTs, no? Having an atomic "switch vif1,vif2,vif3 to chanX" could
>> help - although currently ieee80211_beacon_get() isn't really
>> synchronized well so you still hit the problem.
>>
>> And how do you expect to deal with multi-vif with APs with different
>> beacon intervals? Those inherently can't be tightly synchronized. The
>> same goes for AP+STA if you start AP first (with the other way around
>> you could, in theory, match STA's AP TBTT with your own).
>
> I'm not really sure all of these are cases that we need to consider
> though?
>
> Multi-BSS I totally see, but if you're trying to do that with different
> beacon intervals you're probably in a world of pain already - not sure
> we should support that to start with...

You still can have different TBTTs across your AP vifs. ath10k does
this, although it should be possible to force it to beacon in bursts.


> AP/GO-follows-STA I can also see, due to regulatory and concurrent
> BSS/P2P usage.
>
> As for those other cases, are they really relevant?

I think I lost track of the point of the discussion at some point :-)
Weren't we discussing csa_active?


Michał

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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 11:09                             ` Johannes Berg
  2014-05-07 11:19                               ` Michal Kazior
@ 2014-05-07 11:48                               ` Luca Coelho
  1 sibling, 0 replies; 199+ messages in thread
From: Luca Coelho @ 2014-05-07 11:48 UTC (permalink / raw)
  To: Johannes Berg, Michal Kazior; +Cc: linux-wireless, Simon Wunderlich

On May 7, 2014 2:09:24 PM EEST, Johannes Berg <johannes@sipsolutions.net> wrote:
>On Wed, 2014-05-07 at 12:38 +0200, Michal Kazior wrote:
>
>> I was actually thinking of just providing the bare minimum to fulfill
>> requirements for the CSA case: int foo(*hw, **vifs, n_vifs, *oldctx,
>> *newctx, flags).
>> 
>> Having an array of transactions passed through a single call seems
>> more robust and cleaner. Naiive drivers might just iterate over each
>> entry while more complex drivers might examine the whole request and
>> detect chanctx swapping.
>
>Not sure what you mean by "detect chanctx swapping" - the flags would
>indicate that anyway, no? In any case, I like this better than a more
>general transaction API I think, it's easier for the driver
>implementation and clearer as to what needs to be done/supported.

How is it clearer? I think having a list of transactions is clearer than trying to say with flags what needs to be done for each vif and what their relation to each context is...

Additionally, I'm always for more generic solutions that may help us with future cases we haven't thought of already... unless the generalization complicates things a lot, which I don't think is the case here.

--
Luca.


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

* Re: [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA
  2014-05-07 11:43                       ` Michal Kazior
@ 2014-05-07 11:50                         ` Johannes Berg
  2014-05-07 12:12                           ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-07 11:50 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Luca Coelho

On Wed, 2014-05-07 at 13:43 +0200, Michal Kazior wrote:

> We can't really guarantee how long we'll need to stop beaconing for.
> 
> Assume: AP+STA. Start AP CSA bcn_int=100ms, cs_count=5. While CSA
> progresses STA receives cs_count=100 (with bcn_int=100ms).
> 
> This is all theory and in practice you won't get cs_count that big and
> the lag greater shouldn't be greater than 5 or 6 beacon intervals. Is
> that an "extended" period of time? I don't know. Should we even worry
> about this? I don't think so.

I'm not sure why we'd even allow this to start with though. We should be
able to sync it to 1 beacon interval, it seems? Particularly if we start
the switches together.

> > Multi-BSS I totally see, but if you're trying to do that with different
> > beacon intervals you're probably in a world of pain already - not sure
> > we should support that to start with...
> 
> You still can have different TBTTs across your AP vifs. ath10k does
> this, although it should be possible to force it to beacon in bursts.

True, but then you'd still technically have a single point where the
switch can happen, without missing a beat (beacon)

> > AP/GO-follows-STA I can also see, due to regulatory and concurrent
> > BSS/P2P usage.
> >
> > As for those other cases, are they really relevant?
> 
> I think I lost track of the point of the discussion at some point :-)
> Weren't we discussing csa_active?

:)

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 11:19                               ` Michal Kazior
@ 2014-05-07 11:54                                 ` Johannes Berg
  2014-05-07 12:08                                   ` Luca Coelho
  2014-05-07 12:20                                   ` Michal Kazior
  0 siblings, 2 replies; 199+ messages in thread
From: Johannes Berg @ 2014-05-07 11:54 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 13:19 +0200, Michal Kazior wrote:
> On 7 May 2014 13:09, Johannes Berg <johannes@sipsolutions.net> wrote:
> > On Wed, 2014-05-07 at 12:38 +0200, Michal Kazior wrote:
> >
> >> I was actually thinking of just providing the bare minimum to fulfill
> >> requirements for the CSA case: int foo(*hw, **vifs, n_vifs, *oldctx,
> >> *newctx, flags).
> >>
> >> Having an array of transactions passed through a single call seems
> >> more robust and cleaner. Naiive drivers might just iterate over each
> >> entry while more complex drivers might examine the whole request and
> >> detect chanctx swapping.
> >
> > Not sure what you mean by "detect chanctx swapping" - the flags would
> > indicate that anyway, no? In any case, I like this better than a more
> > general transaction API I think, it's easier for the driver
> > implementation and clearer as to what needs to be done/supported.
> 
> You could submit a transaction sequence:
>  - new chanctx2
>  - switch vif1 chanctx1->chanctx2
>  - switch vif2 chanctx1->chanctx2
>  - remove chanctx1

Well, you don't really have any other choice with the API you proposed,
and IMHO that's a good thing. The only possibilities that can be
expressed with that would seem to be:

 1) for_each_vif: switch vif from oldctx to newctx
 2) add newctx
    for_each_vif: switch vif from oldctx to newctx
    del oldctx

With the option between 1/2 being selected by the flags. I don't see
what the driver has to infer about it being a channel switch - it
necessarily is one, no?

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 11:54                                 ` Johannes Berg
@ 2014-05-07 12:08                                   ` Luca Coelho
  2014-05-07 12:13                                     ` Johannes Berg
  2014-05-07 12:20                                   ` Michal Kazior
  1 sibling, 1 reply; 199+ messages in thread
From: Luca Coelho @ 2014-05-07 12:08 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Michal Kazior, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 13:54 +0200, Johannes Berg wrote:
> On Wed, 2014-05-07 at 13:19 +0200, Michal Kazior wrote:
> > On 7 May 2014 13:09, Johannes Berg <johannes@sipsolutions.net> wrote:
> > > On Wed, 2014-05-07 at 12:38 +0200, Michal Kazior wrote:
> > >
> > >> I was actually thinking of just providing the bare minimum to fulfill
> > >> requirements for the CSA case: int foo(*hw, **vifs, n_vifs, *oldctx,
> > >> *newctx, flags).
> > >>
> > >> Having an array of transactions passed through a single call seems
> > >> more robust and cleaner. Naiive drivers might just iterate over each
> > >> entry while more complex drivers might examine the whole request and
> > >> detect chanctx swapping.
> > >
> > > Not sure what you mean by "detect chanctx swapping" - the flags would
> > > indicate that anyway, no? In any case, I like this better than a more
> > > general transaction API I think, it's easier for the driver
> > > implementation and clearer as to what needs to be done/supported.
> > 
> > You could submit a transaction sequence:
> >  - new chanctx2
> >  - switch vif1 chanctx1->chanctx2
> >  - switch vif2 chanctx1->chanctx2
> >  - remove chanctx1
> 
> Well, you don't really have any other choice with the API you proposed,
> and IMHO that's a good thing. The only possibilities that can be
> expressed with that would seem to be:
> 
>  1) for_each_vif: switch vif from oldctx to newctx
>  2) add newctx
>     for_each_vif: switch vif from oldctx to newctx
>     del oldctx
> 
> With the option between 1/2 being selected by the flags. I don't see
> what the driver has to infer about it being a channel switch - it
> necessarily is one, no?

I was thinking about the case where you you need to involve 3 contexts.
Let's say you have 2 vifs in the same context and after the switch you
need to split them into 2 new ones (for instance, if there is some
incompatibility in the new chandefs).

With the generic transactions you could do:
 - new chanctx2
 - new chanctx3
 - switch vif1 chanctx1->chanctx2
 - switch vif2 chanctx1->chanctx3
 - del chanctx1

--
Luca.


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

* Re: [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA
  2014-05-07 11:50                         ` Johannes Berg
@ 2014-05-07 12:12                           ` Michal Kazior
  0 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-05-07 12:12 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Luca Coelho

On 7 May 2014 13:50, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-05-07 at 13:43 +0200, Michal Kazior wrote:
>
>> We can't really guarantee how long we'll need to stop beaconing for.
>>
>> Assume: AP+STA. Start AP CSA bcn_int=100ms, cs_count=5. While CSA
>> progresses STA receives cs_count=100 (with bcn_int=100ms).
>>
>> This is all theory and in practice you won't get cs_count that big and
>> the lag greater shouldn't be greater than 5 or 6 beacon intervals. Is
>> that an "extended" period of time? I don't know. Should we even worry
>> about this? I don't think so.
>
> I'm not sure why we'd even allow this to start with though. We should be
> able to sync it to 1 beacon interval, it seems? Particularly if we start
> the switches together.

There's no guarantee your AP and STA's AP will finish CSA in sync. So
you either (1) prolong your stay on the (old) channel until STA's AP
completes CSA, or (2) you switch your STA interface prematurely, (3)
or you simply disconnect STA interface if you can't have a really
tight sync.


Michał

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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 12:08                                   ` Luca Coelho
@ 2014-05-07 12:13                                     ` Johannes Berg
  2014-05-07 12:20                                       ` Luca Coelho
  2014-05-07 12:27                                       ` Michal Kazior
  0 siblings, 2 replies; 199+ messages in thread
From: Johannes Berg @ 2014-05-07 12:13 UTC (permalink / raw)
  To: Luca Coelho; +Cc: Michal Kazior, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 15:08 +0300, Luca Coelho wrote:

> I was thinking about the case where you you need to involve 3 contexts.
> Let's say you have 2 vifs in the same context and after the switch you
> need to split them into 2 new ones (for instance, if there is some
> incompatibility in the new chandefs).
> 
> With the generic transactions you could do:
>  - new chanctx2
>  - new chanctx3
>  - switch vif1 chanctx1->chanctx2
>  - switch vif2 chanctx1->chanctx3
>  - del chanctx1

This isn't an interesting case, because it means you have a spare, so
you might as well do

 new chanctx3
 switch vif2 chanctx1->chanctx3
 switch_transaction(chanctx1, chanctx2, vif1)

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 11:54                                 ` Johannes Berg
  2014-05-07 12:08                                   ` Luca Coelho
@ 2014-05-07 12:20                                   ` Michal Kazior
  2014-05-07 12:34                                     ` Johannes Berg
  1 sibling, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-07 12:20 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On 7 May 2014 13:54, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-05-07 at 13:19 +0200, Michal Kazior wrote:
>> On 7 May 2014 13:09, Johannes Berg <johannes@sipsolutions.net> wrote:
>> > On Wed, 2014-05-07 at 12:38 +0200, Michal Kazior wrote:
>> >
>> >> I was actually thinking of just providing the bare minimum to fulfill
>> >> requirements for the CSA case: int foo(*hw, **vifs, n_vifs, *oldctx,
>> >> *newctx, flags).
>> >>
>> >> Having an array of transactions passed through a single call seems
>> >> more robust and cleaner. Naiive drivers might just iterate over each
>> >> entry while more complex drivers might examine the whole request and
>> >> detect chanctx swapping.
>> >
>> > Not sure what you mean by "detect chanctx swapping" - the flags would
>> > indicate that anyway, no? In any case, I like this better than a more
>> > general transaction API I think, it's easier for the driver
>> > implementation and clearer as to what needs to be done/supported.
>>
>> You could submit a transaction sequence:
>>  - new chanctx2
>>  - switch vif1 chanctx1->chanctx2
>>  - switch vif2 chanctx1->chanctx2
>>  - remove chanctx1
>
> Well, you don't really have any other choice with the API you proposed,
> and IMHO that's a good thing. The only possibilities that can be
> expressed with that would seem to be:
>
>  1) for_each_vif: switch vif from oldctx to newctx
>  2) add newctx
>     for_each_vif: switch vif from oldctx to newctx
>     del oldctx
>
> With the option between 1/2 being selected by the flags. I don't see
> what the driver has to infer about it being a channel switch - it
> necessarily is one, no?

Yeah - existing usecases include only CSA and some primitive ops.

What I mean is if you want to avoid chanctx overcommit you need to
perform (2) the other way around (i.e. first unassign and delete
oldctx and then create newctx), at least internally. This would simply
be more of a hassle with multiple call transaction API.


Michał

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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 12:13                                     ` Johannes Berg
@ 2014-05-07 12:20                                       ` Luca Coelho
  2014-05-07 12:38                                         ` Johannes Berg
  2014-05-07 12:27                                       ` Michal Kazior
  1 sibling, 1 reply; 199+ messages in thread
From: Luca Coelho @ 2014-05-07 12:20 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Michal Kazior, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 14:13 +0200, Johannes Berg wrote:
> On Wed, 2014-05-07 at 15:08 +0300, Luca Coelho wrote:
> 
> > I was thinking about the case where you you need to involve 3 contexts.
> > Let's say you have 2 vifs in the same context and after the switch you
> > need to split them into 2 new ones (for instance, if there is some
> > incompatibility in the new chandefs).
> > 
> > With the generic transactions you could do:
> >  - new chanctx2
> >  - new chanctx3
> >  - switch vif1 chanctx1->chanctx2
> >  - switch vif2 chanctx1->chanctx3
> >  - del chanctx1
> 
> This isn't an interesting case, because it means you have a spare, so
> you might as well do
> 
>  new chanctx3
>  switch vif2 chanctx1->chanctx3
>  switch_transaction(chanctx1, chanctx2, vif1)

Couldn't this potentially break the combinations temporarily again?

--
Luca.


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 12:13                                     ` Johannes Berg
  2014-05-07 12:20                                       ` Luca Coelho
@ 2014-05-07 12:27                                       ` Michal Kazior
  2014-05-07 12:36                                         ` Johannes Berg
  1 sibling, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-07 12:27 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On 7 May 2014 14:13, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-05-07 at 15:08 +0300, Luca Coelho wrote:
>
>> I was thinking about the case where you you need to involve 3 contexts.
>> Let's say you have 2 vifs in the same context and after the switch you
>> need to split them into 2 new ones (for instance, if there is some
>> incompatibility in the new chandefs).
>>
>> With the generic transactions you could do:
>>  - new chanctx2
>>  - new chanctx3
>>  - switch vif1 chanctx1->chanctx2
>>  - switch vif2 chanctx1->chanctx3
>>  - del chanctx1
>
> This isn't an interesting case, because it means you have a spare, so
> you might as well do
>
>  new chanctx3
>  switch vif2 chanctx1->chanctx3
>  switch_transaction(chanctx1, chanctx2, vif1)

Don't you mean switch_chandef(chanctx1, chandef)? Or do you assume
chanctx2 was prepared earlier? Don't you need to remove chanctx1 then?
Oh, and the chanctx overcommit.. :-)

I actually think Luca's example is a valid one as it shows the driver
can freely handle things internally, no? Although I don't see when it
would be required to make a transaction like that in real-world..


Michał

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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 12:20                                   ` Michal Kazior
@ 2014-05-07 12:34                                     ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-05-07 12:34 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 14:20 +0200, Michal Kazior wrote:

> >  1) for_each_vif: switch vif from oldctx to newctx
> >  2) add newctx
> >     for_each_vif: switch vif from oldctx to newctx
> >     del oldctx
> >
> > With the option between 1/2 being selected by the flags. I don't see
> > what the driver has to infer about it being a channel switch - it
> > necessarily is one, no?
> 
> Yeah - existing usecases include only CSA and some primitive ops.
> 
> What I mean is if you want to avoid chanctx overcommit you need to
> perform (2) the other way around (i.e. first unassign and delete
> oldctx and then create newctx), at least internally. This would simply
> be more of a hassle with multiple call transaction API.

Well, sure you really have to do it the other way around - but we'd be
assuming the driver does whatever it can internally, for that call

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 12:27                                       ` Michal Kazior
@ 2014-05-07 12:36                                         ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-05-07 12:36 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 14:27 +0200, Michal Kazior wrote:
> On 7 May 2014 14:13, Johannes Berg <johannes@sipsolutions.net> wrote:
> > On Wed, 2014-05-07 at 15:08 +0300, Luca Coelho wrote:
> >
> >> I was thinking about the case where you you need to involve 3 contexts.
> >> Let's say you have 2 vifs in the same context and after the switch you
> >> need to split them into 2 new ones (for instance, if there is some
> >> incompatibility in the new chandefs).
> >>
> >> With the generic transactions you could do:
> >>  - new chanctx2
> >>  - new chanctx3
> >>  - switch vif1 chanctx1->chanctx2
> >>  - switch vif2 chanctx1->chanctx3
> >>  - del chanctx1
> >
> > This isn't an interesting case, because it means you have a spare, so
> > you might as well do
> >
> >  new chanctx3
> >  switch vif2 chanctx1->chanctx3
> >  switch_transaction(chanctx1, chanctx2, vif1)
> 
> Don't you mean switch_chandef(chanctx1, chandef)? Or do you assume
> chanctx2 was prepared earlier? Don't you need to remove chanctx1 then?
> Oh, and the chanctx overcommit.. :-)

I'm assuming "switch_transaction" is the API I proposed, except maybe
modified to have multiple vifs.

> I actually think Luca's example is a valid one as it shows the driver
> can freely handle things internally, no? Although I don't see when it
> would be required to make a transaction like that in real-world..

Yeah but do we want to make the API that complex? I don't see how Luca's
example doesn't degenerate to the simpler APIs + the new "switch
multiple vifs from one to another while possibly swapping those
chanctxs"

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 12:20                                       ` Luca Coelho
@ 2014-05-07 12:38                                         ` Johannes Berg
  2014-05-07 12:44                                           ` Michal Kazior
  2014-05-07 12:53                                           ` Luca Coelho
  0 siblings, 2 replies; 199+ messages in thread
From: Johannes Berg @ 2014-05-07 12:38 UTC (permalink / raw)
  To: Luca Coelho; +Cc: Michal Kazior, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 15:20 +0300, Luca Coelho wrote:
> On Wed, 2014-05-07 at 14:13 +0200, Johannes Berg wrote:
> > On Wed, 2014-05-07 at 15:08 +0300, Luca Coelho wrote:
> > 
> > > I was thinking about the case where you you need to involve 3 contexts.
> > > Let's say you have 2 vifs in the same context and after the switch you
> > > need to split them into 2 new ones (for instance, if there is some
> > > incompatibility in the new chandefs).
> > > 
> > > With the generic transactions you could do:
> > >  - new chanctx2
> > >  - new chanctx3
> > >  - switch vif1 chanctx1->chanctx2
> > >  - switch vif2 chanctx1->chanctx3
> > >  - del chanctx1
> > 
> > This isn't an interesting case, because it means you have a spare, so
> > you might as well do
> > 
> >  new chanctx3
> >  switch vif2 chanctx1->chanctx3
> >  switch_transaction(chanctx1, chanctx2, vif1)
> 
> Couldn't this potentially break the combinations temporarily again?

I don't see why? You had a spare channel context to start with,
otherwise you'd never have accepted this situation. Therefore, you can
use the spare one before actually doing the proposed
switch_vif_chanctx().


Ultimately, what I'm trying to say is that instead of the proposed
switch_vif_chanctx(), we need to have this:

enum ieee80211_chanctx_switch_mode - as before

        (*switch_vif_chanctx)(struct ieee80211_hw *hw,
                              struct ieee80211_vif **vifs, int n_vifs,
                              struct ieee80211_chanctx_conf *old_ctx,
                              struct ieee80211_chanctx_conf *new_ctx,
                              enum ieee80211_chanctx_switch_mode mode);


johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 12:38                                         ` Johannes Berg
@ 2014-05-07 12:44                                           ` Michal Kazior
  2014-05-07 12:53                                             ` Johannes Berg
  2014-05-07 12:53                                           ` Luca Coelho
  1 sibling, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-07 12:44 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On 7 May 2014 14:38, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-05-07 at 15:20 +0300, Luca Coelho wrote:
>> On Wed, 2014-05-07 at 14:13 +0200, Johannes Berg wrote:
>> > On Wed, 2014-05-07 at 15:08 +0300, Luca Coelho wrote:
>> >
>> > > I was thinking about the case where you you need to involve 3 contexts.
>> > > Let's say you have 2 vifs in the same context and after the switch you
>> > > need to split them into 2 new ones (for instance, if there is some
>> > > incompatibility in the new chandefs).
>> > >
>> > > With the generic transactions you could do:
>> > >  - new chanctx2
>> > >  - new chanctx3
>> > >  - switch vif1 chanctx1->chanctx2
>> > >  - switch vif2 chanctx1->chanctx3
>> > >  - del chanctx1
>> >
>> > This isn't an interesting case, because it means you have a spare, so
>> > you might as well do
>> >
>> >  new chanctx3
>> >  switch vif2 chanctx1->chanctx3
>> >  switch_transaction(chanctx1, chanctx2, vif1)
>>
>> Couldn't this potentially break the combinations temporarily again?
>
> I don't see why? You had a spare channel context to start with,
> otherwise you'd never have accepted this situation. Therefore, you can
> use the spare one before actually doing the proposed
> switch_vif_chanctx().
>
>
> Ultimately, what I'm trying to say is that instead of the proposed
> switch_vif_chanctx(), we need to have this:
>
> enum ieee80211_chanctx_switch_mode - as before
>
>         (*switch_vif_chanctx)(struct ieee80211_hw *hw,
>                               struct ieee80211_vif **vifs, int n_vifs,
>                               struct ieee80211_chanctx_conf *old_ctx,
>                               struct ieee80211_chanctx_conf *new_ctx,
>                               enum ieee80211_chanctx_switch_mode mode);

Yeah. This is another way to do it. It does solve the edge case when
you're maxing out on different channels.

It doesn't, however, (if you don't do transactions) prevent from
chanctx overcommit (i.e. you still can end up with more, albeit
"idle", chanctx allocations in driver).


Michał

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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 12:38                                         ` Johannes Berg
  2014-05-07 12:44                                           ` Michal Kazior
@ 2014-05-07 12:53                                           ` Luca Coelho
  2014-05-07 13:06                                             ` Johannes Berg
  1 sibling, 1 reply; 199+ messages in thread
From: Luca Coelho @ 2014-05-07 12:53 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Michal Kazior, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 14:38 +0200, Johannes Berg wrote:
> On Wed, 2014-05-07 at 15:20 +0300, Luca Coelho wrote:
> > On Wed, 2014-05-07 at 14:13 +0200, Johannes Berg wrote:
> > > On Wed, 2014-05-07 at 15:08 +0300, Luca Coelho wrote:
> > > 
> > > > I was thinking about the case where you you need to involve 3 contexts.
> > > > Let's say you have 2 vifs in the same context and after the switch you
> > > > need to split them into 2 new ones (for instance, if there is some
> > > > incompatibility in the new chandefs).
> > > > 
> > > > With the generic transactions you could do:
> > > >  - new chanctx2
> > > >  - new chanctx3
> > > >  - switch vif1 chanctx1->chanctx2
> > > >  - switch vif2 chanctx1->chanctx3
> > > >  - del chanctx1
> > > 
> > > This isn't an interesting case, because it means you have a spare, so
> > > you might as well do
> > > 
> > >  new chanctx3
> > >  switch vif2 chanctx1->chanctx3
> > >  switch_transaction(chanctx1, chanctx2, vif1)
> > 
> > Couldn't this potentially break the combinations temporarily again?
> 
> I don't see why? You had a spare channel context to start with,
> otherwise you'd never have accepted this situation. Therefore, you can
> use the spare one before actually doing the proposed
> switch_vif_chanctx().

It's not about the spare, it's about having this temporarily:

chanctx3-vif2
chanctx1-vif1

Can we be sure that chanctx1 with vif1 is compatible with chanctx3 with
vif2? We only check chanctx2 with vif1 and chanctx3 with vif2, which is
our final goal.

I'm not sure this is even possible, but it was something like this I had
in mind.

--
Luca.



> 
> Ultimately, what I'm trying to say is that instead of the proposed
> switch_vif_chanctx(), we need to have this:
> 
> enum ieee80211_chanctx_switch_mode - as before
> 
>         (*switch_vif_chanctx)(struct ieee80211_hw *hw,
>                               struct ieee80211_vif **vifs, int n_vifs,
>                               struct ieee80211_chanctx_conf *old_ctx,
>                               struct ieee80211_chanctx_conf *new_ctx,
>                               enum ieee80211_chanctx_switch_mode mode);
> 
> 
> johannes
> 



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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 12:44                                           ` Michal Kazior
@ 2014-05-07 12:53                                             ` Johannes Berg
  2014-05-07 13:03                                               ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-07 12:53 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 14:44 +0200, Michal Kazior wrote:

> > Ultimately, what I'm trying to say is that instead of the proposed
> > switch_vif_chanctx(), we need to have this:
> >
> > enum ieee80211_chanctx_switch_mode - as before
> >
> >         (*switch_vif_chanctx)(struct ieee80211_hw *hw,
> >                               struct ieee80211_vif **vifs, int n_vifs,
> >                               struct ieee80211_chanctx_conf *old_ctx,
> >                               struct ieee80211_chanctx_conf *new_ctx,
> >                               enum ieee80211_chanctx_switch_mode mode);
> 
> Yeah. This is another way to do it. It does solve the edge case when
> you're maxing out on different channels.

I thought this was what you were proposing :)

> It doesn't, however, (if you don't do transactions) prevent from
> chanctx overcommit (i.e. you still can end up with more, albeit
> "idle", chanctx allocations in driver).

That I don't understand again - what do you mean by "chanctx
allocations"?

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 12:53                                             ` Johannes Berg
@ 2014-05-07 13:03                                               ` Michal Kazior
  2014-05-08 10:06                                                 ` Johannes Berg
  2014-05-08 10:08                                                 ` Johannes Berg
  0 siblings, 2 replies; 199+ messages in thread
From: Michal Kazior @ 2014-05-07 13:03 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On 7 May 2014 14:53, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-05-07 at 14:44 +0200, Michal Kazior wrote:
>
>> > Ultimately, what I'm trying to say is that instead of the proposed
>> > switch_vif_chanctx(), we need to have this:
>> >
>> > enum ieee80211_chanctx_switch_mode - as before
>> >
>> >         (*switch_vif_chanctx)(struct ieee80211_hw *hw,
>> >                               struct ieee80211_vif **vifs, int n_vifs,
>> >                               struct ieee80211_chanctx_conf *old_ctx,
>> >                               struct ieee80211_chanctx_conf *new_ctx,
>> >                               enum ieee80211_chanctx_switch_mode mode);
>>
>> Yeah. This is another way to do it. It does solve the edge case when
>> you're maxing out on different channels.
>
> I thought this was what you were proposing :)

I think Luca and I have something like this in mind:

  drv_chanctx_update(hw,
    { .type = CHANCTX_NEW_CHANCTX,
      .chanctx = ctx2,
    },
    {
      .type = CHANCTX_BIND,
      .vif = vif1,
      .chanctx_old = ctx1,
      .chanctx_new = ctx2,
    },
    { 0 });

The driver would be free to re-order this internally to fulfill the
entire update request.


>> It doesn't, however, (if you don't do transactions) prevent from
>> chanctx overcommit (i.e. you still can end up with more, albeit
>> "idle", chanctx allocations in driver).
>
> That I don't understand again - what do you mean by "chanctx
> allocations"?

Chanctx lifecycle is:

 drv_add_chanctx()
 drv_assign_vif_chanctx()
 // .. more assign/unassign .. possibly drv_change_chanctx()
 drv_unassign_vif_chanctx()
 drv_remove_chanctx()

What I meant by "chanctx allocations" is drv_add_chanctx.

In particular when I write "chanctx overcommit" I refer to
drv_add_chanctx() being called when in-driver chanctx count is already
at peak for given interface combinations.

Or should we just simply assume this isn't a problem and drivers
should *always* accept empty chanctx? Why bother with a return value
then?


Michał

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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 12:53                                           ` Luca Coelho
@ 2014-05-07 13:06                                             ` Johannes Berg
  2014-05-07 13:10                                               ` Luca Coelho
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-07 13:06 UTC (permalink / raw)
  To: Luca Coelho; +Cc: Michal Kazior, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 15:53 +0300, Luca Coelho wrote:

> > > >  new chanctx3
> > > >  switch vif2 chanctx1->chanctx3
> > > >  switch_transaction(chanctx1, chanctx2, vif1)
> > > 
> > > Couldn't this potentially break the combinations temporarily again?
> > 
> > I don't see why? You had a spare channel context to start with,
> > otherwise you'd never have accepted this situation. Therefore, you can
> > use the spare one before actually doing the proposed
> > switch_vif_chanctx().
> 
> It's not about the spare, it's about having this temporarily:
> 
> chanctx3-vif2
> chanctx1-vif1
> 
> Can we be sure that chanctx1 with vif1 is compatible with chanctx3 with
> vif2? We only check chanctx2 with vif1 and chanctx3 with vif2, which is
> our final goal.
> 
> I'm not sure this is even possible, but it was something like this I had
> in mind.

Oh, I get it, you're thinking that there might be a situation where
those vif types are maybe not supported with different channels?

But in your example you're going from this situation:

chanctx1: vif1, vif2

to

chanctx2: vif1
chanctx3: vif2


The intermediate step that I proposed would give you

chanctx1: vif1
chanctx3: vif2

Which isn't really any different? Maybe you could construct a more
difficult via situation though where it actually does end up with a
conflict - or can we prove that can't happen?

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 13:06                                             ` Johannes Berg
@ 2014-05-07 13:10                                               ` Luca Coelho
  2014-05-08 10:03                                                 ` Johannes Berg
  0 siblings, 1 reply; 199+ messages in thread
From: Luca Coelho @ 2014-05-07 13:10 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Michal Kazior, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 15:06 +0200, Johannes Berg wrote:
> On Wed, 2014-05-07 at 15:53 +0300, Luca Coelho wrote:
> 
> > > > >  new chanctx3
> > > > >  switch vif2 chanctx1->chanctx3
> > > > >  switch_transaction(chanctx1, chanctx2, vif1)
> > > > 
> > > > Couldn't this potentially break the combinations temporarily again?
> > > 
> > > I don't see why? You had a spare channel context to start with,
> > > otherwise you'd never have accepted this situation. Therefore, you can
> > > use the spare one before actually doing the proposed
> > > switch_vif_chanctx().
> > 
> > It's not about the spare, it's about having this temporarily:
> > 
> > chanctx3-vif2
> > chanctx1-vif1
> > 
> > Can we be sure that chanctx1 with vif1 is compatible with chanctx3 with
> > vif2? We only check chanctx2 with vif1 and chanctx3 with vif2, which is
> > our final goal.
> > 
> > I'm not sure this is even possible, but it was something like this I had
> > in mind.
> 
> Oh, I get it, you're thinking that there might be a situation where
> those vif types are maybe not supported with different channels?
> 
> But in your example you're going from this situation:
> 
> chanctx1: vif1, vif2
> 
> to
> 
> chanctx2: vif1
> chanctx3: vif2
> 
> 
> The intermediate step that I proposed would give you
> 
> chanctx1: vif1
> chanctx3: vif2
> 
> Which isn't really any different?

It could be different if the channel in chanctx1 requires radar and
chanctx2 doesn't, couldn't it?


>  Maybe you could construct a more
> difficult via situation though where it actually does end up with a
> conflict - or can we prove that can't happen?

I can't come up with good examples, but yeah, proving it *can't* happen
would be good. :)

--
Luca.


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 13:10                                               ` Luca Coelho
@ 2014-05-08 10:03                                                 ` Johannes Berg
  0 siblings, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-05-08 10:03 UTC (permalink / raw)
  To: Luca Coelho; +Cc: Michal Kazior, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 16:10 +0300, Luca Coelho wrote:


> > Oh, I get it, you're thinking that there might be a situation where
> > those vif types are maybe not supported with different channels?
> > 
> > But in your example you're going from this situation:
> > 
> > chanctx1: vif1, vif2
> > 
> > to
> > 
> > chanctx2: vif1
> > chanctx3: vif2
> > 
> > 
> > The intermediate step that I proposed would give you
> > 
> > chanctx1: vif1
> > chanctx3: vif2
> > 
> > Which isn't really any different?
> 
> It could be different if the channel in chanctx1 requires radar and
> chanctx2 doesn't, couldn't it?

Yeah, I guess that'd be a counter-example...

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 13:03                                               ` Michal Kazior
@ 2014-05-08 10:06                                                 ` Johannes Berg
  2014-05-08 10:41                                                   ` Michal Kazior
  2014-05-08 10:08                                                 ` Johannes Berg
  1 sibling, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-08 10:06 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 15:03 +0200, Michal Kazior wrote:

> I think Luca and I have something like this in mind:
> 
>   drv_chanctx_update(hw,
>     { .type = CHANCTX_NEW_CHANCTX,
>       .chanctx = ctx2,
>     },
>     {
>       .type = CHANCTX_BIND,
>       .vif = vif1,
>       .chanctx_old = ctx1,
>       .chanctx_new = ctx2,
>     },
>     { 0 });
> 
> The driver would be free to re-order this internally to fulfill the
> entire update request.

Yeah, that's just a little complex maybe? And we don't really allow
*arbitrary* transactions, so we'd have to impose limits on the
transactions etc.

In fact, I'd argue that you shouldn't even have the
create/destroy/bind/unbind stuff listed here since that makes it more
difficult for the driver - having this whole "swap()" thing should be
easier to implement.

> Chanctx lifecycle is:
> 
>  drv_add_chanctx()
>  drv_assign_vif_chanctx()
>  // .. more assign/unassign .. possibly drv_change_chanctx()
>  drv_unassign_vif_chanctx()
>  drv_remove_chanctx()
> 
> What I meant by "chanctx allocations" is drv_add_chanctx.
> 
> In particular when I write "chanctx overcommit" I refer to
> drv_add_chanctx() being called when in-driver chanctx count is already
> at peak for given interface combinations.
> 
> Or should we just simply assume this isn't a problem and drivers
> should *always* accept empty chanctx? Why bother with a return value
> then?

No, we shouldn't do that and assume that the driver would reject that.

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-07 13:03                                               ` Michal Kazior
  2014-05-08 10:06                                                 ` Johannes Berg
@ 2014-05-08 10:08                                                 ` Johannes Berg
  1 sibling, 0 replies; 199+ messages in thread
From: Johannes Berg @ 2014-05-08 10:08 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On Wed, 2014-05-07 at 15:03 +0200, Michal Kazior wrote:

> I think Luca and I have something like this in mind:
> 
>   drv_chanctx_update(hw,
>     { .type = CHANCTX_NEW_CHANCTX,
>       .chanctx = ctx2,
>     },
>     {
>       .type = CHANCTX_BIND,
>       .vif = vif1,
>       .chanctx_old = ctx1,
>       .chanctx_new = ctx2,
>     },
>     { 0 });
> 
> The driver would be free to re-order this internally to fulfill the
> entire update request.

Yeah, that's just a little complex maybe? And we don't really allow
*arbitrary* transactions, so we'd have to impose limits on the
transactions etc.

In fact, I'd argue that you shouldn't even have the
create/destroy/bind/unbind stuff listed here since that makes it more
difficult for the driver - having this whole "swap()" thing should be
easier to implement.

> Chanctx lifecycle is:
> 
>  drv_add_chanctx()
>  drv_assign_vif_chanctx()
>  // .. more assign/unassign .. possibly drv_change_chanctx()
>  drv_unassign_vif_chanctx()
>  drv_remove_chanctx()
> 
> What I meant by "chanctx allocations" is drv_add_chanctx.
> 
> In particular when I write "chanctx overcommit" I refer to
> drv_add_chanctx() being called when in-driver chanctx count is already
> at peak for given interface combinations.
> 
> Or should we just simply assume this isn't a problem and drivers
> should *always* accept empty chanctx? Why bother with a return value
> then?

No, we shouldn't do that and assume that the driver would reject that.

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-08 10:06                                                 ` Johannes Berg
@ 2014-05-08 10:41                                                   ` Michal Kazior
  2014-05-13 13:42                                                     ` Johannes Berg
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-08 10:41 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On 8 May 2014 12:06, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-05-07 at 15:03 +0200, Michal Kazior wrote:
>
>> I think Luca and I have something like this in mind:
>>
>>   drv_chanctx_update(hw,
>>     { .type = CHANCTX_NEW_CHANCTX,
>>       .chanctx = ctx2,
>>     },
>>     {
>>       .type = CHANCTX_BIND,
>>       .vif = vif1,
>>       .chanctx_old = ctx1,
>>       .chanctx_new = ctx2,
>>     },
>>     { 0 });
>>
>> The driver would be free to re-order this internally to fulfill the
>> entire update request.
>
> Yeah, that's just a little complex maybe? And we don't really allow
> *arbitrary* transactions, so we'd have to impose limits on the
> transactions etc.

Yeah. I also get the feeling it's overly complex.


>> Chanctx lifecycle is:
>>
>>  drv_add_chanctx()
>>  drv_assign_vif_chanctx()
>>  // .. more assign/unassign .. possibly drv_change_chanctx()
>>  drv_unassign_vif_chanctx()
>>  drv_remove_chanctx()
>>
>> What I meant by "chanctx allocations" is drv_add_chanctx.
>>
>> In particular when I write "chanctx overcommit" I refer to
>> drv_add_chanctx() being called when in-driver chanctx count is already
>> at peak for given interface combinations.
>>
>> Or should we just simply assume this isn't a problem and drivers
>> should *always* accept empty chanctx? Why bother with a return value
>> then?
>
> No, we shouldn't do that and assume that the driver would reject that.

Then, if you want to avoid the chanctx overcommit problem, you need to
make switch_vif_chanctx() to act as drv_add_chanctx(old_ctx) and
drv_remove_chanctx(new_ctx) implicitly, i.e.

 drv_switch_vif_chanctx(hw, vifs, n_vifs, old_ctx, new_ctx, SWAP);

instead of:

 drv_add_chanctx(new_ctx);
 drv_switch_vif_chanctx(hw, vifs, n_vifs, old_ctx, new_ctx, SWAP);
 drv_remove_chanctx(old_ctx);


Michał

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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-08 10:41                                                   ` Michal Kazior
@ 2014-05-13 13:42                                                     ` Johannes Berg
  2014-05-13 13:56                                                       ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-13 13:42 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On Thu, 2014-05-08 at 12:41 +0200, Michal Kazior wrote:

> Then, if you want to avoid the chanctx overcommit problem, you need to
> make switch_vif_chanctx() to act as drv_add_chanctx(old_ctx) and
> drv_remove_chanctx(new_ctx) implicitly, i.e.
> 
>  drv_switch_vif_chanctx(hw, vifs, n_vifs, old_ctx, new_ctx, SWAP);
> 
> instead of:
> 
>  drv_add_chanctx(new_ctx);
>  drv_switch_vif_chanctx(hw, vifs, n_vifs, old_ctx, new_ctx, SWAP);
>  drv_remove_chanctx(old_ctx);

That's pretty much what I'd considered, except that now as far as I read
the thread this wasn't sufficient for multi-context, so we'd need lists
of old/new contexts?

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-13 13:42                                                     ` Johannes Berg
@ 2014-05-13 13:56                                                       ` Michal Kazior
  2014-05-13 15:53                                                         ` Johannes Berg
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-13 13:56 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On 13 May 2014 15:42, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Thu, 2014-05-08 at 12:41 +0200, Michal Kazior wrote:
>
>> Then, if you want to avoid the chanctx overcommit problem, you need to
>> make switch_vif_chanctx() to act as drv_add_chanctx(old_ctx) and
>> drv_remove_chanctx(new_ctx) implicitly, i.e.
>>
>>  drv_switch_vif_chanctx(hw, vifs, n_vifs, old_ctx, new_ctx, SWAP);
>>
>> instead of:
>>
>>  drv_add_chanctx(new_ctx);
>>  drv_switch_vif_chanctx(hw, vifs, n_vifs, old_ctx, new_ctx, SWAP);
>>  drv_remove_chanctx(old_ctx);
>
> That's pretty much what I'd considered, except that now as far as I read
> the thread this wasn't sufficient for multi-context, so we'd need lists
> of old/new contexts?

Hmm.. In what cases do you need a list of old/new contexts?


Michal

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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-13 13:56                                                       ` Michal Kazior
@ 2014-05-13 15:53                                                         ` Johannes Berg
  2014-05-14  5:14                                                           ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-13 15:53 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On Tue, 2014-05-13 at 15:56 +0200, Michal Kazior wrote:

> > That's pretty much what I'd considered, except that now as far as I read
> > the thread this wasn't sufficient for multi-context, so we'd need lists
> > of old/new contexts?
> 
> Hmm.. In what cases do you need a list of old/new contexts?

That was Luca's scenario, no?

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-13 15:53                                                         ` Johannes Berg
@ 2014-05-14  5:14                                                           ` Michal Kazior
  2014-05-14  8:25                                                             ` Johannes Berg
  0 siblings, 1 reply; 199+ messages in thread
From: Michal Kazior @ 2014-05-14  5:14 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On 13 May 2014 17:53, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Tue, 2014-05-13 at 15:56 +0200, Michal Kazior wrote:
>
>> > That's pretty much what I'd considered, except that now as far as I read
>> > the thread this wasn't sufficient for multi-context, so we'd need lists
>> > of old/new contexts?
>>
>> Hmm.. In what cases do you need a list of old/new contexts?
>
> That was Luca's scenario, no?

Hmm.. I thought of it more as a theoretical appliance of the transaction API.

Let me re-post his example:

> With the generic transactions you could do:
>  - new chanctx2
>  - new chanctx3
>  - switch vif1 chanctx1->chanctx2
>  - switch vif2 chanctx1->chanctx3
>  - del chanctx1

>From this I infer you can run at least 2 chanctx since that's what you
end up with. This means you can perform one of the switches separately
because only 1 chanctx was used (that's the easy part that never
really required transactions or multi-vif-chanctx-assign to begin
with). The other switch would fall into the "incompat case" where you
need to basically swap chanctx for one of the vifs in the example.

So I fail to see why we would need to have a list of old/new contexts
in the proposed switch_vif_chanctx(), at least for now.


Michał

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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-14  5:14                                                           ` Michal Kazior
@ 2014-05-14  8:25                                                             ` Johannes Berg
  2014-05-14  8:51                                                               ` Michal Kazior
  0 siblings, 1 reply; 199+ messages in thread
From: Johannes Berg @ 2014-05-14  8:25 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On Wed, 2014-05-14 at 07:14 +0200, Michal Kazior wrote:

> Hmm.. I thought of it more as a theoretical appliance of the transaction API.
> 
> Let me re-post his example:
> 
> > With the generic transactions you could do:
> >  - new chanctx2
> >  - new chanctx3
> >  - switch vif1 chanctx1->chanctx2
> >  - switch vif2 chanctx1->chanctx3
> >  - del chanctx1
> 
> From this I infer you can run at least 2 chanctx since that's what you
> end up with. This means you can perform one of the switches separately
> because only 1 chanctx was used (that's the easy part that never
> really required transactions or multi-vif-chanctx-assign to begin
> with). The other switch would fall into the "incompat case" where you
> need to basically swap chanctx for one of the vifs in the example.
> 
> So I fail to see why we would need to have a list of old/new contexts
> in the proposed switch_vif_chanctx(), at least for now.

Further down the thread there was a discussion about e.g. radar
detection with the combinations, when one needs radar and the other
doesn't or something, then maybe you're running into a situation where
some interface combination allows more than 2 channels and the other
doesn't, or such.

johannes


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

* Re: [PATCH v5] mac80211: implement multi-vif in-place reservations
  2014-05-14  8:25                                                             ` Johannes Berg
@ 2014-05-14  8:51                                                               ` Michal Kazior
  0 siblings, 0 replies; 199+ messages in thread
From: Michal Kazior @ 2014-05-14  8:51 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Luca Coelho, linux-wireless, Simon Wunderlich

On 14 May 2014 10:25, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2014-05-14 at 07:14 +0200, Michal Kazior wrote:
>
>> Hmm.. I thought of it more as a theoretical appliance of the transaction API.
>>
>> Let me re-post his example:
>>
>> > With the generic transactions you could do:
>> >  - new chanctx2
>> >  - new chanctx3
>> >  - switch vif1 chanctx1->chanctx2
>> >  - switch vif2 chanctx1->chanctx3
>> >  - del chanctx1
>>
>> From this I infer you can run at least 2 chanctx since that's what you
>> end up with. This means you can perform one of the switches separately
>> because only 1 chanctx was used (that's the easy part that never
>> really required transactions or multi-vif-chanctx-assign to begin
>> with). The other switch would fall into the "incompat case" where you
>> need to basically swap chanctx for one of the vifs in the example.
>>
>> So I fail to see why we would need to have a list of old/new contexts
>> in the proposed switch_vif_chanctx(), at least for now.
>
> Further down the thread there was a discussion about e.g. radar
> detection with the combinations, when one needs radar and the other
> doesn't or something, then maybe you're running into a situation where
> some interface combination allows more than 2 channels and the other
> doesn't, or such.

Ah, you're right. I missed that. In that case we need to pass a list
of old/new contexts to switch_vif_chanctx().


Michał

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

end of thread, other threads:[~2014-05-14  8:51 UTC | newest]

Thread overview: 199+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-18 13:53 [RFC 00/21] cfg80211/mac80211: multi-vif csa Michal Kazior
2014-03-18 13:53 ` [RFC 01/21] mac80211: add support for radar detection for reservations Michal Kazior
2014-03-18 13:53 ` [RFC 02/21] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
2014-03-18 13:53 ` [RFC 03/21] mac80211: add max channel calculation utility function Michal Kazior
2014-03-18 16:17   ` Eliad Peller
2014-03-19  8:32     ` Michal Kazior
2014-03-19  8:43       ` Eliad Peller
2014-03-19  8:54         ` Michal Kazior
2014-03-19 10:18           ` Eliad Peller
2014-03-18 13:53 ` [RFC 04/21] mac80211: prevent chanctx overcommit Michal Kazior
2014-03-18 16:25   ` Eliad Peller
2014-03-18 13:53 ` [RFC 05/21] mac80211: track assigned vifs in chanctx Michal Kazior
2014-03-18 13:53 ` [RFC 06/21] mac80211: track reserved " Michal Kazior
2014-03-18 13:53 ` [RFC 07/21] mac80211: improve find_chanctx() for reservations Michal Kazior
2014-03-18 16:42   ` Eliad Peller
2014-03-19  8:34     ` Michal Kazior
2014-03-19  8:47       ` Eliad Peller
2014-03-19  9:00         ` Michal Kazior
2014-03-19 10:53           ` Eliad Peller
2014-03-18 13:53 ` [RFC 08/21] mac80211: improve chanctx reservation lookup Michal Kazior
2014-03-18 16:57   ` Eliad Peller
2014-03-19  8:45     ` Michal Kazior
2014-03-18 13:53 ` [RFC 09/21] mac80211: split ieee80211_new_chanctx() Michal Kazior
2014-03-18 13:53 ` [RFC 10/21] mac80211: split ieee80211_free_chanctx() Michal Kazior
2014-03-18 13:53 ` [RFC 11/21] mac80211: fix racy usage of chanctx->refcount Michal Kazior
2014-03-18 13:53 ` [RFC 12/21] mac80211: compute chanctx refcount on-the-fly Michal Kazior
2014-03-18 13:53 ` [RFC 13/21] mac80211: implement multi-vif in-place reservations Michal Kazior
2014-03-19 18:35   ` Eliad Peller
2014-03-20  7:25     ` Michal Kazior
2014-03-18 13:53 ` [RFC 14/21] mac80211: fix CSA tx queue locking Michal Kazior
2014-03-18 13:53 ` [RFC 15/21] mac80211: split CSA finalize function Michal Kazior
2014-03-18 13:53 ` [RFC 16/21] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
2014-03-18 13:53 ` [RFC 17/21] mac80211: use chanctx reservation for AP CSA Michal Kazior
2014-03-18 13:53 ` [RFC 18/21] mac80211: use chanctx reservation for STA CSA Michal Kazior
2014-03-18 13:53 ` [RFC 19/21] mac80211: ignore cqm during csa Michal Kazior
2014-03-18 13:53 ` [RFC 20/21] mac80211: remove old unused channel switching code Michal Kazior
2014-03-18 13:53 ` [RFC 21/21] cfg80211: remove channel_switch combination check Michal Kazior
2014-03-18 15:52 ` [RFC 00/21] cfg80211/mac80211: multi-vif csa Eliad Peller
2014-03-19  9:34   ` Luca Coelho
2014-03-21 13:47 ` [PATCH v2 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
2014-03-21 13:47   ` [PATCH v2 01/13] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
2014-03-28 13:05     ` Johannes Berg
2014-03-28 13:21       ` Michal Kazior
2014-03-28 13:22         ` Johannes Berg
2014-03-28 13:42           ` Michal Kazior
2014-03-28 13:49             ` Johannes Berg
2014-03-21 13:47   ` [PATCH v2 02/13] mac80211: add max channel calculation utility function Michal Kazior
2014-03-21 13:47   ` [PATCH v2 03/13] mac80211: prevent chanctx overcommit Michal Kazior
2014-03-25  7:59     ` Luca Coelho
2014-03-25  8:13       ` Luca Coelho
2014-03-25  8:37       ` Michal Kazior
2014-03-25  9:45         ` Luca Coelho
2014-03-21 13:47   ` [PATCH v2 04/13] mac80211: add support for radar detection for reservations Michal Kazior
2014-03-21 13:47   ` [PATCH v2 05/13] mac80211: track assigned vifs in chanctx Michal Kazior
2014-03-28 13:06     ` Johannes Berg
2014-03-21 13:47   ` [PATCH v2 06/13] mac80211: track reserved " Michal Kazior
2014-03-28 13:07     ` Johannes Berg
2014-03-21 13:47   ` [PATCH v2 07/13] mac80211: improve find_chanctx() for reservations Michal Kazior
2014-03-28 13:08     ` Johannes Berg
2014-03-28 13:32       ` Michal Kazior
2014-03-21 13:47   ` [PATCH v2 08/13] mac80211: improve chanctx reservation lookup Michal Kazior
2014-03-21 13:47   ` [PATCH v2 09/13] mac80211: split ieee80211_new_chanctx() Michal Kazior
2014-03-21 13:47   ` [PATCH v2 10/13] mac80211: split ieee80211_free_chanctx() Michal Kazior
2014-03-21 13:47   ` [PATCH v2 11/13] mac80211: fix racy usage of chanctx->refcount Michal Kazior
2014-03-21 13:47   ` [PATCH v2 12/13] mac80211: compute chanctx refcount on-the-fly Michal Kazior
2014-03-28 13:11     ` Johannes Berg
2014-03-28 13:22       ` Michal Kazior
2014-03-28 13:25         ` Johannes Berg
2014-03-21 13:47   ` [PATCH v2 13/13] mac80211: implement multi-vif in-place reservations Michal Kazior
2014-03-31 10:39   ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Michal Kazior
2014-03-31 10:39     ` [PATCH v3 01/13] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
2014-03-31 10:39     ` [PATCH v3 02/13] mac80211: add max channel calculation utility function Michal Kazior
2014-04-08 13:23       ` Johannes Berg
2014-03-31 10:39     ` [PATCH v3 03/13] mac80211: prevent chanctx overcommit Michal Kazior
2014-03-31 10:39     ` [PATCH v3 04/13] mac80211: add support for radar detection for reservations Michal Kazior
2014-04-08 13:25       ` Johannes Berg
2014-04-09  7:05         ` Michal Kazior
2014-03-31 10:39     ` [PATCH v3 05/13] mac80211: track assigned vifs in chanctx Michal Kazior
2014-03-31 10:39     ` [PATCH v3 06/13] mac80211: track reserved " Michal Kazior
2014-03-31 10:39     ` [PATCH v3 07/13] mac80211: improve find_chanctx() for reservations Michal Kazior
2014-03-31 10:39     ` [PATCH v3 08/13] mac80211: improve chanctx reservation lookup Michal Kazior
2014-03-31 10:39     ` [PATCH v3 09/13] mac80211: split ieee80211_new_chanctx() Michal Kazior
2014-03-31 10:39     ` [PATCH v3 10/13] mac80211: split ieee80211_free_chanctx() Michal Kazior
2014-03-31 10:39     ` [PATCH v3 11/13] mac80211: fix racy usage of chanctx->refcount Michal Kazior
2014-03-31 10:39     ` [PATCH v3 12/13] mac80211: compute chanctx refcount on-the-fly Michal Kazior
2014-03-31 10:39     ` [PATCH v3 13/13] mac80211: implement multi-vif in-place reservations Michal Kazior
2014-03-31 16:15       ` Eliad Peller
2014-04-01  5:10         ` Michal Kazior
2014-04-01  7:46           ` Eliad Peller
2014-04-01  7:54             ` Michal Kazior
2014-04-01  8:10               ` Eliad Peller
2014-04-01  8:26                 ` Michal Kazior
2014-04-08 13:30     ` [PATCH v3 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Johannes Berg
2014-04-08 14:00       ` Luca Coelho
2014-04-09  7:07         ` Michal Kazior
2014-04-09 13:29     ` [PATCH v4 " Michal Kazior
2014-04-09 13:29       ` [PATCH v4 01/13] cfg80211: allow drivers to iterate over matching combinations Michal Kazior
2014-04-09 13:29       ` [PATCH v4 02/13] mac80211: add max channel calculation utility function Michal Kazior
2014-04-09 13:29       ` [PATCH v4 03/13] mac80211: prevent chanctx overcommit Michal Kazior
2014-04-09 13:29       ` [PATCH v4 04/13] mac80211: add support for radar detection for reservations Michal Kazior
2014-04-09 13:29       ` [PATCH v4 05/13] mac80211: track assigned vifs in chanctx Michal Kazior
2014-04-09 13:29       ` [PATCH v4 06/13] mac80211: track reserved " Michal Kazior
2014-04-09 13:29       ` [PATCH v4 07/13] mac80211: improve find_chanctx() for reservations Michal Kazior
2014-04-09 13:29       ` [PATCH v4 08/13] mac80211: improve chanctx reservation lookup Michal Kazior
2014-04-09 13:29       ` [PATCH v4 09/13] mac80211: split ieee80211_new_chanctx() Michal Kazior
2014-04-09 13:29       ` [PATCH v4 10/13] mac80211: split ieee80211_free_chanctx() Michal Kazior
2014-04-09 13:29       ` [PATCH v4 11/13] mac80211: fix racy usage of chanctx->refcount Michal Kazior
2014-04-09 13:29       ` [PATCH v4 12/13] mac80211: compute chanctx refcount on-the-fly Michal Kazior
2014-04-09 13:29       ` [PATCH v4 13/13] mac80211: implement multi-vif in-place reservations Michal Kazior
2014-04-28 16:32         ` [v4 " Zhao, Gang
2014-04-29  6:10           ` Michal Kazior
2014-04-29 19:44             ` Johannes Berg
2014-04-30  9:21         ` [PATCH v5] " Michal Kazior
2014-05-06 10:41           ` Johannes Berg
2014-05-06 12:47             ` Michal Kazior
2014-05-06 14:05               ` Johannes Berg
2014-05-07  6:05                 ` Michal Kazior
2014-05-07  8:07                   ` Johannes Berg
2014-05-07  8:51                     ` Michal Kazior
2014-05-07  9:41                       ` Luca Coelho
2014-05-07  9:40                     ` Luca Coelho
2014-05-07 10:02                       ` Michal Kazior
2014-05-07 10:16                         ` Luca Coelho
2014-05-07 10:38                           ` Michal Kazior
2014-05-07 11:09                             ` Johannes Berg
2014-05-07 11:19                               ` Michal Kazior
2014-05-07 11:54                                 ` Johannes Berg
2014-05-07 12:08                                   ` Luca Coelho
2014-05-07 12:13                                     ` Johannes Berg
2014-05-07 12:20                                       ` Luca Coelho
2014-05-07 12:38                                         ` Johannes Berg
2014-05-07 12:44                                           ` Michal Kazior
2014-05-07 12:53                                             ` Johannes Berg
2014-05-07 13:03                                               ` Michal Kazior
2014-05-08 10:06                                                 ` Johannes Berg
2014-05-08 10:41                                                   ` Michal Kazior
2014-05-13 13:42                                                     ` Johannes Berg
2014-05-13 13:56                                                       ` Michal Kazior
2014-05-13 15:53                                                         ` Johannes Berg
2014-05-14  5:14                                                           ` Michal Kazior
2014-05-14  8:25                                                             ` Johannes Berg
2014-05-14  8:51                                                               ` Michal Kazior
2014-05-08 10:08                                                 ` Johannes Berg
2014-05-07 12:53                                           ` Luca Coelho
2014-05-07 13:06                                             ` Johannes Berg
2014-05-07 13:10                                               ` Luca Coelho
2014-05-08 10:03                                                 ` Johannes Berg
2014-05-07 12:27                                       ` Michal Kazior
2014-05-07 12:36                                         ` Johannes Berg
2014-05-07 12:20                                   ` Michal Kazior
2014-05-07 12:34                                     ` Johannes Berg
2014-05-07 11:48                               ` Luca Coelho
2014-05-07  9:27                   ` Luca Coelho
2014-05-07 11:09                     ` Johannes Berg
2014-05-07 11:24                       ` Luca Coelho
2014-04-25 15:20       ` [PATCH v4 00/13] cfg80211/mac80211: implement multi-vif chanctx reservations Johannes Berg
2014-04-28  6:16         ` Michal Kazior
2014-03-21 13:52 ` [PATCH v2 0/7] cfg80211/mac80211: implement multi-vif csa Michal Kazior
2014-03-21 13:52   ` [PATCH v2 1/7] cfg80211: fix radar_detect combination checking Michal Kazior
2014-03-28 12:59     ` Johannes Berg
2014-03-21 13:52   ` [PATCH v2 2/7] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
2014-03-28 13:00     ` Johannes Berg
2014-03-21 13:52   ` [PATCH v2 3/7] mac80211: use chanctx reservation for AP CSA Michal Kazior
2014-03-28 13:01     ` Johannes Berg
2014-03-21 13:52   ` [PATCH v2 4/7] mac80211: use chanctx reservation for STA CSA Michal Kazior
2014-03-21 13:52   ` [PATCH v2 5/7] mac80211: ignore cqm during csa Michal Kazior
2014-03-21 13:52   ` [PATCH v2 6/7] mac80211: remove old unused channel switching code Michal Kazior
2014-03-28 13:03     ` Johannes Berg
2014-03-21 13:52   ` [PATCH v2 7/7] cfg80211: remove channel_switch combination check Michal Kazior
2014-03-31 12:04   ` [PATCH v3 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
2014-03-31 12:04     ` [PATCH v3 1/5] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
2014-03-31 12:04     ` [PATCH v3 2/5] mac80211: use chanctx reservation for AP CSA Michal Kazior
2014-03-31 13:12       ` Michal Kazior
2014-03-31 12:04     ` [PATCH v3 3/5] mac80211: use chanctx reservation for STA CSA Michal Kazior
2014-03-31 12:04     ` [PATCH v3 4/5] mac80211: ignore cqm during csa Michal Kazior
2014-03-31 12:04     ` [PATCH v3 5/5] cfg80211: remove channel_switch combination check Michal Kazior
2014-04-09 13:45     ` [PATCH v4 0/5] cfg80211/mac80211: implement multi-vif csa Michal Kazior
2014-04-09 13:45       ` [PATCH v4 1/5] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
2014-04-09 13:45       ` [PATCH v4 2/5] mac80211: use chanctx reservation for AP CSA Michal Kazior
2014-05-06 14:42         ` Johannes Berg
2014-05-07  7:25           ` Michal Kazior
2014-05-07  8:05             ` Johannes Berg
2014-05-07  9:05               ` Michal Kazior
2014-05-07  9:06                 ` Michal Kazior
2014-05-07  9:07                 ` Johannes Berg
2014-05-07  9:41                   ` Michal Kazior
2014-05-07 11:17                     ` Johannes Berg
2014-05-07 11:43                       ` Michal Kazior
2014-05-07 11:50                         ` Johannes Berg
2014-05-07 12:12                           ` Michal Kazior
2014-04-09 13:45       ` [PATCH v4 3/5] mac80211: use chanctx reservation for STA CSA Michal Kazior
2014-05-06 14:43         ` Johannes Berg
2014-05-07  7:35           ` Michal Kazior
2014-05-07  8:03             ` Johannes Berg
2014-04-09 13:45       ` [PATCH v4 4/5] mac80211: ignore cqm during csa Michal Kazior
2014-05-06 14:45         ` Johannes Berg
2014-04-09 13:45       ` [PATCH v4 5/5] cfg80211: remove channel_switch combination check Michal Kazior
2014-05-06 14:45         ` Johannes Berg
2014-05-07  7:40           ` Michal Kazior

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.