1*4882a593Smuzhiyun /******************************************************************************
2*4882a593Smuzhiyun *
3*4882a593Smuzhiyun * Copyright(c) 2020 Realtek Corporation.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify it
6*4882a593Smuzhiyun * under the terms of version 2 of the GNU General Public License as
7*4882a593Smuzhiyun * published by the Free Software Foundation.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful, but WITHOUT
10*4882a593Smuzhiyun * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11*4882a593Smuzhiyun * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12*4882a593Smuzhiyun * more details.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun *****************************************************************************/
15*4882a593Smuzhiyun #include "phl_headers.h"
16*4882a593Smuzhiyun #include "phl_chnlplan.h"
17*4882a593Smuzhiyun #include "phl_chnlplan_6g.h"
18*4882a593Smuzhiyun #include "phl_country.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun extern const struct chdef_6ghz chdef6g[MAX_CHDEF_6GHZ];
21*4882a593Smuzhiyun extern const struct regulatory_domain_mapping_6g rdmap6[MAX_RD_MAP_NUM_6GHZ];
22*4882a593Smuzhiyun
_get_6ghz_ch_info(const struct chdef_6ghz * chdef,u8 group,u32 * ch,u32 * passive,u8 * max_num,u8 * ch_start)23*4882a593Smuzhiyun static void _get_6ghz_ch_info(const struct chdef_6ghz *chdef,
24*4882a593Smuzhiyun u8 group, u32 *ch, u32 *passive, u8 *max_num, u8 *ch_start)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun switch (group) {
27*4882a593Smuzhiyun case FREQ_GROUP_6GHZ_UNII5:
28*4882a593Smuzhiyun *ch = ((chdef->support_ch_u5[2] << 16) |
29*4882a593Smuzhiyun (chdef->support_ch_u5[1] << 8) |
30*4882a593Smuzhiyun (chdef->support_ch_u5[0]));
31*4882a593Smuzhiyun *passive = ((chdef->passive_u5[2] << 16) |
32*4882a593Smuzhiyun (chdef->passive_u5[1] << 8) |
33*4882a593Smuzhiyun (chdef->passive_u5[0]));
34*4882a593Smuzhiyun *max_num = MAX_CH_NUM_UNII5;
35*4882a593Smuzhiyun *ch_start = 1;
36*4882a593Smuzhiyun break;
37*4882a593Smuzhiyun case FREQ_GROUP_6GHZ_UNII6:
38*4882a593Smuzhiyun *ch = chdef->support_ch_u6;
39*4882a593Smuzhiyun *passive = chdef->passive_u6;
40*4882a593Smuzhiyun *max_num = MAX_CH_NUM_UNII6;
41*4882a593Smuzhiyun *ch_start = 97;
42*4882a593Smuzhiyun break;
43*4882a593Smuzhiyun case FREQ_GROUP_6GHZ_UNII7:
44*4882a593Smuzhiyun *ch = ((chdef->support_ch_u7[2] << 16) |
45*4882a593Smuzhiyun (chdef->support_ch_u7[1] << 8) |
46*4882a593Smuzhiyun (chdef->support_ch_u7[0]));
47*4882a593Smuzhiyun *passive = ((chdef->passive_u7[2] << 16) |
48*4882a593Smuzhiyun (chdef->passive_u7[1] << 8) |
49*4882a593Smuzhiyun (chdef->passive_u7[0]));
50*4882a593Smuzhiyun *max_num = MAX_CH_NUM_UNII7;
51*4882a593Smuzhiyun *ch_start = 121;
52*4882a593Smuzhiyun break;
53*4882a593Smuzhiyun case FREQ_GROUP_6GHZ_UNII8:
54*4882a593Smuzhiyun *ch = ((chdef->support_ch_u8[1] << 8) |
55*4882a593Smuzhiyun (chdef->support_ch_u8[0]));
56*4882a593Smuzhiyun *passive = ((chdef->passive_u8[1] << 8) |
57*4882a593Smuzhiyun (chdef->passive_u8[0]));
58*4882a593Smuzhiyun *max_num = MAX_CH_NUM_UNII8;
59*4882a593Smuzhiyun *ch_start = 193;
60*4882a593Smuzhiyun break;
61*4882a593Smuzhiyun default:
62*4882a593Smuzhiyun *ch = 0;
63*4882a593Smuzhiyun *passive = 0;
64*4882a593Smuzhiyun *max_num = 0;
65*4882a593Smuzhiyun *ch_start = 0;
66*4882a593Smuzhiyun break;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
_convert_ch6g(u8 unii_6g,struct rtw_regulation * rg,u32 * ch_cnt,struct rtw_regulation_channel * rch,u32 ch,u32 passive,u8 max_num,u8 ch_start)70*4882a593Smuzhiyun static void _convert_ch6g(u8 unii_6g, struct rtw_regulation *rg,
71*4882a593Smuzhiyun u32 *ch_cnt, struct rtw_regulation_channel *rch,
72*4882a593Smuzhiyun u32 ch, u32 passive, u8 max_num, u8 ch_start)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun u16 i = 0;
75*4882a593Smuzhiyun u32 shift = 0;
76*4882a593Smuzhiyun u8 property = 0;
77*4882a593Smuzhiyun u32 cnt = 0;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun PHL_INFO("[REGU], convert 6 ghz unii-%d channels, from %d, ch=0x%x, passive = 0x%x \n",
80*4882a593Smuzhiyun unii_6g, ch_start, ch, passive);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun for (i = 0; i < max_num; i++) {
83*4882a593Smuzhiyun shift = (1 << i);
84*4882a593Smuzhiyun if (ch & shift) {
85*4882a593Smuzhiyun property = 0;
86*4882a593Smuzhiyun rch[*ch_cnt].band = BAND_ON_6G;
87*4882a593Smuzhiyun rch[*ch_cnt].channel = (u8)(ch_start + (i * 4));
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if (passive & shift)
90*4882a593Smuzhiyun property |= CH_PASSIVE;
91*4882a593Smuzhiyun if ((rch[*ch_cnt].channel % 16) == 5)
92*4882a593Smuzhiyun property |= CH_PSC;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun rch[*ch_cnt].property = property;
95*4882a593Smuzhiyun PHL_INFO("[REGU], ch: %d%s%s \n",
96*4882a593Smuzhiyun rch[*ch_cnt].channel,
97*4882a593Smuzhiyun ((property & CH_PASSIVE) ? ", passive" : ""),
98*4882a593Smuzhiyun ((property & CH_PSC) ? ", psc" : ""));
99*4882a593Smuzhiyun (*ch_cnt)++;
100*4882a593Smuzhiyun cnt++;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun PHL_INFO("[REGU], converted channels : %d\n", cnt);
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
_update_psc_group(struct rtw_regulation * rg)107*4882a593Smuzhiyun static void _update_psc_group(struct rtw_regulation *rg)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun u8 group = FREQ_GROUP_6GHZ_UNII5;
110*4882a593Smuzhiyun struct rtw_regulation_chplan_group *plan =
111*4882a593Smuzhiyun &rg->chplan[FREQ_GROUP_6GHZ_PSC];
112*4882a593Smuzhiyun struct rtw_regulation_chplan_group *src = NULL;
113*4882a593Smuzhiyun u32 i = 0, j = 0;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun plan->cnt = 0;
116*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
117*4882a593Smuzhiyun group = (u8)(i + FREQ_GROUP_6GHZ_UNII5);
118*4882a593Smuzhiyun src = &rg->chplan[group];
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun for (j = 0; j < src->cnt; j++) {
121*4882a593Smuzhiyun if (src->ch[j].property & CH_PSC) {
122*4882a593Smuzhiyun plan->ch[plan->cnt].band =
123*4882a593Smuzhiyun src->ch[j].band;
124*4882a593Smuzhiyun plan->ch[plan->cnt].channel =
125*4882a593Smuzhiyun src->ch[j].channel;
126*4882a593Smuzhiyun plan->ch[plan->cnt].property =
127*4882a593Smuzhiyun src->ch[j].property;
128*4882a593Smuzhiyun plan->cnt++;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
_chnlplan_update_6g(struct rtw_regulation * rg,u8 regulation,u8 ch_idx)134*4882a593Smuzhiyun static bool _chnlplan_update_6g(struct rtw_regulation *rg,
135*4882a593Smuzhiyun u8 regulation, u8 ch_idx)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun const struct chdef_6ghz *chdef = NULL;
138*4882a593Smuzhiyun struct rtw_regulation_chplan_group *plan = NULL;
139*4882a593Smuzhiyun u8 group = FREQ_GROUP_6GHZ_UNII5;
140*4882a593Smuzhiyun u8 max_num = 0, ch_start = 0;
141*4882a593Smuzhiyun u16 i = 0;
142*4882a593Smuzhiyun u32 ch = 0, passive = 0;
143*4882a593Smuzhiyun u32 total = 0;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun if (regulation >= REGULATION_MAX)
146*4882a593Smuzhiyun return false;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun for (i = 0; i < MAX_CHDEF_6GHZ; i++) {
149*4882a593Smuzhiyun if (ch_idx == chdef6g[i].idx) {
150*4882a593Smuzhiyun chdef = &chdef6g[i];
151*4882a593Smuzhiyun break;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun if (!chdef)
156*4882a593Smuzhiyun return false;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun rg->ch_idx6g = ch_idx;
159*4882a593Smuzhiyun rg->regulation_6g = regulation;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
162*4882a593Smuzhiyun group = (u8)(i + FREQ_GROUP_6GHZ_UNII5);
163*4882a593Smuzhiyun plan = &rg->chplan[group];
164*4882a593Smuzhiyun plan->cnt = 0;
165*4882a593Smuzhiyun _get_6ghz_ch_info(chdef, group,
166*4882a593Smuzhiyun &ch, &passive, &max_num, &ch_start);
167*4882a593Smuzhiyun _convert_ch6g((u8)(i + 5), rg, &plan->cnt, plan->ch,
168*4882a593Smuzhiyun ch, passive, max_num, ch_start);
169*4882a593Smuzhiyun total += plan->cnt;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun _update_psc_group(rg);
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun PHL_INFO("[REGU], 6 GHz, total channel = %d\n", total);
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun return true;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
_domain_index_6g(u16 domain)179*4882a593Smuzhiyun static u8 _domain_index_6g(u16 domain)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun u8 i = 0;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun for (i = 0; i < MAX_RD_MAP_NUM_6GHZ; i++) {
184*4882a593Smuzhiyun if (domain == rdmap6[i].domain_code) {
185*4882a593Smuzhiyun return i;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun return MAX_RD_MAP_NUM_6GHZ;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
_regulatory_domain_update_6g(struct rtw_regulation * rg,u16 domain,enum regulation_rsn reason)192*4882a593Smuzhiyun static bool _regulatory_domain_update_6g(struct rtw_regulation *rg,
193*4882a593Smuzhiyun u16 domain, enum regulation_rsn reason)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun u8 regulation = REGULATION_NA;
196*4882a593Smuzhiyun u8 ch_idx = 0, did = 0;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun rg->domain_6g.reason = reason;
199*4882a593Smuzhiyun if (domain == RSVD_DOMAIN) {
200*4882a593Smuzhiyun rg->domain_6g.code = RSVD_DOMAIN;
201*4882a593Smuzhiyun return true;
202*4882a593Smuzhiyun } else {
203*4882a593Smuzhiyun /* Note: only valid domain index can reach here */
204*4882a593Smuzhiyun did = _domain_index_6g(domain);
205*4882a593Smuzhiyun rg->domain_6g.code = rdmap6[did].domain_code;
206*4882a593Smuzhiyun regulation = rdmap6[did].regulation;
207*4882a593Smuzhiyun ch_idx = rdmap6[did].ch_idx;
208*4882a593Smuzhiyun return _chnlplan_update_6g(rg, regulation, ch_idx);
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
_get_group_chplan_6g(struct rtw_regulation * rg,struct rtw_regulation_chplan_group * group,struct rtw_regulation_chplan * plan)212*4882a593Smuzhiyun static void _get_group_chplan_6g(struct rtw_regulation *rg,
213*4882a593Smuzhiyun struct rtw_regulation_chplan_group *group,
214*4882a593Smuzhiyun struct rtw_regulation_chplan *plan)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun u32 i = 0;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun for (i = 0; i < group->cnt; i++) {
219*4882a593Smuzhiyun if (group->ch[i].channel) {
220*4882a593Smuzhiyun plan->ch[plan->cnt].band =
221*4882a593Smuzhiyun group->ch[i].band;
222*4882a593Smuzhiyun plan->ch[plan->cnt].channel =
223*4882a593Smuzhiyun group->ch[i].channel;
224*4882a593Smuzhiyun plan->ch[plan->cnt].property =
225*4882a593Smuzhiyun group->ch[i].property;
226*4882a593Smuzhiyun plan->cnt++;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
_history_log_6g(struct rtw_regulation * rg,u16 domain,u8 reason)231*4882a593Smuzhiyun static void _history_log_6g(struct rtw_regulation *rg, u16 domain, u8 reason)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun rg->history_6g[rg->history_cnt_6g].code = domain;
234*4882a593Smuzhiyun rg->history_6g[rg->history_cnt_6g].reason = reason;
235*4882a593Smuzhiyun rg->history_cnt_6g++;
236*4882a593Smuzhiyun if (rg->history_cnt_6g >= MAX_HISTORY_NUM)
237*4882a593Smuzhiyun rg->history_cnt_6g = 0;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
regu_get_chnlplan_6g(struct rtw_regulation * rg,enum rtw_regulation_query type,struct rtw_regulation_chplan * plan)240*4882a593Smuzhiyun void regu_get_chnlplan_6g(struct rtw_regulation *rg,
241*4882a593Smuzhiyun enum rtw_regulation_query type,
242*4882a593Smuzhiyun struct rtw_regulation_chplan *plan)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun struct rtw_regulation_chplan_group *group = NULL;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /* 6ghz */
247*4882a593Smuzhiyun if (rg->capability & CAPABILITY_6GHZ) {
248*4882a593Smuzhiyun /* unii5 */
249*4882a593Smuzhiyun if (type == REGULQ_CHPLAN_6GHZ ||
250*4882a593Smuzhiyun type == REGULQ_CHPLAN_6GHZ_UNII5) {
251*4882a593Smuzhiyun group = &rg->chplan[FREQ_GROUP_6GHZ_UNII5];
252*4882a593Smuzhiyun _get_group_chplan_6g(rg, group, plan);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun /* unii6 */
255*4882a593Smuzhiyun if (type == REGULQ_CHPLAN_6GHZ ||
256*4882a593Smuzhiyun type == REGULQ_CHPLAN_6GHZ_UNII6) {
257*4882a593Smuzhiyun group = &rg->chplan[FREQ_GROUP_6GHZ_UNII6];
258*4882a593Smuzhiyun _get_group_chplan_6g(rg, group, plan);
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun /* unii7 */
261*4882a593Smuzhiyun if (type == REGULQ_CHPLAN_6GHZ ||
262*4882a593Smuzhiyun type == REGULQ_CHPLAN_6GHZ_UNII7) {
263*4882a593Smuzhiyun group = &rg->chplan[FREQ_GROUP_6GHZ_UNII7];
264*4882a593Smuzhiyun _get_group_chplan_6g(rg, group, plan);
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun /* unii8 */
267*4882a593Smuzhiyun if (type == REGULQ_CHPLAN_6GHZ ||
268*4882a593Smuzhiyun type == REGULQ_CHPLAN_6GHZ_UNII8) {
269*4882a593Smuzhiyun group = &rg->chplan[FREQ_GROUP_6GHZ_UNII8];
270*4882a593Smuzhiyun _get_group_chplan_6g(rg, group, plan);
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun /* psc */
273*4882a593Smuzhiyun if (type == REGULQ_CHPLAN_FULL ||
274*4882a593Smuzhiyun type == REGULQ_CHPLAN_6GHZ_PSC) {
275*4882a593Smuzhiyun group = &rg->chplan[FREQ_GROUP_6GHZ_PSC];
276*4882a593Smuzhiyun _get_group_chplan_6g(rg, group, plan);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
regu_valid_domain_6g(u16 domain)281*4882a593Smuzhiyun bool regu_valid_domain_6g(u16 domain)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun if (domain == RSVD_DOMAIN)
284*4882a593Smuzhiyun return true;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun if (_domain_index_6g(domain) >= MAX_RD_MAP_NUM_6GHZ)
287*4882a593Smuzhiyun return false;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun return true;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
regu_set_domain_6g(void * phl,u16 domain,enum regulation_rsn reason)292*4882a593Smuzhiyun bool regu_set_domain_6g(void *phl, u16 domain,
293*4882a593Smuzhiyun enum regulation_rsn reason)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun struct phl_info_t *phl_info = (struct phl_info_t *)phl;
296*4882a593Smuzhiyun struct rtw_regulation *rg = NULL;
297*4882a593Smuzhiyun void *d = NULL;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun PHL_INFO("[REGU], set 6 ghz domain code = 0x%x, reason = 0x%x\n",
300*4882a593Smuzhiyun domain, reason);
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun if (!phl_info)
303*4882a593Smuzhiyun return false;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun rg = &phl_info->regulation;
306*4882a593Smuzhiyun if (!rg->init)
307*4882a593Smuzhiyun return false;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun if (!regu_valid_domain_6g(domain))
310*4882a593Smuzhiyun return false;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun d = phl_to_drvpriv(phl_info);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun _os_spinlock(d, &rg->lock, _bh, NULL);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun _history_log_6g(rg, domain, reason);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (_regulatory_domain_update_6g(rg, domain, reason))
319*4882a593Smuzhiyun rg->valid_6g = true;
320*4882a593Smuzhiyun else {
321*4882a593Smuzhiyun rg->valid_6g = false;
322*4882a593Smuzhiyun rg->invalid_cnt_6g++;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun _os_spinunlock(d, &rg->lock, _bh, NULL);
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun PHL_INFO("[REGU], 6 ghz domain code valid = %d\n", rg->valid_6g);
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun return rg->valid_6g;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun
332