1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright(c) 2020-2022 Realtek Corporation
3 */
4
5 #include "chan.h"
6 #include "debug.h"
7 #include "util.h"
8
rtw89_get_subband_type(enum rtw89_band band,u8 center_chan)9 static enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band,
10 u8 center_chan)
11 {
12 switch (band) {
13 default:
14 case RTW89_BAND_2G:
15 switch (center_chan) {
16 default:
17 case 1 ... 14:
18 return RTW89_CH_2G;
19 }
20 case RTW89_BAND_5G:
21 switch (center_chan) {
22 default:
23 case 36 ... 64:
24 return RTW89_CH_5G_BAND_1;
25 case 100 ... 144:
26 return RTW89_CH_5G_BAND_3;
27 case 149 ... 177:
28 return RTW89_CH_5G_BAND_4;
29 }
30 case RTW89_BAND_6G:
31 switch (center_chan) {
32 default:
33 case 1 ... 29:
34 return RTW89_CH_6G_BAND_IDX0;
35 case 33 ... 61:
36 return RTW89_CH_6G_BAND_IDX1;
37 case 65 ... 93:
38 return RTW89_CH_6G_BAND_IDX2;
39 case 97 ... 125:
40 return RTW89_CH_6G_BAND_IDX3;
41 case 129 ... 157:
42 return RTW89_CH_6G_BAND_IDX4;
43 case 161 ... 189:
44 return RTW89_CH_6G_BAND_IDX5;
45 case 193 ... 221:
46 return RTW89_CH_6G_BAND_IDX6;
47 case 225 ... 253:
48 return RTW89_CH_6G_BAND_IDX7;
49 }
50 }
51 }
52
rtw89_get_primary_chan_idx(enum rtw89_bandwidth bw,u32 center_freq,u32 primary_freq)53 static enum rtw89_sc_offset rtw89_get_primary_chan_idx(enum rtw89_bandwidth bw,
54 u32 center_freq,
55 u32 primary_freq)
56 {
57 u8 primary_chan_idx;
58 u32 offset;
59
60 switch (bw) {
61 default:
62 case RTW89_CHANNEL_WIDTH_20:
63 primary_chan_idx = RTW89_SC_DONT_CARE;
64 break;
65 case RTW89_CHANNEL_WIDTH_40:
66 if (primary_freq > center_freq)
67 primary_chan_idx = RTW89_SC_20_UPPER;
68 else
69 primary_chan_idx = RTW89_SC_20_LOWER;
70 break;
71 case RTW89_CHANNEL_WIDTH_80:
72 case RTW89_CHANNEL_WIDTH_160:
73 if (primary_freq > center_freq) {
74 offset = (primary_freq - center_freq - 10) / 20;
75 primary_chan_idx = RTW89_SC_20_UPPER + offset * 2;
76 } else {
77 offset = (center_freq - primary_freq - 10) / 20;
78 primary_chan_idx = RTW89_SC_20_LOWER + offset * 2;
79 }
80 break;
81 }
82
83 return primary_chan_idx;
84 }
85
rtw89_chan_create(struct rtw89_chan * chan,u8 center_chan,u8 primary_chan,enum rtw89_band band,enum rtw89_bandwidth bandwidth)86 void rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan,
87 enum rtw89_band band, enum rtw89_bandwidth bandwidth)
88 {
89 enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
90 u32 center_freq, primary_freq;
91
92 memset(chan, 0, sizeof(*chan));
93 chan->channel = center_chan;
94 chan->primary_channel = primary_chan;
95 chan->band_type = band;
96 chan->band_width = bandwidth;
97
98 center_freq = ieee80211_channel_to_frequency(center_chan, nl_band);
99 primary_freq = ieee80211_channel_to_frequency(primary_chan, nl_band);
100
101 chan->freq = center_freq;
102 chan->subband_type = rtw89_get_subband_type(band, center_chan);
103 chan->pri_ch_idx = rtw89_get_primary_chan_idx(bandwidth, center_freq,
104 primary_freq);
105 }
106
rtw89_assign_entity_chan(struct rtw89_dev * rtwdev,enum rtw89_sub_entity_idx idx,const struct rtw89_chan * new)107 bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev,
108 enum rtw89_sub_entity_idx idx,
109 const struct rtw89_chan *new)
110 {
111 struct rtw89_hal *hal = &rtwdev->hal;
112 struct rtw89_chan *chan = &hal->sub[idx].chan;
113 struct rtw89_chan_rcd *rcd = &hal->sub[idx].rcd;
114 bool band_changed;
115
116 rcd->prev_primary_channel = chan->primary_channel;
117 rcd->prev_band_type = chan->band_type;
118 band_changed = new->band_type != chan->band_type;
119
120 *chan = *new;
121 return band_changed;
122 }
123
__rtw89_config_entity_chandef(struct rtw89_dev * rtwdev,enum rtw89_sub_entity_idx idx,const struct cfg80211_chan_def * chandef,bool from_stack)124 static void __rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
125 enum rtw89_sub_entity_idx idx,
126 const struct cfg80211_chan_def *chandef,
127 bool from_stack)
128 {
129 struct rtw89_hal *hal = &rtwdev->hal;
130
131 hal->sub[idx].chandef = *chandef;
132
133 if (from_stack)
134 set_bit(idx, hal->entity_map);
135 }
136
rtw89_config_entity_chandef(struct rtw89_dev * rtwdev,enum rtw89_sub_entity_idx idx,const struct cfg80211_chan_def * chandef)137 void rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
138 enum rtw89_sub_entity_idx idx,
139 const struct cfg80211_chan_def *chandef)
140 {
141 __rtw89_config_entity_chandef(rtwdev, idx, chandef, true);
142 }
143
rtw89_config_default_chandef(struct rtw89_dev * rtwdev)144 static void rtw89_config_default_chandef(struct rtw89_dev *rtwdev)
145 {
146 struct cfg80211_chan_def chandef = {0};
147
148 rtw89_get_default_chandef(&chandef);
149 __rtw89_config_entity_chandef(rtwdev, RTW89_SUB_ENTITY_0, &chandef, false);
150 }
151
rtw89_entity_init(struct rtw89_dev * rtwdev)152 void rtw89_entity_init(struct rtw89_dev *rtwdev)
153 {
154 struct rtw89_hal *hal = &rtwdev->hal;
155
156 bitmap_zero(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
157 rtw89_config_default_chandef(rtwdev);
158 }
159
rtw89_entity_recalc(struct rtw89_dev * rtwdev)160 enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
161 {
162 struct rtw89_hal *hal = &rtwdev->hal;
163 enum rtw89_entity_mode mode;
164 u8 weight;
165
166 weight = bitmap_weight(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
167 switch (weight) {
168 default:
169 rtw89_warn(rtwdev, "unknown ent chan weight: %d\n", weight);
170 bitmap_zero(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
171 fallthrough;
172 case 0:
173 rtw89_config_default_chandef(rtwdev);
174 fallthrough;
175 case 1:
176 mode = RTW89_ENTITY_MODE_SCC;
177 break;
178 }
179
180 rtw89_set_entity_mode(rtwdev, mode);
181 return mode;
182 }
183
rtw89_chanctx_ops_add(struct rtw89_dev * rtwdev,struct ieee80211_chanctx_conf * ctx)184 int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
185 struct ieee80211_chanctx_conf *ctx)
186 {
187 struct rtw89_hal *hal = &rtwdev->hal;
188 struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
189 const struct rtw89_chip_info *chip = rtwdev->chip;
190 u8 idx;
191
192 idx = find_first_zero_bit(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
193 if (idx >= chip->support_chanctx_num)
194 return -ENOENT;
195
196 rtw89_config_entity_chandef(rtwdev, idx, &ctx->def);
197 rtw89_set_channel(rtwdev);
198 cfg->idx = idx;
199 hal->sub[idx].cfg = cfg;
200 return 0;
201 }
202
rtw89_chanctx_ops_remove(struct rtw89_dev * rtwdev,struct ieee80211_chanctx_conf * ctx)203 void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
204 struct ieee80211_chanctx_conf *ctx)
205 {
206 struct rtw89_hal *hal = &rtwdev->hal;
207 struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
208 struct rtw89_vif *rtwvif;
209 u8 drop, roll;
210
211 drop = cfg->idx;
212 if (drop != RTW89_SUB_ENTITY_0)
213 goto out;
214
215 roll = find_next_bit(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY, drop + 1);
216
217 /* Follow rtw89_config_default_chandef() when rtw89_entity_recalc(). */
218 if (roll == NUM_OF_RTW89_SUB_ENTITY)
219 goto out;
220
221 /* RTW89_SUB_ENTITY_0 is going to release, and another exists.
222 * Make another roll down to RTW89_SUB_ENTITY_0 to replace.
223 */
224 hal->sub[roll].cfg->idx = RTW89_SUB_ENTITY_0;
225 hal->sub[RTW89_SUB_ENTITY_0] = hal->sub[roll];
226
227 rtw89_for_each_rtwvif(rtwdev, rtwvif) {
228 if (rtwvif->sub_entity_idx == roll)
229 rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0;
230 }
231
232 drop = roll;
233
234 out:
235 clear_bit(drop, hal->entity_map);
236 rtw89_set_channel(rtwdev);
237 }
238
rtw89_chanctx_ops_change(struct rtw89_dev * rtwdev,struct ieee80211_chanctx_conf * ctx,u32 changed)239 void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev,
240 struct ieee80211_chanctx_conf *ctx,
241 u32 changed)
242 {
243 struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
244 u8 idx = cfg->idx;
245
246 if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) {
247 rtw89_config_entity_chandef(rtwdev, idx, &ctx->def);
248 rtw89_set_channel(rtwdev);
249 }
250 }
251
rtw89_chanctx_ops_assign_vif(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif,struct ieee80211_chanctx_conf * ctx)252 int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev,
253 struct rtw89_vif *rtwvif,
254 struct ieee80211_chanctx_conf *ctx)
255 {
256 struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
257
258 rtwvif->sub_entity_idx = cfg->idx;
259 return 0;
260 }
261
rtw89_chanctx_ops_unassign_vif(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif,struct ieee80211_chanctx_conf * ctx)262 void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev,
263 struct rtw89_vif *rtwvif,
264 struct ieee80211_chanctx_conf *ctx)
265 {
266 rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0;
267 }
268