aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2013-11-11 13:14:01 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-11-25 14:52:05 -0500
commit21f659bf1f93f7052b977d95cca560f02dc2edce (patch)
tree4c6634f65996b574b512f864fb77337ba34fbb1c
parentfbdd90ea830162960fb8fbe377dfef9a54d74d2f (diff)
mac80211: add min required channel definition field
Add a new field to ieee80211_chanctx_conf to indicate the min required channel configuration. Tuning to a narrower channel might help reducing the noise level and saving some power. The min required channel definition is the max of all min required channel definitions of the interfaces bound to this channel context. In AP mode, use 20MHz when there are no connected station. When a new station is added/removed, calculate the new max bandwidth supported by any of the stations (e.g. 80MHz when 80MHz and 40MHz stations are connected). In other cases, simply use bss_conf.chandef as the min required chandef. Notify drivers about changes to this field by calling drv_change_chanctx with a new CHANGE_MIN_WIDTH notification. Signed-off-by: Eliad Peller <eliad@wizery.com> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/net/mac80211.h4
-rw-r--r--net/mac80211/chan.c139
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/sta_info.c2
-rw-r--r--net/mac80211/trace.h21
-rw-r--r--net/mac80211/util.c20
6 files changed, 187 insertions, 2 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index cca02b2f5c7e..3cd408b326de 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -154,12 +154,14 @@ struct ieee80211_low_level_stats {
154 * @IEEE80211_CHANCTX_CHANGE_RADAR: radar detection flag changed 154 * @IEEE80211_CHANCTX_CHANGE_RADAR: radar detection flag changed
155 * @IEEE80211_CHANCTX_CHANGE_CHANNEL: switched to another operating channel, 155 * @IEEE80211_CHANCTX_CHANGE_CHANNEL: switched to another operating channel,
156 * this is used only with channel switching with CSA 156 * this is used only with channel switching with CSA
157 * @IEEE80211_CHANCTX_CHANGE_MIN_WIDTH: The min required channel width changed
157 */ 158 */
158enum ieee80211_chanctx_change { 159enum ieee80211_chanctx_change {
159 IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(0), 160 IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(0),
160 IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(1), 161 IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(1),
161 IEEE80211_CHANCTX_CHANGE_RADAR = BIT(2), 162 IEEE80211_CHANCTX_CHANGE_RADAR = BIT(2),
162 IEEE80211_CHANCTX_CHANGE_CHANNEL = BIT(3), 163 IEEE80211_CHANCTX_CHANGE_CHANNEL = BIT(3),
164 IEEE80211_CHANCTX_CHANGE_MIN_WIDTH = BIT(4),
163}; 165};
164 166
165/** 167/**
@@ -169,6 +171,7 @@ enum ieee80211_chanctx_change {
169 * that contains it is visible in mac80211 only. 171 * that contains it is visible in mac80211 only.
170 * 172 *
171 * @def: the channel definition 173 * @def: the channel definition
174 * @min_def: the minimum channel definition currently required.
172 * @rx_chains_static: The number of RX chains that must always be 175 * @rx_chains_static: The number of RX chains that must always be
173 * active on the channel to receive MIMO transmissions 176 * active on the channel to receive MIMO transmissions
174 * @rx_chains_dynamic: The number of RX chains that must be enabled 177 * @rx_chains_dynamic: The number of RX chains that must be enabled
@@ -180,6 +183,7 @@ enum ieee80211_chanctx_change {
180 */ 183 */
181struct ieee80211_chanctx_conf { 184struct ieee80211_chanctx_conf {
182 struct cfg80211_chan_def def; 185 struct cfg80211_chan_def def;
186 struct cfg80211_chan_def min_def;
183 187
184 u8 rx_chains_static, rx_chains_dynamic; 188 u8 rx_chains_static, rx_chains_dynamic;
185 189
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index cefee2be0b8e..a57d5d9466bc 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -9,6 +9,140 @@
9#include "ieee80211_i.h" 9#include "ieee80211_i.h"
10#include "driver-ops.h" 10#include "driver-ops.h"
11 11
12static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
13{
14 switch (sta->bandwidth) {
15 case IEEE80211_STA_RX_BW_20:
16 if (sta->ht_cap.ht_supported)
17 return NL80211_CHAN_WIDTH_20;
18 else
19 return NL80211_CHAN_WIDTH_20_NOHT;
20 case IEEE80211_STA_RX_BW_40:
21 return NL80211_CHAN_WIDTH_40;
22 case IEEE80211_STA_RX_BW_80:
23 return NL80211_CHAN_WIDTH_80;
24 case IEEE80211_STA_RX_BW_160:
25 /*
26 * This applied for both 160 and 80+80. since we use
27 * the returned value to consider degradation of
28 * ctx->conf.min_def, we have to make sure to take
29 * the bigger one (NL80211_CHAN_WIDTH_160).
30 * Otherwise we might try degrading even when not
31 * needed, as the max required sta_bw returned (80+80)
32 * might be smaller than the configured bw (160).
33 */
34 return NL80211_CHAN_WIDTH_160;
35 default:
36 WARN_ON(1);
37 return NL80211_CHAN_WIDTH_20;
38 }
39}
40
41static enum nl80211_chan_width
42ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata)
43{
44 enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
45 struct sta_info *sta;
46
47 rcu_read_lock();
48 list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
49 if (sdata != sta->sdata &&
50 !(sta->sdata->bss && sta->sdata->bss == sdata->bss))
51 continue;
52
53 if (!sta->uploaded)
54 continue;
55
56 max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta));
57 }
58 rcu_read_unlock();
59
60 return max_bw;
61}
62
63static enum nl80211_chan_width
64ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
65 struct ieee80211_chanctx_conf *conf)
66{
67 struct ieee80211_sub_if_data *sdata;
68 enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
69
70 rcu_read_lock();
71 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
72 struct ieee80211_vif *vif = &sdata->vif;
73 enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;
74
75 if (!ieee80211_sdata_running(sdata))
76 continue;
77
78 if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
79 continue;
80
81 switch (vif->type) {
82 case NL80211_IFTYPE_AP:
83 case NL80211_IFTYPE_AP_VLAN:
84 width = ieee80211_get_max_required_bw(sdata);
85 break;
86 case NL80211_IFTYPE_P2P_DEVICE:
87 continue;
88 case NL80211_IFTYPE_STATION:
89 case NL80211_IFTYPE_ADHOC:
90 case NL80211_IFTYPE_WDS:
91 case NL80211_IFTYPE_MESH_POINT:
92 width = vif->bss_conf.chandef.width;
93 break;
94 case NL80211_IFTYPE_UNSPECIFIED:
95 case NUM_NL80211_IFTYPES:
96 case NL80211_IFTYPE_MONITOR:
97 case NL80211_IFTYPE_P2P_CLIENT:
98 case NL80211_IFTYPE_P2P_GO:
99 WARN_ON_ONCE(1);
100 }
101 max_bw = max(max_bw, width);
102 }
103 rcu_read_unlock();
104
105 return max_bw;
106}
107
108/*
109 * recalc the min required chan width of the channel context, which is
110 * the max of min required widths of all the interfaces bound to this
111 * channel context.
112 */
113void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
114 struct ieee80211_chanctx *ctx)
115{
116 enum nl80211_chan_width max_bw;
117 struct cfg80211_chan_def min_def;
118
119 lockdep_assert_held(&local->chanctx_mtx);
120
121 /* don't optimize 5MHz, 10MHz, and radar_enabled confs */
122 if (ctx->conf.def.width == NL80211_CHAN_WIDTH_5 ||
123 ctx->conf.def.width == NL80211_CHAN_WIDTH_10 ||
124 ctx->conf.radar_enabled) {
125 ctx->conf.min_def = ctx->conf.def;
126 return;
127 }
128
129 max_bw = ieee80211_get_chanctx_max_required_bw(local, &ctx->conf);
130
131 /* downgrade chandef up to max_bw */
132 min_def = ctx->conf.def;
133 while (min_def.width > max_bw)
134 ieee80211_chandef_downgrade(&min_def);
135
136 if (cfg80211_chandef_identical(&ctx->conf.min_def, &min_def))
137 return;
138
139 ctx->conf.min_def = min_def;
140 if (!ctx->driver_present)
141 return;
142
143 drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_MIN_WIDTH);
144}
145
12static void ieee80211_change_chanctx(struct ieee80211_local *local, 146static void ieee80211_change_chanctx(struct ieee80211_local *local,
13 struct ieee80211_chanctx *ctx, 147 struct ieee80211_chanctx *ctx,
14 const struct cfg80211_chan_def *chandef) 148 const struct cfg80211_chan_def *chandef)
@@ -20,6 +154,7 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
20 154
21 ctx->conf.def = *chandef; 155 ctx->conf.def = *chandef;
22 drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH); 156 drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);
157 ieee80211_recalc_chanctx_min_def(local, ctx);
23 158
24 if (!local->use_chanctx) { 159 if (!local->use_chanctx) {
25 local->_oper_chandef = *chandef; 160 local->_oper_chandef = *chandef;
@@ -93,6 +228,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
93 ctx->conf.rx_chains_dynamic = 1; 228 ctx->conf.rx_chains_dynamic = 1;
94 ctx->mode = mode; 229 ctx->mode = mode;
95 ctx->conf.radar_enabled = ieee80211_is_radar_required(local); 230 ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
231 ieee80211_recalc_chanctx_min_def(local, ctx);
96 if (!local->use_chanctx) 232 if (!local->use_chanctx)
97 local->hw.conf.radar_enabled = ctx->conf.radar_enabled; 233 local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
98 234
@@ -179,6 +315,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
179 ctx->refcount++; 315 ctx->refcount++;
180 316
181 ieee80211_recalc_txpower(sdata); 317 ieee80211_recalc_txpower(sdata);
318 ieee80211_recalc_chanctx_min_def(local, ctx);
182 sdata->vif.bss_conf.idle = false; 319 sdata->vif.bss_conf.idle = false;
183 320
184 if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && 321 if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
@@ -243,6 +380,7 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
243 ieee80211_recalc_chanctx_chantype(sdata->local, ctx); 380 ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
244 ieee80211_recalc_smps_chanctx(local, ctx); 381 ieee80211_recalc_smps_chanctx(local, ctx);
245 ieee80211_recalc_radar_chanctx(local, ctx); 382 ieee80211_recalc_radar_chanctx(local, ctx);
383 ieee80211_recalc_chanctx_min_def(local, ctx);
246 } 384 }
247} 385}
248 386
@@ -456,6 +594,7 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
456 ieee80211_recalc_chanctx_chantype(local, ctx); 594 ieee80211_recalc_chanctx_chantype(local, ctx);
457 ieee80211_recalc_smps_chanctx(local, ctx); 595 ieee80211_recalc_smps_chanctx(local, ctx);
458 ieee80211_recalc_radar_chanctx(local, ctx); 596 ieee80211_recalc_radar_chanctx(local, ctx);
597 ieee80211_recalc_chanctx_min_def(local, ctx);
459 598
460 ret = 0; 599 ret = 0;
461 out: 600 out:
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 0faadf15cd5c..4022ee1afb9f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1693,6 +1693,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
1693int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata, 1693int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
1694 enum ieee80211_smps_mode smps_mode); 1694 enum ieee80211_smps_mode smps_mode);
1695void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); 1695void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);
1696void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata);
1696 1697
1697size_t ieee80211_ie_split(const u8 *ies, size_t ielen, 1698size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
1698 const u8 *ids, int n_ids, size_t offset); 1699 const u8 *ids, int n_ids, size_t offset);
@@ -1741,6 +1742,8 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
1741 struct ieee80211_chanctx *chanctx); 1742 struct ieee80211_chanctx *chanctx);
1742void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, 1743void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
1743 struct ieee80211_chanctx *chanctx); 1744 struct ieee80211_chanctx *chanctx);
1745void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
1746 struct ieee80211_chanctx *ctx);
1744 1747
1745void ieee80211_dfs_cac_timer(unsigned long data); 1748void ieee80211_dfs_cac_timer(unsigned long data);
1746void ieee80211_dfs_cac_timer_work(struct work_struct *work); 1749void ieee80211_dfs_cac_timer_work(struct work_struct *work);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 45b5f610674e..7b69d4c3db55 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -507,6 +507,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
507 507
508 set_sta_flag(sta, WLAN_STA_INSERTED); 508 set_sta_flag(sta, WLAN_STA_INSERTED);
509 509
510 ieee80211_recalc_min_chandef(sdata);
510 ieee80211_sta_debugfs_add(sta); 511 ieee80211_sta_debugfs_add(sta);
511 rate_control_add_sta_debugfs(sta); 512 rate_control_add_sta_debugfs(sta);
512 513
@@ -869,6 +870,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
869 870
870 rate_control_remove_sta_debugfs(sta); 871 rate_control_remove_sta_debugfs(sta);
871 ieee80211_sta_debugfs_remove(sta); 872 ieee80211_sta_debugfs_remove(sta);
873 ieee80211_recalc_min_chandef(sdata);
872 874
873 call_rcu(&sta->rcu_head, free_sta_rcu); 875 call_rcu(&sta->rcu_head, free_sta_rcu);
874 876
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 5d62c5804819..8db560190ca6 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -41,14 +41,31 @@
41#define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \ 41#define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \
42 __entry->center_freq1, __entry->center_freq2 42 __entry->center_freq1, __entry->center_freq2
43 43
44#define MIN_CHANDEF_ENTRY \
45 __field(u32, min_control_freq) \
46 __field(u32, min_chan_width) \
47 __field(u32, min_center_freq1) \
48 __field(u32, min_center_freq2)
49
50#define MIN_CHANDEF_ASSIGN(c) \
51 __entry->min_control_freq = (c)->chan ? (c)->chan->center_freq : 0; \
52 __entry->min_chan_width = (c)->width; \
53 __entry->min_center_freq1 = (c)->center_freq1; \
54 __entry->min_center_freq2 = (c)->center_freq2;
55#define MIN_CHANDEF_PR_FMT " min_control:%d MHz min_width:%d min_center: %d/%d MHz"
56#define MIN_CHANDEF_PR_ARG __entry->min_control_freq, __entry->min_chan_width, \
57 __entry->min_center_freq1, __entry->min_center_freq2
58
44#define CHANCTX_ENTRY CHANDEF_ENTRY \ 59#define CHANCTX_ENTRY CHANDEF_ENTRY \
60 MIN_CHANDEF_ENTRY \
45 __field(u8, rx_chains_static) \ 61 __field(u8, rx_chains_static) \
46 __field(u8, rx_chains_dynamic) 62 __field(u8, rx_chains_dynamic)
47#define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def) \ 63#define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def) \
64 MIN_CHANDEF_ASSIGN(&ctx->conf.min_def) \
48 __entry->rx_chains_static = ctx->conf.rx_chains_static; \ 65 __entry->rx_chains_static = ctx->conf.rx_chains_static; \
49 __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic 66 __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic
50#define CHANCTX_PR_FMT CHANDEF_PR_FMT " chains:%d/%d" 67#define CHANCTX_PR_FMT CHANDEF_PR_FMT MIN_CHANDEF_PR_FMT " chains:%d/%d"
51#define CHANCTX_PR_ARG CHANDEF_PR_ARG, \ 68#define CHANCTX_PR_ARG CHANDEF_PR_ARG, MIN_CHANDEF_PR_ARG, \
52 __entry->rx_chains_static, __entry->rx_chains_dynamic 69 __entry->rx_chains_static, __entry->rx_chains_dynamic
53 70
54 71
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index bb92f8e0f84e..06265d7f8cc3 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1804,6 +1804,26 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
1804 mutex_unlock(&local->chanctx_mtx); 1804 mutex_unlock(&local->chanctx_mtx);
1805} 1805}
1806 1806
1807void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata)
1808{
1809 struct ieee80211_local *local = sdata->local;
1810 struct ieee80211_chanctx_conf *chanctx_conf;
1811 struct ieee80211_chanctx *chanctx;
1812
1813 mutex_lock(&local->chanctx_mtx);
1814
1815 chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
1816 lockdep_is_held(&local->chanctx_mtx));
1817
1818 if (WARN_ON_ONCE(!chanctx_conf))
1819 goto unlock;
1820
1821 chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
1822 ieee80211_recalc_chanctx_min_def(local, chanctx);
1823 unlock:
1824 mutex_unlock(&local->chanctx_mtx);
1825}
1826
1807static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) 1827static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
1808{ 1828{
1809 int i; 1829 int i;