diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2014-04-09 09:29:33 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2014-04-25 11:08:30 -0400 |
commit | c0166da9fee2aa8de9d1f9460f62d02176c22350 (patch) | |
tree | 1c69b543bd332271501967f9913e0d65d92b6583 /net/mac80211 | |
parent | 2b32713d72c093889fe20642f6a8bc42083267d2 (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.c | 2 | ||||
-rw-r--r-- | net/mac80211/chan.c | 59 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | 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 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 | ||
12 | static 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 | |||
26 | static 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 | |||
40 | int 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 | |||
12 | static int ieee80211_num_chanctx(struct ieee80211_local *local) | 47 | static 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); | |||
1803 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); | 1802 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); |
1804 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | 1803 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, |
1805 | bool clear); | 1804 | bool clear); |
1805 | int ieee80211_chanctx_refcount(struct ieee80211_local *local, | ||
1806 | struct ieee80211_chanctx *ctx); | ||
1806 | 1807 | ||
1807 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | 1808 | void 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, |