OSDN Git Service

1ab3c302db4bb33394ffddfb814d6c11045cc3f0
[android-x86/external-kernel-drivers.git] / rtl8821ce / core / rtw_rf.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2017 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 #include <hal_data.h>
19
20 u8 center_ch_2g[CENTER_CH_2G_NUM] = {
21 /* G00 */1, 2,
22 /* G01 */3, 4, 5,
23 /* G02 */6, 7, 8,
24 /* G03 */9, 10, 11,
25 /* G04 */12, 13,
26 /* G05 */14
27 };
28
29 u8 center_ch_2g_40m[CENTER_CH_2G_40M_NUM] = {
30         3,
31         4,
32         5,
33         6,
34         7,
35         8,
36         9,
37         10,
38         11,
39 };
40
41 u8 op_chs_of_cch_2g_40m[CENTER_CH_2G_40M_NUM][2] = {
42         {1, 5}, /* 3 */
43         {2, 6}, /* 4 */
44         {3, 7}, /* 5 */
45         {4, 8}, /* 6 */
46         {5, 9}, /* 7 */
47         {6, 10}, /* 8 */
48         {7, 11}, /* 9 */
49         {8, 12}, /* 10 */
50         {9, 13}, /* 11 */
51 };
52
53 u8 center_ch_5g_all[CENTER_CH_5G_ALL_NUM] = {
54 /* G00 */36, 38, 40,
55         42,
56 /* G01 */44, 46, 48,
57         /* 50, */
58 /* G02 */52, 54, 56,
59         58,
60 /* G03 */60, 62, 64,
61 /* G04 */100, 102, 104,
62         106,
63 /* G05 */108, 110, 112,
64         /* 114, */
65 /* G06 */116, 118, 120,
66         122,
67 /* G07 */124, 126, 128,
68 /* G08 */132, 134, 136,
69         138,
70 /* G09 */140, 142, 144,
71 /* G10 */149, 151, 153,
72         155,
73 /* G11 */157, 159, 161,
74         /* 163, */
75 /* G12 */165, 167, 169,
76         171,
77 /* G13 */173, 175, 177
78 };
79
80 u8 center_ch_5g_20m[CENTER_CH_5G_20M_NUM] = {
81 /* G00 */36, 40,
82 /* G01 */44, 48,
83 /* G02 */52, 56,
84 /* G03 */60, 64,
85 /* G04 */100, 104,
86 /* G05 */108, 112,
87 /* G06 */116, 120,
88 /* G07 */124, 128,
89 /* G08 */132, 136,
90 /* G09 */140, 144,
91 /* G10 */149, 153,
92 /* G11 */157, 161,
93 /* G12 */165, 169,
94 /* G13 */173, 177
95 };
96
97 u8 center_ch_5g_40m[CENTER_CH_5G_40M_NUM] = {
98 /* G00 */38,
99 /* G01 */46,
100 /* G02 */54,
101 /* G03 */62,
102 /* G04 */102,
103 /* G05 */110,
104 /* G06 */118,
105 /* G07 */126,
106 /* G08 */134,
107 /* G09 */142,
108 /* G10 */151,
109 /* G11 */159,
110 /* G12 */167,
111 /* G13 */175
112 };
113
114 u8 center_ch_5g_20m_40m[CENTER_CH_5G_20M_NUM + CENTER_CH_5G_40M_NUM] = {
115 /* G00 */36, 38, 40,
116 /* G01 */44, 46, 48,
117 /* G02 */52, 54, 56,
118 /* G03 */60, 62, 64,
119 /* G04 */100, 102, 104,
120 /* G05 */108, 110, 112,
121 /* G06 */116, 118, 120,
122 /* G07 */124, 126, 128,
123 /* G08 */132, 134, 136,
124 /* G09 */140, 142, 144,
125 /* G10 */149, 151, 153,
126 /* G11 */157, 159, 161,
127 /* G12 */165, 167, 169,
128 /* G13 */173, 175, 177
129 };
130
131 u8 op_chs_of_cch_5g_40m[CENTER_CH_5G_40M_NUM][2] = {
132         {36, 40}, /* 38 */
133         {44, 48}, /* 46 */
134         {52, 56}, /* 54 */
135         {60, 64}, /* 62 */
136         {100, 104}, /* 102 */
137         {108, 112}, /* 110 */
138         {116, 120}, /* 118 */
139         {124, 128}, /* 126 */
140         {132, 136}, /* 134 */
141         {140, 144}, /* 142 */
142         {149, 153}, /* 151 */
143         {157, 161}, /* 159 */
144         {165, 169}, /* 167 */
145         {173, 177}, /* 175 */
146 };
147
148 u8 center_ch_5g_80m[CENTER_CH_5G_80M_NUM] = {
149 /* G00 ~ G01*/42,
150 /* G02 ~ G03*/58,
151 /* G04 ~ G05*/106,
152 /* G06 ~ G07*/122,
153 /* G08 ~ G09*/138,
154 /* G10 ~ G11*/155,
155 /* G12 ~ G13*/171
156 };
157
158 u8 op_chs_of_cch_5g_80m[CENTER_CH_5G_80M_NUM][4] = {
159         {36, 40, 44, 48}, /* 42 */
160         {52, 56, 60, 64}, /* 58 */
161         {100, 104, 108, 112}, /* 106 */
162         {116, 120, 124, 128}, /* 122 */
163         {132, 136, 140, 144}, /* 138 */
164         {149, 153, 157, 161}, /* 155 */
165         {165, 169, 173, 177}, /* 171 */
166 };
167
168 u8 center_ch_5g_160m[CENTER_CH_5G_160M_NUM] = {
169 /* G00 ~ G03*/50,
170 /* G04 ~ G07*/114,
171 /* G10 ~ G13*/163
172 };
173
174 u8 op_chs_of_cch_5g_160m[CENTER_CH_5G_160M_NUM][8] = {
175         {36, 40, 44, 48, 52, 56, 60, 64}, /* 50 */
176         {100, 104, 108, 112, 116, 120, 124, 128}, /* 114 */
177         {149, 153, 157, 161, 165, 169, 173, 177}, /* 163 */
178 };
179
180 struct center_chs_ent_t {
181         u8 ch_num;
182         u8 *chs;
183 };
184
185 struct center_chs_ent_t center_chs_2g_by_bw[] = {
186         {CENTER_CH_2G_NUM, center_ch_2g},
187         {CENTER_CH_2G_40M_NUM, center_ch_2g_40m},
188 };
189
190 struct center_chs_ent_t center_chs_5g_by_bw[] = {
191         {CENTER_CH_5G_20M_NUM, center_ch_5g_20m},
192         {CENTER_CH_5G_40M_NUM, center_ch_5g_40m},
193         {CENTER_CH_5G_80M_NUM, center_ch_5g_80m},
194         {CENTER_CH_5G_160M_NUM, center_ch_5g_160m},
195 };
196
197 /*
198  * Get center channel of smaller bandwidth by @param cch, @param bw, @param offset
199  * @cch: the given center channel
200  * @bw: the given bandwidth
201  * @offset: the given primary SC offset of the given bandwidth
202  *
203  * return center channel of smaller bandiwdth if valid, or 0
204  */
205 u8 rtw_get_scch_by_cch_offset(u8 cch, u8 bw, u8 offset)
206 {
207         u8 t_cch = 0;
208
209         if (bw == CHANNEL_WIDTH_20) {
210                 t_cch = cch;
211                 goto exit;
212         }
213
214         if (offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) {
215                 rtw_warn_on(1);
216                 goto exit;
217         }
218
219         /* 2.4G, 40MHz */
220         if (cch >= 3 && cch <= 11 && bw == CHANNEL_WIDTH_40) {
221                 t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 2 : cch - 2;
222                 goto exit;
223         }
224
225         /* 5G, 160MHz */
226         if (cch >= 50 && cch <= 163 && bw == CHANNEL_WIDTH_160) {
227                 t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 8 : cch - 8;
228                 goto exit;
229
230         /* 5G, 80MHz */
231         } else if (cch >= 42 && cch <= 171 && bw == CHANNEL_WIDTH_80) {
232                 t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 4 : cch - 4;
233                 goto exit;
234
235         /* 5G, 40MHz */
236         } else if (cch >= 38 && cch <= 175 && bw == CHANNEL_WIDTH_40) {
237                 t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 2 : cch - 2;
238                 goto exit;
239
240         } else {
241                 rtw_warn_on(1);
242                 goto exit;
243         }
244
245 exit:
246         return t_cch;
247 }
248
249 struct op_chs_ent_t {
250         u8 ch_num;
251         u8 *chs;
252 };
253
254 struct op_chs_ent_t op_chs_of_cch_2g_by_bw[] = {
255         {1, center_ch_2g},
256         {2, (u8 *)op_chs_of_cch_2g_40m},
257 };
258
259 struct op_chs_ent_t op_chs_of_cch_5g_by_bw[] = {
260         {1, center_ch_5g_20m},
261         {2, (u8 *)op_chs_of_cch_5g_40m},
262         {4, (u8 *)op_chs_of_cch_5g_80m},
263         {8, (u8 *)op_chs_of_cch_5g_160m},
264 };
265
266 inline u8 center_chs_2g_num(u8 bw)
267 {
268         if (bw > CHANNEL_WIDTH_40)
269                 return 0;
270
271         return center_chs_2g_by_bw[bw].ch_num;
272 }
273
274 inline u8 center_chs_2g(u8 bw, u8 id)
275 {
276         if (bw > CHANNEL_WIDTH_40)
277                 return 0;
278
279         if (id >= center_chs_2g_num(bw))
280                 return 0;
281
282         return center_chs_2g_by_bw[bw].chs[id];
283 }
284
285 inline u8 center_chs_5g_num(u8 bw)
286 {
287         if (bw > CHANNEL_WIDTH_80)
288                 return 0;
289
290         return center_chs_5g_by_bw[bw].ch_num;
291 }
292
293 inline u8 center_chs_5g(u8 bw, u8 id)
294 {
295         if (bw > CHANNEL_WIDTH_80)
296                 return 0;
297
298         if (id >= center_chs_5g_num(bw))
299                 return 0;
300
301         return center_chs_5g_by_bw[bw].chs[id];
302 }
303
304 /*
305  * Get available op channels by @param cch, @param bw
306  * @cch: the given center channel
307  * @bw: the given bandwidth
308  * @op_chs: the pointer to return pointer of op channel array
309  * @op_ch_num: the pointer to return pointer of op channel number
310  *
311  * return valid (1) or not (0)
312  */
313 u8 rtw_get_op_chs_by_cch_bw(u8 cch, u8 bw, u8 **op_chs, u8 *op_ch_num)
314 {
315         int i;
316         struct center_chs_ent_t *c_chs_ent = NULL;
317         struct op_chs_ent_t *op_chs_ent = NULL;
318         u8 valid = 1;
319
320         if (cch <= 14
321                 && bw >= CHANNEL_WIDTH_20 && bw <= CHANNEL_WIDTH_40
322         ) {
323                 c_chs_ent = &center_chs_2g_by_bw[bw];
324                 op_chs_ent = &op_chs_of_cch_2g_by_bw[bw];
325         } else if (cch >= 36 && cch <= 177
326                 && bw >= CHANNEL_WIDTH_20 && bw <= CHANNEL_WIDTH_160
327         ) {
328                 c_chs_ent = &center_chs_5g_by_bw[bw];
329                 op_chs_ent = &op_chs_of_cch_5g_by_bw[bw];
330         } else {
331                 valid = 0;
332                 goto exit;
333         }
334
335         for (i = 0; i < c_chs_ent->ch_num; i++)
336                 if (cch == *(c_chs_ent->chs + i))
337                         break;
338
339         if (i == c_chs_ent->ch_num) {
340                 valid = 0;
341                 goto exit;
342         }
343
344         *op_chs = op_chs_ent->chs + op_chs_ent->ch_num * i;
345         *op_ch_num = op_chs_ent->ch_num;
346
347 exit:
348         return valid;
349 }
350
351 u8 rtw_get_ch_group(u8 ch, u8 *group, u8 *cck_group)
352 {
353         BAND_TYPE band = BAND_MAX;
354         s8 gp = -1, cck_gp = -1;
355
356         if (ch <= 14) {
357                 band = BAND_ON_2_4G;
358
359                 if (1 <= ch && ch <= 2)
360                         gp = 0;
361                 else if (3  <= ch && ch <= 5)
362                         gp = 1;
363                 else if (6  <= ch && ch <= 8)
364                         gp = 2;
365                 else if (9  <= ch && ch <= 11)
366                         gp = 3;
367                 else if (12 <= ch && ch <= 14)
368                         gp = 4;
369                 else
370                         band = BAND_MAX;
371
372                 if (ch == 14)
373                         cck_gp = 5;
374                 else
375                         cck_gp = gp;
376         } else {
377                 band = BAND_ON_5G;
378
379                 if (36 <= ch && ch <= 42)
380                         gp = 0;
381                 else if (44   <= ch && ch <=  48)
382                         gp = 1;
383                 else if (50   <= ch && ch <=  58)
384                         gp = 2;
385                 else if (60   <= ch && ch <=  64)
386                         gp = 3;
387                 else if (100  <= ch && ch <= 106)
388                         gp = 4;
389                 else if (108  <= ch && ch <= 114)
390                         gp = 5;
391                 else if (116  <= ch && ch <= 122)
392                         gp = 6;
393                 else if (124  <= ch && ch <= 130)
394                         gp = 7;
395                 else if (132  <= ch && ch <= 138)
396                         gp = 8;
397                 else if (140  <= ch && ch <= 144)
398                         gp = 9;
399                 else if (149  <= ch && ch <= 155)
400                         gp = 10;
401                 else if (157  <= ch && ch <= 161)
402                         gp = 11;
403                 else if (165  <= ch && ch <= 171)
404                         gp = 12;
405                 else if (173  <= ch && ch <= 177)
406                         gp = 13;
407                 else
408                         band = BAND_MAX;
409         }
410
411         if (band == BAND_MAX
412                 || (band == BAND_ON_2_4G && cck_gp == -1)
413                 || gp == -1
414         ) {
415                 RTW_WARN("%s invalid channel:%u", __func__, ch);
416                 rtw_warn_on(1);
417                 goto exit;
418         }
419
420         if (group)
421                 *group = gp;
422         if (cck_group && band == BAND_ON_2_4G)
423                 *cck_group = cck_gp;
424
425 exit:
426         return band;
427 }
428
429 int rtw_ch2freq(int chan)
430 {
431         /* see 802.11 17.3.8.3.2 and Annex J
432         * there are overlapping channel numbers in 5GHz and 2GHz bands */
433
434         /*
435         * RTK: don't consider the overlapping channel numbers: 5G channel <= 14,
436         * because we don't support it. simply judge from channel number
437         */
438
439         if (chan >= 1 && chan <= 14) {
440                 if (chan == 14)
441                         return 2484;
442                 else if (chan < 14)
443                         return 2407 + chan * 5;
444         } else if (chan >= 36 && chan <= 177)
445                 return 5000 + chan * 5;
446
447         return 0; /* not supported */
448 }
449
450 int rtw_freq2ch(int freq)
451 {
452         /* see 802.11 17.3.8.3.2 and Annex J */
453         if (freq == 2484)
454                 return 14;
455         else if (freq < 2484)
456                 return (freq - 2407) / 5;
457         else if (freq >= 4910 && freq <= 4980)
458                 return (freq - 4000) / 5;
459         else if (freq <= 45000) /* DMG band lower limit */
460                 return (freq - 5000) / 5;
461         else if (freq >= 58320 && freq <= 64800)
462                 return (freq - 56160) / 2160;
463         else
464                 return 0;
465 }
466
467 bool rtw_chbw_to_freq_range(u8 ch, u8 bw, u8 offset, u32 *hi, u32 *lo)
468 {
469         u8 c_ch;
470         u32 freq;
471         u32 hi_ret = 0, lo_ret = 0;
472         bool valid = _FALSE;
473
474         if (hi)
475                 *hi = 0;
476         if (lo)
477                 *lo = 0;
478
479         c_ch = rtw_get_center_ch(ch, bw, offset);
480         freq = rtw_ch2freq(c_ch);
481
482         if (!freq) {
483                 rtw_warn_on(1);
484                 goto exit;
485         }
486
487         if (bw == CHANNEL_WIDTH_80) {
488                 hi_ret = freq + 40;
489                 lo_ret = freq - 40;
490         } else if (bw == CHANNEL_WIDTH_40) {
491                 hi_ret = freq + 20;
492                 lo_ret = freq - 20;
493         } else if (bw == CHANNEL_WIDTH_20) {
494                 hi_ret = freq + 10;
495                 lo_ret = freq - 10;
496         } else
497                 rtw_warn_on(1);
498
499         if (hi)
500                 *hi = hi_ret;
501         if (lo)
502                 *lo = lo_ret;
503
504         valid = _TRUE;
505
506 exit:
507         return valid;
508 }
509
510 const char *const _ch_width_str[CHANNEL_WIDTH_MAX] = {
511         "20MHz",
512         "40MHz",
513         "80MHz",
514         "160MHz",
515         "80_80MHz",
516         "5MHz",
517         "10MHz",
518 };
519
520 const u8 _ch_width_to_bw_cap[CHANNEL_WIDTH_MAX] = {
521         BW_CAP_20M,
522         BW_CAP_40M,
523         BW_CAP_80M,
524         BW_CAP_160M,
525         BW_CAP_80_80M,
526         BW_CAP_5M,
527         BW_CAP_10M,
528 };
529
530 const char *const _band_str[] = {
531         "2.4G",
532         "5G",
533         "BOTH",
534         "BAND_MAX",
535 };
536
537 const u8 _band_to_band_cap[] = {
538         BAND_CAP_2G,
539         BAND_CAP_5G,
540         0,
541         0,
542 };
543
544 const u8 _rf_type_to_rf_tx_cnt[] = {
545         1, /*RF_1T1R*/
546         1, /*RF_1T2R*/
547         2, /*RF_2T2R*/
548         2, /*RF_2T3R*/
549         2, /*RF_2T4R*/
550         3, /*RF_3T3R*/
551         3, /*RF_3T4R*/
552         4, /*RF_4T4R*/
553         1, /*RF_TYPE_MAX*/
554 };
555
556 const u8 _rf_type_to_rf_rx_cnt[] = {
557         1, /*RF_1T1R*/
558         2, /*RF_1T2R*/
559         2, /*RF_2T2R*/
560         3, /*RF_2T3R*/
561         4, /*RF_2T4R*/
562         3, /*RF_3T3R*/
563         4, /*RF_3T4R*/
564         4, /*RF_4T4R*/
565         1, /*RF_TYPE_MAX*/
566 };
567
568 const char *const _regd_str[] = {
569         "NONE",
570         "FCC",
571         "MKK",
572         "ETSI",
573         "IC",
574         "KCC",
575         "ACMA",
576         "CHILE",
577         "WW",
578 };
579
580 #ifdef CONFIG_TXPWR_LIMIT
581 void _dump_regd_exc_list(void *sel, struct rf_ctl_t *rfctl)
582 {
583         struct regd_exc_ent *ent;
584         _list *cur, *head;
585
586         RTW_PRINT_SEL(sel, "regd_exc_num:%u\n", rfctl->regd_exc_num);
587
588         if (!rfctl->regd_exc_num)
589                 goto exit;
590
591         RTW_PRINT_SEL(sel, "%-7s %-6s %-9s\n", "country", "domain", "regd_name");
592
593         head = &rfctl->reg_exc_list;
594         cur = get_next(head);
595
596         while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
597                 u8 has_country;
598
599                 ent = LIST_CONTAINOR(cur, struct regd_exc_ent, list);
600                 cur = get_next(cur);
601                 has_country = (ent->country[0] == '\0' && ent->country[1] == '\0') ? 0 : 1;
602
603                 RTW_PRINT_SEL(sel, "     %c%c   0x%02x %s\n"
604                         , has_country ? ent->country[0] : '0'
605                         , has_country ? ent->country[1] : '0'
606                         , ent->domain
607                         , ent->regd_name
608                 );
609         }
610
611 exit:
612         return;
613 }
614
615 inline void dump_regd_exc_list(void *sel, struct rf_ctl_t *rfctl)
616 {
617         _irqL irqL;
618
619         _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
620         _dump_regd_exc_list(sel, rfctl);
621         _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
622 }
623
624 void rtw_regd_exc_add_with_nlen(struct rf_ctl_t *rfctl, const char *country, u8 domain, const char *regd_name, u32 nlen)
625 {
626         struct regd_exc_ent *ent;
627         _irqL irqL;
628
629         if (!regd_name || !nlen) {
630                 rtw_warn_on(1);
631                 goto exit;
632         }
633
634         ent = (struct regd_exc_ent *)rtw_zmalloc(sizeof(struct regd_exc_ent) + nlen + 1);
635         if (!ent)
636                 goto exit;
637
638         _rtw_init_listhead(&ent->list);
639         if (country)
640                 _rtw_memcpy(ent->country, country, 2);
641         ent->domain = domain;
642         _rtw_memcpy(ent->regd_name, regd_name, nlen);
643
644         _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
645
646         rtw_list_insert_tail(&ent->list, &rfctl->reg_exc_list);
647         rfctl->regd_exc_num++;
648
649         _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
650
651 exit:
652         return;
653 }
654
655 inline void rtw_regd_exc_add(struct rf_ctl_t *rfctl, const char *country, u8 domain, const char *regd_name)
656 {
657         rtw_regd_exc_add_with_nlen(rfctl, country, domain, regd_name, strlen(regd_name));
658 }
659
660 struct regd_exc_ent *_rtw_regd_exc_search(struct rf_ctl_t *rfctl, const char *country, u8 domain)
661 {
662         struct regd_exc_ent *ent;
663         _list *cur, *head;
664         u8 match = 0;
665
666         head = &rfctl->reg_exc_list;
667         cur = get_next(head);
668
669         while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
670                 u8 has_country;
671
672                 ent = LIST_CONTAINOR(cur, struct regd_exc_ent, list);
673                 cur = get_next(cur);
674                 has_country = (ent->country[0] == '\0' && ent->country[1] == '\0') ? 0 : 1;
675
676                 /* entry has country condition to match */
677                 if (has_country) {
678                         if (!country)
679                                 continue;
680                         if (ent->country[0] != country[0]
681                                 || ent->country[1] != country[1])
682                                 continue;
683                 }
684
685                 /* entry has domain condition to match */
686                 if (ent->domain != 0xFF) {
687                         if (domain == 0xFF)
688                                 continue;
689                         if (ent->domain != domain)
690                                 continue;
691                 }
692
693                 match = 1;
694                 break;
695         }
696
697         if (match)
698                 return ent;
699         else
700                 return NULL;
701 }
702
703 inline struct regd_exc_ent *rtw_regd_exc_search(struct rf_ctl_t *rfctl, const char *country, u8 domain)
704 {
705         struct regd_exc_ent *ent;
706         _irqL irqL;
707
708         _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
709         ent = _rtw_regd_exc_search(rfctl, country, domain);
710         _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
711
712         return ent;
713 }
714
715 void rtw_regd_exc_list_free(struct rf_ctl_t *rfctl)
716 {
717         struct regd_exc_ent *ent;
718         _irqL irqL;
719         _list *cur, *head;
720
721         _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
722
723         head = &rfctl->reg_exc_list;
724         cur = get_next(head);
725
726         while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
727                 ent = LIST_CONTAINOR(cur, struct regd_exc_ent, list);
728                 cur = get_next(cur);
729                 rtw_list_delete(&ent->list);
730                 rtw_mfree((u8 *)ent, sizeof(struct regd_exc_ent) + strlen(ent->regd_name) + 1);
731         }
732         rfctl->regd_exc_num = 0;
733
734         _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
735 }
736
737 void dump_txpwr_lmt(void *sel, _adapter *adapter)
738 {
739 #define TMP_STR_LEN 16
740         struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
741         struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter);
742         _irqL irqL;
743         char fmt[16];
744         char tmp_str[TMP_STR_LEN];
745         s8 *lmt_idx = NULL;
746         int bw, band, ch_num, tlrs, ntx_idx, rs, i, path;
747         u8 ch, n, rfpath_num;
748
749         _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
750
751         _dump_regd_exc_list(sel, rfctl);
752         RTW_PRINT_SEL(sel, "\n");
753
754         if (!rfctl->txpwr_regd_num)
755                 goto release_lock;
756
757         lmt_idx = rtw_malloc(sizeof(s8) * RF_PATH_MAX * rfctl->txpwr_regd_num);
758         if (!lmt_idx) {
759                 RTW_ERR("%s alloc fail\n", __func__);
760                 goto release_lock;
761         }
762
763         RTW_PRINT_SEL(sel, "txpwr_lmt_2g_cck_ofdm_state:0x%02x\n", rfctl->txpwr_lmt_2g_cck_ofdm_state);
764         #ifdef CONFIG_IEEE80211_BAND_5GHZ
765         if (IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(adapter))
766                 RTW_PRINT_SEL(sel, "txpwr_lmt_5g_cck_ofdm_state:0x%02x\n", rfctl->txpwr_lmt_5g_cck_ofdm_state);
767                 RTW_PRINT_SEL(sel, "txpwr_lmt_5g_20_40_ref:0x%02x\n", rfctl->txpwr_lmt_5g_20_40_ref);
768         #endif
769         RTW_PRINT_SEL(sel, "\n");
770
771         for (band = BAND_ON_2_4G; band <= BAND_ON_5G; band++) {
772                 if (!hal_is_band_support(adapter, band))
773                         continue;
774
775                 rfpath_num = (band == BAND_ON_2_4G ? hal_spec->rfpath_num_2g : hal_spec->rfpath_num_5g);
776
777                 for (bw = 0; bw < MAX_5G_BANDWIDTH_NUM; bw++) {
778
779                         if (bw >= CHANNEL_WIDTH_160)
780                                 break;
781                         if (band == BAND_ON_2_4G && bw >= CHANNEL_WIDTH_80)
782                                 break;
783
784                         if (band == BAND_ON_2_4G)
785                                 ch_num = CENTER_CH_2G_NUM;
786                         else
787                                 ch_num = center_chs_5g_num(bw);
788
789                         if (ch_num == 0) {
790                                 rtw_warn_on(1);
791                                 break;
792                         }
793
794                         for (tlrs = TXPWR_LMT_RS_CCK; tlrs < TXPWR_LMT_RS_NUM; tlrs++) {
795
796                                 if (band == BAND_ON_2_4G && tlrs == TXPWR_LMT_RS_VHT)
797                                         continue;
798                                 if (band == BAND_ON_5G && tlrs == TXPWR_LMT_RS_CCK)
799                                         continue;
800                                 if (bw > CHANNEL_WIDTH_20 && (tlrs == TXPWR_LMT_RS_CCK || tlrs == TXPWR_LMT_RS_OFDM))
801                                         continue;
802                                 if (bw > CHANNEL_WIDTH_40 && tlrs == TXPWR_LMT_RS_HT)
803                                         continue;
804                                 if (tlrs == TXPWR_LMT_RS_VHT && !IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(adapter))
805                                         continue;
806
807                                 for (ntx_idx = RF_1TX; ntx_idx < MAX_TX_COUNT; ntx_idx++) {
808                                         struct txpwr_lmt_ent *ent;
809                                         _list *cur, *head;
810
811                                         if (ntx_idx >= hal_spec->tx_nss_num)
812                                                 continue;
813
814                                         /* bypass CCK multi-TX is not defined */
815                                         if (tlrs == TXPWR_LMT_RS_CCK && ntx_idx > RF_1TX) {
816                                                 if (band == BAND_ON_2_4G
817                                                         && !(rfctl->txpwr_lmt_2g_cck_ofdm_state & (TXPWR_LMT_HAS_CCK_1T << ntx_idx)))
818                                                         continue;
819                                         }
820
821                                         /* bypass OFDM multi-TX is not defined */
822                                         if (tlrs == TXPWR_LMT_RS_OFDM && ntx_idx > RF_1TX) {
823                                                 if (band == BAND_ON_2_4G
824                                                         && !(rfctl->txpwr_lmt_2g_cck_ofdm_state & (TXPWR_LMT_HAS_OFDM_1T << ntx_idx)))
825                                                         continue;
826                                                 #ifdef CONFIG_IEEE80211_BAND_5GHZ
827                                                 if (band == BAND_ON_5G
828                                                         && !(rfctl->txpwr_lmt_5g_cck_ofdm_state & (TXPWR_LMT_HAS_OFDM_1T << ntx_idx)))
829                                                         continue;
830                                                 #endif
831                                         }
832
833                                         /* bypass 5G 20M, 40M pure reference */
834                                         #ifdef CONFIG_IEEE80211_BAND_5GHZ
835                                         if (band == BAND_ON_5G && (bw == CHANNEL_WIDTH_20 || bw == CHANNEL_WIDTH_40)) {
836                                                 if (rfctl->txpwr_lmt_5g_20_40_ref == TXPWR_LMT_REF_HT_FROM_VHT) {
837                                                         if (tlrs == TXPWR_LMT_RS_HT)
838                                                                 continue;
839                                                 } else if (rfctl->txpwr_lmt_5g_20_40_ref == TXPWR_LMT_REF_VHT_FROM_HT) {
840                                                         if (tlrs == TXPWR_LMT_RS_VHT && bw <= CHANNEL_WIDTH_40)
841                                                                 continue;
842                                                 }
843                                         }
844                                         #endif
845
846                                         /* choose n-SS mapping rate section to get lmt diff value */
847                                         if (tlrs == TXPWR_LMT_RS_CCK)
848                                                 rs = CCK;
849                                         else if (tlrs == TXPWR_LMT_RS_OFDM)
850                                                 rs = OFDM;
851                                         else if (tlrs == TXPWR_LMT_RS_HT)
852                                                 rs = HT_1SS + ntx_idx;
853                                         else if (tlrs == TXPWR_LMT_RS_VHT)
854                                                 rs = VHT_1SS + ntx_idx;
855                                         else {
856                                                 RTW_ERR("%s invalid tlrs %u\n", __func__, tlrs);
857                                                 continue;
858                                         }
859
860                                         RTW_PRINT_SEL(sel, "[%s][%s][%s][%uT]\n"
861                                                 , band_str(band)
862                                                 , ch_width_str(bw)
863                                                 , txpwr_lmt_rs_str(tlrs)
864                                                 , ntx_idx + 1
865                                         );
866
867                                         /* header for limit in db */
868                                         RTW_PRINT_SEL(sel, "%3s ", "ch");
869
870                                         head = &rfctl->txpwr_lmt_list;
871                                         cur = get_next(head);
872                                         while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
873                                                 ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
874                                                 cur = get_next(cur);
875
876                                                 sprintf(fmt, "%%%zus%%s ", strlen(ent->regd_name) >= 6 ? 1 : 6 - strlen(ent->regd_name));
877                                                 snprintf(tmp_str, TMP_STR_LEN, fmt
878                                                         , strcmp(ent->regd_name, rfctl->regd_name) == 0 ? "*" : ""
879                                                         , ent->regd_name);
880                                                 _RTW_PRINT_SEL(sel, "%s", tmp_str);
881                                         }
882                                         sprintf(fmt, "%%%zus%%s ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? 1 : 6 - strlen(regd_str(TXPWR_LMT_WW)));
883                                         snprintf(tmp_str, TMP_STR_LEN, fmt
884                                                 , strcmp(rfctl->regd_name, regd_str(TXPWR_LMT_WW)) == 0 ? "*" : ""
885                                                 , regd_str(TXPWR_LMT_WW));
886                                         _RTW_PRINT_SEL(sel, "%s", tmp_str);
887
888                                         /* header for limit offset */
889                                         for (path = 0; path < RF_PATH_MAX; path++) {
890                                                 if (path >= rfpath_num)
891                                                         break;
892                                                 _RTW_PRINT_SEL(sel, "|");
893                                                 head = &rfctl->txpwr_lmt_list;
894                                                 cur = get_next(head);
895                                                 while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
896                                                         ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
897                                                         cur = get_next(cur);
898                                                         _RTW_PRINT_SEL(sel, "%3c "
899                                                                 , strcmp(ent->regd_name, rfctl->regd_name) == 0 ? rf_path_char(path) : ' ');
900                                                 }
901                                                 _RTW_PRINT_SEL(sel, "%3c "
902                                                                 , strcmp(rfctl->regd_name, regd_str(TXPWR_LMT_WW)) == 0 ? rf_path_char(path) : ' ');
903                                         }
904                                         _RTW_PRINT_SEL(sel, "\n");
905
906                                         for (n = 0; n < ch_num; n++) {
907                                                 s8 lmt;
908                                                 s8 lmt_offset;
909                                                 u8 base;
910
911                                                 if (band == BAND_ON_2_4G)
912                                                         ch = n + 1;
913                                                 else
914                                                         ch = center_chs_5g(bw, n);
915
916                                                 if (ch == 0) {
917                                                         rtw_warn_on(1);
918                                                         break;
919                                                 }
920
921                                                 /* dump limit in db */
922                                                 RTW_PRINT_SEL(sel, "%3u ", ch);
923                                                 head = &rfctl->txpwr_lmt_list;
924                                                 cur = get_next(head);
925                                                 while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
926                                                         ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
927                                                         cur = get_next(cur);
928                                                         lmt = phy_get_txpwr_lmt_abs(adapter, ent->regd_name, band, bw, tlrs, ntx_idx, ch, 0);
929                                                         if (lmt == hal_spec->txgi_max) {
930                                                                 sprintf(fmt, "%%%zus ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) + 1 : 6);
931                                                                 snprintf(tmp_str, TMP_STR_LEN, fmt, "NA");
932                                                                 _RTW_PRINT_SEL(sel, "%s", tmp_str);
933                                                         } else if (lmt > -hal_spec->txgi_pdbm && lmt < 0) { /* -0.xx */
934                                                                 sprintf(fmt, "%%%zus-0.%%d ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) - 4 : 1);
935                                                                 snprintf(tmp_str, TMP_STR_LEN, fmt, "", (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);
936                                                                 _RTW_PRINT_SEL(sel, "%s", tmp_str);
937                                                         } else if (lmt % hal_spec->txgi_pdbm) { /* d.xx */
938                                                                 sprintf(fmt, "%%%zud.%%d ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) - 2 : 3);
939                                                                 snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm, (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);
940                                                                 _RTW_PRINT_SEL(sel, "%s", tmp_str);
941                                                         } else { /* d */
942                                                                 sprintf(fmt, "%%%zud ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) + 1 : 6);
943                                                                 snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm);
944                                                                 _RTW_PRINT_SEL(sel, "%s", tmp_str);
945                                                         }
946                                                 }
947                                                 lmt = phy_get_txpwr_lmt_abs(adapter, regd_str(TXPWR_LMT_WW), band, bw, tlrs, ntx_idx, ch, 0);
948                                                 if (lmt == hal_spec->txgi_max) {
949                                                         sprintf(fmt, "%%%zus ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) + 1 : 6);
950                                                         snprintf(tmp_str, TMP_STR_LEN, fmt, "NA");
951                                                         _RTW_PRINT_SEL(sel, "%s", tmp_str);
952                                                 } else if (lmt > -hal_spec->txgi_pdbm && lmt < 0) { /* -0.xx */
953                                                         sprintf(fmt, "%%%zus-0.%%d ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) - 4 : 1);
954                                                         snprintf(tmp_str, TMP_STR_LEN, fmt, "", (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);
955                                                         _RTW_PRINT_SEL(sel, "%s", tmp_str);
956                                                 } else if (lmt % hal_spec->txgi_pdbm) { /* d.xx */
957                                                         sprintf(fmt, "%%%zud.%%d ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) - 2 : 3);
958                                                         snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm, (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);
959                                                         _RTW_PRINT_SEL(sel, "%s", tmp_str);
960                                                 } else { /* d */
961                                                         sprintf(fmt, "%%%zud ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) + 1 : 6);
962                                                         snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm);
963                                                         _RTW_PRINT_SEL(sel, "%s", tmp_str);
964                                                 }
965
966                                                 /* dump limit offset of each path */
967                                                 for (path = RF_PATH_A; path < RF_PATH_MAX; path++) {
968                                                         if (path >= rfpath_num)
969                                                                 break;
970
971                                                         base = PHY_GetTxPowerByRateBase(adapter, band, path, rs);
972
973                                                         _RTW_PRINT_SEL(sel, "|");
974                                                         head = &rfctl->txpwr_lmt_list;
975                                                         cur = get_next(head);
976                                                         i = 0;
977                                                         while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
978                                                                 ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
979                                                                 cur = get_next(cur);
980                                                                 lmt_offset = phy_get_txpwr_lmt(adapter, ent->regd_name, band, bw, path, rs, ntx_idx, ch, 0);
981                                                                 if (lmt_offset == hal_spec->txgi_max) {
982                                                                         *(lmt_idx + i * RF_PATH_MAX + path) = hal_spec->txgi_max;
983                                                                         _RTW_PRINT_SEL(sel, "%3s ", "NA");
984                                                                 } else {
985                                                                         *(lmt_idx + i * RF_PATH_MAX + path) = lmt_offset + base;
986                                                                         _RTW_PRINT_SEL(sel, "%3d ", lmt_offset);
987                                                                 }
988                                                                 i++;
989                                                         }
990                                                         lmt_offset = phy_get_txpwr_lmt(adapter, regd_str(TXPWR_LMT_WW), band, bw, path, rs, ntx_idx, ch, 0);
991                                                         if (lmt_offset == hal_spec->txgi_max)
992                                                                 _RTW_PRINT_SEL(sel, "%3s ", "NA");
993                                                         else
994                                                                 _RTW_PRINT_SEL(sel, "%3d ", lmt_offset);
995
996                                                 }
997
998                                                 /* compare limit_idx of each path, print 'x' when mismatch */
999                                                 if (rfpath_num > 1) {
1000                                                         for (i = 0; i < rfctl->txpwr_regd_num; i++) {
1001                                                                 for (path = 0; path < RF_PATH_MAX; path++) {
1002                                                                         if (path >= rfpath_num)
1003                                                                                 break;
1004                                                                         if (*(lmt_idx + i * RF_PATH_MAX + path) != *(lmt_idx + i * RF_PATH_MAX + ((path + 1) % rfpath_num)))
1005                                                                                 break;
1006                                                                 }
1007                                                                 if (path >= rfpath_num)
1008                                                                         _RTW_PRINT_SEL(sel, " ");
1009                                                                 else
1010                                                                         _RTW_PRINT_SEL(sel, "x");
1011                                                         }
1012                                                 }
1013                                                 _RTW_PRINT_SEL(sel, "\n");
1014
1015                                         }
1016                                         RTW_PRINT_SEL(sel, "\n");
1017                                 }
1018                         } /* loop for rate sections */
1019                 } /* loop for bandwidths */
1020         } /* loop for bands */
1021
1022         if (lmt_idx)
1023                 rtw_mfree(lmt_idx, sizeof(s8) * RF_PATH_MAX * rfctl->txpwr_regd_num);
1024
1025 release_lock:
1026         _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1027 }
1028
1029 /* search matcing first, if not found, alloc one */
1030 void rtw_txpwr_lmt_add_with_nlen(struct rf_ctl_t *rfctl, const char *regd_name, u32 nlen
1031         , u8 band, u8 bw, u8 tlrs, u8 ntx_idx, u8 ch_idx, s8 lmt)
1032 {
1033         struct hal_spec_t *hal_spec = GET_HAL_SPEC(dvobj_get_primary_adapter(rfctl_to_dvobj(rfctl)));
1034         struct txpwr_lmt_ent *ent;
1035         _irqL irqL;
1036         _list *cur, *head;
1037         s8 pre_lmt;
1038
1039         if (!regd_name || !nlen) {
1040                 rtw_warn_on(1);
1041                 goto exit;
1042         }
1043
1044         _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1045
1046         /* search for existed entry */
1047         head = &rfctl->txpwr_lmt_list;
1048         cur = get_next(head);
1049         while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
1050                 ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
1051                 cur = get_next(cur);
1052
1053                 if (strlen(ent->regd_name) == nlen
1054                         && _rtw_memcmp(ent->regd_name, regd_name, nlen) == _TRUE)
1055                         goto chk_lmt_val;
1056         }
1057
1058         /* alloc new one */
1059         ent = (struct txpwr_lmt_ent *)rtw_zvmalloc(sizeof(struct txpwr_lmt_ent) + nlen + 1);
1060         if (!ent)
1061                 goto release_lock;
1062
1063         _rtw_init_listhead(&ent->list);
1064         _rtw_memcpy(ent->regd_name, regd_name, nlen);
1065         {
1066                 u8 j, k, l, m;
1067
1068                 for (j = 0; j < MAX_2_4G_BANDWIDTH_NUM; ++j)
1069                         for (k = 0; k < TXPWR_LMT_RS_NUM_2G; ++k)
1070                                 for (m = 0; m < CENTER_CH_2G_NUM; ++m)
1071                                         for (l = 0; l < MAX_TX_COUNT; ++l)
1072                                                 ent->lmt_2g[j][k][m][l] = hal_spec->txgi_max;
1073                 #ifdef CONFIG_IEEE80211_BAND_5GHZ
1074                 for (j = 0; j < MAX_5G_BANDWIDTH_NUM; ++j)
1075                         for (k = 0; k < TXPWR_LMT_RS_NUM_5G; ++k)
1076                                 for (m = 0; m < CENTER_CH_5G_ALL_NUM; ++m)
1077                                         for (l = 0; l < MAX_TX_COUNT; ++l)
1078                                                 ent->lmt_5g[j][k][m][l] = hal_spec->txgi_max;
1079                 #endif
1080         }
1081
1082         rtw_list_insert_tail(&ent->list, &rfctl->txpwr_lmt_list);
1083         rfctl->txpwr_regd_num++;
1084
1085 chk_lmt_val:
1086         if (band == BAND_ON_2_4G)
1087                 pre_lmt = ent->lmt_2g[bw][tlrs][ch_idx][ntx_idx];
1088         #ifdef CONFIG_IEEE80211_BAND_5GHZ
1089         else if (band == BAND_ON_5G)
1090                 pre_lmt = ent->lmt_5g[bw][tlrs - 1][ch_idx][ntx_idx];
1091         #endif
1092         else
1093                 goto release_lock;
1094
1095         if (pre_lmt != hal_spec->txgi_max)
1096                 RTW_PRINT("duplicate txpwr_lmt for [%s][%s][%s][%s][%uT][%d]\n"
1097                         , regd_name, band_str(band), ch_width_str(bw), txpwr_lmt_rs_str(tlrs), ntx_idx + 1
1098                         , band == BAND_ON_2_4G ? ch_idx + 1 : center_ch_5g_all[ch_idx]);
1099
1100         lmt = rtw_min(pre_lmt, lmt);
1101         if (band == BAND_ON_2_4G)
1102                 ent->lmt_2g[bw][tlrs][ch_idx][ntx_idx] = lmt;
1103         #ifdef CONFIG_IEEE80211_BAND_5GHZ
1104         else if (band == BAND_ON_5G)
1105                 ent->lmt_5g[bw][tlrs - 1][ch_idx][ntx_idx] = lmt;
1106         #endif
1107
1108         if (0)
1109                 RTW_PRINT("%s, %4s, %6s, %7s, %uT, ch%3d = %d\n"
1110                         , regd_name, band_str(band), ch_width_str(bw), txpwr_lmt_rs_str(tlrs), ntx_idx + 1
1111                         , band == BAND_ON_2_4G ? ch_idx + 1 : center_ch_5g_all[ch_idx]
1112                         , lmt);
1113
1114 release_lock:
1115         _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1116
1117 exit:
1118         return;
1119 }
1120
1121 inline void rtw_txpwr_lmt_add(struct rf_ctl_t *rfctl, const char *regd_name
1122         , u8 band, u8 bw, u8 tlrs, u8 ntx_idx, u8 ch_idx, s8 lmt)
1123 {
1124         rtw_txpwr_lmt_add_with_nlen(rfctl, regd_name, strlen(regd_name)
1125                 , band, bw, tlrs, ntx_idx, ch_idx, lmt);
1126 }
1127
1128 struct txpwr_lmt_ent *_rtw_txpwr_lmt_get_by_name(struct rf_ctl_t *rfctl, const char *regd_name)
1129 {
1130         struct txpwr_lmt_ent *ent;
1131         _list *cur, *head;
1132         u8 found = 0;
1133
1134         head = &rfctl->txpwr_lmt_list;
1135         cur = get_next(head);
1136
1137         while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
1138                 ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
1139                 cur = get_next(cur);
1140
1141                 if (strcmp(ent->regd_name, regd_name) == 0) {
1142                         found = 1;
1143                         break;
1144                 }
1145         }
1146
1147         if (found)
1148                 return ent;
1149         return NULL;
1150 }
1151
1152 inline struct txpwr_lmt_ent *rtw_txpwr_lmt_get_by_name(struct rf_ctl_t *rfctl, const char *regd_name)
1153 {
1154         struct txpwr_lmt_ent *ent;
1155         _irqL irqL;
1156
1157         _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1158         ent = _rtw_txpwr_lmt_get_by_name(rfctl, regd_name);
1159         _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1160
1161         return ent;
1162 }
1163
1164 void rtw_txpwr_lmt_list_free(struct rf_ctl_t *rfctl)
1165 {
1166         struct txpwr_lmt_ent *ent;
1167         _irqL irqL;
1168         _list *cur, *head;
1169
1170         _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1171
1172         head = &rfctl->txpwr_lmt_list;
1173         cur = get_next(head);
1174
1175         while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
1176                 ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
1177                 cur = get_next(cur);
1178                 if (ent->regd_name == rfctl->regd_name)
1179                         rfctl->regd_name = regd_str(TXPWR_LMT_NONE);
1180                 rtw_list_delete(&ent->list);
1181                 rtw_vmfree((u8 *)ent, sizeof(struct txpwr_lmt_ent) + strlen(ent->regd_name) + 1);
1182         }
1183         rfctl->txpwr_regd_num = 0;
1184
1185         _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1186 }
1187 #endif /* CONFIG_TXPWR_LIMIT */
1188
1189 int rtw_ch_to_bb_gain_sel(int ch)
1190 {
1191         int sel = -1;
1192
1193         if (ch >= 1 && ch <= 14)
1194                 sel = BB_GAIN_2G;
1195 #ifdef CONFIG_IEEE80211_BAND_5GHZ
1196         else if (ch >= 36 && ch < 48)
1197                 sel = BB_GAIN_5GLB1;
1198         else if (ch >= 52 && ch <= 64)
1199                 sel = BB_GAIN_5GLB2;
1200         else if (ch >= 100 && ch <= 120)
1201                 sel = BB_GAIN_5GMB1;
1202         else if (ch >= 124 && ch <= 144)
1203                 sel = BB_GAIN_5GMB2;
1204         else if (ch >= 149 && ch <= 177)
1205                 sel = BB_GAIN_5GHB;
1206 #endif
1207
1208         return sel;
1209 }
1210
1211 s8 rtw_rf_get_kfree_tx_gain_offset(_adapter *padapter, u8 path, u8 ch)
1212 {
1213         s8 kfree_offset = 0;
1214
1215 #ifdef CONFIG_RF_POWER_TRIM
1216         struct kfree_data_t *kfree_data = GET_KFREE_DATA(padapter);
1217         s8 bb_gain_sel = rtw_ch_to_bb_gain_sel(ch);
1218
1219         if (bb_gain_sel < BB_GAIN_2G || bb_gain_sel >= BB_GAIN_NUM) {
1220                 rtw_warn_on(1);
1221                 goto exit;
1222         }
1223
1224         if (kfree_data->flag & KFREE_FLAG_ON) {
1225                 kfree_offset = kfree_data->bb_gain[bb_gain_sel][path];
1226                 if (IS_HARDWARE_TYPE_8723D(padapter))
1227                         RTW_INFO("%s path:%s, ch:%u, bb_gain_sel:%d, kfree_offset:%d\n"
1228                                 , __func__, (path == 0)?"S1":"S0",
1229                                 ch, bb_gain_sel, kfree_offset);
1230                 else
1231                         RTW_INFO("%s path:%u, ch:%u, bb_gain_sel:%d, kfree_offset:%d\n"
1232                                 , __func__, path, ch, bb_gain_sel, kfree_offset);
1233         }
1234 exit:
1235 #endif /* CONFIG_RF_POWER_TRIM */
1236         return kfree_offset;
1237 }
1238
1239 void rtw_rf_set_tx_gain_offset(_adapter *adapter, u8 path, s8 offset)
1240 {
1241 #if !defined(CONFIG_RTL8814A) && !defined(CONFIG_RTL8822B) && !defined(CONFIG_RTL8821C)
1242         u8 write_value;
1243 #endif
1244         u8 target_path = 0;
1245         u32 val32 = 0;
1246
1247         if (IS_HARDWARE_TYPE_8723D(adapter)) {
1248                 target_path = RF_PATH_A; /*in 8723D case path means S0/S1*/
1249                 if (path == PPG_8723D_S1)
1250                         RTW_INFO("kfree gain_offset 0x55:0x%x ",
1251                         rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff));
1252                 else if (path == PPG_8723D_S0)
1253                         RTW_INFO("kfree gain_offset 0x65:0x%x ",
1254                         rtw_hal_read_rfreg(adapter, target_path, 0x65, 0xffffffff));
1255         } else {
1256                 target_path = path;
1257                 RTW_INFO("kfree gain_offset 0x55:0x%x ", rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff));
1258         }
1259
1260         switch (rtw_get_chip_type(adapter)) {
1261 #ifdef CONFIG_RTL8723D
1262         case RTL8723D:
1263                 write_value = RF_TX_GAIN_OFFSET_8723D(offset);
1264                 if (path == PPG_8723D_S1)
1265                         rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value);
1266                 else if (path == PPG_8723D_S0)
1267                         rtw_hal_write_rfreg(adapter, target_path, 0x65, 0x0f8000, write_value);
1268                 break;
1269 #endif /* CONFIG_RTL8723D */
1270 #ifdef CONFIG_RTL8703B
1271         case RTL8703B:
1272                 write_value = RF_TX_GAIN_OFFSET_8703B(offset);
1273                 rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0fc000, write_value);
1274                 break;
1275 #endif /* CONFIG_RTL8703B */
1276 #ifdef CONFIG_RTL8188F
1277         case RTL8188F:
1278                 write_value = RF_TX_GAIN_OFFSET_8188F(offset);
1279                 rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0fc000, write_value);
1280                 break;
1281 #endif /* CONFIG_RTL8188F */
1282 #ifdef CONFIG_RTL8188GTV
1283         case RTL8188GTV:
1284                 write_value = RF_TX_GAIN_OFFSET_8188GTV(offset);
1285                 rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0fc000, write_value);
1286                 break;
1287 #endif /* CONFIG_RTL8188GTV */
1288 #ifdef CONFIG_RTL8192E
1289         case RTL8192E:
1290                 write_value = RF_TX_GAIN_OFFSET_8192E(offset);
1291                 rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value);
1292                 break;
1293 #endif /* CONFIG_RTL8188F */
1294
1295 #ifdef CONFIG_RTL8821A
1296         case RTL8821:
1297                 write_value = RF_TX_GAIN_OFFSET_8821A(offset);
1298                 rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value);
1299                 break;
1300 #endif /* CONFIG_RTL8821A */
1301 #if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) || defined(CONFIG_RTL8192F)
1302         case RTL8814A:
1303         case RTL8822B:
1304         case RTL8821C:
1305         case RTL8192F:
1306                 RTW_INFO("\nkfree by PhyDM on the sw CH. path %d\n", path);
1307                 break;
1308 #endif /* CONFIG_RTL8814A || CONFIG_RTL8822B || CONFIG_RTL8821C */
1309
1310         default:
1311                 rtw_warn_on(1);
1312                 break;
1313         }
1314
1315         if (IS_HARDWARE_TYPE_8723D(adapter)) {
1316                 if (path == PPG_8723D_S1)
1317                         val32 = rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff);
1318                 else if (path == PPG_8723D_S0)
1319                         val32 = rtw_hal_read_rfreg(adapter, target_path, 0x65, 0xffffffff);
1320         } else {
1321                 val32 = rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff);
1322         }
1323         RTW_INFO(" after :0x%x\n", val32);
1324 }
1325
1326 void rtw_rf_apply_tx_gain_offset(_adapter *adapter, u8 ch)
1327 {
1328         HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
1329         s8 kfree_offset = 0;
1330         s8 tx_pwr_track_offset = 0; /* TODO: 8814A should consider tx pwr track when setting tx gain offset */
1331         s8 total_offset;
1332         int i, total = 0;
1333
1334         if (IS_HARDWARE_TYPE_8723D(adapter))
1335                 total = 2; /* S1 and S0 */
1336         else
1337                 total = hal_data->NumTotalRFPath;
1338
1339         for (i = 0; i < total; i++) {
1340                 kfree_offset = rtw_rf_get_kfree_tx_gain_offset(adapter, i, ch);
1341                 total_offset = kfree_offset + tx_pwr_track_offset;
1342                 rtw_rf_set_tx_gain_offset(adapter, i, total_offset);
1343         }
1344 }
1345
1346 inline u8 rtw_is_dfs_range(u32 hi, u32 lo)
1347 {
1348         return rtw_is_range_overlap(hi, lo, 5720 + 10, 5260 - 10);
1349 }
1350
1351 u8 rtw_is_dfs_ch(u8 ch)
1352 {
1353         u32 hi, lo;
1354
1355         if (!rtw_chbw_to_freq_range(ch, CHANNEL_WIDTH_20, HAL_PRIME_CHNL_OFFSET_DONT_CARE, &hi, &lo))
1356                 return 0;
1357
1358         return rtw_is_dfs_range(hi, lo);
1359 }
1360
1361 u8 rtw_is_dfs_chbw(u8 ch, u8 bw, u8 offset)
1362 {
1363         u32 hi, lo;
1364
1365         if (!rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo))
1366                 return 0;
1367
1368         return rtw_is_dfs_range(hi, lo);
1369 }
1370
1371 bool rtw_is_long_cac_range(u32 hi, u32 lo, u8 dfs_region)
1372 {
1373         return (dfs_region == PHYDM_DFS_DOMAIN_ETSI && rtw_is_range_overlap(hi, lo, 5650, 5600)) ? _TRUE : _FALSE;
1374 }
1375
1376 bool rtw_is_long_cac_ch(u8 ch, u8 bw, u8 offset, u8 dfs_region)
1377 {
1378         u32 hi, lo;
1379
1380         if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE)
1381                 return _FALSE;
1382
1383         return rtw_is_long_cac_range(hi, lo, dfs_region) ? _TRUE : _FALSE;
1384 }