aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2014-04-09 09:29:33 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-04-25 11:08:30 -0400
commitc0166da9fee2aa8de9d1f9460f62d02176c22350 (patch)
tree1c69b543bd332271501967f9913e0d65d92b6583 /net/mac80211
parent2b32713d72c093889fe20642f6a8bc42083267d2 (diff)
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: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/cfg.c2
-rw-r--r--net/mac80211/chan.c59
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/mlme.c2
4 files changed, 49 insertions, 17 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 9620d4fba0d1..4d15a1566cd5 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,
3251 3251
3252 /* don't handle for multi-VIF cases */ 3252 /* don't handle for multi-VIF cases */
3253 chanctx = container_of(conf, struct ieee80211_chanctx, conf); 3253 chanctx = container_of(conf, struct ieee80211_chanctx, conf);
3254 if (chanctx->refcount > 1) { 3254 if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
3255 mutex_unlock(&local->chanctx_mtx); 3255 mutex_unlock(&local->chanctx_mtx);
3256 return -EBUSY; 3256 return -EBUSY;
3257 } 3257 }
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index e4166b3af5d4..d8b1b8614842 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -9,6 +9,41 @@
9#include "ieee80211_i.h" 9#include "ieee80211_i.h"
10#include "driver-ops.h" 10#include "driver-ops.h"
11 11
12static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
13 struct ieee80211_chanctx *ctx)
14{
15 struct ieee80211_sub_if_data *sdata;
16 int num = 0;
17
18 lockdep_assert_held(&local->chanctx_mtx);
19
20 list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
21 num++;
22
23 return num;
24}
25
26static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
27 struct ieee80211_chanctx *ctx)
28{
29 struct ieee80211_sub_if_data *sdata;
30 int num = 0;
31
32 lockdep_assert_held(&local->chanctx_mtx);
33
34 list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list)
35 num++;
36
37 return num;
38}
39
40int ieee80211_chanctx_refcount(struct ieee80211_local *local,
41 struct ieee80211_chanctx *ctx)
42{
43 return ieee80211_chanctx_num_assigned(local, ctx) +
44 ieee80211_chanctx_num_reserved(local, ctx);
45}
46
12static int ieee80211_num_chanctx(struct ieee80211_local *local) 47static int ieee80211_num_chanctx(struct ieee80211_local *local)
13{ 48{
14 struct ieee80211_chanctx *ctx; 49 struct ieee80211_chanctx *ctx;
@@ -463,7 +498,7 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
463{ 498{
464 lockdep_assert_held(&local->chanctx_mtx); 499 lockdep_assert_held(&local->chanctx_mtx);
465 500
466 WARN_ON_ONCE(ctx->refcount != 0); 501 WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
467 502
468 list_del_rcu(&ctx->list); 503 list_del_rcu(&ctx->list);
469 ieee80211_del_chanctx(local, ctx); 504 ieee80211_del_chanctx(local, ctx);
@@ -542,7 +577,6 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
542 if (conf) { 577 if (conf) {
543 curr_ctx = container_of(conf, struct ieee80211_chanctx, conf); 578 curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
544 579
545 curr_ctx->refcount--;
546 drv_unassign_vif_chanctx(local, sdata, curr_ctx); 580 drv_unassign_vif_chanctx(local, sdata, curr_ctx);
547 conf = NULL; 581 conf = NULL;
548 list_del(&sdata->assigned_chanctx_list); 582 list_del(&sdata->assigned_chanctx_list);
@@ -553,7 +587,6 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
553 if (ret) 587 if (ret)
554 goto out; 588 goto out;
555 589
556 new_ctx->refcount++;
557 conf = &new_ctx->conf; 590 conf = &new_ctx->conf;
558 list_add(&sdata->assigned_chanctx_list, 591 list_add(&sdata->assigned_chanctx_list,
559 &new_ctx->assigned_vifs); 592 &new_ctx->assigned_vifs);
@@ -564,14 +597,14 @@ out:
564 597
565 sdata->vif.bss_conf.idle = !conf; 598 sdata->vif.bss_conf.idle = !conf;
566 599
567 if (curr_ctx && curr_ctx->refcount > 0) { 600 if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
568 ieee80211_recalc_chanctx_chantype(local, curr_ctx); 601 ieee80211_recalc_chanctx_chantype(local, curr_ctx);
569 ieee80211_recalc_smps_chanctx(local, curr_ctx); 602 ieee80211_recalc_smps_chanctx(local, curr_ctx);
570 ieee80211_recalc_radar_chanctx(local, curr_ctx); 603 ieee80211_recalc_radar_chanctx(local, curr_ctx);
571 ieee80211_recalc_chanctx_min_def(local, curr_ctx); 604 ieee80211_recalc_chanctx_min_def(local, curr_ctx);
572 } 605 }
573 606
574 if (new_ctx && new_ctx->refcount > 0) { 607 if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
575 ieee80211_recalc_txpower(sdata); 608 ieee80211_recalc_txpower(sdata);
576 ieee80211_recalc_chanctx_min_def(local, new_ctx); 609 ieee80211_recalc_chanctx_min_def(local, new_ctx);
577 } 610 }
@@ -603,7 +636,7 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
603 ieee80211_vif_unreserve_chanctx(sdata); 636 ieee80211_vif_unreserve_chanctx(sdata);
604 637
605 ieee80211_assign_vif_chanctx(sdata, NULL); 638 ieee80211_assign_vif_chanctx(sdata, NULL);
606 if (ctx->refcount == 0) 639 if (ieee80211_chanctx_refcount(local, ctx) == 0)
607 ieee80211_free_chanctx(local, ctx); 640 ieee80211_free_chanctx(local, ctx);
608} 641}
609 642
@@ -735,7 +768,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
735 ret = ieee80211_assign_vif_chanctx(sdata, ctx); 768 ret = ieee80211_assign_vif_chanctx(sdata, ctx);
736 if (ret) { 769 if (ret) {
737 /* if assign fails refcount stays the same */ 770 /* if assign fails refcount stays the same */
738 if (ctx->refcount == 0) 771 if (ieee80211_chanctx_refcount(local, ctx) == 0)
739 ieee80211_free_chanctx(local, ctx); 772 ieee80211_free_chanctx(local, ctx);
740 goto out; 773 goto out;
741 } 774 }
@@ -759,7 +792,7 @@ static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
759 IEEE80211_CHAN_DISABLED)) 792 IEEE80211_CHAN_DISABLED))
760 return -EINVAL; 793 return -EINVAL;
761 794
762 if (ctx->refcount != 1) 795 if (ieee80211_chanctx_refcount(local, ctx) != 1)
763 return -EINVAL; 796 return -EINVAL;
764 797
765 if (sdata->vif.bss_conf.chandef.width != chandef->width) { 798 if (sdata->vif.bss_conf.chandef.width != chandef->width) {
@@ -865,7 +898,7 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
865 list_del(&sdata->reserved_chanctx_list); 898 list_del(&sdata->reserved_chanctx_list);
866 sdata->reserved_chanctx = NULL; 899 sdata->reserved_chanctx = NULL;
867 900
868 if (--ctx->refcount == 0) 901 if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0)
869 ieee80211_free_chanctx(sdata->local, ctx); 902 ieee80211_free_chanctx(sdata->local, ctx);
870 903
871 return 0; 904 return 0;
@@ -894,7 +927,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
894 927
895 new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode); 928 new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
896 if (!new_ctx) { 929 if (!new_ctx) {
897 if (curr_ctx->refcount == 1 && 930 if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 &&
898 (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) { 931 (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
899 /* if we're the only users of the chanctx and 932 /* if we're the only users of the chanctx and
900 * the driver supports changing a running 933 * the driver supports changing a running
@@ -915,7 +948,6 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
915 } 948 }
916 949
917 list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs); 950 list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
918 new_ctx->refcount++;
919 sdata->reserved_chanctx = new_ctx; 951 sdata->reserved_chanctx = new_ctx;
920 sdata->reserved_chandef = *chandef; 952 sdata->reserved_chandef = *chandef;
921 sdata->reserved_radar_required = radar_required; 953 sdata->reserved_radar_required = radar_required;
@@ -961,7 +993,6 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
961 sdata->vif.bss_conf.chandef = sdata->reserved_chandef; 993 sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
962 994
963 /* unref our reservation */ 995 /* unref our reservation */
964 ctx->refcount--;
965 sdata->reserved_chanctx = NULL; 996 sdata->reserved_chanctx = NULL;
966 sdata->radar_required = sdata->reserved_radar_required; 997 sdata->radar_required = sdata->reserved_radar_required;
967 list_del(&sdata->reserved_chanctx_list); 998 list_del(&sdata->reserved_chanctx_list);
@@ -974,11 +1005,11 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
974 goto out; 1005 goto out;
975 } else { 1006 } else {
976 ret = ieee80211_assign_vif_chanctx(sdata, ctx); 1007 ret = ieee80211_assign_vif_chanctx(sdata, ctx);
977 if (old_ctx->refcount == 0) 1008 if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
978 ieee80211_free_chanctx(local, old_ctx); 1009 ieee80211_free_chanctx(local, old_ctx);
979 if (ret) { 1010 if (ret) {
980 /* if assign fails refcount stays the same */ 1011 /* if assign fails refcount stays the same */
981 if (ctx->refcount == 0) 1012 if (ieee80211_chanctx_refcount(local, ctx) == 0)
982 ieee80211_free_chanctx(local, ctx); 1013 ieee80211_free_chanctx(local, ctx);
983 goto out; 1014 goto out;
984 } 1015 }
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3eaf6d7fad52..b455f62d357a 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -695,7 +695,6 @@ struct ieee80211_chanctx {
695 struct list_head reserved_vifs; 695 struct list_head reserved_vifs;
696 696
697 enum ieee80211_chanctx_mode mode; 697 enum ieee80211_chanctx_mode mode;
698 int refcount;
699 bool driver_present; 698 bool driver_present;
700 699
701 struct ieee80211_chanctx_conf conf; 700 struct ieee80211_chanctx_conf conf;
@@ -1803,6 +1802,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
1803void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); 1802void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
1804void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, 1803void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
1805 bool clear); 1804 bool clear);
1805int ieee80211_chanctx_refcount(struct ieee80211_local *local,
1806 struct ieee80211_chanctx *ctx);
1806 1807
1807void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, 1808void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
1808 struct ieee80211_chanctx *chanctx); 1809 struct ieee80211_chanctx *chanctx);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index dee50aefd6e8..98755ce49af3 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,
1089 } 1089 }
1090 chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf), 1090 chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
1091 struct ieee80211_chanctx, conf); 1091 struct ieee80211_chanctx, conf);
1092 if (chanctx->refcount > 1) { 1092 if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
1093 sdata_info(sdata, 1093 sdata_info(sdata,
1094 "channel switch with multiple interfaces on the same channel, disconnecting\n"); 1094 "channel switch with multiple interfaces on the same channel, disconnecting\n");
1095 ieee80211_queue_work(&local->hw, 1095 ieee80211_queue_work(&local->hw,