xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852be/core/rtw_rf.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2019 Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  *****************************************************************************/
15 #define _RTW_RF_C_
16 
17 #include <drv_types.h>
18 
19 u8 center_ch_2g[CENTER_CH_2G_NUM] = {
20 /* G00 */1, 2,
21 /* G01 */3, 4, 5,
22 /* G02 */6, 7, 8,
23 /* G03 */9, 10, 11,
24 /* G04 */12, 13,
25 /* G05 */14
26 };
27 
28 #define ch_to_cch_2g_idx(ch) ((ch) - 1)
29 
30 u8 center_ch_2g_40m[CENTER_CH_2G_40M_NUM] = {
31 	3,
32 	4,
33 	5,
34 	6,
35 	7,
36 	8,
37 	9,
38 	10,
39 	11,
40 };
41 
42 u8 op_chs_of_cch_2g_40m[CENTER_CH_2G_40M_NUM][2] = {
43 	{1, 5}, /* 3 */
44 	{2, 6}, /* 4 */
45 	{3, 7}, /* 5 */
46 	{4, 8}, /* 6 */
47 	{5, 9}, /* 7 */
48 	{6, 10}, /* 8 */
49 	{7, 11}, /* 9 */
50 	{8, 12}, /* 10 */
51 	{9, 13}, /* 11 */
52 };
53 
54 u8 center_ch_5g_all[CENTER_CH_5G_ALL_NUM] = {
55 /* G00 */36, 38, 40,
56 	42,
57 /* G01 */44, 46, 48,
58 	/* 50, */
59 /* G02 */52, 54, 56,
60 	58,
61 /* G03 */60, 62, 64,
62 /* G04 */100, 102, 104,
63 	106,
64 /* G05 */108, 110, 112,
65 	/* 114, */
66 /* G06 */116, 118, 120,
67 	122,
68 /* G07 */124, 126, 128,
69 /* G08 */132, 134, 136,
70 	138,
71 /* G09 */140, 142, 144,
72 /* G10 */149, 151, 153,
73 	155,
74 /* G11 */157, 159, 161,
75 	/* 163, */
76 /* G12 */165, 167, 169,
77 	171,
78 /* G13 */173, 175, 177
79 };
80 
81 u8 center_ch_5g_20m[CENTER_CH_5G_20M_NUM] = {
82 /* G00 */36, 40,
83 /* G01 */44, 48,
84 /* G02 */52, 56,
85 /* G03 */60, 64,
86 /* G04 */100, 104,
87 /* G05 */108, 112,
88 /* G06 */116, 120,
89 /* G07 */124, 128,
90 /* G08 */132, 136,
91 /* G09 */140, 144,
92 /* G10 */149, 153,
93 /* G11 */157, 161,
94 /* G12 */165, 169,
95 /* G13 */173, 177
96 };
97 
98 #define ch_to_cch_5g_20m_idx(ch) \
99 	( \
100 		((ch) >= 36 && (ch) <= 64) ? (((ch) - 36) >> 2) : \
101 		((ch) >= 100 && (ch) <= 144) ? 8 + (((ch) - 100) >> 2) : \
102 		((ch) >= 149 && (ch) <= 177) ? 20 + (((ch) - 149) >> 2) : 255 \
103 	)
104 
105 u8 center_ch_5g_40m[CENTER_CH_5G_40M_NUM] = {
106 /* G00 */38,
107 /* G01 */46,
108 /* G02 */54,
109 /* G03 */62,
110 /* G04 */102,
111 /* G05 */110,
112 /* G06 */118,
113 /* G07 */126,
114 /* G08 */134,
115 /* G09 */142,
116 /* G10 */151,
117 /* G11 */159,
118 /* G12 */167,
119 /* G13 */175
120 };
121 
122 u8 center_ch_5g_20m_40m[CENTER_CH_5G_20M_NUM + CENTER_CH_5G_40M_NUM] = {
123 /* G00 */36, 38, 40,
124 /* G01 */44, 46, 48,
125 /* G02 */52, 54, 56,
126 /* G03 */60, 62, 64,
127 /* G04 */100, 102, 104,
128 /* G05 */108, 110, 112,
129 /* G06 */116, 118, 120,
130 /* G07 */124, 126, 128,
131 /* G08 */132, 134, 136,
132 /* G09 */140, 142, 144,
133 /* G10 */149, 151, 153,
134 /* G11 */157, 159, 161,
135 /* G12 */165, 167, 169,
136 /* G13 */173, 175, 177
137 };
138 
139 u8 op_chs_of_cch_5g_40m[CENTER_CH_5G_40M_NUM][2] = {
140 	{36, 40}, /* 38 */
141 	{44, 48}, /* 46 */
142 	{52, 56}, /* 54 */
143 	{60, 64}, /* 62 */
144 	{100, 104}, /* 102 */
145 	{108, 112}, /* 110 */
146 	{116, 120}, /* 118 */
147 	{124, 128}, /* 126 */
148 	{132, 136}, /* 134 */
149 	{140, 144}, /* 142 */
150 	{149, 153}, /* 151 */
151 	{157, 161}, /* 159 */
152 	{165, 169}, /* 167 */
153 	{173, 177}, /* 175 */
154 };
155 
156 u8 center_ch_5g_80m[CENTER_CH_5G_80M_NUM] = {
157 /* G00 ~ G01*/42,
158 /* G02 ~ G03*/58,
159 /* G04 ~ G05*/106,
160 /* G06 ~ G07*/122,
161 /* G08 ~ G09*/138,
162 /* G10 ~ G11*/155,
163 /* G12 ~ G13*/171
164 };
165 
166 u8 op_chs_of_cch_5g_80m[CENTER_CH_5G_80M_NUM][4] = {
167 	{36, 40, 44, 48}, /* 42 */
168 	{52, 56, 60, 64}, /* 58 */
169 	{100, 104, 108, 112}, /* 106 */
170 	{116, 120, 124, 128}, /* 122 */
171 	{132, 136, 140, 144}, /* 138 */
172 	{149, 153, 157, 161}, /* 155 */
173 	{165, 169, 173, 177}, /* 171 */
174 };
175 
176 u8 center_ch_5g_160m[CENTER_CH_5G_160M_NUM] = {
177 /* G00 ~ G03*/50,
178 /* G04 ~ G07*/114,
179 /* G10 ~ G13*/163
180 };
181 
182 u8 op_chs_of_cch_5g_160m[CENTER_CH_5G_160M_NUM][8] = {
183 	{36, 40, 44, 48, 52, 56, 60, 64}, /* 50 */
184 	{100, 104, 108, 112, 116, 120, 124, 128}, /* 114 */
185 	{149, 153, 157, 161, 165, 169, 173, 177}, /* 163 */
186 };
187 
188 struct center_chs_ent_t {
189 	u8 ch_num;
190 	u8 *chs;
191 };
192 
193 struct center_chs_ent_t center_chs_2g_by_bw[] = {
194 	{CENTER_CH_2G_NUM, center_ch_2g},
195 	{CENTER_CH_2G_40M_NUM, center_ch_2g_40m},
196 };
197 
198 struct center_chs_ent_t center_chs_5g_by_bw[] = {
199 	{CENTER_CH_5G_20M_NUM, center_ch_5g_20m},
200 	{CENTER_CH_5G_40M_NUM, center_ch_5g_40m},
201 	{CENTER_CH_5G_80M_NUM, center_ch_5g_80m},
202 	{CENTER_CH_5G_160M_NUM, center_ch_5g_160m},
203 };
204 
205 /*
206  * Get center channel of smaller bandwidth by @param cch, @param bw, @param offset
207  * @cch: the given center channel
208  * @bw: the given bandwidth
209  * @offset: the given primary SC offset of the given bandwidth
210  *
211  * return center channel of smaller bandiwdth if valid, or 0
212  */
rtw_get_scch_by_cch_offset(u8 cch,u8 bw,u8 offset)213 u8 rtw_get_scch_by_cch_offset(u8 cch, u8 bw, u8 offset)
214 {
215 	u8 t_cch = 0;
216 
217 	if (bw == CHANNEL_WIDTH_20) {
218 		t_cch = cch;
219 		goto exit;
220 	}
221 
222 	if (offset == CHAN_OFFSET_NO_EXT) {
223 		rtw_warn_on(1);
224 		goto exit;
225 	}
226 
227 	/* 2.4G, 40MHz */
228 	if (cch >= 3 && cch <= 11 && bw == CHANNEL_WIDTH_40) {
229 		t_cch = (offset == CHAN_OFFSET_LOWER) ? cch + 2 : cch - 2;
230 		goto exit;
231 	}
232 
233 	/* 5G, 160MHz */
234 	if (cch >= 50 && cch <= 163 && bw == CHANNEL_WIDTH_160) {
235 		t_cch = (offset == CHAN_OFFSET_LOWER) ? cch + 8 : cch - 8;
236 		goto exit;
237 
238 	/* 5G, 80MHz */
239 	} else if (cch >= 42 && cch <= 171 && bw == CHANNEL_WIDTH_80) {
240 		t_cch = (offset == CHAN_OFFSET_LOWER) ? cch + 4 : cch - 4;
241 		goto exit;
242 
243 	/* 5G, 40MHz */
244 	} else if (cch >= 38 && cch <= 175 && bw == CHANNEL_WIDTH_40) {
245 		t_cch = (offset == CHAN_OFFSET_LOWER) ? cch + 2 : cch - 2;
246 		goto exit;
247 
248 	} else {
249 		rtw_warn_on(1);
250 		goto exit;
251 	}
252 
253 exit:
254 	return t_cch;
255 }
256 
257 struct op_chs_ent_t {
258 	u8 ch_num;
259 	u8 *chs;
260 };
261 
262 struct op_chs_ent_t op_chs_of_cch_2g_by_bw[] = {
263 	{1, center_ch_2g},
264 	{2, (u8 *)op_chs_of_cch_2g_40m},
265 };
266 
267 struct op_chs_ent_t op_chs_of_cch_5g_by_bw[] = {
268 	{1, center_ch_5g_20m},
269 	{2, (u8 *)op_chs_of_cch_5g_40m},
270 	{4, (u8 *)op_chs_of_cch_5g_80m},
271 	{8, (u8 *)op_chs_of_cch_5g_160m},
272 };
273 
center_chs_2g_num(u8 bw)274 inline u8 center_chs_2g_num(u8 bw)
275 {
276 	if (bw > CHANNEL_WIDTH_40)
277 		return 0;
278 
279 	return center_chs_2g_by_bw[bw].ch_num;
280 }
281 
center_chs_2g(u8 bw,u8 id)282 inline u8 center_chs_2g(u8 bw, u8 id)
283 {
284 	if (bw > CHANNEL_WIDTH_40)
285 		return 0;
286 
287 	if (id >= center_chs_2g_num(bw))
288 		return 0;
289 
290 	return center_chs_2g_by_bw[bw].chs[id];
291 }
292 
center_chs_5g_num(u8 bw)293 inline u8 center_chs_5g_num(u8 bw)
294 {
295 	if (bw > CHANNEL_WIDTH_160)
296 		return 0;
297 
298 	return center_chs_5g_by_bw[bw].ch_num;
299 }
300 
center_chs_5g(u8 bw,u8 id)301 inline u8 center_chs_5g(u8 bw, u8 id)
302 {
303 	if (bw > CHANNEL_WIDTH_160)
304 		return 0;
305 
306 	if (id >= center_chs_5g_num(bw))
307 		return 0;
308 
309 	return center_chs_5g_by_bw[bw].chs[id];
310 }
311 
312 /*
313  * Get available op channels by @param cch, @param bw
314  * @cch: the given center channel
315  * @bw: the given bandwidth
316  * @op_chs: the pointer to return pointer of op channel array
317  * @op_ch_num: the pointer to return pointer of op channel number
318  *
319  * return valid (1) or not (0)
320  */
rtw_get_op_chs_by_cch_bw(u8 cch,u8 bw,u8 ** op_chs,u8 * op_ch_num)321 u8 rtw_get_op_chs_by_cch_bw(u8 cch, u8 bw, u8 **op_chs, u8 *op_ch_num)
322 {
323 	int i;
324 	struct center_chs_ent_t *c_chs_ent = NULL;
325 	struct op_chs_ent_t *op_chs_ent = NULL;
326 	u8 valid = 1;
327 
328 	if (cch <= 14
329 		&& bw <= CHANNEL_WIDTH_40
330 	) {
331 		c_chs_ent = &center_chs_2g_by_bw[bw];
332 		op_chs_ent = &op_chs_of_cch_2g_by_bw[bw];
333 	} else if (cch >= 36 && cch <= 177
334 		&& bw <= CHANNEL_WIDTH_160
335 	) {
336 		c_chs_ent = &center_chs_5g_by_bw[bw];
337 		op_chs_ent = &op_chs_of_cch_5g_by_bw[bw];
338 	} else {
339 		valid = 0;
340 		goto exit;
341 	}
342 
343 	for (i = 0; i < c_chs_ent->ch_num; i++)
344 		if (cch == *(c_chs_ent->chs + i))
345 			break;
346 
347 	if (i == c_chs_ent->ch_num) {
348 		valid = 0;
349 		goto exit;
350 	}
351 
352 	*op_chs = op_chs_ent->chs + op_chs_ent->ch_num * i;
353 	*op_ch_num = op_chs_ent->ch_num;
354 
355 exit:
356 	return valid;
357 }
358 
rtw_get_offset_by_chbw(u8 ch,u8 bw,u8 * r_offset)359 u8 rtw_get_offset_by_chbw(u8 ch, u8 bw, u8 *r_offset)
360 {
361 	u8 valid = 1;
362 	u8 offset = CHAN_OFFSET_NO_EXT;
363 
364 	if (bw == CHANNEL_WIDTH_20)
365 		goto exit;
366 
367 	if (bw >= CHANNEL_WIDTH_80 && ch <= 14) {
368 		valid = 0;
369 		goto exit;
370 	}
371 
372 	if (ch >= 1 && ch <= 4)
373 		offset = CHAN_OFFSET_UPPER;
374 	else if (ch >= 5 && ch <= 9) {
375 		if (*r_offset == CHAN_OFFSET_UPPER || *r_offset == CHAN_OFFSET_LOWER)
376 			offset = *r_offset; /* both lower and upper is valid, obey input value */
377 		else
378 			offset = CHAN_OFFSET_LOWER; /* default use upper */
379 	} else if (ch >= 10 && ch <= 13)
380 		offset = CHAN_OFFSET_LOWER;
381 	else if (ch == 14) {
382 		valid = 0; /* ch14 doesn't support 40MHz bandwidth */
383 		goto exit;
384 	} else if (ch >= 36 && ch <= 177) {
385 		switch (ch) {
386 		case 36:
387 		case 44:
388 		case 52:
389 		case 60:
390 		case 100:
391 		case 108:
392 		case 116:
393 		case 124:
394 		case 132:
395 		case 140:
396 		case 149:
397 		case 157:
398 		case 165:
399 		case 173:
400 			offset = CHAN_OFFSET_UPPER;
401 			break;
402 		case 40:
403 		case 48:
404 		case 56:
405 		case 64:
406 		case 104:
407 		case 112:
408 		case 120:
409 		case 128:
410 		case 136:
411 		case 144:
412 		case 153:
413 		case 161:
414 		case 169:
415 		case 177:
416 			offset = CHAN_OFFSET_LOWER;
417 			break;
418 		default:
419 			valid = 0;
420 			break;
421 		}
422 	} else
423 		valid = 0;
424 
425 exit:
426 	if (valid && r_offset)
427 		*r_offset = offset;
428 	return valid;
429 }
430 
rtw_get_center_ch(u8 ch,u8 bw,u8 offset)431 u8 rtw_get_center_ch(u8 ch, u8 bw, u8 offset)
432 {
433 	return rtw_phl_get_center_ch(ch, bw, offset);
434 }
435 
rtw_get_ch_group(u8 ch,u8 * group,u8 * cck_group)436 u8 rtw_get_ch_group(u8 ch, u8 *group, u8 *cck_group)
437 {
438 	enum band_type band = BAND_MAX;
439 	s8 gp = -1, cck_gp = -1;
440 
441 	if (ch <= 14) {
442 		band = BAND_ON_24G;
443 
444 		if (1 <= ch && ch <= 2)
445 			gp = 0;
446 		else if (3  <= ch && ch <= 5)
447 			gp = 1;
448 		else if (6  <= ch && ch <= 8)
449 			gp = 2;
450 		else if (9  <= ch && ch <= 11)
451 			gp = 3;
452 		else if (12 <= ch && ch <= 14)
453 			gp = 4;
454 		else
455 			band = BAND_MAX;
456 
457 		if (ch == 14)
458 			cck_gp = 5;
459 		else
460 			cck_gp = gp;
461 	} else {
462 		band = BAND_ON_5G;
463 
464 		if (36 <= ch && ch <= 42)
465 			gp = 0;
466 		else if (44   <= ch && ch <=  48)
467 			gp = 1;
468 		else if (50   <= ch && ch <=  58)
469 			gp = 2;
470 		else if (60   <= ch && ch <=  64)
471 			gp = 3;
472 		else if (100  <= ch && ch <= 106)
473 			gp = 4;
474 		else if (108  <= ch && ch <= 114)
475 			gp = 5;
476 		else if (116  <= ch && ch <= 122)
477 			gp = 6;
478 		else if (124  <= ch && ch <= 130)
479 			gp = 7;
480 		else if (132  <= ch && ch <= 138)
481 			gp = 8;
482 		else if (140  <= ch && ch <= 144)
483 			gp = 9;
484 		else if (149  <= ch && ch <= 155)
485 			gp = 10;
486 		else if (157  <= ch && ch <= 161)
487 			gp = 11;
488 		else if (165  <= ch && ch <= 171)
489 			gp = 12;
490 		else if (173  <= ch && ch <= 177)
491 			gp = 13;
492 		else
493 			band = BAND_MAX;
494 	}
495 
496 	if (band == BAND_MAX
497 		|| (band == BAND_ON_24G && cck_gp == -1)
498 		|| gp == -1
499 	) {
500 		RTW_WARN("%s invalid channel:%u", __func__, ch);
501 		rtw_warn_on(1);
502 		goto exit;
503 	}
504 
505 	if (group)
506 		*group = gp;
507 	if (cck_group && band == BAND_ON_24G)
508 		*cck_group = cck_gp;
509 
510 exit:
511 	return band;
512 }
513 
514 #if CONFIG_IEEE80211_BAND_6GHZ
rtw_6gch2freq(int chan)515 int rtw_6gch2freq(int chan)
516 {
517 	if (chan >= 1 && chan <= 253)
518 		return 5950 + chan * 5;
519 
520 	return 0; /* not supported */
521 }
522 #endif
523 
rtw_ch2freq(int chan)524 int rtw_ch2freq(int chan)
525 {
526 	/* see 802.11 17.3.8.3.2 and Annex J
527 	* there are overlapping channel numbers in 5GHz and 2GHz bands */
528 
529 	/*
530 	* RTK: don't consider the overlapping channel numbers: 5G channel <= 14,
531 	* because we don't support it. simply judge from channel number
532 	*/
533 
534 	if (chan >= 1 && chan <= 14) {
535 		if (chan == 14)
536 			return 2484;
537 		else if (chan < 14)
538 			return 2407 + chan * 5;
539 	} else if (chan >= 36 && chan <= 177)
540 		return 5000 + chan * 5;
541 
542 	return 0; /* not supported */
543 }
544 
rtw_ch2freq_by_band(enum band_type band,int ch)545 int rtw_ch2freq_by_band(enum band_type band, int ch)
546 {
547 #if CONFIG_IEEE80211_BAND_6GHZ
548 	if (band == BAND_ON_6G)
549 		return rtw_6gch2freq(ch);
550 	else
551 #endif
552 		return rtw_ch2freq(ch);
553 }
554 
rtw_freq2ch(int freq)555 int rtw_freq2ch(int freq)
556 {
557 	/* see 802.11 17.3.8.3.2 and Annex J */
558 	if (freq == 2484)
559 		return 14;
560 	else if (freq < 2484)
561 		return (freq - 2407) / 5;
562 	else if (freq >= 4910 && freq <= 4980)
563 		return (freq - 4000) / 5;
564 	else if (freq >= 5000 && freq < 5950)
565 		return (freq - 5000) / 5;
566 	else if (freq >= 5950 && freq <= 7215)
567 		return (freq - 5950) / 5;
568 	else if (freq >= 58320 && freq <= 64800)
569 		return (freq - 56160) / 2160;
570 	else
571 		return 0;
572 }
573 
rtw_freq2band(int freq)574 enum band_type rtw_freq2band(int freq)
575 {
576 	if (freq <= 2484)
577 		return BAND_ON_24G;
578 	else if (freq >= 5000 && freq < 5950)
579 		return BAND_ON_5G;
580 #if CONFIG_IEEE80211_BAND_6GHZ
581 	else if (freq >= 5950 && freq <= 7215)
582 		return BAND_ON_6G;
583 #endif
584 	else
585 		return BAND_MAX;
586 }
587 
rtw_freq_consecutive(int a,int b)588 bool rtw_freq_consecutive(int a, int b)
589 {
590 	enum band_type band_a, band_b;
591 
592 	band_a = rtw_freq2band(a);
593 	if (band_a == BAND_MAX)
594 		return 0;
595 	band_b = rtw_freq2band(b);
596 	if (band_b == BAND_MAX || band_a != band_b)
597 		return 0;
598 
599 	switch (band_a) {
600 	case BAND_ON_24G:
601 		return rtw_abs(a - b) == 5;
602 	case BAND_ON_5G:
603 #if CONFIG_IEEE80211_BAND_6GHZ
604 	case BAND_ON_6G:
605 #endif
606 		return rtw_abs(a - b) == 20;
607 	default:
608 		return 0;
609 	}
610 }
611 
rtw_chbw_to_freq_range(u8 ch,u8 bw,u8 offset,u32 * hi,u32 * lo)612 bool rtw_chbw_to_freq_range(u8 ch, u8 bw, u8 offset, u32 *hi, u32 *lo)
613 {
614 	u8 c_ch;
615 	u32 freq;
616 	u32 hi_ret = 0, lo_ret = 0;
617 	bool valid = _FALSE;
618 
619 	if (hi)
620 		*hi = 0;
621 	if (lo)
622 		*lo = 0;
623 
624 	c_ch = rtw_phl_get_center_ch(ch, bw, offset);
625 	freq = rtw_ch2freq(c_ch);
626 
627 	if (!freq) {
628 		rtw_warn_on(1);
629 		goto exit;
630 	}
631 
632 	if (bw == CHANNEL_WIDTH_160) {
633 		hi_ret = freq + 80;
634 		lo_ret = freq - 80;
635 	} else if (bw == CHANNEL_WIDTH_80) {
636 		hi_ret = freq + 40;
637 		lo_ret = freq - 40;
638 	} else if (bw == CHANNEL_WIDTH_40) {
639 		hi_ret = freq + 20;
640 		lo_ret = freq - 20;
641 	} else if (bw == CHANNEL_WIDTH_20) {
642 		hi_ret = freq + 10;
643 		lo_ret = freq - 10;
644 	} else
645 		rtw_warn_on(1);
646 
647 	if (hi)
648 		*hi = hi_ret;
649 	if (lo)
650 		*lo = lo_ret;
651 
652 	valid = _TRUE;
653 
654 exit:
655 	return valid;
656 }
657 
658 const char *const _ch_width_str[CHANNEL_WIDTH_MAX] = {
659 	"20MHz",
660 	"40MHz",
661 	"80MHz",
662 	"160MHz",
663 	"80_80MHz",
664 	"5MHz",
665 	"10MHz",
666 };
667 
668 const u8 _ch_width_to_bw_cap[CHANNEL_WIDTH_MAX] = {
669 	BW_CAP_20M,
670 	BW_CAP_40M,
671 	BW_CAP_80M,
672 	BW_CAP_160M,
673 	BW_CAP_80_80M,
674 	BW_CAP_5M,
675 	BW_CAP_10M,
676 };
677 
678 const char *const _rtw_band_str[] = {
679 	[BAND_ON_24G]	= "2.4G",
680 	[BAND_ON_5G]	= "5G",
681 	[BAND_ON_6G]	= "6G",
682 	[BAND_MAX]		= "BAND_MAX",
683 };
684 
685 const u8 _band_to_band_cap[] = {
686 	[BAND_ON_24G]	= BAND_CAP_2G,
687 	[BAND_ON_5G]	= BAND_CAP_5G,
688 	[BAND_ON_6G]	= BAND_CAP_6G,
689 	[BAND_MAX]		= 0,
690 };
691 
692 const char *const _opc_bw_str[OPC_BW_NUM] = {
693 	"20M ",		/* OPC_BW20 */
694 	"40M+",		/* OPC_BW40PLUS */
695 	"40M-",		/* OPC_BW40MINUS */
696 	"80M ",		/* OPC_BW80 */
697 	"160M ",	/* OPC_BW160 */
698 	"80+80M ",	/* OPC_BW80P80 */
699 };
700 
701 const u8 _opc_bw_to_ch_width[OPC_BW_NUM] = {
702 	CHANNEL_WIDTH_20,		/* OPC_BW20 */
703 	CHANNEL_WIDTH_40,		/* OPC_BW40PLUS */
704 	CHANNEL_WIDTH_40,		/* OPC_BW40MINUS */
705 	CHANNEL_WIDTH_80,		/* OPC_BW80 */
706 	CHANNEL_WIDTH_160,		/* OPC_BW160 */
707 	CHANNEL_WIDTH_80_80,	/* OPC_BW80P80 */
708 };
709 
710 /* global operating class database */
711 
712 struct op_class_t {
713 	u8 class_id;
714 	enum band_type band;
715 	enum opc_bw bw;
716 	u8 *len_ch_attr;
717 };
718 
719 #define OPC_CH_LIST_LEN(_opc) (_opc.len_ch_attr[0])
720 #define OPC_CH_LIST_CH(_opc, _i) (_opc.len_ch_attr[_i + 1])
721 
722 #define OP_CLASS_ENT(_class, _band, _bw, _len, arg...) \
723 	{.class_id = _class, .band = _band, .bw = _bw, .len_ch_attr = (uint8_t[_len + 1]) {_len, ##arg},}
724 
725 /* 802.11-2020, 802.11ax-2021 Table E-4, partial */
726 static const struct op_class_t global_op_class[] = {
727 	/* 2G ch1~13, 20M */
728 	OP_CLASS_ENT(81,	BAND_ON_24G,	OPC_BW20,		13,	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
729 	/* 2G ch14, 20M */
730 	OP_CLASS_ENT(82,	BAND_ON_24G,	OPC_BW20,		1,	14),
731 	/* 2G, 40M */
732 	OP_CLASS_ENT(83,	BAND_ON_24G,	OPC_BW40PLUS,	9,	1, 2, 3, 4, 5, 6, 7, 8, 9),
733 	OP_CLASS_ENT(84,	BAND_ON_24G,	OPC_BW40MINUS,	9,	5, 6, 7, 8, 9, 10, 11, 12, 13),
734 	/* 5G band 1, 20M & 40M */
735 	OP_CLASS_ENT(115,	BAND_ON_5G,		OPC_BW20,		4,	36, 40, 44, 48),
736 	OP_CLASS_ENT(116,	BAND_ON_5G,		OPC_BW40PLUS,	2,	36, 44),
737 	OP_CLASS_ENT(117,	BAND_ON_5G,		OPC_BW40MINUS,	2,	40, 48),
738 	/* 5G band 2, 20M & 40M */
739 	OP_CLASS_ENT(118,	BAND_ON_5G,		OPC_BW20,		4,	52, 56, 60, 64),
740 	OP_CLASS_ENT(119,	BAND_ON_5G,		OPC_BW40PLUS,	2,	52, 60),
741 	OP_CLASS_ENT(120,	BAND_ON_5G,		OPC_BW40MINUS,	2,	56, 64),
742 	/* 5G band 3, 20M & 40M */
743 	OP_CLASS_ENT(121,	BAND_ON_5G,		OPC_BW20,		12,	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144),
744 	OP_CLASS_ENT(122,	BAND_ON_5G,		OPC_BW40PLUS,	6,	100, 108, 116, 124, 132, 140),
745 	OP_CLASS_ENT(123,	BAND_ON_5G,		OPC_BW40MINUS,	6,	104, 112, 120, 128, 136, 144),
746 	/* 5G band 4, 20M & 40M */
747 	OP_CLASS_ENT(124,	BAND_ON_5G,		OPC_BW20,		4,	149, 153, 157, 161),
748 	OP_CLASS_ENT(125,	BAND_ON_5G,		OPC_BW20,		8,	149, 153, 157, 161, 165, 169, 173, 177),
749 	OP_CLASS_ENT(126,	BAND_ON_5G,		OPC_BW40PLUS,	4,	149, 157, 165, 173),
750 	OP_CLASS_ENT(127,	BAND_ON_5G,		OPC_BW40MINUS,	4,	153, 161, 169, 177),
751 	/* 5G, 80M & 160M */
752 	OP_CLASS_ENT(128,	BAND_ON_5G,		OPC_BW80,		28,	36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 169, 173, 177),
753 	OP_CLASS_ENT(129,	BAND_ON_5G,		OPC_BW160,		24,	36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 149, 153, 157, 161, 165, 169, 173, 177),
754 	#if 0 /* TODO */
755 	/* 5G, 80+80M */
756 	OP_CLASS_ENT(130,	BAND_ON_5G,		OPC_BW80P80,	28,	36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 169, 173, 177),
757 	#endif
758 };
759 
760 static const int global_op_class_num = sizeof(global_op_class) / sizeof(struct op_class_t);
761 
get_global_op_class_by_id(u8 gid)762 static const struct op_class_t *get_global_op_class_by_id(u8 gid)
763 {
764 	int i;
765 
766 	for (i = 0; i < global_op_class_num; i++)
767 		if (global_op_class[i].class_id == gid)
768 			break;
769 
770 	return i < global_op_class_num ? &global_op_class[i] : NULL;
771 }
772 
is_valid_global_op_class_id(u8 gid)773 bool is_valid_global_op_class_id(u8 gid)
774 {
775 	return get_global_op_class_by_id(gid) ? 1 : 0;
776 }
777 
is_valid_global_op_class_ch(const struct op_class_t * opc,u8 ch)778 static bool is_valid_global_op_class_ch(const struct op_class_t *opc, u8 ch)
779 {
780 	int array_idx;
781 	int i;
782 
783 	if (opc < global_op_class
784 		|| (((u8 *)opc) - ((u8 *)global_op_class)) % sizeof(struct op_class_t)
785 	) {
786 		RTW_ERR("Invalid opc pointer:%p (global_op_class:%p, sizeof(struct op_class_t):%zu, %zu)\n"
787 			, opc, global_op_class, sizeof(struct op_class_t), (((u8 *)opc) - ((u8 *)global_op_class)) % sizeof(struct op_class_t));
788 		return 0;
789 	}
790 
791 	array_idx = (((u8 *)opc) - ((u8 *)global_op_class)) / sizeof(struct op_class_t);
792 
793 	for (i = 0; i < OPC_CH_LIST_LEN(global_op_class[array_idx]); i++)
794 		if (OPC_CH_LIST_CH(global_op_class[array_idx], i) == ch)
795 			break;
796 
797 	return i < OPC_CH_LIST_LEN(global_op_class[array_idx]);
798 }
799 
get_global_opc_bw_by_id(u8 gid)800 static enum opc_bw get_global_opc_bw_by_id(u8 gid)
801 {
802 	int i;
803 
804 	for (i = 0; i < global_op_class_num; i++)
805 		if (global_op_class[i].class_id == gid)
806 			break;
807 
808 	return i < global_op_class_num ? global_op_class[i].bw : OPC_BW_NUM;
809 }
810 
811 /* -2: logic error, -1: error, 0: is already BW20 */
get_sub_op_class(u8 gid,u8 ch)812 s16 get_sub_op_class(u8 gid, u8 ch)
813 {
814 	const struct op_class_t *opc = get_global_op_class_by_id(gid);
815 	int i;
816 	enum channel_width bw;
817 
818 	if (!opc)
819 		return -1;
820 
821 	if (!is_valid_global_op_class_ch(opc, ch)) {
822 		return -1;
823 	}
824 
825 	if (opc->bw == OPC_BW20)
826 		return 0;
827 
828 	bw = opc_bw_to_ch_width(opc->bw);
829 
830 	for (i = 0; i < global_op_class_num; i++) {
831 		if (bw != opc_bw_to_ch_width(global_op_class[i].bw) + 1)
832 			continue;
833 		if (is_valid_global_op_class_ch(&global_op_class[i], ch))
834 			break;
835 	}
836 
837 	return i < global_op_class_num ? global_op_class[i].class_id : -2;
838 }
839 
dump_op_class_ch_title(void * sel)840 static void dump_op_class_ch_title(void *sel)
841 {
842 	RTW_PRINT_SEL(sel, "%-5s %-4s %-7s ch_list\n"
843 		, "class", "band", "bw");
844 }
845 
dump_global_op_class_ch_single(void * sel,u8 gid)846 static void dump_global_op_class_ch_single(void *sel, u8 gid)
847 {
848 	u8 i;
849 
850 	RTW_PRINT_SEL(sel, "%5u %4s %7s"
851 		, global_op_class[gid].class_id
852 		, band_str(global_op_class[gid].band)
853 		, opc_bw_str(global_op_class[gid].bw));
854 
855 	for (i = 0; i < OPC_CH_LIST_LEN(global_op_class[gid]); i++)
856 		_RTW_PRINT_SEL(sel, " %u", OPC_CH_LIST_CH(global_op_class[gid], i));
857 
858 	_RTW_PRINT_SEL(sel, "\n");
859 }
860 
861 #ifdef CONFIG_RTW_DEBUG
dbg_global_op_class_validate(u8 gid)862 static bool dbg_global_op_class_validate(u8 gid)
863 {
864 	u8 i;
865 	u8 ch, bw, offset, cch;
866 	bool ret = 1;
867 
868 	switch (global_op_class[gid].bw) {
869 	case OPC_BW20:
870 		bw = CHANNEL_WIDTH_20;
871 		offset = CHAN_OFFSET_NO_EXT;
872 		break;
873 	case OPC_BW40PLUS:
874 		bw = CHANNEL_WIDTH_40;
875 		offset = CHAN_OFFSET_UPPER;
876 		break;
877 	case OPC_BW40MINUS:
878 		bw = CHANNEL_WIDTH_40;
879 		offset = CHAN_OFFSET_LOWER;
880 		break;
881 	case OPC_BW80:
882 		bw = CHANNEL_WIDTH_80;
883 		offset = CHAN_OFFSET_NO_EXT;
884 		break;
885 	case OPC_BW160:
886 		bw = CHANNEL_WIDTH_160;
887 		offset = CHAN_OFFSET_NO_EXT;
888 		break;
889 	case OPC_BW80P80: /* TODO */
890 	default:
891 		RTW_ERR("%s class:%u unsupported opc_bw:%u\n"
892 			, __func__, global_op_class[gid].class_id, global_op_class[gid].bw);
893 		ret = 0;
894 		goto exit;
895 	}
896 
897 	for (i = 0; i < OPC_CH_LIST_LEN(global_op_class[gid]); i++) {
898 		u8 *op_chs;
899 		u8 op_ch_num;
900 		u8 k;
901 
902 		ch = OPC_CH_LIST_CH(global_op_class[gid], i);
903 		cch = rtw_get_center_ch(ch ,bw, offset);
904 		if (!cch) {
905 			RTW_ERR("%s can't get cch from class:%u ch:%u\n"
906 				, __func__, global_op_class[gid].class_id, ch);
907 			ret = 0;
908 			continue;
909 		}
910 
911 		if (!rtw_get_op_chs_by_cch_bw(cch, bw, &op_chs, &op_ch_num)) {
912 			RTW_ERR("%s can't get op chs from class:%u cch:%u\n"
913 				, __func__, global_op_class[gid].class_id, cch);
914 			ret = 0;
915 			continue;
916 		}
917 
918 		for (k = 0; k < op_ch_num; k++) {
919 			if (*(op_chs + k) == ch)
920 				break;
921 		}
922 		if (k >= op_ch_num) {
923 			RTW_ERR("%s can't get ch:%u from op_chs class:%u cch:%u\n"
924 				, __func__, ch, global_op_class[i].class_id, cch);
925 			ret = 0;
926 		}
927 	}
928 
929 exit:
930 	return ret;
931 }
932 #endif /* CONFIG_RTW_DEBUG */
933 
dump_global_op_class(void * sel)934 void dump_global_op_class(void *sel)
935 {
936 	u8 i;
937 
938 	dump_op_class_ch_title(sel);
939 
940 	for (i = 0; i < global_op_class_num; i++)
941 		dump_global_op_class_ch_single(sel, i);
942 }
943 
rtw_get_op_class_by_chbw(u8 ch,u8 bw,u8 offset)944 u8 rtw_get_op_class_by_chbw(u8 ch, u8 bw, u8 offset)
945 {
946 	enum band_type band = BAND_MAX;
947 	int i;
948 	u8 gid = 0; /* invalid */
949 
950 	if (rtw_is_2g_ch(ch))
951 		band = BAND_ON_24G;
952 	else if (rtw_is_5g_ch(ch))
953 		band = BAND_ON_5G;
954 	else
955 		goto exit;
956 
957 	switch (bw) {
958 	case CHANNEL_WIDTH_20:
959 	case CHANNEL_WIDTH_40:
960 	case CHANNEL_WIDTH_80:
961 	case CHANNEL_WIDTH_160:
962 	#if 0 /* TODO */
963 	case CHANNEL_WIDTH_80_80:
964 	#endif
965 		break;
966 	default:
967 		goto exit;
968 	}
969 
970 	for (i = 0; i < global_op_class_num; i++) {
971 		if (band != global_op_class[i].band)
972 			continue;
973 
974 		if (opc_bw_to_ch_width(global_op_class[i].bw) != bw)
975 			continue;
976 
977 		if ((global_op_class[i].bw == OPC_BW40PLUS
978 				&& offset != CHAN_OFFSET_UPPER)
979 			|| (global_op_class[i].bw == OPC_BW40MINUS
980 				&& offset != CHAN_OFFSET_LOWER)
981 		)
982 			continue;
983 
984 		if (is_valid_global_op_class_ch(&global_op_class[i], ch))
985 			goto get;
986 	}
987 
988 get:
989 	if (i < global_op_class_num) {
990 		#if 0 /* TODO */
991 		if (bw == CHANNEL_WIDTH_80_80) {
992 			/* search another ch */
993 			if (!is_valid_global_op_class_ch(&global_op_class[i], ch2))
994 				goto exit;
995 		}
996 		#endif
997 
998 		gid = global_op_class[i].class_id;
999 	}
1000 
1001 exit:
1002 	return gid;
1003 }
1004 
rtw_get_bw_offset_by_op_class_ch(u8 gid,u8 ch,u8 * bw,u8 * offset)1005 u8 rtw_get_bw_offset_by_op_class_ch(u8 gid, u8 ch, u8 *bw, u8 *offset)
1006 {
1007 	enum opc_bw opc_bw;
1008 	u8 valid = 0;
1009 	int i;
1010 
1011 	opc_bw = get_global_opc_bw_by_id(gid);
1012 	if (opc_bw == OPC_BW_NUM)
1013 		goto exit;
1014 
1015 	*bw = opc_bw_to_ch_width(opc_bw);
1016 
1017 	if (opc_bw == OPC_BW40PLUS)
1018 		*offset = CHAN_OFFSET_UPPER;
1019 	else if (opc_bw == OPC_BW40MINUS)
1020 		*offset = CHAN_OFFSET_LOWER;
1021 
1022 	if (rtw_get_offset_by_chbw(ch, *bw, offset))
1023 		valid = 1;
1024 
1025 exit:
1026 	return valid;
1027 }
1028 
opc_pref_alloc(u8 class_id)1029 static struct op_class_pref_t *opc_pref_alloc(u8 class_id)
1030 {
1031 	int i, j;
1032 	struct op_class_pref_t *opc_pref = NULL;
1033 	u8 ch_num;
1034 
1035 	for (i = 0; i < global_op_class_num; i++)
1036 		if (global_op_class[i].class_id == class_id)
1037 			break;
1038 
1039 	if (i >= global_op_class_num)
1040 		goto exit;
1041 
1042 	ch_num = OPC_CH_LIST_LEN(global_op_class[i]);
1043 	opc_pref = rtw_zmalloc(sizeof(*opc_pref) + (sizeof(struct op_ch_t) * ch_num));
1044 	if (!opc_pref)
1045 		goto exit;
1046 
1047 	opc_pref->class_id = global_op_class[i].class_id;
1048 	opc_pref->band = global_op_class[i].band;
1049 	opc_pref->bw = global_op_class[i].bw;
1050 
1051 	for (j = 0; j < OPC_CH_LIST_LEN(global_op_class[i]); j++) {
1052 		opc_pref->chs[j].ch = OPC_CH_LIST_CH(global_op_class[i], j);
1053 		opc_pref->chs[j].static_non_op = 1;
1054 		opc_pref->chs[j].no_ir = 1;
1055 		opc_pref->chs[j].max_txpwr = UNSPECIFIED_MBM;
1056 	}
1057 	opc_pref->ch_num = ch_num;
1058 
1059 exit:
1060 	return opc_pref;
1061 }
1062 
opc_pref_free(struct op_class_pref_t * opc_pref)1063 static void opc_pref_free(struct op_class_pref_t *opc_pref)
1064 {
1065 	rtw_mfree(opc_pref, sizeof(*opc_pref) + (sizeof(struct op_ch_t) * opc_pref->ch_num));
1066 }
1067 
op_class_pref_init(_adapter * adapter)1068 int op_class_pref_init(_adapter *adapter)
1069 {
1070 	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
1071 	struct rf_ctl_t *rfctl = dvobj_to_rfctl(dvobj);
1072 	struct registry_priv *regsty = dvobj_to_regsty(dvobj);
1073 	u8 bw;
1074 	struct op_class_pref_t *opc_pref;
1075 	int i;
1076 	u8 op_class_num = 0;
1077 	u8 band_bmp = 0;
1078 	u8 bw_bmp[BAND_MAX] = {0};
1079 	int ret = _FAIL;
1080 
1081 	rfctl->spt_op_class_ch = rtw_zmalloc(sizeof(struct op_class_pref_t *) * global_op_class_num);
1082 	if (!rfctl->spt_op_class_ch) {
1083 		RTW_ERR("%s alloc rfctl->spt_op_class_ch fail\n", __func__);
1084 		goto exit;
1085 	}
1086 
1087 	if (is_supported_24g(regsty->band_type) && rtw_hw_chk_band_cap(dvobj, BAND_CAP_2G))
1088 		band_bmp |= BAND_CAP_2G;
1089 	if (is_supported_5g(regsty->band_type) && rtw_hw_chk_band_cap(dvobj, BAND_CAP_5G))
1090 		band_bmp |= BAND_CAP_5G;
1091 
1092 	bw_bmp[BAND_ON_24G] = (ch_width_to_bw_cap(REGSTY_BW_2G(regsty) + 1) - 1) & (GET_HAL_SPEC(dvobj)->bw_cap);
1093 	bw_bmp[BAND_ON_5G] = (ch_width_to_bw_cap(REGSTY_BW_5G(regsty) + 1) - 1) & (GET_HAL_SPEC(dvobj)->bw_cap);
1094 	if (!REGSTY_IS_11AC_ENABLE(regsty)
1095 		|| !is_supported_vht(regsty->wireless_mode)
1096 	)
1097 		bw_bmp[BAND_ON_5G] &= ~(BW_CAP_80M | BW_CAP_160M);
1098 
1099 	if (0) {
1100 		RTW_INFO("REGSTY_BW_2G(regsty):%u\n", REGSTY_BW_2G(regsty));
1101 		RTW_INFO("REGSTY_BW_5G(regsty):%u\n", REGSTY_BW_5G(regsty));
1102 		RTW_INFO("GET_HAL_SPEC(adapter)->bw_cap:0x%x\n", GET_HAL_SPEC(dvobj)->bw_cap);
1103 		RTW_INFO("band_bmp:0x%x\n", band_bmp);
1104 		RTW_INFO("bw_bmp[2G]:0x%x\n", bw_bmp[BAND_ON_24G]);
1105 		RTW_INFO("bw_bmp[5G]:0x%x\n", bw_bmp[BAND_ON_5G]);
1106 	}
1107 
1108 	for (i = 0; i < global_op_class_num; i++) {
1109 		#ifdef CONFIG_RTW_DEBUG
1110 		rtw_warn_on(!dbg_global_op_class_validate(i));
1111 		#endif
1112 
1113 		if (!(band_bmp & band_to_band_cap(global_op_class[i].band)))
1114 			continue;
1115 
1116 		bw = opc_bw_to_ch_width(global_op_class[i].bw);
1117 		if (bw == CHANNEL_WIDTH_MAX
1118 			|| bw == CHANNEL_WIDTH_80_80 /* TODO */
1119 		)
1120 			continue;
1121 
1122 		if (!(bw_bmp[global_op_class[i].band] & ch_width_to_bw_cap(bw)))
1123 			continue;
1124 
1125 		opc_pref = opc_pref_alloc(global_op_class[i].class_id);
1126 		if (!opc_pref) {
1127 			RTW_ERR("%s opc_pref_alloc(%u) fail\n", __func__, global_op_class[i].class_id);
1128 			goto exit;
1129 		}
1130 
1131 		if (opc_pref->ch_num) {
1132 			rfctl->spt_op_class_ch[i] = opc_pref;
1133 			op_class_num++;
1134 		} else
1135 			opc_pref_free(opc_pref);
1136 	}
1137 
1138 	rfctl->cap_spt_op_class_num = op_class_num;
1139 	ret = _SUCCESS;
1140 
1141 exit:
1142 	return ret;
1143 }
1144 
op_class_pref_deinit(_adapter * adapter)1145 void op_class_pref_deinit(_adapter *adapter)
1146 {
1147 	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
1148 	int i;
1149 
1150 	if (!rfctl->spt_op_class_ch)
1151 		return;
1152 
1153 	for (i = 0; i < global_op_class_num; i++) {
1154 		if (rfctl->spt_op_class_ch[i]) {
1155 			opc_pref_free(rfctl->spt_op_class_ch[i]);
1156 			rfctl->spt_op_class_ch[i] = NULL;
1157 		}
1158 	}
1159 
1160 	rtw_mfree(rfctl->spt_op_class_ch, sizeof(struct op_class_pref_t *) * global_op_class_num);
1161 	rfctl->spt_op_class_ch = NULL;
1162 }
1163 
op_class_pref_apply_regulatory(_adapter * adapter,u8 reason)1164 void op_class_pref_apply_regulatory(_adapter *adapter, u8 reason)
1165 {
1166 	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
1167 	RT_CHANNEL_INFO *chset = rfctl->channel_set;
1168 	struct registry_priv *regsty = adapter_to_regsty(adapter);
1169 	u8 ch, bw, offset, cch;
1170 	struct op_class_pref_t *opc_pref;
1171 	int i, j;
1172 	u8 reg_op_class_num = 0;
1173 	u8 op_class_num = 0;
1174 
1175 	for (i = 0; i < global_op_class_num; i++) {
1176 		if (!rfctl->spt_op_class_ch[i])
1177 			continue;
1178 		opc_pref = rfctl->spt_op_class_ch[i];
1179 
1180 		/* reset all channel */
1181 		for (j = 0; j < opc_pref->ch_num; j++) {
1182 			if (reason >= REG_CHANGE)
1183 				opc_pref->chs[j].static_non_op = 1;
1184 			if (reason != REG_TXPWR_CHANGE)
1185 				opc_pref->chs[j].no_ir = 1;
1186 			if (reason >= REG_TXPWR_CHANGE)
1187 				opc_pref->chs[j].max_txpwr = UNSPECIFIED_MBM;
1188 		}
1189 		if (reason >= REG_CHANGE)
1190 			opc_pref->op_ch_num = 0;
1191 		if (reason != REG_TXPWR_CHANGE)
1192 			opc_pref->ir_ch_num = 0;
1193 
1194 		switch (opc_pref->bw) {
1195 		case OPC_BW20:
1196 			bw = CHANNEL_WIDTH_20;
1197 			offset = CHAN_OFFSET_NO_EXT;
1198 			break;
1199 		case OPC_BW40PLUS:
1200 			bw = CHANNEL_WIDTH_40;
1201 			offset = CHAN_OFFSET_UPPER;
1202 			break;
1203 		case OPC_BW40MINUS:
1204 			bw = CHANNEL_WIDTH_40;
1205 			offset = CHAN_OFFSET_LOWER;
1206 			break;
1207 		case OPC_BW80:
1208 			bw = CHANNEL_WIDTH_80;
1209 			offset = CHAN_OFFSET_NO_EXT;
1210 			break;
1211 		case OPC_BW160:
1212 			bw = CHANNEL_WIDTH_160;
1213 			offset = CHAN_OFFSET_NO_EXT;
1214 			break;
1215 		case OPC_BW80P80: /* TODO */
1216 		default:
1217 			continue;
1218 		}
1219 
1220 		if (!RFCTL_REG_EN_11AC(rfctl)
1221 			&& (bw == CHANNEL_WIDTH_80 || bw == CHANNEL_WIDTH_160))
1222 			continue;
1223 
1224 		for (j = 0; j < opc_pref->ch_num; j++) {
1225 			u8 *op_chs;
1226 			u8 op_ch_num;
1227 			u8 k, l;
1228 			int chset_idx;
1229 
1230 			ch = opc_pref->chs[j].ch;
1231 
1232 			if (reason >= REG_TXPWR_CHANGE)
1233 				opc_pref->chs[j].max_txpwr = rtw_rfctl_get_reg_max_txpwr_mbm(rfctl, ch, bw, offset, 1);
1234 
1235 			if (reason == REG_TXPWR_CHANGE)
1236 				continue;
1237 
1238 			cch = rtw_get_center_ch(ch ,bw, offset);
1239 			if (!cch)
1240 				continue;
1241 
1242 			if (!rtw_get_op_chs_by_cch_bw(cch, bw, &op_chs, &op_ch_num))
1243 				continue;
1244 
1245 			for (k = 0, l = 0; k < op_ch_num; k++) {
1246 				chset_idx = rtw_chset_search_ch(chset, *(op_chs + k));
1247 				if (chset_idx == -1)
1248 					break;
1249 				if (bw >= CHANNEL_WIDTH_40) {
1250 					if ((chset[chset_idx].flags & RTW_CHF_NO_HT40U) && k % 2 == 0)
1251 						break;
1252 					if ((chset[chset_idx].flags & RTW_CHF_NO_HT40L) && k % 2 == 1)
1253 						break;
1254 				}
1255 				if (bw >= CHANNEL_WIDTH_80 && (chset[chset_idx].flags & RTW_CHF_NO_80MHZ))
1256 					break;
1257 				if (bw >= CHANNEL_WIDTH_160 && (chset[chset_idx].flags & RTW_CHF_NO_160MHZ))
1258 					break;
1259 				if ((chset[chset_idx].flags & RTW_CHF_DFS) && rtw_rfctl_dfs_domain_unknown(rfctl))
1260 					continue;
1261 				if (chset[chset_idx].flags & RTW_CHF_NO_IR)
1262 					continue;
1263 				l++;
1264 			}
1265 			if (k < op_ch_num)
1266 				continue;
1267 
1268 			if (reason >= REG_CHANGE) {
1269 				opc_pref->chs[j].static_non_op = 0;
1270 				opc_pref->op_ch_num++;
1271 			}
1272 
1273 			if (l >= op_ch_num) {
1274 				opc_pref->chs[j].no_ir = 0;
1275 				opc_pref->ir_ch_num++;
1276 			}
1277 		}
1278 
1279 		if (opc_pref->op_ch_num)
1280 			reg_op_class_num++;
1281 		if (opc_pref->ir_ch_num)
1282 			op_class_num++;
1283 	}
1284 
1285 	rfctl->reg_spt_op_class_num = reg_op_class_num;
1286 	rfctl->cur_spt_op_class_num = op_class_num;
1287 }
1288 
dump_opc_pref_single(void * sel,struct op_class_pref_t * opc_pref,bool show_snon_ocp,bool show_no_ir,bool detail)1289 static void dump_opc_pref_single(void *sel, struct op_class_pref_t *opc_pref, bool show_snon_ocp, bool show_no_ir, bool detail)
1290 {
1291 	u8 i;
1292 	u8 ch_num = 0;
1293 
1294 	if (!show_snon_ocp && !opc_pref->op_ch_num)
1295 		return;
1296 	if (!show_no_ir && !opc_pref->ir_ch_num)
1297 		return;
1298 
1299 	RTW_PRINT_SEL(sel, "%5u %4s %7s"
1300 		, opc_pref->class_id
1301 		, band_str(opc_pref->band)
1302 		, opc_bw_str(opc_pref->bw));
1303 	for (i = 0; i < opc_pref->ch_num; i++) {
1304 		if ((show_snon_ocp || !opc_pref->chs[i].static_non_op)
1305 			&& (show_no_ir || !opc_pref->chs[i].no_ir)
1306 		) {
1307 			if (detail)
1308 				_RTW_PRINT_SEL(sel, " %4u", opc_pref->chs[i].ch);
1309 			else
1310 				_RTW_PRINT_SEL(sel, " %u", opc_pref->chs[i].ch);
1311 		}
1312 	}
1313 	_RTW_PRINT_SEL(sel, "\n");
1314 
1315 	if (!detail)
1316 		return;
1317 
1318 	RTW_PRINT_SEL(sel, "                  ");
1319 	for (i = 0; i < opc_pref->ch_num; i++) {
1320 		if ((show_snon_ocp || !opc_pref->chs[i].static_non_op)
1321 			&& (show_no_ir || !opc_pref->chs[i].no_ir)
1322 		) {
1323 			_RTW_PRINT_SEL(sel, "   %c%c"
1324 				, opc_pref->chs[i].no_ir ? ' ' : 'I'
1325 				, opc_pref->chs[i].static_non_op ? ' ' : 'E'
1326 			);
1327 		}
1328 	}
1329 	_RTW_PRINT_SEL(sel, "\n");
1330 
1331 	RTW_PRINT_SEL(sel, "                  ");
1332 	for (i = 0; i < opc_pref->ch_num; i++) {
1333 		if ((show_snon_ocp || !opc_pref->chs[i].static_non_op)
1334 			&& (show_no_ir || !opc_pref->chs[i].no_ir)
1335 		) {
1336 			if (opc_pref->chs[i].max_txpwr == UNSPECIFIED_MBM)
1337 				_RTW_PRINT_SEL(sel, "     ");
1338 			else
1339 				_RTW_PRINT_SEL(sel, " %4d", opc_pref->chs[i].max_txpwr);
1340 		}
1341 	}
1342 	_RTW_PRINT_SEL(sel, "\n");
1343 }
1344 
dump_cap_spt_op_class_ch(void * sel,struct rf_ctl_t * rfctl,bool detail)1345 void dump_cap_spt_op_class_ch(void *sel, struct rf_ctl_t *rfctl, bool detail)
1346 {
1347 	u8 i;
1348 
1349 	dump_op_class_ch_title(sel);
1350 
1351 	for (i = 0; i < global_op_class_num; i++) {
1352 		if (!rfctl->spt_op_class_ch[i])
1353 			continue;
1354 		dump_opc_pref_single(sel, rfctl->spt_op_class_ch[i], 1, 1, detail);
1355 	}
1356 
1357 	RTW_PRINT_SEL(sel, "op_class number:%d\n", rfctl->cap_spt_op_class_num);
1358 }
1359 
dump_reg_spt_op_class_ch(void * sel,struct rf_ctl_t * rfctl,bool detail)1360 void dump_reg_spt_op_class_ch(void *sel, struct rf_ctl_t *rfctl, bool detail)
1361 {
1362 	u8 i;
1363 
1364 	dump_op_class_ch_title(sel);
1365 
1366 	for (i = 0; i < global_op_class_num; i++) {
1367 		if (!rfctl->spt_op_class_ch[i])
1368 			continue;
1369 		dump_opc_pref_single(sel, rfctl->spt_op_class_ch[i], 0, 1, detail);
1370 	}
1371 
1372 	RTW_PRINT_SEL(sel, "op_class number:%d\n", rfctl->reg_spt_op_class_num);
1373 }
1374 
dump_cur_spt_op_class_ch(void * sel,struct rf_ctl_t * rfctl,bool detail)1375 void dump_cur_spt_op_class_ch(void *sel, struct rf_ctl_t *rfctl, bool detail)
1376 {
1377 	u8 i;
1378 
1379 	dump_op_class_ch_title(sel);
1380 
1381 	for (i = 0; i < global_op_class_num; i++) {
1382 		if (!rfctl->spt_op_class_ch[i])
1383 			continue;
1384 		dump_opc_pref_single(sel, rfctl->spt_op_class_ch[i], 0, 0, detail);
1385 	}
1386 
1387 	RTW_PRINT_SEL(sel, "op_class number:%d\n", rfctl->cur_spt_op_class_num);
1388 }
1389 
1390 const u8 _rf_type_to_rf_tx_cnt[] = {
1391 	1, /*RF_1T1R*/
1392 	1, /*RF_1T2R*/
1393 	2, /*RF_2T2R*/
1394 	2, /*RF_2T3R*/
1395 	2, /*RF_2T4R*/
1396 	3, /*RF_3T3R*/
1397 	3, /*RF_3T4R*/
1398 	4, /*RF_4T4R*/
1399 	1, /*RF_TYPE_MAX*/
1400 };
1401 
1402 const u8 _rf_type_to_rf_rx_cnt[] = {
1403 	1, /*RF_1T1R*/
1404 	2, /*RF_1T2R*/
1405 	2, /*RF_2T2R*/
1406 	3, /*RF_2T3R*/
1407 	4, /*RF_2T4R*/
1408 	3, /*RF_3T3R*/
1409 	4, /*RF_3T4R*/
1410 	4, /*RF_4T4R*/
1411 	1, /*RF_TYPE_MAX*/
1412 };
1413 
1414 const char *const _rf_type_to_rfpath_str[] = {
1415 	"RF_1T1R",
1416 	"RF_1T2R",
1417 	"RF_2T2R",
1418 	"RF_2T3R",
1419 	"RF_2T4R",
1420 	"RF_3T3R",
1421 	"RF_3T4R",
1422 	"RF_4T4R",
1423 	"RF_TYPE_MAX"
1424 };
1425 
1426 static const u8 _trx_num_to_rf_type[RF_PATH_MAX][RF_PATH_MAX] = {
1427 	{RF_1T1R,		RF_1T2R,		RF_TYPE_MAX,	RF_TYPE_MAX},
1428 	{RF_TYPE_MAX,	RF_2T2R,		RF_2T3R,		RF_2T4R},
1429 	{RF_TYPE_MAX,	RF_TYPE_MAX,	RF_3T3R,		RF_3T4R},
1430 	{RF_TYPE_MAX,	RF_TYPE_MAX,	RF_TYPE_MAX,	RF_4T4R},
1431 };
1432 
trx_num_to_rf_type(u8 tx_num,u8 rx_num)1433 enum rf_type trx_num_to_rf_type(u8 tx_num, u8 rx_num)
1434 {
1435 	if (tx_num > 0 && tx_num <= RF_PATH_MAX && rx_num > 0 && rx_num <= RF_PATH_MAX)
1436 		return _trx_num_to_rf_type[tx_num - 1][rx_num - 1];
1437 	return RF_TYPE_MAX;
1438 }
1439 
trx_bmp_to_rf_type(u8 tx_bmp,u8 rx_bmp)1440 enum rf_type trx_bmp_to_rf_type(u8 tx_bmp, u8 rx_bmp)
1441 {
1442 	u8 tx_num = 0;
1443 	u8 rx_num = 0;
1444 	int i;
1445 
1446 	for (i = 0; i < RF_PATH_MAX; i++) {
1447 		if (tx_bmp >> i & BIT0)
1448 			tx_num++;
1449 		if (rx_bmp >> i & BIT0)
1450 			rx_num++;
1451 	}
1452 
1453 	return trx_num_to_rf_type(tx_num, rx_num);
1454 }
1455 
rf_type_is_a_in_b(enum rf_type a,enum rf_type b)1456 bool rf_type_is_a_in_b(enum rf_type a, enum rf_type b)
1457 {
1458 	return rf_type_to_rf_tx_cnt(a) <= rf_type_to_rf_tx_cnt(b)
1459 		&& rf_type_to_rf_rx_cnt(a) <= rf_type_to_rf_rx_cnt(b);
1460 }
1461 
rtw_path_bmp_limit_from_higher(u8 * bmp,u8 * bmp_bit_cnt,u8 bit_cnt_lmt)1462 static void rtw_path_bmp_limit_from_higher(u8 *bmp, u8 *bmp_bit_cnt, u8 bit_cnt_lmt)
1463 {
1464 	int i;
1465 
1466 	for (i = RF_PATH_MAX - 1; *bmp_bit_cnt > bit_cnt_lmt && i >= 0; i--) {
1467 		if (*bmp & BIT(i)) {
1468 			*bmp &= ~BIT(i);
1469 			(*bmp_bit_cnt)--;
1470 		}
1471 	}
1472 }
1473 
rtw_restrict_trx_path_bmp_by_rftype(u8 trx_path_bmp,enum rf_type type,u8 * tx_num,u8 * rx_num)1474 u8 rtw_restrict_trx_path_bmp_by_rftype(u8 trx_path_bmp, enum rf_type type, u8 *tx_num, u8 *rx_num)
1475 {
1476 	u8 bmp_tx = (trx_path_bmp & 0xF0) >> 4;
1477 	u8 bmp_rx = trx_path_bmp & 0x0F;
1478 	u8 bmp_tx_num = 0, bmp_rx_num = 0;
1479 	u8 tx_num_lmt, rx_num_lmt;
1480 	enum rf_type ret_type = RF_TYPE_MAX;
1481 	int i, j;
1482 
1483 	for (i = 0; i < RF_PATH_MAX; i++) {
1484 		if (bmp_tx & BIT(i))
1485 			bmp_tx_num++;
1486 		if (bmp_rx & BIT(i))
1487 			bmp_rx_num++;
1488 	}
1489 
1490 	/* limit higher bit first according to input type */
1491 	tx_num_lmt = rf_type_to_rf_tx_cnt(type);
1492 	rx_num_lmt = rf_type_to_rf_rx_cnt(type);
1493 	rtw_path_bmp_limit_from_higher(&bmp_tx, &bmp_tx_num, tx_num_lmt);
1494 	rtw_path_bmp_limit_from_higher(&bmp_rx, &bmp_rx_num, rx_num_lmt);
1495 
1496 	/* search for valid rf_type (larger RX prefer) */
1497 	for (j = bmp_rx_num; j > 0; j--) {
1498 		for (i = bmp_tx_num; i > 0; i--) {
1499 			ret_type = trx_num_to_rf_type(i, j);
1500 			if (RF_TYPE_VALID(ret_type)) {
1501 				rtw_path_bmp_limit_from_higher(&bmp_tx, &bmp_tx_num, i);
1502 				rtw_path_bmp_limit_from_higher(&bmp_rx, &bmp_rx_num, j);
1503 				if (tx_num)
1504 					*tx_num = bmp_tx_num;
1505 				if (rx_num)
1506 					*rx_num = bmp_rx_num;
1507 				goto exit;
1508 			}
1509 		}
1510 	}
1511 
1512 exit:
1513 	return RF_TYPE_VALID(ret_type) ? ((bmp_tx << 4) | bmp_rx) : 0x00;
1514 }
1515 
1516 /*
1517 * input with txpwr value in unit of txpwr index
1518 * return string in length 6 at least (for -xx.xx)
1519 */
txpwr_idx_get_dbm_str(s8 idx,u8 txgi_max,u8 txgi_pdbm,SIZE_T cwidth,char dbm_str[],u8 dbm_str_len)1520 void txpwr_idx_get_dbm_str(s8 idx, u8 txgi_max, u8 txgi_pdbm, SIZE_T cwidth, char dbm_str[], u8 dbm_str_len)
1521 {
1522 	char fmt[16];
1523 
1524 	if (idx == txgi_max) {
1525 		snprintf(fmt, 16, "%%%zus", cwidth >= 6 ? cwidth + 1 : 6);
1526 		snprintf(dbm_str, dbm_str_len, fmt, "NA");
1527 	} else if (idx > -txgi_pdbm && idx < 0) { /* -0.xx */
1528 		snprintf(fmt, 16, "%%%zus-0.%%02d", cwidth >= 6 ? cwidth - 4 : 1);
1529 		snprintf(dbm_str, dbm_str_len, fmt, "", (rtw_abs(idx) % txgi_pdbm) * 100 / txgi_pdbm);
1530 	} else if (idx % txgi_pdbm) { /* d.xx */
1531 		snprintf(fmt, 16, "%%%zud.%%02d", cwidth >= 6 ? cwidth - 2 : 3);
1532 		snprintf(dbm_str, dbm_str_len, fmt, idx / txgi_pdbm, (rtw_abs(idx) % txgi_pdbm) * 100 / txgi_pdbm);
1533 	} else { /* d */
1534 		snprintf(fmt, 16, "%%%zud", cwidth >= 6 ? cwidth + 1 : 6);
1535 		snprintf(dbm_str, dbm_str_len, fmt, idx / txgi_pdbm);
1536 	}
1537 }
1538 
1539 /*
1540 * input with txpwr value in unit of mbm
1541 * return string in length 6 at least (for -xx.xx)
1542 */
txpwr_mbm_get_dbm_str(s16 mbm,SIZE_T cwidth,char dbm_str[],u8 dbm_str_len)1543 void txpwr_mbm_get_dbm_str(s16 mbm, SIZE_T cwidth, char dbm_str[], u8 dbm_str_len)
1544 {
1545 	char fmt[16];
1546 
1547 	if (mbm == UNSPECIFIED_MBM) {
1548 		snprintf(fmt, 16, "%%%zus", cwidth >= 6 ? cwidth + 1 : 6);
1549 		snprintf(dbm_str, dbm_str_len, fmt, "NA");
1550 	} else if (mbm > -MBM_PDBM && mbm < 0) { /* -0.xx */
1551 		snprintf(fmt, 16, "%%%zus-0.%%02d", cwidth >= 6 ? cwidth - 4 : 1);
1552 		snprintf(dbm_str, dbm_str_len, fmt, "", (rtw_abs(mbm) % MBM_PDBM) * 100 / MBM_PDBM);
1553 	} else if (mbm % MBM_PDBM) { /* d.xx */
1554 		snprintf(fmt, 16, "%%%zud.%%02d", cwidth >= 6 ? cwidth - 2 : 3);
1555 		snprintf(dbm_str, dbm_str_len, fmt, mbm / MBM_PDBM, (rtw_abs(mbm) % MBM_PDBM) * 100 / MBM_PDBM);
1556 	} else { /* d */
1557 		snprintf(fmt, 16, "%%%zud", cwidth >= 6 ? cwidth + 1 : 6);
1558 		snprintf(dbm_str, dbm_str_len, fmt, mbm / MBM_PDBM);
1559 	}
1560 }
1561 
1562 static const s16 _mb_of_ntx[] = {
1563 	0,		/* 1TX */
1564 	301,	/* 2TX */
1565 	477,	/* 3TX */
1566 	602,	/* 4TX */
1567 	699,	/* 5TX */
1568 	778,	/* 6TX */
1569 	845,	/* 7TX */
1570 	903,	/* 8TX */
1571 };
1572 
1573 /* get mB(100 *dB) for specifc TX count relative to 1TX */
mb_of_ntx(u8 ntx)1574 s16 mb_of_ntx(u8 ntx)
1575 {
1576 	if (ntx == 0 || ntx > 8) {
1577 		RTW_ERR("ntx=%u, out of range\n", ntx);
1578 		rtw_warn_on(1);
1579 	}
1580 
1581 	return _mb_of_ntx[ntx - 1];
1582 }
1583 
1584 #if CONFIG_TXPWR_LIMIT
dump_regd_exc_list(void * sel,struct rf_ctl_t * rfctl)1585 void dump_regd_exc_list(void *sel, struct rf_ctl_t *rfctl)
1586 {
1587 	/* TODO: get from phl */
1588 }
1589 
dump_txpwr_lmt(void * sel,_adapter * adapter)1590 void dump_txpwr_lmt(void *sel, _adapter *adapter)
1591 {
1592 	/* TODO: get from phl */
1593 }
1594 #endif /* CONFIG_TXPWR_LIMIT */
1595 
rtw_is_long_cac_range(u32 hi,u32 lo,u8 dfs_region)1596 bool rtw_is_long_cac_range(u32 hi, u32 lo, u8 dfs_region)
1597 {
1598 	return (dfs_region == RTW_DFS_REGD_ETSI && rtw_is_range_overlap(hi, lo, 5650, 5600)) ? _TRUE : _FALSE;
1599 }
1600 
rtw_is_long_cac_ch(u8 ch,u8 bw,u8 offset,u8 dfs_region)1601 bool rtw_is_long_cac_ch(u8 ch, u8 bw, u8 offset, u8 dfs_region)
1602 {
1603 	u32 hi, lo;
1604 
1605 	if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE)
1606 		return _FALSE;
1607 
1608 	return rtw_is_long_cac_range(hi, lo, dfs_region) ? _TRUE : _FALSE;
1609 }
1610