Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
nu11secur1ty
GitHub Repository: nu11secur1ty/Kali-Linux
Path: blob/master/ALFA-W1F1/RTL8814AU/core/rtw_rf.c
1307 views
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_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_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 _rf_type_to_rfpath_str[] = {
569
"RF_1T1R",
570
"RF_1T2R",
571
"RF_2T2R",
572
"RF_2T3R",
573
"RF_2T4R",
574
"RF_3T3R",
575
"RF_3T4R",
576
"RF_4T4R",
577
"RF_TYPE_MAX"
578
};
579
580
void rf_type_to_default_trx_bmp(enum rf_type rf, enum bb_path *tx, enum bb_path *rx)
581
{
582
switch (rf) {
583
case RF_1T1R:
584
*tx = BB_PATH_A;
585
*rx = BB_PATH_A;
586
break;
587
case RF_1T2R:
588
*tx = BB_PATH_A;
589
*rx = BB_PATH_AB;
590
break;
591
case RF_2T2R:
592
*tx = BB_PATH_AB;
593
*rx = BB_PATH_AB;
594
break;
595
case RF_2T3R:
596
*tx = BB_PATH_AB;
597
*rx = BB_PATH_ABC;
598
break;
599
case RF_2T4R:
600
*tx = BB_PATH_AB;
601
*rx = BB_PATH_ABCD;
602
break;
603
case RF_3T3R:
604
*tx = BB_PATH_ABC;
605
*rx = BB_PATH_ABC;
606
break;
607
case RF_3T4R:
608
*tx = BB_PATH_ABC;
609
*rx = BB_PATH_ABCD;
610
break;
611
case RF_4T4R:
612
*tx = BB_PATH_ABCD;
613
*rx = BB_PATH_ABCD;
614
break;
615
default:
616
*tx = BB_PATH_A;
617
*rx = BB_PATH_A;
618
break;
619
}
620
}
621
622
static const u8 _trx_num_to_rf_type[RF_PATH_MAX][RF_PATH_MAX] = {
623
{RF_1T1R, RF_1T2R, RF_TYPE_MAX, RF_TYPE_MAX},
624
{RF_TYPE_MAX, RF_2T2R, RF_2T3R, RF_2T4R},
625
{RF_TYPE_MAX, RF_TYPE_MAX, RF_3T3R, RF_3T4R},
626
{RF_TYPE_MAX, RF_TYPE_MAX, RF_TYPE_MAX, RF_4T4R},
627
};
628
629
enum rf_type trx_num_to_rf_type(u8 tx_num, u8 rx_num)
630
{
631
if (tx_num > 0 && tx_num <= RF_PATH_MAX && rx_num > 0 && rx_num <= RF_PATH_MAX)
632
return _trx_num_to_rf_type[tx_num - 1][rx_num - 1];
633
return RF_TYPE_MAX;
634
}
635
636
enum rf_type trx_bmp_to_rf_type(u8 tx_bmp, u8 rx_bmp)
637
{
638
u8 tx_num = 0;
639
u8 rx_num = 0;
640
int i;
641
642
for (i = 0; i < RF_PATH_MAX; i++) {
643
if (tx_bmp >> i & BIT0)
644
tx_num++;
645
if (rx_bmp >> i & BIT0)
646
rx_num++;
647
}
648
649
return trx_num_to_rf_type(tx_num, rx_num);
650
}
651
652
bool rf_type_is_a_in_b(enum rf_type a, enum rf_type b)
653
{
654
return rf_type_to_rf_tx_cnt(a) <= rf_type_to_rf_tx_cnt(b)
655
&& rf_type_to_rf_rx_cnt(a) <= rf_type_to_rf_rx_cnt(b);
656
}
657
658
static void rtw_path_bmp_limit_from_higher(u8 *bmp, u8 *bmp_bit_cnt, u8 bit_cnt_lmt)
659
{
660
int i;
661
662
for (i = RF_PATH_MAX - 1; *bmp_bit_cnt > bit_cnt_lmt && i >= 0; i--) {
663
if (*bmp & BIT(i)) {
664
*bmp &= ~BIT(i);
665
(*bmp_bit_cnt)--;
666
}
667
}
668
}
669
670
u8 rtw_restrict_trx_path_bmp_by_rftype(u8 trx_path_bmp, enum rf_type type, u8 *tx_num, u8 *rx_num)
671
{
672
u8 bmp_tx = (trx_path_bmp & 0xF0) >> 4;
673
u8 bmp_rx = trx_path_bmp & 0x0F;
674
u8 bmp_tx_num = 0, bmp_rx_num = 0;
675
u8 tx_num_lmt, rx_num_lmt;
676
enum rf_type ret_type = RF_TYPE_MAX;
677
int i, j;
678
679
for (i = 0; i < RF_PATH_MAX; i++) {
680
if (bmp_tx & BIT(i))
681
bmp_tx_num++;
682
if (bmp_rx & BIT(i))
683
bmp_rx_num++;
684
}
685
686
/* limit higher bit first according to input type */
687
tx_num_lmt = rf_type_to_rf_tx_cnt(type);
688
rx_num_lmt = rf_type_to_rf_rx_cnt(type);
689
rtw_path_bmp_limit_from_higher(&bmp_tx, &bmp_tx_num, tx_num_lmt);
690
rtw_path_bmp_limit_from_higher(&bmp_rx, &bmp_rx_num, rx_num_lmt);
691
692
/* search for valid rf_type (larger RX prefer) */
693
for (j = bmp_rx_num; j > 0; j--) {
694
for (i = bmp_tx_num; i > 0; i--) {
695
ret_type = trx_num_to_rf_type(i, j);
696
if (RF_TYPE_VALID(ret_type)) {
697
rtw_path_bmp_limit_from_higher(&bmp_tx, &bmp_tx_num, i);
698
rtw_path_bmp_limit_from_higher(&bmp_rx, &bmp_rx_num, j);
699
if (tx_num)
700
*tx_num = bmp_tx_num;
701
if (rx_num)
702
*rx_num = bmp_rx_num;
703
goto exit;
704
}
705
}
706
}
707
708
exit:
709
return RF_TYPE_VALID(ret_type) ? ((bmp_tx << 4) | bmp_rx) : 0x00;
710
}
711
712
/* config to non N-TX value, path with lower index prefer */
713
void tx_path_nss_set_default(enum bb_path txpath_nss[], u8 txpath_num_nss[], u8 txpath)
714
{
715
int i, j;
716
u8 cnt;
717
718
for (i = 4; i > 0; i--) {
719
cnt = 0;
720
txpath_nss[i - 1] = 0;
721
for (j = 0; j < RF_PATH_MAX; j++) {
722
if (txpath & BIT(j)) {
723
txpath_nss[i - 1] |= BIT(j);
724
if (++cnt == i)
725
break;
726
}
727
}
728
txpath_num_nss[i - 1] = i;
729
}
730
}
731
732
/* config to full N-TX value */
733
void tx_path_nss_set_full_tx(enum bb_path txpath_nss[], u8 txpath_num_nss[], u8 txpath)
734
{
735
u8 tx_num = 0;
736
int i;
737
738
for (i = 0; i < RF_PATH_MAX; i++)
739
if (txpath & BIT(i))
740
tx_num++;
741
742
for (i = 4; i > 0; i--) {
743
txpath_nss[i - 1] = txpath;
744
txpath_num_nss[i - 1] = tx_num;
745
}
746
}
747
748
const char *const _regd_str[] = {
749
"NONE",
750
"FCC",
751
"MKK",
752
"ETSI",
753
"IC",
754
"KCC",
755
"ACMA",
756
"CHILE",
757
"MEXICO",
758
"WW",
759
};
760
761
#if CONFIG_TXPWR_LIMIT
762
void _dump_regd_exc_list(void *sel, struct rf_ctl_t *rfctl)
763
{
764
struct regd_exc_ent *ent;
765
_list *cur, *head;
766
767
RTW_PRINT_SEL(sel, "regd_exc_num:%u\n", rfctl->regd_exc_num);
768
769
if (!rfctl->regd_exc_num)
770
goto exit;
771
772
RTW_PRINT_SEL(sel, "%-7s %-6s %-9s\n", "country", "domain", "regd_name");
773
774
head = &rfctl->reg_exc_list;
775
cur = get_next(head);
776
777
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
778
u8 has_country;
779
780
ent = LIST_CONTAINOR(cur, struct regd_exc_ent, list);
781
cur = get_next(cur);
782
has_country = (ent->country[0] == '\0' && ent->country[1] == '\0') ? 0 : 1;
783
784
RTW_PRINT_SEL(sel, " %c%c 0x%02x %s\n"
785
, has_country ? ent->country[0] : '0'
786
, has_country ? ent->country[1] : '0'
787
, ent->domain
788
, ent->regd_name
789
);
790
}
791
792
exit:
793
return;
794
}
795
796
inline void dump_regd_exc_list(void *sel, struct rf_ctl_t *rfctl)
797
{
798
_irqL irqL;
799
800
_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
801
_dump_regd_exc_list(sel, rfctl);
802
_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
803
}
804
805
void rtw_regd_exc_add_with_nlen(struct rf_ctl_t *rfctl, const char *country, u8 domain, const char *regd_name, u32 nlen)
806
{
807
struct regd_exc_ent *ent;
808
_irqL irqL;
809
810
if (!regd_name || !nlen) {
811
rtw_warn_on(1);
812
goto exit;
813
}
814
815
ent = (struct regd_exc_ent *)rtw_zmalloc(sizeof(struct regd_exc_ent) + nlen + 1);
816
if (!ent)
817
goto exit;
818
819
_rtw_init_listhead(&ent->list);
820
if (country)
821
_rtw_memcpy(ent->country, country, 2);
822
ent->domain = domain;
823
_rtw_memcpy(ent->regd_name, regd_name, nlen);
824
825
_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
826
827
rtw_list_insert_tail(&ent->list, &rfctl->reg_exc_list);
828
rfctl->regd_exc_num++;
829
830
_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
831
832
exit:
833
return;
834
}
835
836
inline void rtw_regd_exc_add(struct rf_ctl_t *rfctl, const char *country, u8 domain, const char *regd_name)
837
{
838
rtw_regd_exc_add_with_nlen(rfctl, country, domain, regd_name, strlen(regd_name));
839
}
840
841
struct regd_exc_ent *_rtw_regd_exc_search(struct rf_ctl_t *rfctl, const char *country, u8 domain)
842
{
843
struct regd_exc_ent *ent;
844
_list *cur, *head;
845
u8 match = 0;
846
847
head = &rfctl->reg_exc_list;
848
cur = get_next(head);
849
850
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
851
u8 has_country;
852
853
ent = LIST_CONTAINOR(cur, struct regd_exc_ent, list);
854
cur = get_next(cur);
855
has_country = (ent->country[0] == '\0' && ent->country[1] == '\0') ? 0 : 1;
856
857
/* entry has country condition to match */
858
if (has_country) {
859
if (!country)
860
continue;
861
if (ent->country[0] != country[0]
862
|| ent->country[1] != country[1])
863
continue;
864
}
865
866
/* entry has domain condition to match */
867
if (ent->domain != 0xFF) {
868
if (domain == 0xFF)
869
continue;
870
if (ent->domain != domain)
871
continue;
872
}
873
874
match = 1;
875
break;
876
}
877
878
if (match)
879
return ent;
880
else
881
return NULL;
882
}
883
884
inline struct regd_exc_ent *rtw_regd_exc_search(struct rf_ctl_t *rfctl, const char *country, u8 domain)
885
{
886
struct regd_exc_ent *ent;
887
_irqL irqL;
888
889
_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
890
ent = _rtw_regd_exc_search(rfctl, country, domain);
891
_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
892
893
return ent;
894
}
895
896
void rtw_regd_exc_list_free(struct rf_ctl_t *rfctl)
897
{
898
struct regd_exc_ent *ent;
899
_irqL irqL;
900
_list *cur, *head;
901
902
_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
903
904
head = &rfctl->reg_exc_list;
905
cur = get_next(head);
906
907
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
908
ent = LIST_CONTAINOR(cur, struct regd_exc_ent, list);
909
cur = get_next(cur);
910
rtw_list_delete(&ent->list);
911
rtw_mfree((u8 *)ent, sizeof(struct regd_exc_ent) + strlen(ent->regd_name) + 1);
912
}
913
rfctl->regd_exc_num = 0;
914
915
_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
916
}
917
918
void dump_txpwr_lmt(void *sel, _adapter *adapter)
919
{
920
#define TMP_STR_LEN 16
921
struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
922
HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
923
struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter);
924
_irqL irqL;
925
char fmt[16];
926
char tmp_str[TMP_STR_LEN];
927
s8 *lmt_idx = NULL;
928
int bw, band, ch_num, tlrs, ntx_idx, rs, i, path;
929
u8 ch, n, rfpath_num;
930
931
_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
932
933
_dump_regd_exc_list(sel, rfctl);
934
RTW_PRINT_SEL(sel, "\n");
935
936
if (!rfctl->txpwr_regd_num)
937
goto release_lock;
938
939
lmt_idx = rtw_malloc(sizeof(s8) * RF_PATH_MAX * rfctl->txpwr_regd_num);
940
if (!lmt_idx) {
941
RTW_ERR("%s alloc fail\n", __func__);
942
goto release_lock;
943
}
944
945
RTW_PRINT_SEL(sel, "txpwr_lmt_2g_cck_ofdm_state:0x%02x\n", rfctl->txpwr_lmt_2g_cck_ofdm_state);
946
#ifdef CONFIG_IEEE80211_BAND_5GHZ
947
if (IS_HARDWARE_TYPE_JAGUAR_ALL(adapter)) {
948
RTW_PRINT_SEL(sel, "txpwr_lmt_5g_cck_ofdm_state:0x%02x\n", rfctl->txpwr_lmt_5g_cck_ofdm_state);
949
RTW_PRINT_SEL(sel, "txpwr_lmt_5g_20_40_ref:0x%02x\n", rfctl->txpwr_lmt_5g_20_40_ref);
950
}
951
#endif
952
RTW_PRINT_SEL(sel, "\n");
953
954
for (band = BAND_ON_2_4G; band <= BAND_ON_5G; band++) {
955
if (!hal_is_band_support(adapter, band))
956
continue;
957
958
rfpath_num = (band == BAND_ON_2_4G ? hal_spec->rfpath_num_2g : hal_spec->rfpath_num_5g);
959
960
for (bw = 0; bw < MAX_5G_BANDWIDTH_NUM; bw++) {
961
962
if (bw >= CHANNEL_WIDTH_160)
963
break;
964
if (band == BAND_ON_2_4G && bw >= CHANNEL_WIDTH_80)
965
break;
966
967
if (band == BAND_ON_2_4G)
968
ch_num = CENTER_CH_2G_NUM;
969
else
970
ch_num = center_chs_5g_num(bw);
971
972
if (ch_num == 0) {
973
rtw_warn_on(1);
974
break;
975
}
976
977
for (tlrs = TXPWR_LMT_RS_CCK; tlrs < TXPWR_LMT_RS_NUM; tlrs++) {
978
979
if (band == BAND_ON_2_4G && tlrs == TXPWR_LMT_RS_VHT)
980
continue;
981
if (band == BAND_ON_5G && tlrs == TXPWR_LMT_RS_CCK)
982
continue;
983
if (bw > CHANNEL_WIDTH_20 && (tlrs == TXPWR_LMT_RS_CCK || tlrs == TXPWR_LMT_RS_OFDM))
984
continue;
985
if (bw > CHANNEL_WIDTH_40 && tlrs == TXPWR_LMT_RS_HT)
986
continue;
987
if (tlrs == TXPWR_LMT_RS_VHT && !IS_HARDWARE_TYPE_JAGUAR_ALL(adapter))
988
continue;
989
990
for (ntx_idx = RF_1TX; ntx_idx < MAX_TX_COUNT; ntx_idx++) {
991
struct txpwr_lmt_ent *ent;
992
_list *cur, *head;
993
994
if (ntx_idx + 1 > hal_data->max_tx_cnt)
995
continue;
996
997
/* bypass CCK multi-TX is not defined */
998
if (tlrs == TXPWR_LMT_RS_CCK && ntx_idx > RF_1TX) {
999
if (band == BAND_ON_2_4G
1000
&& !(rfctl->txpwr_lmt_2g_cck_ofdm_state & (TXPWR_LMT_HAS_CCK_1T << ntx_idx)))
1001
continue;
1002
}
1003
1004
/* bypass OFDM multi-TX is not defined */
1005
if (tlrs == TXPWR_LMT_RS_OFDM && ntx_idx > RF_1TX) {
1006
if (band == BAND_ON_2_4G
1007
&& !(rfctl->txpwr_lmt_2g_cck_ofdm_state & (TXPWR_LMT_HAS_OFDM_1T << ntx_idx)))
1008
continue;
1009
#ifdef CONFIG_IEEE80211_BAND_5GHZ
1010
if (band == BAND_ON_5G
1011
&& !(rfctl->txpwr_lmt_5g_cck_ofdm_state & (TXPWR_LMT_HAS_OFDM_1T << ntx_idx)))
1012
continue;
1013
#endif
1014
}
1015
1016
/* bypass 5G 20M, 40M pure reference */
1017
#ifdef CONFIG_IEEE80211_BAND_5GHZ
1018
if (band == BAND_ON_5G && (bw == CHANNEL_WIDTH_20 || bw == CHANNEL_WIDTH_40)) {
1019
if (rfctl->txpwr_lmt_5g_20_40_ref == TXPWR_LMT_REF_HT_FROM_VHT) {
1020
if (tlrs == TXPWR_LMT_RS_HT)
1021
continue;
1022
} else if (rfctl->txpwr_lmt_5g_20_40_ref == TXPWR_LMT_REF_VHT_FROM_HT) {
1023
if (tlrs == TXPWR_LMT_RS_VHT && bw <= CHANNEL_WIDTH_40)
1024
continue;
1025
}
1026
}
1027
#endif
1028
1029
/* choose n-SS mapping rate section to get lmt diff value */
1030
if (tlrs == TXPWR_LMT_RS_CCK)
1031
rs = CCK;
1032
else if (tlrs == TXPWR_LMT_RS_OFDM)
1033
rs = OFDM;
1034
else if (tlrs == TXPWR_LMT_RS_HT)
1035
rs = HT_1SS + ntx_idx;
1036
else if (tlrs == TXPWR_LMT_RS_VHT)
1037
rs = VHT_1SS + ntx_idx;
1038
else {
1039
RTW_ERR("%s invalid tlrs %u\n", __func__, tlrs);
1040
continue;
1041
}
1042
1043
RTW_PRINT_SEL(sel, "[%s][%s][%s][%uT]\n"
1044
, band_str(band)
1045
, ch_width_str(bw)
1046
, txpwr_lmt_rs_str(tlrs)
1047
, ntx_idx + 1
1048
);
1049
1050
/* header for limit in db */
1051
RTW_PRINT_SEL(sel, "%3s ", "ch");
1052
1053
head = &rfctl->txpwr_lmt_list;
1054
cur = get_next(head);
1055
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
1056
ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
1057
cur = get_next(cur);
1058
1059
sprintf(fmt, "%%%zus%%s ", strlen(ent->regd_name) >= 6 ? 1 : 6 - strlen(ent->regd_name));
1060
snprintf(tmp_str, TMP_STR_LEN, fmt
1061
, strcmp(ent->regd_name, rfctl->regd_name) == 0 ? "*" : ""
1062
, ent->regd_name);
1063
_RTW_PRINT_SEL(sel, "%s", tmp_str);
1064
}
1065
sprintf(fmt, "%%%zus%%s ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? 1 : 6 - strlen(regd_str(TXPWR_LMT_WW)));
1066
snprintf(tmp_str, TMP_STR_LEN, fmt
1067
, strcmp(rfctl->regd_name, regd_str(TXPWR_LMT_WW)) == 0 ? "*" : ""
1068
, regd_str(TXPWR_LMT_WW));
1069
_RTW_PRINT_SEL(sel, "%s", tmp_str);
1070
1071
/* header for limit offset */
1072
for (path = 0; path < RF_PATH_MAX; path++) {
1073
if (path >= rfpath_num)
1074
break;
1075
_RTW_PRINT_SEL(sel, "|");
1076
head = &rfctl->txpwr_lmt_list;
1077
cur = get_next(head);
1078
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
1079
ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
1080
cur = get_next(cur);
1081
_RTW_PRINT_SEL(sel, "%3c "
1082
, strcmp(ent->regd_name, rfctl->regd_name) == 0 ? rf_path_char(path) : ' ');
1083
}
1084
_RTW_PRINT_SEL(sel, "%3c "
1085
, strcmp(rfctl->regd_name, regd_str(TXPWR_LMT_WW)) == 0 ? rf_path_char(path) : ' ');
1086
}
1087
_RTW_PRINT_SEL(sel, "\n");
1088
1089
for (n = 0; n < ch_num; n++) {
1090
s8 lmt;
1091
s8 lmt_offset;
1092
u8 base;
1093
1094
if (band == BAND_ON_2_4G)
1095
ch = n + 1;
1096
else
1097
ch = center_chs_5g(bw, n);
1098
1099
if (ch == 0) {
1100
rtw_warn_on(1);
1101
break;
1102
}
1103
1104
/* dump limit in db */
1105
RTW_PRINT_SEL(sel, "%3u ", ch);
1106
head = &rfctl->txpwr_lmt_list;
1107
cur = get_next(head);
1108
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
1109
ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
1110
cur = get_next(cur);
1111
lmt = phy_get_txpwr_lmt_abs(adapter, ent->regd_name, band, bw, tlrs, ntx_idx, ch, 0);
1112
if (lmt == hal_spec->txgi_max) {
1113
sprintf(fmt, "%%%zus ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) + 1 : 6);
1114
snprintf(tmp_str, TMP_STR_LEN, fmt, "NA");
1115
_RTW_PRINT_SEL(sel, "%s", tmp_str);
1116
} else if (lmt > -hal_spec->txgi_pdbm && lmt < 0) { /* -0.xx */
1117
sprintf(fmt, "%%%zus-0.%%d ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) - 4 : 1);
1118
snprintf(tmp_str, TMP_STR_LEN, fmt, "", (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);
1119
_RTW_PRINT_SEL(sel, "%s", tmp_str);
1120
} else if (lmt % hal_spec->txgi_pdbm) { /* d.xx */
1121
sprintf(fmt, "%%%zud.%%d ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) - 2 : 3);
1122
snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm, (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);
1123
_RTW_PRINT_SEL(sel, "%s", tmp_str);
1124
} else { /* d */
1125
sprintf(fmt, "%%%zud ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) + 1 : 6);
1126
snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm);
1127
_RTW_PRINT_SEL(sel, "%s", tmp_str);
1128
}
1129
}
1130
lmt = phy_get_txpwr_lmt_abs(adapter, regd_str(TXPWR_LMT_WW), band, bw, tlrs, ntx_idx, ch, 0);
1131
if (lmt == hal_spec->txgi_max) {
1132
sprintf(fmt, "%%%zus ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) + 1 : 6);
1133
snprintf(tmp_str, TMP_STR_LEN, fmt, "NA");
1134
_RTW_PRINT_SEL(sel, "%s", tmp_str);
1135
} else if (lmt > -hal_spec->txgi_pdbm && lmt < 0) { /* -0.xx */
1136
sprintf(fmt, "%%%zus-0.%%d ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) - 4 : 1);
1137
snprintf(tmp_str, TMP_STR_LEN, fmt, "", (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);
1138
_RTW_PRINT_SEL(sel, "%s", tmp_str);
1139
} else if (lmt % hal_spec->txgi_pdbm) { /* d.xx */
1140
sprintf(fmt, "%%%zud.%%d ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) - 2 : 3);
1141
snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm, (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);
1142
_RTW_PRINT_SEL(sel, "%s", tmp_str);
1143
} else { /* d */
1144
sprintf(fmt, "%%%zud ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) + 1 : 6);
1145
snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm);
1146
_RTW_PRINT_SEL(sel, "%s", tmp_str);
1147
}
1148
1149
/* dump limit offset of each path */
1150
for (path = RF_PATH_A; path < RF_PATH_MAX; path++) {
1151
if (path >= rfpath_num)
1152
break;
1153
1154
#ifdef CONFIG_USE_TSSI
1155
base = PHY_GetTxPowerByRateOriginal(adapter, band, path, MGN_MCS7);
1156
#else
1157
base = PHY_GetTxPowerByRateBase(adapter, band, path, rs);
1158
#endif
1159
1160
_RTW_PRINT_SEL(sel, "|");
1161
head = &rfctl->txpwr_lmt_list;
1162
cur = get_next(head);
1163
i = 0;
1164
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
1165
ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
1166
cur = get_next(cur);
1167
lmt_offset = phy_get_txpwr_lmt(adapter, ent->regd_name, band, bw, path, rs, ntx_idx, ch, 0);
1168
if (lmt_offset == hal_spec->txgi_max) {
1169
*(lmt_idx + i * RF_PATH_MAX + path) = hal_spec->txgi_max;
1170
_RTW_PRINT_SEL(sel, "%3s ", "NA");
1171
} else {
1172
*(lmt_idx + i * RF_PATH_MAX + path) = lmt_offset + base;
1173
_RTW_PRINT_SEL(sel, "%3d ", lmt_offset);
1174
}
1175
i++;
1176
}
1177
lmt_offset = phy_get_txpwr_lmt(adapter, regd_str(TXPWR_LMT_WW), band, bw, path, rs, ntx_idx, ch, 0);
1178
if (lmt_offset == hal_spec->txgi_max)
1179
_RTW_PRINT_SEL(sel, "%3s ", "NA");
1180
else
1181
_RTW_PRINT_SEL(sel, "%3d ", lmt_offset);
1182
1183
}
1184
1185
/* compare limit_idx of each path, print 'x' when mismatch */
1186
if (rfpath_num > 1) {
1187
for (i = 0; i < rfctl->txpwr_regd_num; i++) {
1188
for (path = 0; path < RF_PATH_MAX; path++) {
1189
if (path >= rfpath_num)
1190
break;
1191
if (*(lmt_idx + i * RF_PATH_MAX + path) != *(lmt_idx + i * RF_PATH_MAX + ((path + 1) % rfpath_num)))
1192
break;
1193
}
1194
if (path >= rfpath_num)
1195
_RTW_PRINT_SEL(sel, " ");
1196
else
1197
_RTW_PRINT_SEL(sel, "x");
1198
}
1199
}
1200
_RTW_PRINT_SEL(sel, "\n");
1201
1202
}
1203
RTW_PRINT_SEL(sel, "\n");
1204
}
1205
} /* loop for rate sections */
1206
} /* loop for bandwidths */
1207
} /* loop for bands */
1208
1209
if (lmt_idx)
1210
rtw_mfree(lmt_idx, sizeof(s8) * RF_PATH_MAX * rfctl->txpwr_regd_num);
1211
1212
release_lock:
1213
_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1214
}
1215
1216
/* search matcing first, if not found, alloc one */
1217
void rtw_txpwr_lmt_add_with_nlen(struct rf_ctl_t *rfctl, const char *regd_name, u32 nlen
1218
, u8 band, u8 bw, u8 tlrs, u8 ntx_idx, u8 ch_idx, s8 lmt)
1219
{
1220
struct hal_spec_t *hal_spec = GET_HAL_SPEC(dvobj_get_primary_adapter(rfctl_to_dvobj(rfctl)));
1221
struct txpwr_lmt_ent *ent;
1222
_irqL irqL;
1223
_list *cur, *head;
1224
s8 pre_lmt;
1225
1226
if (!regd_name || !nlen) {
1227
rtw_warn_on(1);
1228
goto exit;
1229
}
1230
1231
_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1232
1233
/* search for existed entry */
1234
head = &rfctl->txpwr_lmt_list;
1235
cur = get_next(head);
1236
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
1237
ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
1238
cur = get_next(cur);
1239
1240
if (strlen(ent->regd_name) == nlen
1241
&& _rtw_memcmp(ent->regd_name, regd_name, nlen) == _TRUE)
1242
goto chk_lmt_val;
1243
}
1244
1245
/* alloc new one */
1246
ent = (struct txpwr_lmt_ent *)rtw_zvmalloc(sizeof(struct txpwr_lmt_ent) + nlen + 1);
1247
if (!ent)
1248
goto release_lock;
1249
1250
_rtw_init_listhead(&ent->list);
1251
_rtw_memcpy(ent->regd_name, regd_name, nlen);
1252
{
1253
u8 j, k, l, m;
1254
1255
for (j = 0; j < MAX_2_4G_BANDWIDTH_NUM; ++j)
1256
for (k = 0; k < TXPWR_LMT_RS_NUM_2G; ++k)
1257
for (m = 0; m < CENTER_CH_2G_NUM; ++m)
1258
for (l = 0; l < MAX_TX_COUNT; ++l)
1259
ent->lmt_2g[j][k][m][l] = hal_spec->txgi_max;
1260
#ifdef CONFIG_IEEE80211_BAND_5GHZ
1261
for (j = 0; j < MAX_5G_BANDWIDTH_NUM; ++j)
1262
for (k = 0; k < TXPWR_LMT_RS_NUM_5G; ++k)
1263
for (m = 0; m < CENTER_CH_5G_ALL_NUM; ++m)
1264
for (l = 0; l < MAX_TX_COUNT; ++l)
1265
ent->lmt_5g[j][k][m][l] = hal_spec->txgi_max;
1266
#endif
1267
}
1268
1269
rtw_list_insert_tail(&ent->list, &rfctl->txpwr_lmt_list);
1270
rfctl->txpwr_regd_num++;
1271
1272
chk_lmt_val:
1273
if (band == BAND_ON_2_4G)
1274
pre_lmt = ent->lmt_2g[bw][tlrs][ch_idx][ntx_idx];
1275
#ifdef CONFIG_IEEE80211_BAND_5GHZ
1276
else if (band == BAND_ON_5G)
1277
pre_lmt = ent->lmt_5g[bw][tlrs - 1][ch_idx][ntx_idx];
1278
#endif
1279
else
1280
goto release_lock;
1281
1282
if (pre_lmt != hal_spec->txgi_max)
1283
RTW_PRINT("duplicate txpwr_lmt for [%s][%s][%s][%s][%uT][%d]\n"
1284
, regd_name, band_str(band), ch_width_str(bw), txpwr_lmt_rs_str(tlrs), ntx_idx + 1
1285
, band == BAND_ON_2_4G ? ch_idx + 1 : center_ch_5g_all[ch_idx]);
1286
1287
lmt = rtw_min(pre_lmt, lmt);
1288
if (band == BAND_ON_2_4G)
1289
ent->lmt_2g[bw][tlrs][ch_idx][ntx_idx] = lmt;
1290
#ifdef CONFIG_IEEE80211_BAND_5GHZ
1291
else if (band == BAND_ON_5G)
1292
ent->lmt_5g[bw][tlrs - 1][ch_idx][ntx_idx] = lmt;
1293
#endif
1294
1295
if (0)
1296
RTW_PRINT("%s, %4s, %6s, %7s, %uT, ch%3d = %d\n"
1297
, regd_name, band_str(band), ch_width_str(bw), txpwr_lmt_rs_str(tlrs), ntx_idx + 1
1298
, band == BAND_ON_2_4G ? ch_idx + 1 : center_ch_5g_all[ch_idx]
1299
, lmt);
1300
1301
release_lock:
1302
_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1303
1304
exit:
1305
return;
1306
}
1307
1308
inline void rtw_txpwr_lmt_add(struct rf_ctl_t *rfctl, const char *regd_name
1309
, u8 band, u8 bw, u8 tlrs, u8 ntx_idx, u8 ch_idx, s8 lmt)
1310
{
1311
rtw_txpwr_lmt_add_with_nlen(rfctl, regd_name, strlen(regd_name)
1312
, band, bw, tlrs, ntx_idx, ch_idx, lmt);
1313
}
1314
1315
struct txpwr_lmt_ent *_rtw_txpwr_lmt_get_by_name(struct rf_ctl_t *rfctl, const char *regd_name)
1316
{
1317
struct txpwr_lmt_ent *ent;
1318
_list *cur, *head;
1319
u8 found = 0;
1320
1321
head = &rfctl->txpwr_lmt_list;
1322
cur = get_next(head);
1323
1324
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
1325
ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
1326
cur = get_next(cur);
1327
1328
if (strcmp(ent->regd_name, regd_name) == 0) {
1329
found = 1;
1330
break;
1331
}
1332
}
1333
1334
if (found)
1335
return ent;
1336
return NULL;
1337
}
1338
1339
inline struct txpwr_lmt_ent *rtw_txpwr_lmt_get_by_name(struct rf_ctl_t *rfctl, const char *regd_name)
1340
{
1341
struct txpwr_lmt_ent *ent;
1342
_irqL irqL;
1343
1344
_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1345
ent = _rtw_txpwr_lmt_get_by_name(rfctl, regd_name);
1346
_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1347
1348
return ent;
1349
}
1350
1351
void rtw_txpwr_lmt_list_free(struct rf_ctl_t *rfctl)
1352
{
1353
struct txpwr_lmt_ent *ent;
1354
_irqL irqL;
1355
_list *cur, *head;
1356
1357
_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1358
1359
head = &rfctl->txpwr_lmt_list;
1360
cur = get_next(head);
1361
1362
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
1363
ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
1364
cur = get_next(cur);
1365
if (ent->regd_name == rfctl->regd_name)
1366
rfctl->regd_name = regd_str(TXPWR_LMT_NONE);
1367
rtw_list_delete(&ent->list);
1368
rtw_vmfree((u8 *)ent, sizeof(struct txpwr_lmt_ent) + strlen(ent->regd_name) + 1);
1369
}
1370
rfctl->txpwr_regd_num = 0;
1371
1372
_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1373
}
1374
#endif /* CONFIG_TXPWR_LIMIT */
1375
1376
int rtw_ch_to_bb_gain_sel(int ch)
1377
{
1378
int sel = -1;
1379
1380
if (ch >= 1 && ch <= 14)
1381
sel = BB_GAIN_2G;
1382
#ifdef CONFIG_IEEE80211_BAND_5GHZ
1383
else if (ch >= 36 && ch < 48)
1384
sel = BB_GAIN_5GLB1;
1385
else if (ch >= 52 && ch <= 64)
1386
sel = BB_GAIN_5GLB2;
1387
else if (ch >= 100 && ch <= 120)
1388
sel = BB_GAIN_5GMB1;
1389
else if (ch >= 124 && ch <= 144)
1390
sel = BB_GAIN_5GMB2;
1391
else if (ch >= 149 && ch <= 177)
1392
sel = BB_GAIN_5GHB;
1393
#endif
1394
1395
return sel;
1396
}
1397
1398
s8 rtw_rf_get_kfree_tx_gain_offset(_adapter *padapter, u8 path, u8 ch)
1399
{
1400
s8 kfree_offset = 0;
1401
1402
#ifdef CONFIG_RF_POWER_TRIM
1403
struct kfree_data_t *kfree_data = GET_KFREE_DATA(padapter);
1404
s8 bb_gain_sel = rtw_ch_to_bb_gain_sel(ch);
1405
1406
if (bb_gain_sel < BB_GAIN_2G || bb_gain_sel >= BB_GAIN_NUM) {
1407
rtw_warn_on(1);
1408
goto exit;
1409
}
1410
1411
if (kfree_data->flag & KFREE_FLAG_ON) {
1412
kfree_offset = kfree_data->bb_gain[bb_gain_sel][path];
1413
if (IS_HARDWARE_TYPE_8723D(padapter))
1414
RTW_INFO("%s path:%s, ch:%u, bb_gain_sel:%d, kfree_offset:%d\n"
1415
, __func__, (path == 0)?"S1":"S0",
1416
ch, bb_gain_sel, kfree_offset);
1417
else
1418
RTW_INFO("%s path:%u, ch:%u, bb_gain_sel:%d, kfree_offset:%d\n"
1419
, __func__, path, ch, bb_gain_sel, kfree_offset);
1420
}
1421
exit:
1422
#endif /* CONFIG_RF_POWER_TRIM */
1423
return kfree_offset;
1424
}
1425
1426
void rtw_rf_set_tx_gain_offset(_adapter *adapter, u8 path, s8 offset)
1427
{
1428
#if !defined(CONFIG_RTL8814A) && !defined(CONFIG_RTL8822B) && !defined(CONFIG_RTL8821C) && !defined(CONFIG_RTL8822C)
1429
u8 write_value;
1430
#endif
1431
u8 target_path = 0;
1432
u32 val32 = 0;
1433
1434
if (IS_HARDWARE_TYPE_8723D(adapter)) {
1435
target_path = RF_PATH_A; /*in 8723D case path means S0/S1*/
1436
if (path == PPG_8723D_S1)
1437
RTW_INFO("kfree gain_offset 0x55:0x%x ",
1438
rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff));
1439
else if (path == PPG_8723D_S0)
1440
RTW_INFO("kfree gain_offset 0x65:0x%x ",
1441
rtw_hal_read_rfreg(adapter, target_path, 0x65, 0xffffffff));
1442
} else {
1443
target_path = path;
1444
RTW_INFO("kfree gain_offset 0x55:0x%x ", rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff));
1445
}
1446
1447
switch (rtw_get_chip_type(adapter)) {
1448
#ifdef CONFIG_RTL8723D
1449
case RTL8723D:
1450
write_value = RF_TX_GAIN_OFFSET_8723D(offset);
1451
if (path == PPG_8723D_S1)
1452
rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value);
1453
else if (path == PPG_8723D_S0)
1454
rtw_hal_write_rfreg(adapter, target_path, 0x65, 0x0f8000, write_value);
1455
break;
1456
#endif /* CONFIG_RTL8723D */
1457
#ifdef CONFIG_RTL8703B
1458
case RTL8703B:
1459
write_value = RF_TX_GAIN_OFFSET_8703B(offset);
1460
rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0fc000, write_value);
1461
break;
1462
#endif /* CONFIG_RTL8703B */
1463
#ifdef CONFIG_RTL8188F
1464
case RTL8188F:
1465
write_value = RF_TX_GAIN_OFFSET_8188F(offset);
1466
rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0fc000, write_value);
1467
break;
1468
#endif /* CONFIG_RTL8188F */
1469
#ifdef CONFIG_RTL8188GTV
1470
case RTL8188GTV:
1471
write_value = RF_TX_GAIN_OFFSET_8188GTV(offset);
1472
rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0fc000, write_value);
1473
break;
1474
#endif /* CONFIG_RTL8188GTV */
1475
#ifdef CONFIG_RTL8192E
1476
case RTL8192E:
1477
write_value = RF_TX_GAIN_OFFSET_8192E(offset);
1478
rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value);
1479
break;
1480
#endif /* CONFIG_RTL8188F */
1481
1482
#ifdef CONFIG_RTL8821A
1483
case RTL8821:
1484
write_value = RF_TX_GAIN_OFFSET_8821A(offset);
1485
rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value);
1486
break;
1487
#endif /* CONFIG_RTL8821A */
1488
#if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) || defined(CONFIG_RTL8192F) || defined(CONFIG_RTL8822C)
1489
case RTL8814A:
1490
case RTL8822B:
1491
case RTL8822C:
1492
case RTL8821C:
1493
case RTL8192F:
1494
RTW_INFO("\nkfree by PhyDM on the sw CH. path %d\n", path);
1495
break;
1496
#endif /* CONFIG_RTL8814A || CONFIG_RTL8822B || CONFIG_RTL8821C */
1497
1498
default:
1499
rtw_warn_on(1);
1500
break;
1501
}
1502
1503
if (IS_HARDWARE_TYPE_8723D(adapter)) {
1504
if (path == PPG_8723D_S1)
1505
val32 = rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff);
1506
else if (path == PPG_8723D_S0)
1507
val32 = rtw_hal_read_rfreg(adapter, target_path, 0x65, 0xffffffff);
1508
} else {
1509
val32 = rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff);
1510
}
1511
RTW_INFO(" after :0x%x\n", val32);
1512
}
1513
1514
void rtw_rf_apply_tx_gain_offset(_adapter *adapter, u8 ch)
1515
{
1516
HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
1517
s8 kfree_offset = 0;
1518
s8 tx_pwr_track_offset = 0; /* TODO: 8814A should consider tx pwr track when setting tx gain offset */
1519
s8 total_offset;
1520
int i, total = 0;
1521
1522
if (IS_HARDWARE_TYPE_8723D(adapter))
1523
total = 2; /* S1 and S0 */
1524
else
1525
total = hal_data->NumTotalRFPath;
1526
1527
for (i = 0; i < total; i++) {
1528
kfree_offset = rtw_rf_get_kfree_tx_gain_offset(adapter, i, ch);
1529
total_offset = kfree_offset + tx_pwr_track_offset;
1530
rtw_rf_set_tx_gain_offset(adapter, i, total_offset);
1531
}
1532
}
1533
1534
inline u8 rtw_is_dfs_range(u32 hi, u32 lo)
1535
{
1536
return rtw_is_range_overlap(hi, lo, 5720 + 10, 5260 - 10);
1537
}
1538
1539
u8 rtw_is_dfs_ch(u8 ch)
1540
{
1541
u32 hi, lo;
1542
1543
if (!rtw_chbw_to_freq_range(ch, CHANNEL_WIDTH_20, HAL_PRIME_CHNL_OFFSET_DONT_CARE, &hi, &lo))
1544
return 0;
1545
1546
return rtw_is_dfs_range(hi, lo);
1547
}
1548
1549
u8 rtw_is_dfs_chbw(u8 ch, u8 bw, u8 offset)
1550
{
1551
u32 hi, lo;
1552
1553
if (!rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo))
1554
return 0;
1555
1556
return rtw_is_dfs_range(hi, lo);
1557
}
1558
1559
bool rtw_is_long_cac_range(u32 hi, u32 lo, u8 dfs_region)
1560
{
1561
return (dfs_region == PHYDM_DFS_DOMAIN_ETSI && rtw_is_range_overlap(hi, lo, 5650, 5600)) ? _TRUE : _FALSE;
1562
}
1563
1564
bool rtw_is_long_cac_ch(u8 ch, u8 bw, u8 offset, u8 dfs_region)
1565
{
1566
u32 hi, lo;
1567
1568
if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE)
1569
return _FALSE;
1570
1571
return rtw_is_long_cac_range(hi, lo, dfs_region) ? _TRUE : _FALSE;
1572
}
1573
1574