1

wifi: mac80211: don't enter idle during link switch

When doing link switch with a disjoint set of links before
and after the switch, we end up removing all channel contexts,
adding new ones later. This looks like 'idle' to the code now,
and we enter idle which also includes flushing queues. But we
can't actually flush since we don't have a link active (bound
to a channel context), and entering idle just to leave it again
is also wrong.

Fix this by passing through an indication that we shouldn't do
any idle checks in this case.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://msgid.link/20240320091155.170328bac555.If4a522a9dd3133b91983854b909a4de13aa635da@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2024-03-20 09:13:59 +02:00
parent 62bdd97598
commit 3c9ff1a1e1
3 changed files with 22 additions and 16 deletions

View File

@ -695,26 +695,29 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
} }
static void ieee80211_del_chanctx(struct ieee80211_local *local, static void ieee80211_del_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx) struct ieee80211_chanctx *ctx,
bool skip_idle_recalc)
{ {
lockdep_assert_wiphy(local->hw.wiphy); lockdep_assert_wiphy(local->hw.wiphy);
drv_remove_chanctx(local, ctx); drv_remove_chanctx(local, ctx);
if (!skip_idle_recalc)
ieee80211_recalc_idle(local); ieee80211_recalc_idle(local);
ieee80211_remove_wbrf(local, &ctx->conf.def); ieee80211_remove_wbrf(local, &ctx->conf.def);
} }
static void ieee80211_free_chanctx(struct ieee80211_local *local, static void ieee80211_free_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx) struct ieee80211_chanctx *ctx,
bool skip_idle_recalc)
{ {
lockdep_assert_wiphy(local->hw.wiphy); lockdep_assert_wiphy(local->hw.wiphy);
WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0); WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
list_del_rcu(&ctx->list); list_del_rcu(&ctx->list);
ieee80211_del_chanctx(local, ctx); ieee80211_del_chanctx(local, ctx, skip_idle_recalc);
kfree_rcu(ctx, rcu_head); kfree_rcu(ctx, rcu_head);
} }
@ -1002,7 +1005,7 @@ int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link)
list_del_rcu(&ctx->list); list_del_rcu(&ctx->list);
kfree_rcu(ctx, rcu_head); kfree_rcu(ctx, rcu_head);
} else { } else {
ieee80211_free_chanctx(sdata->local, ctx); ieee80211_free_chanctx(sdata->local, ctx, false);
} }
} }
@ -1218,7 +1221,7 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
CHANCTX_SWMODE_REASSIGN_VIF); CHANCTX_SWMODE_REASSIGN_VIF);
if (err) { if (err) {
if (ieee80211_chanctx_refcount(local, new_ctx) == 0) if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
ieee80211_free_chanctx(local, new_ctx); ieee80211_free_chanctx(local, new_ctx, false);
goto out; goto out;
} }
@ -1232,7 +1235,7 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
ieee80211_check_fast_xmit_iface(sdata); ieee80211_check_fast_xmit_iface(sdata);
if (ieee80211_chanctx_refcount(local, old_ctx) == 0) if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
ieee80211_free_chanctx(local, old_ctx); ieee80211_free_chanctx(local, old_ctx, false);
ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL); ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL);
ieee80211_recalc_smps_chanctx(local, new_ctx); ieee80211_recalc_smps_chanctx(local, new_ctx);
@ -1286,7 +1289,7 @@ ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link)
err = ieee80211_assign_link_chanctx(link, new_ctx); err = ieee80211_assign_link_chanctx(link, new_ctx);
if (err) { if (err) {
if (ieee80211_chanctx_refcount(local, new_ctx) == 0) if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
ieee80211_free_chanctx(local, new_ctx); ieee80211_free_chanctx(local, new_ctx, false);
goto out; goto out;
} }
@ -1383,7 +1386,7 @@ static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local)
if (!list_empty(&ctx->replace_ctx->assigned_links)) if (!list_empty(&ctx->replace_ctx->assigned_links))
continue; continue;
ieee80211_del_chanctx(local, ctx->replace_ctx); ieee80211_del_chanctx(local, ctx->replace_ctx, false);
err = ieee80211_add_chanctx(local, ctx); err = ieee80211_add_chanctx(local, ctx);
if (err) if (err)
goto err; goto err;
@ -1400,7 +1403,7 @@ err:
if (!list_empty(&ctx->replace_ctx->assigned_links)) if (!list_empty(&ctx->replace_ctx->assigned_links))
continue; continue;
ieee80211_del_chanctx(local, ctx); ieee80211_del_chanctx(local, ctx, false);
WARN_ON(ieee80211_add_chanctx(local, ctx->replace_ctx)); WARN_ON(ieee80211_add_chanctx(local, ctx->replace_ctx));
} }
@ -1652,7 +1655,8 @@ err:
return err; return err;
} }
static void __ieee80211_link_release_channel(struct ieee80211_link_data *link) void __ieee80211_link_release_channel(struct ieee80211_link_data *link,
bool skip_idle_recalc)
{ {
struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_bss_conf *link_conf = link->conf; struct ieee80211_bss_conf *link_conf = link->conf;
@ -1680,7 +1684,7 @@ static void __ieee80211_link_release_channel(struct ieee80211_link_data *link)
ieee80211_assign_link_chanctx(link, NULL); ieee80211_assign_link_chanctx(link, NULL);
if (ieee80211_chanctx_refcount(local, ctx) == 0) if (ieee80211_chanctx_refcount(local, ctx) == 0)
ieee80211_free_chanctx(local, ctx); ieee80211_free_chanctx(local, ctx, skip_idle_recalc);
link->radar_required = false; link->radar_required = false;
@ -1721,7 +1725,7 @@ int ieee80211_link_use_channel(struct ieee80211_link_data *link,
if (ret < 0) if (ret < 0)
goto out; goto out;
__ieee80211_link_release_channel(link); __ieee80211_link_release_channel(link, false);
ctx = ieee80211_find_chanctx(local, chanreq, mode); ctx = ieee80211_find_chanctx(local, chanreq, mode);
if (!ctx) if (!ctx)
@ -1737,7 +1741,7 @@ int ieee80211_link_use_channel(struct ieee80211_link_data *link,
if (ret) { if (ret) {
/* if assign fails refcount stays the same */ /* if assign fails refcount stays the same */
if (ieee80211_chanctx_refcount(local, ctx) == 0) if (ieee80211_chanctx_refcount(local, ctx) == 0)
ieee80211_free_chanctx(local, ctx); ieee80211_free_chanctx(local, ctx, false);
goto out; goto out;
} }
@ -1930,7 +1934,7 @@ void ieee80211_link_release_channel(struct ieee80211_link_data *link)
lockdep_assert_wiphy(sdata->local->hw.wiphy); lockdep_assert_wiphy(sdata->local->hw.wiphy);
if (rcu_access_pointer(link->conf->chanctx_conf)) if (rcu_access_pointer(link->conf->chanctx_conf))
__ieee80211_link_release_channel(link); __ieee80211_link_release_channel(link, false);
} }
void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link) void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link)

View File

@ -2567,6 +2567,8 @@ int __must_check
ieee80211_link_change_chanreq(struct ieee80211_link_data *link, ieee80211_link_change_chanreq(struct ieee80211_link_data *link,
const struct ieee80211_chan_req *req, const struct ieee80211_chan_req *req,
u64 *changed); u64 *changed);
void __ieee80211_link_release_channel(struct ieee80211_link_data *link,
bool skip_idle_recalc);
void ieee80211_link_release_channel(struct ieee80211_link_data *link); void ieee80211_link_release_channel(struct ieee80211_link_data *link);
void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link); void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link);
void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link, void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,

View File

@ -358,7 +358,7 @@ static int _ieee80211_set_active_links(struct ieee80211_sub_if_data *sdata,
ieee80211_teardown_tdls_peers(link); ieee80211_teardown_tdls_peers(link);
ieee80211_link_release_channel(link); __ieee80211_link_release_channel(link, true);
} }
list_for_each_entry(sta, &local->sta_list, list) { list_for_each_entry(sta, &local->sta_list, list) {