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 = ¢er_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 = ¢er_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