Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0166da9 authored by Michal Kazior's avatar Michal Kazior Committed by Johannes Berg
Browse files

mac80211: compute chanctx refcount on-the-fly



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: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 2b32713d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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;
	}
+45 −14
Original line number Diff line number Diff line
@@ -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 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,

	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;
		}
+2 −1
Original line number Diff line number Diff line
@@ -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;
@@ -1803,6 +1802,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);
+1 −1
Original line number Diff line number Diff line
@@ -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,