xref: /freebsd/sys/contrib/dev/rtw89/chan.c (revision 783d3ff6d7fae619db8a7990b8a6387de0c677b5)
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 
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 
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 
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 
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 
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 
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 
144 void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev,
145 			      enum rtw89_sub_entity_idx idx,
146 			      const struct cfg80211_chan_def *chandef)
147 {
148 	struct rtw89_hal *hal = &rtwdev->hal;
149 	enum rtw89_sub_entity_idx cur;
150 
151 	if (chandef) {
152 		cur = atomic_cmpxchg(&hal->roc_entity_idx,
153 				     RTW89_SUB_ENTITY_IDLE, idx);
154 		if (cur != RTW89_SUB_ENTITY_IDLE) {
155 			rtw89_debug(rtwdev, RTW89_DBG_TXRX,
156 				    "ROC still processing on entity %d\n", idx);
157 			return;
158 		}
159 
160 		hal->roc_chandef = *chandef;
161 	} else {
162 		cur = atomic_cmpxchg(&hal->roc_entity_idx, idx,
163 				     RTW89_SUB_ENTITY_IDLE);
164 		if (cur == idx)
165 			return;
166 
167 		if (cur == RTW89_SUB_ENTITY_IDLE)
168 			rtw89_debug(rtwdev, RTW89_DBG_TXRX,
169 				    "ROC already finished on entity %d\n", idx);
170 		else
171 			rtw89_debug(rtwdev, RTW89_DBG_TXRX,
172 				    "ROC is processing on entity %d\n", cur);
173 	}
174 }
175 
176 static void rtw89_config_default_chandef(struct rtw89_dev *rtwdev)
177 {
178 	struct cfg80211_chan_def chandef = {0};
179 
180 	rtw89_get_default_chandef(&chandef);
181 	__rtw89_config_entity_chandef(rtwdev, RTW89_SUB_ENTITY_0, &chandef, false);
182 }
183 
184 void rtw89_entity_init(struct rtw89_dev *rtwdev)
185 {
186 	struct rtw89_hal *hal = &rtwdev->hal;
187 
188 	bitmap_zero(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
189 	atomic_set(&hal->roc_entity_idx, RTW89_SUB_ENTITY_IDLE);
190 	rtw89_config_default_chandef(rtwdev);
191 }
192 
193 enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
194 {
195 	struct rtw89_hal *hal = &rtwdev->hal;
196 	enum rtw89_entity_mode mode;
197 	u8 weight;
198 
199 	weight = bitmap_weight(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
200 	switch (weight) {
201 	default:
202 		rtw89_warn(rtwdev, "unknown ent chan weight: %d\n", weight);
203 		bitmap_zero(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
204 		fallthrough;
205 	case 0:
206 		rtw89_config_default_chandef(rtwdev);
207 		fallthrough;
208 	case 1:
209 		mode = RTW89_ENTITY_MODE_SCC;
210 		break;
211 	}
212 
213 	rtw89_set_entity_mode(rtwdev, mode);
214 	return mode;
215 }
216 
217 int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
218 			  struct ieee80211_chanctx_conf *ctx)
219 {
220 	struct rtw89_hal *hal = &rtwdev->hal;
221 	struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
222 	const struct rtw89_chip_info *chip = rtwdev->chip;
223 	u8 idx;
224 
225 	idx = find_first_zero_bit(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
226 	if (idx >= chip->support_chanctx_num)
227 		return -ENOENT;
228 
229 	rtw89_config_entity_chandef(rtwdev, idx, &ctx->def);
230 	rtw89_set_channel(rtwdev);
231 	cfg->idx = idx;
232 	hal->sub[idx].cfg = cfg;
233 	return 0;
234 }
235 
236 void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
237 			      struct ieee80211_chanctx_conf *ctx)
238 {
239 	struct rtw89_hal *hal = &rtwdev->hal;
240 	struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
241 	struct rtw89_vif *rtwvif;
242 	u8 drop, roll;
243 
244 	drop = cfg->idx;
245 	if (drop != RTW89_SUB_ENTITY_0)
246 		goto out;
247 
248 	roll = find_next_bit(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY, drop + 1);
249 
250 	/* Follow rtw89_config_default_chandef() when rtw89_entity_recalc(). */
251 	if (roll == NUM_OF_RTW89_SUB_ENTITY)
252 		goto out;
253 
254 	/* RTW89_SUB_ENTITY_0 is going to release, and another exists.
255 	 * Make another roll down to RTW89_SUB_ENTITY_0 to replace.
256 	 */
257 	hal->sub[roll].cfg->idx = RTW89_SUB_ENTITY_0;
258 	hal->sub[RTW89_SUB_ENTITY_0] = hal->sub[roll];
259 
260 	rtw89_for_each_rtwvif(rtwdev, rtwvif) {
261 		if (rtwvif->sub_entity_idx == roll)
262 			rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0;
263 	}
264 
265 	atomic_cmpxchg(&hal->roc_entity_idx, roll, RTW89_SUB_ENTITY_0);
266 
267 	drop = roll;
268 
269 out:
270 	clear_bit(drop, hal->entity_map);
271 	rtw89_set_channel(rtwdev);
272 }
273 
274 void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev,
275 			      struct ieee80211_chanctx_conf *ctx,
276 			      u32 changed)
277 {
278 	struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
279 	u8 idx = cfg->idx;
280 
281 	if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) {
282 		rtw89_config_entity_chandef(rtwdev, idx, &ctx->def);
283 		rtw89_set_channel(rtwdev);
284 	}
285 }
286 
287 int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev,
288 				 struct rtw89_vif *rtwvif,
289 				 struct ieee80211_chanctx_conf *ctx)
290 {
291 	struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
292 
293 	rtwvif->sub_entity_idx = cfg->idx;
294 	return 0;
295 }
296 
297 void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev,
298 				    struct rtw89_vif *rtwvif,
299 				    struct ieee80211_chanctx_conf *ctx)
300 {
301 	rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0;
302 }
303