2014-02-28 12:23:25

by Luca Coelho

[permalink] [raw]
Subject: [PATCH v3 0/3] mac802111: channel context reservation

From: Luciano Coelho <[email protected]>

Hi,

In v3:

* promoted to PATCH ;)
* applied comments by Michał (see inlined in the patches);
* removed the "add usage of CS channel reservation for STA" patch,
since it's independent and is not ready;

This series is based on top of mac80211-next/master, without including
my combination check changes. When the combination check patchset
gets applied, I can either send the "merge" of the two features as a
separate patchset or I can modify this patchset accordingly (though I
prefer the former, so I can do things in small steps ;).

--
Cheers,
Luca.

Luciano Coelho (3):
mac80211: split ieee80211_vif_change_channel in two
mac80211: implement chanctx reservation
mac80211: allow reservation of a running chanctx

include/net/mac80211.h | 7 ++
net/mac80211/chan.c | 227 +++++++++++++++++++++++++++++++++++++++++----
net/mac80211/ieee80211_i.h | 20 +++-
3 files changed, 236 insertions(+), 18 deletions(-)

--
1.8.5.3



2014-02-28 12:23:26

by Luca Coelho

[permalink] [raw]
Subject: [PATCH v3 3/3] mac80211: allow reservation of a running chanctx

From: Luciano Coelho <[email protected]>

With single-channel drivers, we need to be able to change a running
chanctx if we want to use chanctx reservation. Not all drivers may be
able to do this, so add a flag that indicates support for it.

Changing a running chanctx can also be used as an optimization in
multi-channel drivers when the context needs to be reserved for future
usage.

Introduce IEEE80211_CHANCTX_RESERVED chanctx mode to mark a channel as
reserved so nobody else can use it (since we know it's going to
change). In the future, we may allow several vifs to use the same
reservation as long as they plan to use the chanctx on the same
future channel.

Signed-off-by: Luciano Coelho <[email protected]>
---
In v3:

* reworded the TODO, slightly;
---
include/net/mac80211.h | 7 ++++++
net/mac80211/chan.c | 61 ++++++++++++++++++++++++++++++++++++++++------
net/mac80211/ieee80211_i.h | 7 +++++-
3 files changed, 67 insertions(+), 8 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 86faa41..54c9ce7 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1553,6 +1553,12 @@ 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,
@@ -1584,6 +1590,7 @@ 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 9897c2e..1aec5ac 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -177,6 +177,13 @@ 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_RESERVED)
+ continue;
+
if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
continue;

@@ -621,7 +628,9 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
if (WARN_ON(!sdata->reserved_chanctx))
return -EINVAL;

- if (--sdata->reserved_chanctx->refcount == 0)
+ if (sdata->reserved_chanctx->mode == IEEE80211_CHANCTX_RESERVED)
+ sdata->reserved_chanctx->mode = sdata->reserved_mode;
+ else if (--sdata->reserved_chanctx->refcount == 0)
ieee80211_free_chanctx(sdata->local, sdata->reserved_chanctx);

sdata->reserved_chanctx = NULL;
@@ -651,19 +660,42 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
/* try to find another context with the chandef we want */
new_ctx = ieee80211_find_chanctx(local, chandef,
IEEE80211_CHANCTX_SHARED);
- if (!new_ctx) {
- /* create a new context */
+ if (new_ctx) {
+ /* reserve the existing compatible context */
+ sdata->reserved_chanctx = new_ctx;
+ new_ctx->refcount++;
+ } else if (curr_ctx->refcount == 1 &&
+ (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
+ /* TODO: when implementing support for multiple
+ * interfaces switching at the same time, we may want
+ * other vifs to reserve it as well, as long as
+ * they're planning to switch to the same channel. In
+ * that case, we probably have to save the
+ * reserved_chandef and the reserved_mode elements in
+ * the context as well.
+ */
+ sdata->reserved_mode = curr_ctx->mode;
+
+ /* We're the only user of the current context, mark it
+ * as reserved, so nobody tries to use it until we
+ * finish the channel switch. This is an optimization
+ * to prevent waste of contexts when the number is
+ * limited.
+ */
+ curr_ctx->mode = IEEE80211_CHANCTX_RESERVED;
+ sdata->reserved_chanctx = curr_ctx;
+ } else {
+ /* create a new context and reserve it */
new_ctx = ieee80211_new_chanctx(local, chandef,
IEEE80211_CHANCTX_SHARED);
if (IS_ERR(new_ctx)) {
ret = PTR_ERR(new_ctx);
goto out;
}
- }
+ sdata->reserved_chanctx = new_ctx;

- /* reserve the new or existing context */
- sdata->reserved_chanctx = new_ctx;
- new_ctx->refcount++;
+ new_ctx->refcount++;
+ }

sdata->reserved_chandef = *chandef;
out:
@@ -701,6 +733,21 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,

old_ctx = container_of(conf, struct ieee80211_chanctx, conf);

+ if (old_ctx == ctx) {
+ WARN_ON(!ctx->mode != IEEE80211_CHANCTX_RESERVED);
+
+ /* This is our own context, just change it */
+ ret = __ieee80211_vif_change_channel(sdata, old_ctx,
+ &local_changed);
+ if (ret)
+ goto out;
+
+ ctx->mode = sdata->reserved_mode;
+
+ *changed = local_changed;
+ goto out;
+ }
+
ieee80211_stop_queues_by_reason(&local->hw,
IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CHANCTX);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 58b6477..56f1981 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -681,10 +681,14 @@ enum ieee80211_sdata_state_bits {
* @IEEE80211_CHANCTX_EXCLUSIVE: channel context can be used
* only by a single interface. This can be used for example for
* non-fixed channel IBSS.
+ * @IEEE80211_CHANCTX_RESERVED: the channel context is reserved for
+ * future change and cannot be used by other interfaces until the
+ * reservation is taken into use.
*/
enum ieee80211_chanctx_mode {
IEEE80211_CHANCTX_SHARED,
- IEEE80211_CHANCTX_EXCLUSIVE
+ IEEE80211_CHANCTX_EXCLUSIVE,
+ IEEE80211_CHANCTX_RESERVED
};

struct ieee80211_chanctx {
@@ -759,6 +763,7 @@ struct ieee80211_sub_if_data {
/* context reservation -- protected with chanctx_mtx */
struct ieee80211_chanctx *reserved_chanctx;
struct cfg80211_chan_def reserved_chandef;
+ enum ieee80211_chanctx_mode reserved_mode;

/* used to reconfigure hardware SM PS */
struct work_struct recalc_smps;
--
1.8.5.3


2014-02-28 12:23:26

by Luca Coelho

[permalink] [raw]
Subject: [PATCH v3 2/3] mac80211: implement chanctx reservation

From: Luciano Coelho <[email protected]>

In order to support channel switch with multiple vifs and multiple
contexts, we implement a concept of channel context reservation. This
allows us to reserve a channel context to be used later.

The reservation functionality is not tied directly to channel switch
and may be used in other situations (eg. reserving a channel context
during IBSS join).

We first check if an existing compatible context exists and if it
does, we reserve it. If there is no compatible context we create a
new one and reserve it.

Signed-off-by: Luciano Coelho <[email protected]>
---
In RFC v2:

* reformulated the patch to make channel reservation generic and
not only for channel switch, as we may find other uses for it in
the future;
* added ieee80211_vif_unreserve_chanctx();
* removed reservation of the current chanctx from this patch;
* added a stop_queue_reason for chanctx reservation;
* added a few TODOs according to Michal's comments to be handled in
future patch series;
* set sdata->csa_chandef to the received chandef in all cases (it
was only happening in the alone-in-the-vif case;

In v3:

* removed stray empty line;
* reworded the commit message;
* added reserved_chandef;
* added comment about reserved_chanctx and reserved_chandef protection;
* wake the queues if ieee80211_assign_vif_chanctx() fails;
---
net/mac80211/chan.c | 138 +++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/ieee80211_i.h | 13 +++++
2 files changed, 151 insertions(+)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index a27c6ec..9897c2e 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -419,6 +419,9 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)

ctx = container_of(conf, struct ieee80211_chanctx, conf);

+ if (sdata->reserved_chanctx)
+ ieee80211_vif_unreserve_chanctx(sdata);
+
ieee80211_unassign_vif_chanctx(sdata, ctx);
if (ctx->refcount == 0)
ieee80211_free_chanctx(local, ctx);
@@ -611,6 +614,141 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
return ret;
}

+int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
+{
+ lockdep_assert_held(&sdata->local->chanctx_mtx);
+
+ if (WARN_ON(!sdata->reserved_chanctx))
+ return -EINVAL;
+
+ if (--sdata->reserved_chanctx->refcount == 0)
+ ieee80211_free_chanctx(sdata->local, sdata->reserved_chanctx);
+
+ sdata->reserved_chanctx = NULL;
+
+ return 0;
+}
+
+int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
+ const struct cfg80211_chan_def *chandef)
+{
+ 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);
+
+ conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+ lockdep_is_held(&local->chanctx_mtx));
+ if (!conf) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ 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,
+ IEEE80211_CHANCTX_SHARED);
+ if (!new_ctx) {
+ /* create a new context */
+ new_ctx = ieee80211_new_chanctx(local, chandef,
+ IEEE80211_CHANCTX_SHARED);
+ if (IS_ERR(new_ctx)) {
+ ret = PTR_ERR(new_ctx);
+ goto out;
+ }
+ }
+
+ /* reserve the new or existing context */
+ sdata->reserved_chanctx = new_ctx;
+ new_ctx->refcount++;
+
+ sdata->reserved_chandef = *chandef;
+out:
+ mutex_unlock(&local->chanctx_mtx);
+ return ret;
+}
+
+int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
+ u32 *changed)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_chanctx *ctx;
+ struct ieee80211_chanctx *old_ctx;
+ struct ieee80211_chanctx_conf *conf;
+ int ret, local_changed = *changed;
+
+ /* TODO: need to recheck if the chandef is usable etc.? */
+
+ lockdep_assert_held(&local->mtx);
+
+ mutex_lock(&local->chanctx_mtx);
+
+ ctx = sdata->reserved_chanctx;
+ if (WARN_ON(!ctx)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+ lockdep_is_held(&local->chanctx_mtx));
+ if (!conf) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
+
+ ieee80211_stop_queues_by_reason(&local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_CHANCTX);
+
+ ieee80211_unassign_vif_chanctx(sdata, old_ctx);
+ if (old_ctx->refcount == 0)
+ ieee80211_free_chanctx(local, old_ctx);
+
+ /* TODO: we're assuming that the bandwidth of the context
+ * changes here, but in fact, it will only change if the
+ * combination of the channels used in this context change.
+ * We should set this flag according to what happens when
+ * ieee80211_recalc_chanctx_chantype() is called. Maybe the
+ * nicest thing to do would be to change that function so that
+ * it returns changed flags (which will be either 0 or
+ * BSS_CHANGED_BANDWIDTH).
+ */
+
+ if (sdata->vif.bss_conf.chandef.width != ctx->conf.def.width)
+ local_changed |= BSS_CHANGED_BANDWIDTH;
+
+ sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
+
+ /* unref our reservation before assigning */
+ ctx->refcount--;
+ sdata->reserved_chanctx = NULL;
+ ret = ieee80211_assign_vif_chanctx(sdata, ctx);
+ if (ret) {
+ /* if assign fails refcount stays the same */
+ if (ctx->refcount == 0)
+ ieee80211_free_chanctx(local, ctx);
+ goto out_wake;
+ }
+
+ *changed = local_changed;
+
+ ieee80211_recalc_chanctx_chantype(local, ctx);
+ ieee80211_recalc_smps_chanctx(local, ctx);
+ ieee80211_recalc_radar_chanctx(local, ctx);
+out_wake:
+ ieee80211_wake_queues_by_reason(&sdata->local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_CHANCTX);
+out:
+ mutex_unlock(&local->chanctx_mtx);
+ return ret;
+}
+
int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
u32 *changed)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8603dfb..58b6477 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -756,6 +756,10 @@ struct ieee80211_sub_if_data {
bool csa_radar_required;
struct cfg80211_chan_def csa_chandef;

+ /* context reservation -- protected with chanctx_mtx */
+ struct ieee80211_chanctx *reserved_chanctx;
+ struct cfg80211_chan_def reserved_chandef;
+
/* used to reconfigure hardware SM PS */
struct work_struct recalc_smps;

@@ -899,6 +903,7 @@ enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL,
IEEE80211_QUEUE_STOP_REASON_FLUSH,
+ IEEE80211_QUEUE_STOP_REASON_CHANCTX,
};

#ifdef CONFIG_MAC80211_LEDS
@@ -1776,6 +1781,14 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode);
int __must_check
+ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
+ const struct cfg80211_chan_def *chandef);
+int __must_check
+ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
+ u32 *changed);
+int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata);
+
+int __must_check
ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
u32 *changed);
--
1.8.5.3


2014-02-28 12:23:26

by Luca Coelho

[permalink] [raw]
Subject: [PATCH v3 1/3] mac80211: split ieee80211_vif_change_channel in two

From: Luciano Coelho <[email protected]>

ieee80211_vif_change_channel() locks chanctx_mtx. When implementing
channel reservation for CS, we will need to call the function to
change channel when the lock is already held, so split the part that
requires the lock out and leave the locking in the original function.

Signed-off-by: Luciano Coelho <[email protected]>
---
net/mac80211/chan.c | 58 ++++++++++++++++++++++++++++++-----------------------
1 file changed, 33 insertions(+), 25 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 42c6592..a27c6ec 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -547,39 +547,20 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
return ret;
}

-int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
- u32 *changed)
+static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_chanctx *ctx,
+ u32 *changed)
{
struct ieee80211_local *local = sdata->local;
- struct ieee80211_chanctx_conf *conf;
- struct ieee80211_chanctx *ctx;
const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;
- int ret;
u32 chanctx_changed = 0;

- lockdep_assert_held(&local->mtx);
-
- /* should never be called if not performing a channel switch. */
- if (WARN_ON(!sdata->vif.csa_active))
- return -EINVAL;
-
if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
IEEE80211_CHAN_DISABLED))
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);
- if (ctx->refcount != 1) {
- ret = -EINVAL;
- goto out;
- }
+ if (ctx->refcount != 1)
+ return -EINVAL;

if (sdata->vif.bss_conf.chandef.width != chandef->width) {
chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH;
@@ -597,7 +578,34 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
ieee80211_recalc_radar_chanctx(local, ctx);
ieee80211_recalc_chanctx_min_def(local, ctx);

- ret = 0;
+ 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;
--
1.8.5.3


2014-03-03 13:08:17

by Luca Coelho

[permalink] [raw]
Subject: Re: [PATCH v3 2/3] mac80211: implement chanctx reservation

On Mon, 2014-03-03 at 13:46 +0100, Michal Kazior wrote:
> On 28 February 2014 13:23, Luca Coelho <[email protected]> wrote:
>
> [...]
>
> > +int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
> > + const struct cfg80211_chan_def *chandef)
> > +{
> > + 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);
> > +
> > + conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
> > + lockdep_is_held(&local->chanctx_mtx));
> > + if (!conf) {
> > + ret = -EINVAL;
> > + goto out;
> > + }
> > +
> > + 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,
> > + IEEE80211_CHANCTX_SHARED);
>
> I find one thing puzzling -- why is ieee80211_find_chanctx() calling
> ieee80211_change_chanctx()? I don't think it makes sense.

It shouldn't be calling it. I had already spotted it with Johannes. If
something fails later on, we have already changed the changed the
context, but we shouldn't.



> I can't
> understand why chanctx has two chandefs (isn't min_def enough
> already?).

Beats me, I'm not very familiar with this part. :\


> > + /* TODO: we're assuming that the bandwidth of the context
> > + * changes here, but in fact, it will only change if the
> > + * combination of the channels used in this context change.
> > + * We should set this flag according to what happens when
> > + * ieee80211_recalc_chanctx_chantype() is called. Maybe the
> > + * nicest thing to do would be to change that function so that
> > + * it returns changed flags (which will be either 0 or
> > + * BSS_CHANGED_BANDWIDTH).
> > + */
>
> I don't understand this. Either I'm missing something here or we had a
> misunderstanding earlier. It doesn't matter what chanctx width we end
> up with. What's important is the BSS width here and it's readily
> available to check & use.

Okay, I think I was confused.


> > +
> > + if (sdata->vif.bss_conf.chandef.width != ctx->conf.def.width)
> > + local_changed |= BSS_CHANGED_BANDWIDTH;
>
> This should use sdata->reserved_chandef.width instead of
> ctx->conf.def.width, shouldn't it?

But I think I understand now, this is about the width of this vif, not
about the combination used by the chanctx. The chanctx updates its own
width according to the widths of all vifs assigned to it. I'll fix
this.

--
Luca.


2014-03-03 12:46:44

by Michal Kazior

[permalink] [raw]
Subject: Re: [PATCH v3 2/3] mac80211: implement chanctx reservation

On 28 February 2014 13:23, Luca Coelho <[email protected]> wrote:

[...]

> +int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
> + const struct cfg80211_chan_def *chandef)
> +{
> + 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);
> +
> + conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
> + lockdep_is_held(&local->chanctx_mtx));
> + if (!conf) {
> + ret = -EINVAL;
> + goto out;
> + }
> +
> + 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,
> + IEEE80211_CHANCTX_SHARED);

I find one thing puzzling -- why is ieee80211_find_chanctx() calling
ieee80211_change_chanctx()? I don't think it makes sense. I can't
understand why chanctx has two chandefs (isn't min_def enough
already?).


> + /* TODO: we're assuming that the bandwidth of the context
> + * changes here, but in fact, it will only change if the
> + * combination of the channels used in this context change.
> + * We should set this flag according to what happens when
> + * ieee80211_recalc_chanctx_chantype() is called. Maybe the
> + * nicest thing to do would be to change that function so that
> + * it returns changed flags (which will be either 0 or
> + * BSS_CHANGED_BANDWIDTH).
> + */

I don't understand this. Either I'm missing something here or we had a
misunderstanding earlier. It doesn't matter what chanctx width we end
up with. What's important is the BSS width here and it's readily
available to check & use.


> +
> + if (sdata->vif.bss_conf.chandef.width != ctx->conf.def.width)
> + local_changed |= BSS_CHANGED_BANDWIDTH;

This should use sdata->reserved_chandef.width instead of
ctx->conf.def.width, shouldn't it?


Michał

2014-03-03 11:54:07

by Michal Kazior

[permalink] [raw]
Subject: Re: [PATCH v3 2/3] mac80211: implement chanctx reservation

On 28 February 2014 13:23, Luca Coelho <[email protected]> wrote:

[...]

> +int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
> + const struct cfg80211_chan_def *chandef)
> +{
> + 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);
> +
> + conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
> + lockdep_is_held(&local->chanctx_mtx));
> + if (!conf) {
> + ret = -EINVAL;
> + goto out;
> + }
> +
> + 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,
> + IEEE80211_CHANCTX_SHARED);
> + if (!new_ctx) {
> + /* create a new context */
> + new_ctx = ieee80211_new_chanctx(local, chandef,
> + IEEE80211_CHANCTX_SHARED);

Shouldn't you use curr_ctx->mode here instead of SHARED? Or perhaps
the function should take `mode` argument..

For CSA it's probably okay to just use curr_ctx->mode, but for a more
generic reservation it should probably be an argument.


Michał

2014-03-04 09:03:44

by Luca Coelho

[permalink] [raw]
Subject: Re: [PATCH v3 2/3] mac80211: implement chanctx reservation

On Mon, 2014-03-03 at 12:54 +0100, Michal Kazior wrote:
> On 28 February 2014 13:23, Luca Coelho <[email protected]> wrote:
>
> [...]
>
> > +int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
> > + const struct cfg80211_chan_def *chandef)
> > +{
> > + 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);
> > +
> > + conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
> > + lockdep_is_held(&local->chanctx_mtx));
> > + if (!conf) {
> > + ret = -EINVAL;
> > + goto out;
> > + }
> > +
> > + 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,
> > + IEEE80211_CHANCTX_SHARED);
> > + if (!new_ctx) {
> > + /* create a new context */
> > + new_ctx = ieee80211_new_chanctx(local, chandef,
> > + IEEE80211_CHANCTX_SHARED);
>
> Shouldn't you use curr_ctx->mode here instead of SHARED? Or perhaps
> the function should take `mode` argument..
>
> For CSA it's probably okay to just use curr_ctx->mode, but for a more
> generic reservation it should probably be an argument.

You're right. I'll add mode as an argument to this function in v4.

--
Luca