1 /******************************************************************************
2 *
3 * Copyright(c) 2020 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 #include "phl_headers.h"
16 #include "phl_chnlplan.h"
17 #include "phl_country.h"
18 #include "phl_regulation_6g.h"
19
20 extern const struct regulatory_domain_mapping rdmap[MAX_RD_MAP_NUM];
21 extern const struct chdef_2ghz chdef2g[MAX_CHDEF_2GHZ];
22 extern const struct chdef_5ghz chdef5g[MAX_CHDEF_5GHZ];
23 extern const struct country_domain_mapping cdmap[MAX_COUNTRY_NUM];
24
25 /*
26 * @ Function description
27 * Convert 2 ghz channels from bit definition and then fill to
28 * struct rtw_regulation_channel *ch array[] and
29 * *ch_cnt will also be calculated.
30 *
31 * @ parameter
32 * *rg : internal regulatory information
33 * *ch_cnt : final converted 2ghz channel numbers.
34 * *rch : converted channels will be filled here.
35 * ch : 2 ghz bit difinitions
36 * passive : 2 ghz passive bit difinitions
37 *
38 */
_convert_ch2g(struct rtw_regulation * rg,u32 * ch_cnt,struct rtw_regulation_channel * rch,u16 ch,u16 passive)39 static void _convert_ch2g(struct rtw_regulation *rg, u32 *ch_cnt,
40 struct rtw_regulation_channel *rch, u16 ch, u16 passive)
41 {
42 u8 i = 0, property = 0;
43 u32 shift = 0, cnt = 0;
44
45 PHL_INFO("[REGU], convert 2 ghz channels\n");
46
47 for (i = 0; i < MAX_CH_NUM_2GHZ; i++) {
48 property = 0;
49 shift = (1 << i);
50 if (ch & shift) {
51 rch[*ch_cnt].band = BAND_ON_24G;
52 rch[*ch_cnt].channel = (u8)(i + 1);
53
54 if (passive & shift)
55 property |= CH_PASSIVE;
56
57 rch[*ch_cnt].property = property;
58 (*ch_cnt)++;
59 PHL_INFO("[REGU], ch: %d%s\n", (i + 1),
60 ((property & CH_PASSIVE) ? ", passive" : " " ));
61 cnt++;
62 }
63 }
64
65 PHL_INFO("[REGU], converted channels : %d\n", cnt);
66 }
67
_chnlplan_update_2g(struct rtw_regulation * rg,const struct freq_plan * f)68 static enum rtw_regulation_status _chnlplan_update_2g(
69 struct rtw_regulation *rg, const struct freq_plan *f)
70 {
71 const struct chdef_2ghz *chdef = NULL;
72 struct rtw_regulation_chplan_group *plan = NULL;
73 u16 i = 0, ch = 0, passive = 0;
74
75 if (!f)
76 return REGULATION_FAILURE;
77
78 if (f->regulation >= REGULATION_MAX)
79 return REGULATION_FAILURE;
80
81 for (i = 0; i < MAX_CHDEF_2GHZ; i++) {
82 if (f->ch_idx == chdef2g[i].idx) {
83 chdef = &chdef2g[i];
84 break;
85 }
86 }
87
88 if (!chdef)
89 return REGULATION_FAILURE;
90
91 rg->ch_idx2g = f->ch_idx;
92 rg->regulation_2g = f->regulation;
93
94 plan = &rg->chplan[FREQ_GROUP_2GHZ];
95 plan->cnt = 0;
96 ch = ((chdef->support_ch[1] << 8) | (chdef->support_ch[0]));
97 passive = ((chdef->passive[1] << 8) | (chdef->passive[0]));
98 _convert_ch2g(rg, &plan->cnt, plan->ch, ch, passive);
99
100 PHL_INFO("[REGU], 2 GHz, total channel = %d\n", plan->cnt);
101
102 return REGULATION_SUCCESS;
103 }
104
_get_5ghz_ch_info(const struct chdef_5ghz * chdef,u8 group,u16 * ch,u16 * passive,u16 * dfs,u8 * max_num,u8 * ch_start)105 static void _get_5ghz_ch_info(const struct chdef_5ghz *chdef,
106 u8 group, u16 *ch, u16 *passive, u16 *dfs, u8 *max_num, u8 *ch_start)
107 {
108 switch (group) {
109 case FREQ_GROUP_5GHZ_BAND1:
110 *ch = chdef->support_ch_b1;
111 *passive = chdef->passive_b1;
112 *dfs = chdef->dfs_b1;
113 *max_num = MAX_CH_NUM_BAND1;
114 *ch_start = 36;
115 break;
116 case FREQ_GROUP_5GHZ_BAND2:
117 *ch = chdef->support_ch_b2;
118 *passive = chdef->passive_b2;
119 *dfs = chdef->dfs_b2;
120 *max_num = MAX_CH_NUM_BAND2;
121 *ch_start = 52;
122 break;
123 case FREQ_GROUP_5GHZ_BAND3:
124 *ch = ((chdef->support_ch_b3[1] << 8) |
125 (chdef->support_ch_b3[0]));
126 *passive = ((chdef->passive_b3[1] << 8) |
127 (chdef->passive_b3[0]));
128 *dfs = ((chdef->dfs_b3[1] << 8) |
129 (chdef->dfs_b3[0])) ;
130 *max_num = MAX_CH_NUM_BAND3;
131 *ch_start = 100;
132 break;
133 case FREQ_GROUP_5GHZ_BAND4:
134 *ch = chdef->support_ch_b4;
135 *passive = chdef->passive_b4;
136 *dfs = chdef->dfs_b4;
137 *max_num = MAX_CH_NUM_BAND4;
138 *ch_start = 149;
139 break;
140 default:
141 *ch = 0;
142 *passive = 0;
143 *dfs = 0;
144 *max_num = 0;
145 *ch_start = 0;
146 break;
147 }
148 }
149
150 /*
151 * @ Function description
152 * Convert 5 ghz channels from bit definition and then fill to
153 * struct rtw_regulation_channel *ch array[] and
154 * *ch_cnt will also be calculated.
155 *
156 * @ parameter
157 * band_5g : 1~4 (5g band-1 ~ 5g band-4)
158 * *rg : internal regulatory information
159 * *ch_cnt : final converted 2ghz channel numbers.
160 * *rch : converted channels will be filled here.
161 * ch : 5 ghz bnad channel bit difinitions
162 * passive : 5 ghz band passive bit difinitions
163 * dfs : 5 ghz band dfs bit difinitions
164 * max_num : maximum channel numbers of the 5 ghz band.
165 * ch_start : start channel index of the 5 ghz band.
166 */
_convert_ch5g(u8 band_5g,struct rtw_regulation * rg,u32 * ch_cnt,struct rtw_regulation_channel * rch,u16 ch,u16 passive,u16 dfs,u8 max_num,u8 ch_start)167 static void _convert_ch5g(u8 band_5g, struct rtw_regulation *rg,
168 u32 *ch_cnt, struct rtw_regulation_channel *rch,
169 u16 ch, u16 passive, u16 dfs, u8 max_num, u8 ch_start)
170 {
171 u16 i = 0;
172 u32 shift = 0;
173 u8 property = 0;
174 u32 cnt = 0;
175
176 PHL_INFO("[REGU], convert 5ghz band-%d channels, from %d, ch=0x%x, passive = 0x%x, dfs=0x%x \n",
177 band_5g, ch_start, ch, passive, dfs);
178
179 for (i = 0; i < max_num; i++) {
180 shift = (1 << i);
181 if (ch & shift) {
182 property = 0;
183 rch[*ch_cnt].band = BAND_ON_5G;
184 rch[*ch_cnt].channel = (u8)(ch_start + (i * 4));
185
186 if (passive & shift)
187 property |= CH_PASSIVE;
188 if (dfs & shift)
189 property |= CH_DFS;
190
191 rch[*ch_cnt].property = property;
192 PHL_INFO("[REGU], ch: %d%s%s \n",
193 rch[*ch_cnt].channel,
194 ((property & CH_PASSIVE) ? ", passive" : ""),
195 ((property & CH_DFS) ? ", dfs" : ""));
196 (*ch_cnt)++;
197 cnt++;
198 }
199 }
200
201 PHL_INFO("[REGU], converted channels : %d\n", cnt);
202 }
203
_chnlplan_update_5g(struct rtw_regulation * rg,const struct freq_plan * f)204 static enum rtw_regulation_status _chnlplan_update_5g(
205 struct rtw_regulation *rg, const struct freq_plan *f)
206 {
207 const struct chdef_5ghz *chdef = NULL;
208 struct rtw_regulation_chplan_group *plan = NULL;
209 u8 group = FREQ_GROUP_5GHZ_BAND1;
210 u8 max_num = 0, ch_start = 0;
211 u16 i = 0, ch = 0, passive = 0, dfs = 0;
212 u32 total = 0;
213
214 if (!f)
215 return REGULATION_FAILURE;
216
217 if (f->regulation >= REGULATION_MAX)
218 return REGULATION_FAILURE;
219
220 for (i = 0; i < MAX_CHDEF_5GHZ; i++) {
221 if (f->ch_idx == chdef5g[i].idx) {
222 chdef = &chdef5g[i];
223 break;
224 }
225 }
226
227 if (!chdef)
228 return REGULATION_FAILURE;
229
230 rg->ch_idx5g = f->ch_idx;
231 rg->regulation_5g = f->regulation;
232
233 for (i = 0; i < 4; i++) {
234 group = (u8)(i + FREQ_GROUP_5GHZ_BAND1);
235 plan = &rg->chplan[group];
236 plan->cnt = 0;
237 _get_5ghz_ch_info(chdef, group,
238 &ch, &passive, &dfs, &max_num, &ch_start);
239 _convert_ch5g((u8)(i + 1), rg, &plan->cnt, plan->ch,
240 ch, passive, dfs, max_num, ch_start);
241 total += plan->cnt;
242 }
243
244 PHL_INFO("[REGU], 5 GHz, total channel = %d\n", total);
245
246 return REGULATION_SUCCESS;
247 }
248
_regulatory_domain_update(struct rtw_regulation * rg,u8 did,enum regulation_rsn reason)249 static enum rtw_regulation_status _regulatory_domain_update(
250 struct rtw_regulation *rg, u8 did, enum regulation_rsn reason)
251 {
252 enum rtw_regulation_status status = REGULATION_SUCCESS;
253 const struct freq_plan *plan_2g = NULL;
254 const struct freq_plan *plan_5g = NULL;
255
256 plan_2g = &rdmap[did].freq_2g;
257 plan_5g = &rdmap[did].freq_5g;
258
259 rg->domain.code = rdmap[did].domain_code;
260 rg->domain.reason = reason;
261
262 status = _chnlplan_update_2g(rg, plan_2g);
263 if (status != REGULATION_SUCCESS)
264 return status;
265 status = _chnlplan_update_5g(rg, plan_5g);
266 if (status != REGULATION_SUCCESS)
267 return status;
268
269 return status;
270 }
271
_get_group_chplan(struct rtw_regulation * rg,struct rtw_regulation_chplan_group * group,struct rtw_regulation_chplan * plan)272 static void _get_group_chplan(struct rtw_regulation *rg,
273 struct rtw_regulation_chplan_group *group,
274 struct rtw_regulation_chplan *plan)
275 {
276 u32 i = 0;
277 u8 dfs = 0;
278
279 for (i = 0; i < group->cnt; i++) {
280 dfs = ((group->ch[i].property & CH_DFS) ? 1 : 0);
281
282 if ((group->ch[i].channel) &&
283 (!dfs || ((rg->capability & CAPABILITY_DFS) && dfs))) {
284 plan->ch[plan->cnt].band =
285 group->ch[i].band;
286 plan->ch[plan->cnt].channel =
287 group->ch[i].channel;
288 plan->ch[plan->cnt].property =
289 group->ch[i].property;
290 plan->cnt++;
291 }
292 }
293 }
294
_domain_index(u8 domain)295 static u8 _domain_index(u8 domain)
296 {
297 u8 i = 0;
298
299 for (i = 0; i < MAX_RD_MAP_NUM; i++) {
300 if (domain == rdmap[i].domain_code) {
301 return i;
302 }
303 }
304
305 return MAX_RD_MAP_NUM;
306 }
307
_get_chnlplan(struct rtw_regulation * rg,enum rtw_regulation_query type,struct rtw_regulation_chplan * plan)308 static enum rtw_regulation_status _get_chnlplan(struct rtw_regulation *rg,
309 enum rtw_regulation_query type,
310 struct rtw_regulation_chplan *plan)
311 {
312 struct rtw_regulation_chplan_group *group = NULL;
313
314 if (rg->domain.code == INVALID_DOMAIN_CODE)
315 return REGULATION_INVALID_DOMAIN;
316
317 plan->cnt = 0;
318
319 /* 2ghz */
320 if (rg->capability & CAPABILITY_2GHZ) {
321 if (type == REGULQ_CHPLAN_FULL ||
322 type == REGULQ_CHPLAN_2GHZ_5GHZ ||
323 type == REGULQ_CHPLAN_2GHZ) {
324 group = &rg->chplan[FREQ_GROUP_2GHZ];
325 _get_group_chplan(rg, group, plan);
326 }
327 }
328
329 /* 5ghz */
330 if (rg->capability & CAPABILITY_5GHZ) {
331 /* band1 */
332 if (type == REGULQ_CHPLAN_FULL ||
333 type == REGULQ_CHPLAN_2GHZ_5GHZ ||
334 type == REGULQ_CHPLAN_5GHZ_ALL ||
335 type == REGULQ_CHPLAN_5GHZ_BAND1) {
336 group = &rg->chplan[FREQ_GROUP_5GHZ_BAND1];
337 _get_group_chplan(rg, group, plan);
338 }
339 /* band2 */
340 if (type == REGULQ_CHPLAN_FULL ||
341 type == REGULQ_CHPLAN_2GHZ_5GHZ ||
342 type == REGULQ_CHPLAN_5GHZ_ALL ||
343 type == REGULQ_CHPLAN_5GHZ_BAND2) {
344 group = &rg->chplan[FREQ_GROUP_5GHZ_BAND2];
345 _get_group_chplan(rg, group, plan);
346 }
347 /* band3 */
348 if (type == REGULQ_CHPLAN_FULL ||
349 type == REGULQ_CHPLAN_2GHZ_5GHZ ||
350 type == REGULQ_CHPLAN_5GHZ_ALL ||
351 type == REGULQ_CHPLAN_5GHZ_BAND3) {
352 group = &rg->chplan[FREQ_GROUP_5GHZ_BAND3];
353 _get_group_chplan(rg, group, plan);
354 }
355 /* band4 */
356 if (type == REGULQ_CHPLAN_FULL ||
357 type == REGULQ_CHPLAN_2GHZ_5GHZ ||
358 type == REGULQ_CHPLAN_5GHZ_ALL ||
359 type == REGULQ_CHPLAN_5GHZ_BAND4) {
360 group = &rg->chplan[FREQ_GROUP_5GHZ_BAND4];
361 _get_group_chplan(rg, group, plan);
362 }
363 }
364
365 #ifdef CONFIG_6GHZ
366 regu_get_chnlplan_6g(rg, type, plan);
367 #endif
368 return REGULATION_SUCCESS;
369 }
370
_valid_property(u8 property,u8 reject)371 static bool _valid_property(u8 property, u8 reject)
372 {
373 u8 i = 0;
374
375 /* accept all property */
376 if (!reject)
377 return true;
378
379 /* check if ch property rejected */
380 for (i = 0; i < 8; i++) {
381 if ((BIT(i) & property) & reject)
382 return false;
383 }
384
385 return true;
386 }
387
_filter_chnlplan(void * d,struct rtw_regulation_chplan * plan,struct rtw_chlist * filter)388 static void _filter_chnlplan(void *d,
389 struct rtw_regulation_chplan *plan,
390 struct rtw_chlist *filter)
391 {
392 struct rtw_regulation_chplan inplan = {0};
393 u32 i = 0, j = 0, k = 0;
394
395 if (!d || !plan || !filter)
396 return;
397
398 if (plan->cnt < filter->cnt)
399 return;
400
401 _os_mem_cpy(d, &inplan, plan, sizeof(struct rtw_regulation_chplan));
402
403 /*
404 * generate output chplan
405 * ex: filter : {1, 6}, inplan : {1, 6, 6, 11}, ouput => {1, 6, 6}
406 */
407 plan->cnt = 0;
408 for (i = 0; i < filter->cnt; i++) {
409 for (j = 0; j < inplan.cnt; j++) {
410 if ((filter->ch[i].band == inplan.ch[j].band) &&
411 (filter->ch[i].ch == inplan.ch[j].channel)) {
412 plan->ch[k].band = inplan.ch[j].band;
413 plan->ch[k].channel = inplan.ch[j].channel;
414 plan->ch[k].property = inplan.ch[j].property;
415 k++;
416 plan->cnt++;
417 }
418 }
419 }
420 }
421
_regulation_valid(void * phl)422 static bool _regulation_valid(void *phl)
423 {
424 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
425 struct rtw_regulation *rg = NULL;
426 void *d = NULL;
427 bool valid = false;
428
429 if (!phl)
430 return false;
431
432 rg = &phl_info->regulation;
433 if (!rg->init)
434 return false;
435
436 d = phl_to_drvpriv(phl_info);
437 _os_spinlock(d, &rg->lock, _bh, NULL);
438 valid = rg->valid;
439 _os_spinunlock(d, &rg->lock, _bh, NULL);
440
441 return valid;
442 }
443
_query_channel(struct rtw_regulation * rg,enum band_type band,u16 channel,struct rtw_regulation_channel * ch)444 static bool _query_channel(struct rtw_regulation *rg,
445 enum band_type band, u16 channel,
446 struct rtw_regulation_channel *ch)
447 {
448 struct rtw_regulation_chplan_group *plan = NULL;
449 u32 i = 0, j = 0;
450
451 if ((BAND_2GHZ(band) && !(rg->capability & CAPABILITY_2GHZ)) ||
452 (BAND_5GHZ(band) && !(rg->capability & CAPABILITY_5GHZ)) ||
453 (BAND_6GHZ(band) && !(rg->capability & CAPABILITY_6GHZ)))
454 return false;
455
456 for (i = FREQ_GROUP_2GHZ; i < FREQ_GROUP_MAX; i++) {
457 plan = &rg->chplan[i];
458 for (j = 0; j < plan->cnt; j++) {
459 if (channel == plan->ch[j].channel) {
460 ch->band = plan->ch[j].band;
461 ch->channel = plan->ch[j].channel;
462 ch->property = plan->ch[j].property;
463 return true;
464 }
465 }
466 }
467
468 return false;
469 }
470
_display_chplan(struct rtw_regulation_chplan * plan)471 static void _display_chplan(struct rtw_regulation_chplan *plan)
472 {
473 u32 i = 0;
474
475 for (i = 0; i < plan->cnt; i++) {
476 PHL_INFO("[REGU], %d, %shz: ch %d%s%s%s\n", (i + 1),
477 ((plan->ch[i].band == BAND_ON_24G) ? "2g" :
478 ((plan->ch[i].band == BAND_ON_5G) ? "5g" :
479 ((plan->ch[i].band == BAND_ON_6G) ? "6g" : ""))),
480 (plan->ch[i].channel),
481 ((plan->ch[i].property & CH_PASSIVE) ?
482 ", passive" : ""),
483 ((plan->ch[i].property & CH_DFS) ? ", dfs" : ""),
484 ((plan->ch[i].property & CH_PSC) ? ", psc" : ""));
485 }
486 }
487
_phl_regulation_send_msg(struct phl_info_t * phl_info,u8 evt_id)488 static void _phl_regulation_send_msg(struct phl_info_t *phl_info, u8 evt_id)
489 {
490 struct phl_msg msg = {0};
491 msg.inbuf = NULL;
492 msg.inlen = 0;
493 msg.band_idx = HW_BAND_0;
494 SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_REGU);
495 SET_MSG_EVT_ID_FIELD(msg.msg_id, evt_id);
496
497 if (RTW_PHL_STATUS_SUCCESS != phl_msg_hub_send(phl_info, NULL, &msg))
498 PHL_ERR("[REGULATION] sending message failed (evt_id: %u) \n", evt_id);
499 }
500
_history_log(struct rtw_regulation * rg,u8 domain,u8 reason)501 static void _history_log(struct rtw_regulation *rg, u8 domain, u8 reason)
502 {
503 rg->history[rg->history_cnt].code = domain;
504 rg->history[rg->history_cnt].reason = reason;
505 rg->history_cnt++;
506 if (rg->history_cnt >= MAX_HISTORY_NUM)
507 rg->history_cnt = 0;
508 }
509
510
_get_5ghz_udef_ch_info(struct rtw_user_def_chplan * udef,u8 group,u16 * ch,u16 * passive,u16 * dfs,u8 * max_num,u8 * ch_start)511 static void _get_5ghz_udef_ch_info(struct rtw_user_def_chplan *udef,
512 u8 group, u16 *ch, u16 *passive, u16 *dfs, u8 *max_num, u8 *ch_start)
513 {
514 switch (group) {
515 case FREQ_GROUP_5GHZ_BAND1:
516 *ch = (u16)udef->ch5g & 0xf;
517 *passive = (u16)udef->passive5g & 0xf;
518 *dfs = (u16)udef->dfs5g & 0xf;
519 *max_num = MAX_CH_NUM_BAND1;
520 *ch_start = 36;
521 break;
522 case FREQ_GROUP_5GHZ_BAND2:
523 *ch = (u16)((udef->ch5g & 0xf0) >> 4);
524 *passive = (u16)((udef->passive5g & 0xf0) >> 4);
525 *dfs = (u16)((udef->dfs5g & 0xf0) >> 4);
526 *max_num = MAX_CH_NUM_BAND2;
527 *ch_start = 52;
528 break;
529 case FREQ_GROUP_5GHZ_BAND3:
530 *ch = (u16)((udef->ch5g & 0xfff00) >> 8);
531 *passive = (u16)((udef->passive5g & 0xfff00) >> 8);
532 *dfs = (u16)((udef->dfs5g & 0xfff00) >> 8);
533 *max_num = MAX_CH_NUM_BAND3;
534 *ch_start = 100;
535 break;
536 case FREQ_GROUP_5GHZ_BAND4:
537 *ch = (u16)((udef->ch5g & 0xff00000) >> 20);
538 *passive = (u16)((udef->passive5g & 0xff00000) >> 20);
539 *dfs = (u16)((udef->dfs5g & 0xff00000) >> 20);
540 *max_num = MAX_CH_NUM_BAND4;
541 *ch_start = 149;
542 break;
543 default:
544 *ch = 0;
545 *passive = 0;
546 *dfs = 0;
547 *max_num = 0;
548 *ch_start = 0;
549 break;
550 }
551 }
552
553 /*
554 * @ Function description
555 * Reset regulatory info for non-specific country
556 */
_reset_for_non_specific_country(struct rtw_regulation * rg)557 static void _reset_for_non_specific_country(struct rtw_regulation *rg)
558 {
559 /* reset country */
560 rg->country[0] = 0;
561 rg->country[1] = 0;
562
563 /* reset TPO */
564 rg->tpo = TPO_NA;
565
566 /* default support all */
567 rg->support_mode |= (SUPPORT_11B | SUPPORT_11G | SUPPORT_11N |
568 SUPPORT_11A | SUPPORT_11AC | SUPPORT_11AX);
569 }
570
571 /*
572 * @ Function description
573 * Set user defined channel plans
574 *
575 * @ parameter
576 * struct rtw_user_def_chplan *udef : user defined channels, bit definition
577 *
578 * @ return :
579 * true : if set successfully
580 * false : failed to set
581 *
582 */
rtw_phl_set_user_def_chplan(void * phl,struct rtw_user_def_chplan * udef)583 bool rtw_phl_set_user_def_chplan(void *phl, struct rtw_user_def_chplan *udef)
584 {
585 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
586 struct rtw_regulation *rg = NULL;
587 struct rtw_regulation_chplan_group *plan = NULL;
588 u8 max_num = 0, ch_start = 0;
589 u16 ch = 0, passive = 0, dfs = 0;
590 u8 group = FREQ_GROUP_5GHZ_BAND1;
591 void *d = NULL;
592 u32 i = 0;
593
594 if (!phl || !udef)
595 return false;
596
597 rg = &phl_info->regulation;
598 if (!rg->init)
599 return false;
600
601 if (rg->domain.code != RSVD_DOMAIN) {
602 PHL_INFO("[REGU], Only reserved domain can set udef channel plan \n");
603 return false;
604 }
605
606 PHL_INFO("[REGU], set udef channel plan, ch2g:0x%x, ch5g:0x%x\n",
607 udef->ch2g, udef->ch5g);
608
609 d = phl_to_drvpriv(phl_info);
610 _os_spinlock(d, &rg->lock, _bh, NULL);
611
612 rg->regulation_2g = (u8)udef->regulatory_idx;
613 rg->regulation_5g = (u8)udef->regulatory_idx;
614 rg->tpo = udef->tpo;
615
616 /* 2 ghz */
617 plan = &rg->chplan[FREQ_GROUP_2GHZ];
618 plan->cnt = 0;
619 ch = udef->ch2g;
620 passive = udef->passive2g;
621 _convert_ch2g(rg, &plan->cnt, plan->ch, ch, passive);
622
623 PHL_INFO("[REGU], 2 GHz, total channel = %d\n", plan->cnt);
624
625 /* 5 ghz */
626 for (i = 0; i < 4; i++) {
627 group = (u8)(i + FREQ_GROUP_5GHZ_BAND1);
628 plan = &rg->chplan[group];
629 plan->cnt = 0;
630 _get_5ghz_udef_ch_info(udef, group,
631 &ch, &passive, &dfs, &max_num, &ch_start);
632 _convert_ch5g((u8)(i + 1), rg, &plan->cnt, plan->ch,
633 ch, passive, dfs, max_num, ch_start);
634 }
635
636 _os_spinunlock(d, &rg->lock, _bh, NULL);
637
638 return true;
639 }
640
641
642 /*
643 * @ Function description
644 * Check if domain is valid or not
645 *
646 * @ parameter
647 * domain : domain code to query
648 *
649 * @ return :
650 * true : if domain code exists in data base
651 * false : invalid domain code
652 *
653 */
rtw_phl_valid_regulation_domain(u8 domain)654 bool rtw_phl_valid_regulation_domain(u8 domain)
655 {
656 if (domain == RSVD_DOMAIN)
657 return true;
658
659 if (_domain_index(domain) >= MAX_RD_MAP_NUM)
660 return false;
661
662 return true;
663 }
664
665 /*
666 * @ Function description
667 * Set regulatory domain code
668 *
669 * @ parameter
670 * phl : struct phl_info_t *
671 * domain : domain code
672 * reason : why
673 *
674 * @ return :
675 * true : set domain successfully
676 * false : set fail
677 *
678 */
rtw_phl_regulation_set_domain(void * phl,u8 domain,enum regulation_rsn reason)679 bool rtw_phl_regulation_set_domain(void *phl, u8 domain,
680 enum regulation_rsn reason)
681 {
682 enum rtw_regulation_status status = REGULATION_SUCCESS;
683 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
684 struct rtw_regulation *rg = NULL;
685 void *d = NULL;
686 u8 did = MAX_RD_MAP_NUM;
687
688 PHL_INFO("[REGU], set domain code = 0x%x, reason = 0x%x\n",
689 domain, reason);
690
691 if (!phl_info)
692 return false;
693
694 rg = &phl_info->regulation;
695 if (!rg->init)
696 return false;
697
698 if (!rtw_phl_valid_regulation_domain(domain))
699 return false;
700
701 did = _domain_index(domain);
702
703 d = phl_to_drvpriv(phl_info);
704
705 _os_spinlock(d, &rg->lock, _bh, NULL);
706
707 _history_log(rg, domain, reason);
708
709 if (domain == RSVD_DOMAIN) {
710 rg->domain.code = RSVD_DOMAIN;
711 rg->domain.reason = reason;
712 status = REGULATION_SUCCESS;
713 } else
714 status = _regulatory_domain_update(rg, did, reason);
715
716 if (status == REGULATION_SUCCESS) {
717 _reset_for_non_specific_country(rg);
718 rg->valid = true;
719 } else {
720 rg->valid = false;
721 rg->invalid_cnt++;
722 }
723 _os_spinunlock(d, &rg->lock, _bh, NULL);
724
725 PHL_INFO("[REGU], domain code update status = 0x%x\n", status);
726
727 if (status == REGULATION_SUCCESS) {
728 _phl_regulation_send_msg(phl_info, MSG_EVT_REGU_SET_DOMAIN);
729 #ifdef CONFIG_6GHZ
730 regu_set_domain_6g(phl, 0x7f, reason);
731 #endif
732 return true;
733 } else {
734 return false;
735 }
736 }
737
738 /*
739 * @ Function description
740 * Set regulation by 2bytes country code
741 *
742 * @ parameter
743 * phl : struct phl_info_t *
744 * country : 2 bytes char
745 * reason : why
746 *
747 * @ return :
748 * true : set country/domain successfully
749 * false : set fail
750 *
751 */
rtw_phl_regulation_set_country(void * phl,char * country,enum regulation_rsn reason)752 bool rtw_phl_regulation_set_country(void *phl, char *country,
753 enum regulation_rsn reason)
754 {
755 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
756 struct rtw_regulation *rg = NULL;
757 void *d = NULL;
758 u32 i = 0;
759
760 PHL_INFO("[REGU], set country code = \"%c%c\", reason = 0x%x\n",
761 country[0], country[1], reason);
762
763 if (!phl_info)
764 return false;
765
766 d = phl_to_drvpriv(phl_info);
767 rg = &phl_info->regulation;
768 if (!rg->init)
769 return false;
770
771 if (rg->domain.code == RSVD_DOMAIN)
772 return false;
773
774 for (i = 0; i < MAX_COUNTRY_NUM; i++) {
775 if (cdmap[i].char2[0] == country[0] &&
776 cdmap[i].char2[1] == country[1] ) {
777 if (!rtw_phl_regulation_set_domain(phl,
778 cdmap[i].domain_code, reason))
779 return false;
780 _os_spinlock(d, &rg->lock, _bh, NULL);
781 rg->country[0] = country[0];
782 rg->country[1] = country[1];
783 rg->tpo = cdmap[i].tpo;
784 rg->support_mode = 0;
785 if(cdmap[i].support & BIT(0))
786 rg->support_mode |= (SUPPORT_11B | SUPPORT_11G | SUPPORT_11N);
787 if(cdmap[i].support & BIT(1))
788 rg->support_mode |= (SUPPORT_11A);
789 if(cdmap[i].support & BIT(2))
790 rg->support_mode |= (SUPPORT_11AC);
791 if(cdmap[i].support & BIT(3))
792 rg->support_mode |= (SUPPORT_11AX);
793 _os_spinunlock(d, &rg->lock, _bh, NULL);
794 return true;
795 }
796 }
797
798 PHL_INFO("[REGU], country mismatch !!\n");
799 return false;
800 }
801
802 /*
803 * @ Function description
804 * Query current regulation channel plan
805 *
806 * @ parameter
807 * phl : struct phl_info_t *
808 * capability : enum rtw_regulation_capability
809 *
810 * @ return :
811 * true : set capability successfully
812 * false : set capability fail
813 *
814 */
rtw_phl_regulation_set_capability(void * phl,enum rtw_regulation_capability capability)815 bool rtw_phl_regulation_set_capability(void *phl,
816 enum rtw_regulation_capability capability)
817 {
818 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
819 struct rtw_regulation *rg = NULL;
820 void *d = NULL;
821
822 PHL_INFO("[REGU], set capability = 0x%x \n", capability);
823
824 if (!phl_info)
825 return false;
826
827 rg = &phl_info->regulation;
828 if (!rg->init)
829 return false;
830
831 d = phl_to_drvpriv(phl_info);
832 _os_spinlock(d, &rg->lock, _bh, NULL);
833 rg->capability = capability;
834 _os_spinunlock(d, &rg->lock, _bh, NULL);
835
836 PHL_INFO("[REGU], set capability = 0x%x successfully !!\n",
837 rg->capability);
838 return true;
839 }
840
841 /*
842 * @ Function description
843 * Query current regulation channel plan
844 *
845 * @ parameter
846 * phl : struct phl_info_t *
847 * type : enum rtw_regulation_query, different query type
848 * filter : struct rtw_chlist *, used to filter regulation channels
849 * plan : struct rtw_regulation_chplan *, query result will be filled here
850 * - result will be the intersection of regulation channel plan and
851 * the filter channels.
852 *
853 * @ return :
854 * true : regulation query successfully, caller can check result
855 * by input parameter *plan.
856 * false : regulation query fail
857 *
858 */
rtw_phl_regulation_query_chplan(void * phl,enum rtw_regulation_query type,struct rtw_chlist * filter,struct rtw_regulation_chplan * plan)859 bool rtw_phl_regulation_query_chplan(
860 void *phl, enum rtw_regulation_query type,
861 struct rtw_chlist *filter,
862 struct rtw_regulation_chplan *plan)
863 {
864 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
865 struct rtw_regulation *rg = NULL;
866 enum rtw_regulation_status status = REGULATION_FAILURE;
867 void *d = NULL;
868
869 if (!phl || !plan)
870 return false;
871
872 if (!_regulation_valid(phl))
873 return false;
874
875 rg = &phl_info->regulation;
876 d = phl_to_drvpriv(phl_info);
877
878 _os_spinlock(d, &rg->lock, _bh, NULL);
879 switch (type) {
880 case REGULQ_CHPLAN_FULL:
881 case REGULQ_CHPLAN_2GHZ:
882 case REGULQ_CHPLAN_5GHZ_ALL:
883 case REGULQ_CHPLAN_5GHZ_BAND1:
884 case REGULQ_CHPLAN_5GHZ_BAND2:
885 case REGULQ_CHPLAN_5GHZ_BAND3:
886 case REGULQ_CHPLAN_5GHZ_BAND4:
887 case REGULQ_CHPLAN_6GHZ_UNII5:
888 case REGULQ_CHPLAN_6GHZ_UNII6:
889 case REGULQ_CHPLAN_6GHZ_UNII7:
890 case REGULQ_CHPLAN_6GHZ_UNII8:
891 case REGULQ_CHPLAN_6GHZ:
892 case REGULQ_CHPLAN_6GHZ_PSC:
893 case REGULQ_CHPLAN_2GHZ_5GHZ:
894 status = _get_chnlplan(rg, type, plan);
895 if (filter)
896 _filter_chnlplan(d, plan, filter);
897 break;
898 default:
899 break;
900 }
901 _os_spinunlock(d, &rg->lock, _bh, NULL);
902
903 if (status == REGULATION_SUCCESS) {
904 /* _display_chplan(plan); */
905 return true;
906 }
907 else
908 return false;
909 }
910
911 /*
912 * @ Function description
913 * Query specific regulation channel plan by domain code
914 *
915 * @ parameter
916 * domain : domain code
917 * plan : struct rtw_regulation_chplan *, query result will be filled here
918 *
919 * @ return :
920 * true : regulation query successfully, caller can check result
921 * by input parameter *plan.
922 * false : regulation query fail
923 *
924 */
rtw_phl_query_specific_chplan(void * phl,u8 domain,struct rtw_regulation_chplan * plan)925 bool rtw_phl_query_specific_chplan(void *phl, u8 domain,
926 struct rtw_regulation_chplan *plan)
927 {
928 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
929 const struct chdef_2ghz *chdef2 = NULL;
930 const struct chdef_5ghz *chdef5 = NULL;
931 struct rtw_regulation *rg = NULL;
932 u8 did = MAX_RD_MAP_NUM;
933 u8 idx2g = INVALID_CHDEF;
934 u8 idx5g = INVALID_CHDEF;
935 u16 i = 0, ch = 0, passive = 0, dfs = 0;
936 u8 group = FREQ_GROUP_5GHZ_BAND1;
937 u8 max_num = 0, ch_start = 0;
938
939 if (!plan)
940 return false;
941 plan->cnt = 0;
942
943 PHL_INFO("[REGU], query specific channel plan for domain : 0x%x!!\n",
944 domain);
945
946 if (!rtw_phl_valid_regulation_domain(domain))
947 return false;
948
949 /* find channel definition for 2 ghz & 5 ghz */
950 did = _domain_index(domain);
951 idx2g = rdmap[did].freq_2g.ch_idx;
952 for (i = 0; i < MAX_CHDEF_2GHZ; i++) {
953 if (idx2g == chdef2g[i].idx) {
954 chdef2 = &chdef2g[i];
955 }
956 }
957 idx5g = rdmap[did].freq_5g.ch_idx;
958 for (i = 0; i < MAX_CHDEF_5GHZ; i++) {
959 if (idx5g == chdef5g[i].idx) {
960 chdef5 = &chdef5g[i];
961 }
962 }
963
964 /* when regulatory domain & capability is set, check regulatory capability setting first */
965 if (_regulation_valid(phl)) {
966 rg = &phl_info->regulation;
967 if (!(rg->capability & CAPABILITY_2GHZ))
968 chdef2 = NULL;
969 if (!(rg->capability & CAPABILITY_5GHZ))
970 chdef5 = NULL;
971 }
972
973 /* 2ghz */
974 if (chdef2) {
975 ch = ((chdef2->support_ch[1] << 8) |
976 (chdef2->support_ch[0]));
977 passive = ((chdef2->passive[1] << 8) |
978 (chdef2->passive[0]));
979 _convert_ch2g(rg, &plan->cnt, plan->ch, ch, passive);
980 }
981
982 /* 5ghz */
983 if (chdef5) {
984 for (i = 0; i < 4; i++) {
985 group = (u8)(i + FREQ_GROUP_5GHZ_BAND1);
986 _get_5ghz_ch_info(chdef5, group, &ch, &passive, &dfs,
987 &max_num, &ch_start);
988 _convert_ch5g((u8)(i + 1), rg, &plan->cnt, plan->ch,
989 ch, passive, dfs, max_num, ch_start);
990 }
991 }
992
993 PHL_INFO("[REGU], query specific channel plan for domain : 0x%x, total channels : %d !!\n",
994 domain, plan->cnt);
995 _display_chplan(plan);
996
997 return true;
998 }
999
1000 /*
1001 * @ Function description
1002 * Query basic regulation info
1003 *
1004 * @ parameter
1005 * phl : struct phl_info_t *
1006 * info : struct rtw_regulation_info *, query result will be filled here
1007 *
1008 * @ return :
1009 * true : regulation query successfully, caller can check result
1010 * by input parameter *info.
1011 * false : regulation query fail
1012 *
1013 */
rtw_phl_query_regulation_info(void * phl,struct rtw_regulation_info * info)1014 bool rtw_phl_query_regulation_info(void *phl, struct rtw_regulation_info *info)
1015 {
1016 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1017 struct rtw_regulation *rg = NULL;
1018 void *d = NULL;
1019
1020 if (!phl || !info)
1021 return false;
1022
1023 if (!_regulation_valid(phl))
1024 return false;
1025
1026 rg = &phl_info->regulation;
1027 d = phl_to_drvpriv(phl_info);
1028
1029 _os_spinlock(d, &rg->lock, _bh, NULL);
1030
1031 info->domain_code = (u8)rg->domain.code;
1032 info->domain_reason = rg->domain.reason;
1033 info->country[0] = rg->country[0];
1034 info->country[1] = rg->country[1];
1035 info->tpo = rg->tpo;
1036 info->support_mode = rg->support_mode;
1037 info->regulation_2g = rg->regulation_2g;
1038 info->regulation_5g = rg->regulation_5g;
1039 info->chplan_ver = REGULATION_CHPLAN_VERSION;
1040 info->country_ver = REGULATION_COUNTRY_VERSION;
1041 info->capability = rg->capability;
1042
1043 _os_spinunlock(d, &rg->lock, _bh, NULL);
1044
1045 return true;
1046 }
1047
1048 /*
1049 * @ Function description
1050 * Use the coutry code to query the corresponding
1051 * domain code and properties
1052 *
1053 * @ parameter
1054 * country : 2 bytes char
1055 * country_chplan : pointer to structre of chplan's info
1056 *
1057 * @ return :
1058 * true : successfully search the entry form cdmap
1059 * false : country chplan query fail
1060 */
rtw_phl_query_country_chplan(char * country,struct rtw_regulation_country_chplan * country_chplan)1061 bool rtw_phl_query_country_chplan(char *country,
1062 struct rtw_regulation_country_chplan* country_chplan)
1063 {
1064 u32 i = 0;
1065
1066 PHL_INFO("[REGU], query country code = \"%c%c\"\n",
1067 country[0], country[1]);
1068
1069 for (i = 0; i < MAX_COUNTRY_NUM; i++) {
1070 if (cdmap[i].char2[0] == country[0] &&
1071 cdmap[i].char2[1] == country[1] ) {
1072 country_chplan->domain_code = cdmap[i].domain_code;
1073 if(cdmap[i].support & BIT(0))
1074 country_chplan->support_mode |= (SUPPORT_11B | SUPPORT_11G | SUPPORT_11N);
1075 if(cdmap[i].support & BIT(1))
1076 country_chplan->support_mode |= (SUPPORT_11A);
1077 if(cdmap[i].support & BIT(2))
1078 country_chplan->support_mode |= (SUPPORT_11AC);
1079 if(cdmap[i].support & BIT(3))
1080 country_chplan->support_mode |= (SUPPORT_11AX);
1081 country_chplan->tpo = cdmap[i].tpo;
1082 return true;
1083 }
1084 }
1085 return false;
1086 }
1087
rtw_phl_regulation_valid(void * phl)1088 bool rtw_phl_regulation_valid(void *phl)
1089 {
1090 return _regulation_valid(phl);
1091 }
1092
1093 /*
1094 * @ Function description
1095 * Used to check if channel is in regulation channel list
1096 *
1097 * @ parameter
1098 * phl : struct phl_info_t *
1099 * channel : channel to be checked
1100 * reject : enum ch_property, ex: (CH_PASSIVE | CH_DFS)
1101 *
1102 * @ return :
1103 * true : channel is in regulation list and not rejected
1104 * false : query regulation failed or channel is not in regulation
1105 * channel list
1106 */
rtw_phl_regulation_valid_channel(void * phl,enum band_type band,u16 channel,u8 reject)1107 bool rtw_phl_regulation_valid_channel(void *phl, enum band_type band,
1108 u16 channel, u8 reject)
1109 {
1110 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1111 struct rtw_regulation *rg = NULL;
1112 struct rtw_regulation_channel ch = {0};
1113 bool valid = false;
1114 void *d = NULL;
1115 u8 rej_property = reject;
1116
1117 if (!_regulation_valid(phl))
1118 return false;
1119
1120 rg = &phl_info->regulation;
1121 d = phl_to_drvpriv(phl_info);
1122
1123 _os_spinlock(d, &rg->lock, _bh, NULL);
1124 if (_query_channel(rg, band, channel, &ch)) {
1125 if (!(rg->capability & CAPABILITY_DFS))
1126 rej_property |= CAPABILITY_DFS;
1127 if (_valid_property(ch.property, rej_property))
1128 valid = true;
1129 }
1130 _os_spinunlock(d, &rg->lock, _bh, NULL);
1131
1132 return valid;
1133 }
1134
1135 /*
1136 * @ Function description
1137 * Used to check if channel is a regulation DFS channel
1138 *
1139 * @ parameter
1140 * phl : struct phl_info_t *
1141 * channel : channel to be checked
1142 * dfs : result will be filled here
1143 *
1144 * @ return :
1145 * true : regulation query successfully, caller can check result
1146 * by input parameter *dfs.
1147 * false : regulation fail
1148 *
1149 */
rtw_phl_regulation_dfs_channel(void * phl,enum band_type band,u16 channel,bool * dfs)1150 bool rtw_phl_regulation_dfs_channel(void *phl, enum band_type band,
1151 u16 channel, bool *dfs)
1152 {
1153 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1154 struct rtw_regulation *rg = NULL;
1155 struct rtw_regulation_channel ch = {0};
1156 void *d = NULL;
1157 bool query = false;
1158
1159 if (!_regulation_valid(phl) || !dfs)
1160 return false;
1161
1162 rg = &phl_info->regulation;
1163 d = phl_to_drvpriv(phl_info);
1164
1165 _os_spinlock(d, &rg->lock, _bh, NULL);
1166 if (_query_channel(rg, band, channel, &ch)) {
1167 query = true;
1168 if (ch.property & CH_DFS)
1169 *dfs = true;
1170 else
1171 *dfs = false;
1172 }
1173 _os_spinunlock(d, &rg->lock, _bh, NULL);
1174
1175 return query;
1176 }
1177
1178 /*
1179 * @ Function description
1180 * Query regulation channel
1181 *
1182 * @ parameter
1183 * phl : struct phl_info_t *
1184 * channel : channel for query
1185 * ch : query result will be filled here
1186 *
1187 * @ return :
1188 * true : regulation query successfully, caller can check result
1189 * by input parameter *ch.
1190 * false : regulation query fail
1191 *
1192 */
rtw_phl_regulation_query_ch(void * phl,enum band_type band,u8 channel,struct rtw_regulation_channel * ch)1193 bool rtw_phl_regulation_query_ch(void *phl, enum band_type band, u8 channel,
1194 struct rtw_regulation_channel *ch)
1195 {
1196 struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1197 struct rtw_regulation *rg = NULL;
1198 void *d = NULL;
1199 bool query = false;
1200
1201 if (!_regulation_valid(phl) || !ch)
1202 return false;
1203
1204 rg = &phl_info->regulation;
1205 d = phl_to_drvpriv(phl_info);
1206
1207 _os_spinlock(d, &rg->lock, _bh, NULL);
1208 if (_query_channel(rg, band, channel, ch))
1209 query = true;
1210 _os_spinunlock(d, &rg->lock, _bh, NULL);
1211
1212 return query;
1213 }
1214
rtw_phl_get_domain_regulation_2g(u8 domain)1215 u8 rtw_phl_get_domain_regulation_2g(u8 domain)
1216 {
1217 u8 did = MAX_RD_MAP_NUM;
1218
1219 if (!rtw_phl_valid_regulation_domain(domain))
1220 return REGULATION_MAX;
1221
1222 did = _domain_index(domain);
1223 if (did >= MAX_RD_MAP_NUM)
1224 return REGULATION_MAX;
1225
1226 return rdmap[did].freq_2g.regulation;
1227 }
1228
rtw_phl_get_domain_regulation_5g(u8 domain)1229 u8 rtw_phl_get_domain_regulation_5g(u8 domain)
1230 {
1231 u8 did = MAX_RD_MAP_NUM;
1232
1233 if (!rtw_phl_valid_regulation_domain(domain))
1234 return REGULATION_MAX;
1235
1236 did = _domain_index(domain);
1237 if (did >= MAX_RD_MAP_NUM)
1238 return REGULATION_MAX;
1239
1240 return rdmap[did].freq_5g.regulation;
1241 }
1242
1243