xref: /wlan-driver/qca-wifi-host-cmn/umac/regulatory/core/src/reg_opclass.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: reg_opclass.c
22  * This file defines regulatory opclass functions.
23  */
24 
25 #include <qdf_types.h>
26 #include <wlan_cmn.h>
27 #include <reg_services_public_struct.h>
28 #include <wlan_objmgr_psoc_obj.h>
29 #include <wlan_objmgr_pdev_obj.h>
30 #include "reg_priv_objs.h"
31 #include "reg_utils.h"
32 #include "reg_db.h"
33 #include "reg_db_parser.h"
34 #include "reg_host_11d.h"
35 #include <scheduler_api.h>
36 #include "reg_build_chan_list.h"
37 #include "reg_opclass.h"
38 #include "reg_services_common.h"
39 #include <wlan_objmgr_pdev_obj.h>
40 #ifdef QCA_SUPPORT_DFS_CHAN_POSTNOL
41 #include <dfs_postnol_ucfg.h>
42 #include <wlan_reg_channel_api.h>
43 #endif
44 
45 #ifdef HOST_OPCLASS
46 static struct reg_dmn_supp_op_classes reg_dmn_curr_supp_opp_classes = { 0 };
47 #endif
48 
49 /*
50  * Given a global opclass number create the corresponding  array token.
51  * Examples:
52  *     'CFISARR(132)' expands to  'opcls_132_cfis_arr'
53  *     'CFISARR(133)' expands to  'opcls_133_cfis_arr'
54  */
55 #define CFISARR(_g_opcls)  opcls_ ## _g_opcls ## _cfis_arr
56 
57 /*
58  * Given a global opclass number create the corresponding list token.
59  * Examples:
60  *     'CFISLST(132)' expands to  'opcls_132_cfis_lst'
61  *     'CFISLST(133)' expands to  'opcls_133_cfis_lst'
62  */
63 #define CFISLST(_g_opcls)  opcls_ ## _g_opcls ## _cfis_lst
64 
65 /* The type of the opclass list objects */
66 #define CFISLST_TYPE static const struct c_freq_lst
67 
68 /* The number of elements of the array */
69 #define NELEMS QDF_ARRAY_SIZE
70 
71 /*
72  * Given a global opclass number create the corresponding cfis list and assign
73  * the corresponding cfis array and size of the cfis array
74  * Examples:
75  *     'CREATE_CFIS_LST(132);'
76  *     expands to
77  *     '
78  *     static const struct c_freq_lst opcls_132_cfis_lst =
79  *                   {QDF_ARRAY_SIZE(opcls_132_cfis_arr), opcls_132_cfis_arr};
80  *     '
81  *
82  *     'CREATE_CFIS_LST(133);'
83  *     expands to
84  *     '
85  *     static const struct c_freq_lst opcls_133_cfis_lst =
86  *                   {QDF_ARRAY_SIZE(opcls_133_cfis_arr), opcls_133_cfis_arr};
87  *     '
88  */
89 #define CREATE_CFIS_LST(_gopcls) \
90 CFISLST_TYPE CFISLST(_gopcls) = {NELEMS(CFISARR(_gopcls)), CFISARR(_gopcls)}
91 
92 /* The NULL pointer to a cfis list object */
93 #define NULL_CFIS_LST NULL
94 
95 /* CFIs for global opclass 131: (start Freq=5925 BW=20MHz) */
96 static const uint8_t opcls_131_cfis_arr[] = {
97 #ifdef CONFIG_AFC_SUPPORT
98 	  1, 5, 9, 13, 17, 21, 25, 29, 33,
99 	  37, 41, 45, 49, 53, 57, 61, 65, 69,
100 	  73, 77, 81, 85, 89, 93, 97,
101 	  101, 105, 109, 113, 117, 121, 125,
102 	  129, 133, 137, 141, 145, 149, 153,
103 	  157, 161, 165, 169, 173, 177, 181,
104 	  185, 189, 193, 197, 201, 205, 209,
105 	  213, 217, 221, 225, 229, 233,
106 #endif
107 };
108 
109 /* CFIs for global opclass 132: (start Freq=5925 BW=40MHz) */
110 static const uint8_t opcls_132_cfis_arr[] = {
111 #ifdef CONFIG_AFC_SUPPORT
112 	3, 11, 19, 27, 35, 43, 51, 59, 67, 75,
113 	83, 91, 99, 107, 115, 123, 131, 139, 147, 155,
114 	163, 171, 179, 187, 195, 203, 211, 219, 227,
115 #endif
116 };
117 
118 /* CFIs for global opclass 133: (start Freq=5925 BW=80MHz) */
119 static const uint8_t opcls_133_cfis_arr[] = {
120 #ifdef CONFIG_AFC_SUPPORT
121 	7, 23, 39, 55, 71, 87, 103, 119, 135, 151, 167, 183,
122 	  199, 215,
123 #endif
124 };
125 
126 /* CFIs for global opclass 134: (start Freq=5950 BW=160MHz) */
127 static const uint8_t opcls_134_cfis_arr[] = {
128 #ifdef CONFIG_AFC_SUPPORT
129 	15, 47, 79, 111, 143, 175, 207,
130 #endif
131 };
132 
133 /* CFIs for global opclass 135: (start Freq=5950 BW=80MHz+80MHz) */
134 static const uint8_t opcls_135_cfis_arr[] = {
135 #ifdef CONFIG_AFC_SUPPORT
136 	7, 23, 39, 55, 71, 87, 103, 119, 135, 151, 167, 183,
137 	199, 215,
138 #endif
139 };
140 
141 /* CFIs for global opclass 136: (start Freq=5925 BW=20MHz) */
142 static const uint8_t opcls_136_cfis_arr[] = {
143 #ifdef CONFIG_AFC_SUPPORT
144 	2,
145 #endif
146 };
147 
148 /* CFIs for global opclass 137: (start Freq=5950 BW=320MHz) */
149 #ifdef WLAN_FEATURE_11BE
150 static const uint8_t opcls_137_cfis_arr[] = {
151 #ifdef CONFIG_AFC_SUPPORT
152 	31, 63, 95, 127, 159, 191,
153 #endif
154 };
155 #endif
156 
157 /* Create the CFIS static constant lists */
158 CREATE_CFIS_LST(131);
159 CREATE_CFIS_LST(132);
160 CREATE_CFIS_LST(133);
161 CREATE_CFIS_LST(134);
162 CREATE_CFIS_LST(135);
163 CREATE_CFIS_LST(136);
164 #ifdef WLAN_FEATURE_11BE
165 CREATE_CFIS_LST(137);
166 #endif
167 
168 static const struct reg_dmn_op_class_map_t global_op_class[] = {
169 	{81, 25, BW20, BIT(BEHAV_NONE), 2407,
170 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
171 	 NULL_CFIS_LST },
172 	{82, 25, BW20, BIT(BEHAV_NONE), 2414,
173 	 {14},
174 	 NULL_CFIS_LST },
175 	{83, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407,
176 	 {1, 2, 3, 4, 5, 6, 7, 8, 9},
177 	 NULL_CFIS_LST },
178 	{84, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407,
179 	 {5, 6, 7, 8, 9, 10, 11, 12, 13},
180 	 NULL_CFIS_LST },
181 	{115, 20, BW20, BIT(BEHAV_NONE), 5000,
182 	 {36, 40, 44, 48},
183 	 NULL_CFIS_LST },
184 	{116, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
185 	 {36, 44},
186 	 NULL_CFIS_LST },
187 	{117, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
188 	 {40, 48},
189 	 NULL_CFIS_LST },
190 	{118, 20, BW20, BIT(BEHAV_NONE), 5000,
191 	 {52, 56, 60, 64},
192 	 NULL_CFIS_LST },
193 	{119, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
194 	 {52, 60},
195 	 NULL_CFIS_LST },
196 	{120, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
197 	 {56, 64},
198 	 NULL_CFIS_LST },
199 	{121, 20, BW20, BIT(BEHAV_NONE), 5000,
200 	 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144},
201 	 NULL_CFIS_LST },
202 	{122, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
203 	 {100, 108, 116, 124, 132, 140},
204 	 NULL_CFIS_LST },
205 	{123, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
206 	 {104, 112, 120, 128, 136, 144},
207 	 NULL_CFIS_LST },
208 	{125, 20, BW20, BIT(BEHAV_NONE), 5000,
209 	 {149, 153, 157, 161, 165, 169, 173, 177},
210 	 NULL_CFIS_LST },
211 	{126, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
212 	 {149, 157, 165, 173},
213 	 NULL_CFIS_LST },
214 	{127, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
215 	 {153, 161, 169, 177},
216 	 NULL_CFIS_LST },
217 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
218 	 {36, 40, 44, 48, 52, 56, 60, 64,
219 	  100, 104, 108, 112, 116, 120, 124, 128,
220 	  132, 136, 140, 144, 149, 153, 157, 161,
221 	  165, 169, 173, 177},
222 	  NULL_CFIS_LST },
223 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
224 	 {36, 40, 44, 48, 52, 56, 60, 64,
225 	  100, 104, 108, 112, 116, 120, 124, 128,
226 	  149, 153, 157, 161, 165, 169, 173, 177},
227 	 NULL_CFIS_LST },
228 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
229 	 {36, 40, 44, 48, 52, 56, 60, 64,
230 	  100, 104, 108, 112, 116, 120, 124, 128,
231 	  132, 136, 140, 144, 149, 153, 157, 161,
232 	  165, 169, 173, 177},
233 	 NULL_CFIS_LST },
234 
235 #ifdef CONFIG_BAND_6GHZ
236 	{131, 20, BW20, BIT(BEHAV_NONE), 5950,
237 	 {1, 5, 9, 13, 17, 21, 25, 29, 33,
238 	  37, 41, 45, 49, 53, 57, 61, 65, 69,
239 	  73, 77, 81, 85, 89, 93, 97,
240 	  101, 105, 109, 113, 117, 121, 125,
241 	  129, 133, 137, 141, 145, 149, 153,
242 	  157, 161, 165, 169, 173, 177, 181,
243 	  185, 189, 193, 197, 201, 205, 209,
244 	  213, 217, 221, 225, 229, 233},
245 	&CFISLST(131)},
246 
247 	{132, 40, BW40_LOW_PRIMARY, BIT(BEHAV_NONE), 5950,
248 	 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49,
249 	  53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97,
250 	  101, 105, 109, 113, 117, 121, 125, 129, 133, 137,
251 	  141, 145, 149, 153, 157, 161, 165, 169, 173, 177,
252 	  181, 185, 189, 193, 197, 201, 205, 209, 213, 217,
253 	  221, 225, 229, 233},
254 	&CFISLST(132)},
255 
256 	{133, 80, BW80, BIT(BEHAV_NONE), 5950,
257 	 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49,
258 	  53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97,
259 	  101, 105, 109, 113, 117, 121, 125, 129, 133, 137,
260 	  141, 145, 149, 153, 157, 161, 165, 169, 173,
261 	  177, 181, 185, 189, 193, 197, 201, 205, 209, 213,
262 	  217, 221, 225, 229, 233},
263 	&CFISLST(133)},
264 
265 	{134, 160, BW80, BIT(BEHAV_NONE), 5950,
266 	 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45,
267 	  49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89,
268 	  93, 97, 101, 105, 109, 113, 117, 121, 125,
269 	  129, 133, 137, 141, 145, 149, 153, 157, 161,
270 	  165, 169, 173, 177, 181, 185, 189, 193, 197,
271 	     201, 205, 209, 213, 217, 221, 225, 229, 233},
272 	&CFISLST(134)},
273 
274 	{135, 80, BW80, BIT(BEHAV_BW80_PLUS), 5950,
275 	 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41,
276 	  45, 49, 53, 57, 61, 65, 69, 73, 77, 81,
277 	  85, 89, 93, 97, 101, 105, 109, 113, 117,
278 	  121, 125, 129, 133, 137, 141, 145, 149,
279 	  153, 157, 161, 165, 169, 173, 177, 181,
280 	  185, 189, 193, 197, 201, 205, 209, 213,
281 	  217, 221, 225, 229, 233},
282 	&CFISLST(135)},
283 
284 	{136, 20, BW20, BIT(BEHAV_NONE), 5925,
285 	 {2},
286 	&CFISLST(136)},
287 #ifdef WLAN_FEATURE_11BE
288 	{137, 320, BW20, BIT(BEHAV_NONE), 5950,
289 	 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41,
290 	  45, 49, 53, 57, 61, 65, 69, 73, 77, 81,
291 	  85, 89, 93, 97, 101, 105, 109, 113, 117,
292 	  121, 125, 129, 133, 137, 141, 145, 149,
293 	  153, 157, 161, 165, 169, 173, 177, 181,
294 	  185, 189, 193, 197, 201, 205, 209, 213,
295 	  217, 221, 225, 229, 233},
296 	&CFISLST(137)},
297 #endif
298 #endif
299 	{0, 0, 0, 0, 0, {0},
300 	NULL_CFIS_LST },
301 };
302 
303 static const struct reg_dmn_op_class_map_t us_op_class[] = {
304 	{1, 20, BW20, BIT(BEHAV_NONE), 5000,
305 	 {36, 40, 44, 48},
306 	 NULL_CFIS_LST },
307 	{2, 20, BW20, BIT(BEHAV_NONE), 5000,
308 	 {52, 56, 60, 64},
309 	 NULL_CFIS_LST },
310 	{4, 20, BW20, BIT(BEHAV_NONE), 5000,
311 	 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144},
312 	 NULL_CFIS_LST },
313 	{5, 20, BW20, BIT(BEHAV_NONE), 5000,
314 	 {149, 153, 157, 161, 165},
315 	 NULL_CFIS_LST },
316 	{12, 25, BW20, BIT(BEHAV_NONE), 2407,
317 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
318 	 NULL_CFIS_LST },
319 	{22, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
320 	 {36, 44},
321 	 NULL_CFIS_LST },
322 	{23, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
323 	 {52, 60},
324 	 NULL_CFIS_LST },
325 	{24, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
326 	 {100, 108, 116, 124, 132, 140},
327 	 NULL_CFIS_LST },
328 	{26, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
329 	 {149, 157},
330 	 NULL_CFIS_LST },
331 	{27, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
332 	 {40, 48},
333 	 NULL_CFIS_LST },
334 	{28, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
335 	 {56, 64},
336 	 NULL_CFIS_LST },
337 	{29, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
338 	 {104, 112, 120, 128, 136, 144},
339 	 NULL_CFIS_LST },
340 	{30, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
341 	 {153, 161},
342 	 NULL_CFIS_LST },
343 	{31, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
344 	 {153, 161},
345 	 NULL_CFIS_LST },
346 	{32, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407,
347 	 {1, 2, 3, 4, 5, 6, 7},
348 	 NULL_CFIS_LST },
349 	{33, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407,
350 	 {5, 6, 7, 8, 9, 10, 11},
351 	 NULL_CFIS_LST },
352 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
353 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
354 	  104, 108, 112, 116, 120, 124, 128, 132,
355 	  136, 140, 144, 149, 153, 157, 161},
356 	 NULL_CFIS_LST },
357 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
358 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
359 	  104, 108, 112, 116, 120, 124, 128},
360 	 NULL_CFIS_LST },
361 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
362 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
363 	  104, 108, 112, 116, 120, 124, 128, 132,
364 	  136, 140, 144, 149, 153, 157, 161},
365 	 NULL_CFIS_LST },
366 	{0, 0, 0, 0, 0, {0},
367 	 NULL_CFIS_LST },
368 };
369 
370 static const struct reg_dmn_op_class_map_t euro_op_class[] = {
371 	{1, 20, BW20, BIT(BEHAV_NONE), 5000,
372 	 {36, 40, 44, 48},
373 	 NULL_CFIS_LST },
374 	{2, 20, BW20, BIT(BEHAV_NONE), 5000,
375 	 {52, 56, 60, 64},
376 	 NULL_CFIS_LST },
377 	{3, 20, BW20, BIT(BEHAV_NONE), 5000,
378 	 {100, 104, 108, 112, 116, 120,
379 	  124, 128, 132, 136, 140},
380 	 NULL_CFIS_LST },
381 	{4, 25, BW20, BIT(BEHAV_NONE), 2407,
382 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
383 	 NULL_CFIS_LST },
384 	{5, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
385 	 {36, 44},
386 	 NULL_CFIS_LST },
387 	{6, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
388 	 {52, 60},
389 	 NULL_CFIS_LST },
390 	{7, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
391 	 {100, 108, 116, 124, 132},
392 	 NULL_CFIS_LST },
393 	{8, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
394 	 {40, 48},
395 	 NULL_CFIS_LST },
396 	{9, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
397 	 {56, 64},
398 	 NULL_CFIS_LST },
399 	{10, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
400 	 {104, 112, 120, 128, 136},
401 	 NULL_CFIS_LST },
402 	{11, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407,
403 	 {1, 2, 3, 4, 5, 6, 7, 8, 9},
404 	 NULL_CFIS_LST },
405 	{12, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407,
406 	 {5, 6, 7, 8, 9, 10, 11, 12, 13},
407 	 NULL_CFIS_LST },
408 	{17, 20, BW20, BIT(BEHAV_NONE), 5000,
409 	 {149, 153, 157, 161, 165, 169},
410 	 NULL_CFIS_LST },
411 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
412 	 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
413 	  124, 128},
414 	 NULL_CFIS_LST },
415 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
416 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
417 	  104, 108, 112, 116, 120, 124, 128},
418 	 NULL_CFIS_LST },
419 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
420 	 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
421 	  124, 128},
422 	 NULL_CFIS_LST },
423 	{0, 0, 0, 0, 0, {0},
424 	 NULL_CFIS_LST },
425 };
426 
427 static const struct reg_dmn_op_class_map_t japan_op_class[] = {
428 	{1, 20, BW20, BIT(BEHAV_NONE), 5000,
429 	 {36, 40, 44, 48},
430 	 NULL_CFIS_LST },
431 	{30, 25, BW20, BIT(BEHAV_NONE), 2407,
432 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
433 	 NULL_CFIS_LST },
434 	{31, 25, BW20, BIT(BEHAV_NONE), 2414,
435 	 {14},
436 	 NULL_CFIS_LST },
437 	{32, 20, BW20, BIT(BEHAV_NONE), 5000,
438 	 {52, 56, 60, 64},
439 	 NULL_CFIS_LST },
440 	{34, 20, BW20, BIT(BEHAV_NONE), 5000,
441 	 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140},
442 	 NULL_CFIS_LST },
443 	{36, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
444 	 {36, 44},
445 	 NULL_CFIS_LST },
446 	{37, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
447 	 {52, 60},
448 	 NULL_CFIS_LST },
449 	{39, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
450 	 {100, 108, 116, 124, 132},
451 	 NULL_CFIS_LST },
452 	{41, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
453 	 {40, 48},
454 	 NULL_CFIS_LST },
455 	{42, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
456 	 {56, 64},
457 	 NULL_CFIS_LST },
458 	{44, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
459 	 {104, 112, 120, 128, 136},
460 	 NULL_CFIS_LST },
461 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
462 	 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
463 	  124, 128, 132, 136, 140, 144},
464 	 NULL_CFIS_LST },
465 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
466 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
467 	  104, 108, 112, 116, 120, 124, 128},
468 	 NULL_CFIS_LST },
469 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
470 	 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
471 	  124, 128, 132, 136, 140, 144},
472 	 NULL_CFIS_LST },
473 	{0, 0, 0, 0, 0, {0},
474 	 NULL_CFIS_LST },
475 };
476 
477 static const struct reg_dmn_op_class_map_t china_op_class[] = {
478 	{7, 25, BW20, BIT(BEHAV_NONE), 2407,
479 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
480 	 NULL_CFIS_LST },
481 	{8, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407,
482 	 {1, 2, 3, 4, 5, 6, 7, 8, 9},
483 	 NULL_CFIS_LST },
484 	{9, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407,
485 	 {5, 6, 7, 8, 9, 10, 11, 12, 13},
486 	 NULL_CFIS_LST },
487 	{1, 20, BW20, BIT(BEHAV_NONE), 5000,
488 	 {36, 40, 44, 48},
489 	 NULL_CFIS_LST },
490 	{4, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
491 	 {36, 44},
492 	 NULL_CFIS_LST },
493 	{117, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
494 	 {40, 48},
495 	 NULL_CFIS_LST },
496 	{2, 20, BW20, BIT(BEHAV_NONE), 5000,
497 	 {52, 56, 60, 64},
498 	 NULL_CFIS_LST },
499 	{5, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
500 	 {52, 60},
501 	 NULL_CFIS_LST },
502 	{3, 20, BW20, BIT(BEHAV_NONE), 5000,
503 	 {149, 153, 157, 161, 165},
504 	 NULL_CFIS_LST },
505 	{6, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
506 	 {149, 157},
507 	 NULL_CFIS_LST },
508 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
509 	 {36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161},
510 	 NULL_CFIS_LST },
511 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
512 	 {36, 40, 44, 48, 52, 56, 60, 64,},
513 	 NULL_CFIS_LST },
514 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
515 	 {36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161},
516 	 NULL_CFIS_LST },
517 	{0, 0, 0, 0, 0, {0},
518 	 NULL_CFIS_LST },
519 };
520 #ifdef HOST_OPCLASS
521 /**
522  * reg_get_class_from_country()- Get Class from country
523  * @country: Country
524  *
525  * Return: class.
526  */
527 static const struct reg_dmn_op_class_map_t
reg_get_class_from_country(const uint8_t * country)528 *reg_get_class_from_country(const uint8_t *country)
529 {
530 	const struct reg_dmn_op_class_map_t *class = NULL;
531 
532 	if (!country)
533 		return global_op_class;
534 
535 	reg_debug_rl("Country %c%c 0x%x", country[0], country[1], country[2]);
536 
537 	switch (country[2]) {
538 	case OP_CLASS_US:
539 		class = us_op_class;
540 		break;
541 
542 	case OP_CLASS_EU:
543 		class = euro_op_class;
544 		break;
545 
546 	case OP_CLASS_JAPAN:
547 		class = japan_op_class;
548 		break;
549 
550 	case OP_CLASS_GLOBAL:
551 		class = global_op_class;
552 		break;
553 
554 	case OP_CLASS_CHINA:
555 		class = china_op_class;
556 		break;
557 	default:
558 		if (!qdf_mem_cmp(country, "US", 2))
559 			class = us_op_class;
560 		else if (!qdf_mem_cmp(country, "EU", 2))
561 			class = euro_op_class;
562 		else if (!qdf_mem_cmp(country, "JP", 2))
563 			class = japan_op_class;
564 		else if (!qdf_mem_cmp(country, "CN", 2))
565 			class = china_op_class;
566 		else
567 			class = global_op_class;
568 	}
569 	return class;
570 }
571 
572 #ifdef CONFIG_AFC_SUPPORT
reg_is_range_valid(struct freq_range * range)573 static bool reg_is_range_valid(struct freq_range *range)
574 {
575 	return (range->right > range->left);
576 }
577 
578 /**
579  * reg_is_subrange() - Check if range_first is a subrange of range_second
580  * @range_first: Pointer to first range
581  * @range_second: Pointer to first range
582  *
583  * Return: True if the range_first is a subrange range_second, else false
584  */
reg_is_subrange(struct freq_range * range_first,struct freq_range * range_second)585 static bool reg_is_subrange(struct freq_range *range_first,
586 			    struct freq_range *range_second)
587 {
588 	bool is_subrange;
589 	bool is_valid;
590 
591 	is_valid = reg_is_range_valid(range_first) &&
592 		   reg_is_range_valid(range_second);
593 
594 	if (!is_valid)
595 		return false;
596 
597 	is_subrange = (range_first->left >= range_second->left) &&
598 		      (range_first->right <= range_second->right);
599 
600 	return is_subrange;
601 }
602 
603 /**
604  * reg_is_cfi_freq_in_ranges() - Check if the given 'cfi' in the any of the
605  * frequency ranges
606  * @cfi_freq: The center frequency index frequency
607  * @bw: bandwidth of the band with center freq cfi_freq
608  * @p_frange_lst: Pointer to frequency range list (AFC)
609  *
610  * return: True if the cfi is in the ranges, else false
611  */
reg_is_cfi_freq_in_ranges(qdf_freq_t cfi_freq,uint16_t bw,struct wlan_afc_frange_list * p_frange_lst)612 static bool reg_is_cfi_freq_in_ranges(qdf_freq_t cfi_freq,
613 				      uint16_t bw,
614 				      struct wlan_afc_frange_list *p_frange_lst)
615 {
616 	uint32_t num_ranges;
617 	struct wlan_afc_freq_range_obj *p_range_objs;
618 	uint8_t i;
619 	bool is_cfi_supported = false;
620 
621 	num_ranges = p_frange_lst->num_ranges;
622 	p_range_objs = &p_frange_lst->range_objs[0];
623 	for (i = 0; i <  num_ranges; i++) {
624 		qdf_freq_t cfi_band_left;
625 		qdf_freq_t cfi_band_right;
626 		struct freq_range range_cfi;
627 		struct freq_range range_chip;
628 
629 		cfi_band_left = cfi_freq - bw / 2;
630 		cfi_band_right = cfi_freq + bw / 2;
631 
632 		range_cfi = reg_init_freq_range(cfi_band_left,
633 						cfi_band_right);
634 		range_chip = reg_init_freq_range(p_range_objs->lowfreq,
635 						 p_range_objs->highfreq);
636 		is_cfi_supported = reg_is_subrange(&range_cfi, &range_chip);
637 
638 		if (is_cfi_supported)
639 			return true;
640 
641 		p_range_objs++;
642 	}
643 
644 	return is_cfi_supported;
645 }
646 
reg_dmn_free_6g_opclasses_and_channels(struct wlan_objmgr_pdev * pdev,uint8_t num_opclasses,uint8_t * opclass_lst,uint8_t * chansize_lst,uint8_t * channel_lists[])647 void reg_dmn_free_6g_opclasses_and_channels(struct wlan_objmgr_pdev *pdev,
648 					    uint8_t num_opclasses,
649 					    uint8_t *opclass_lst,
650 					    uint8_t *chansize_lst,
651 					    uint8_t *channel_lists[])
652 {
653 	/*
654 	 * All the elements of channel_lists were allocated as a single
655 	 * allocation with 'channel_lists[0]' holding the first location of the
656 	 * allocation. Therefore, freeing only 'channel_lists[0]' is enough.
657 	 * Freeing any other 'channel_lists[i]' will result in error of freeing
658 	 * unallocated memory.
659 
660 	 */
661 	if (channel_lists)
662 		qdf_mem_free(channel_lists[0]);
663 
664 	/*
665 	 * opclass_lst, chansize_lst and channel_lists were allocated as a
666 	 * single allocation with 'opclass_lst' holding the first location of
667 	 * allocation. Therefore, freeing only 'opclass_lst' is enough.
668 	 * Freeing chansize_lst, channel_lists will result in error of freeing
669 	 * unallocated memory.
670 	 */
671 	qdf_mem_free(opclass_lst);
672 }
673 
674 /**
675  * reg_dmn_get_num_6g_opclasses() - Calculate the number of opclasses in the
676  *                                  6 GHz band.
677  * @pdev: Pointer to pdev.
678  *
679  * Return: The number of opclasses
680  */
reg_dmn_get_num_6g_opclasses(struct wlan_objmgr_pdev * pdev)681 static uint8_t reg_dmn_get_num_6g_opclasses(struct wlan_objmgr_pdev *pdev)
682 {
683 	const struct reg_dmn_op_class_map_t *op_class_tbl;
684 	uint8_t count;
685 
686 	op_class_tbl = global_op_class;
687 
688 	count = 0;
689 	while (op_class_tbl && op_class_tbl->op_class) {
690 		const struct c_freq_lst *p_lst;
691 
692 		p_lst = op_class_tbl->p_cfi_lst_obj;
693 		if (p_lst &&
694 		    reg_is_6ghz_op_class(pdev, op_class_tbl->op_class))
695 			count++;
696 
697 		op_class_tbl++;
698 	}
699 
700 	return count;
701 }
702 
703 /**
704  * reg_dmn_fill_cfis() - Fill the cfis for the given
705  * opclass and frequency range.
706  * @op_class_tbl: Pointer to struct reg_dmn_op_class_map_t
707  * @p_lst: Pointer to struct c_freq_lst
708  * @p_frange_lst: Pointer to struct wlan_afc_frange_list
709  * @dst: Pointer to dst buffer
710  *
711  * Return: Number of valid cfis
712  */
713 static uint8_t
reg_dmn_fill_cfis(const struct reg_dmn_op_class_map_t * op_class_tbl,const struct c_freq_lst * p_lst,struct wlan_afc_frange_list * p_frange_lst,uint8_t * dst)714 reg_dmn_fill_cfis(const struct reg_dmn_op_class_map_t *op_class_tbl,
715 		  const struct c_freq_lst *p_lst,
716 		  struct wlan_afc_frange_list *p_frange_lst,
717 		  uint8_t *dst)
718 {
719 	uint8_t j;
720 	uint8_t cfi_idx = 0;
721 
722 	for (j = 0; j < p_lst->num_cfis; j++) {
723 		uint8_t cfi;
724 		qdf_freq_t cfi_freq;
725 		qdf_freq_t start_freq = op_class_tbl->start_freq;
726 		uint16_t bw = op_class_tbl->chan_spacing;
727 
728 		cfi = p_lst->p_cfis_arr[j];
729 		cfi_freq = start_freq + FREQ_TO_CHAN_SCALE * cfi;
730 
731 		if (reg_is_cfi_freq_in_ranges(cfi_freq, bw, p_frange_lst))
732 			dst[cfi_idx++] = cfi;
733 	}
734 	return cfi_idx;
735 }
736 
737 /**
738  * reg_is_unsupported_opclass() - Checks if the given opclass is unsupported or
739  * not.
740  * @pdev: Pointer to pdev.
741  * @op_class: Opclass number.
742  *
743  * Return: True if opclass is unsupported, else false.
744  */
745 static bool
reg_is_unsupported_opclass(struct wlan_objmgr_pdev * pdev,uint8_t op_class)746 reg_is_unsupported_opclass(struct wlan_objmgr_pdev *pdev, uint8_t op_class)
747 {
748 	return ((op_class == GLOBAL_6G_OPCLASS_80P80) &&
749 		(!reg_is_dev_supports_80p80(pdev)));
750 }
751 
752 /**
753  * reg_dmn_fill_6g_opcls_chan_lists() - Copy the channel lists for 6g opclasses
754  * to the output argument list ('channel_lists')
755  * @pdev: Pointer to pdev.
756  * @p_frange_lst: Pointer to frequency range list (AFC)
757  * @chansize_lst: Array of sizes of channel lists
758  * @channel_lists: The array list pointers where the channel lists are to be
759  *                 copied.
760  *
761  * Return: Void
762  */
reg_dmn_fill_6g_opcls_chan_lists(struct wlan_objmgr_pdev * pdev,struct wlan_afc_frange_list * p_frange_lst,uint8_t chansize_lst[],uint8_t * channel_lists[])763 static void reg_dmn_fill_6g_opcls_chan_lists(struct wlan_objmgr_pdev *pdev,
764 					     struct wlan_afc_frange_list *p_frange_lst,
765 					     uint8_t chansize_lst[],
766 					     uint8_t *channel_lists[])
767 {
768 	uint8_t i = 0;
769 	const struct reg_dmn_op_class_map_t *op_class_tbl;
770 
771 	op_class_tbl = global_op_class;
772 
773 	while (op_class_tbl && op_class_tbl->op_class) {
774 		const struct c_freq_lst *p_lst;
775 
776 		p_lst = op_class_tbl->p_cfi_lst_obj;
777 		if (p_lst &&
778 		    reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) {
779 			uint8_t *dst;
780 			uint8_t num_valid_cfi = 0;
781 
782 			if (reg_is_unsupported_opclass(pdev, op_class_tbl->op_class)) {
783 				op_class_tbl++;
784 				continue;
785 			}
786 
787 			dst = channel_lists[i];
788 			if (!dst) {
789 				reg_debug("dest list empty\n");
790 				return;
791 			}
792 			num_valid_cfi = reg_dmn_fill_cfis(op_class_tbl, p_lst,
793 							  p_frange_lst, dst);
794 			if (num_valid_cfi)
795 				i++;
796 
797 		}
798 		op_class_tbl++;
799 	}
800 }
801 
reg_dmn_get_6g_opclasses_and_channels(struct wlan_objmgr_pdev * pdev,struct wlan_afc_frange_list * p_frange_lst,uint8_t * num_opclasses,uint8_t ** opclass_lst,uint8_t ** chansize_lst,uint8_t ** channel_lists[])802 QDF_STATUS reg_dmn_get_6g_opclasses_and_channels(struct wlan_objmgr_pdev *pdev,
803 						 struct wlan_afc_frange_list *p_frange_lst,
804 						 uint8_t *num_opclasses,
805 						 uint8_t **opclass_lst,
806 						 uint8_t **chansize_lst,
807 						 uint8_t **channel_lists[])
808 {
809 	const struct reg_dmn_op_class_map_t *op_class_tbl;
810 	uint8_t *l_opcls_lst;
811 	uint8_t *l_chansize_lst;
812 	uint8_t count;
813 	uint8_t i;
814 	uint8_t **arr_chan_lists;
815 	uint16_t total_alloc_size;
816 	uint16_t opcls_lst_size;
817 	uint16_t chansize_lst_size;
818 	uint16_t arr_chan_lists_size;
819 	uint8_t *p_total_alloc1;
820 	uint8_t *p_total_alloc2;
821 	uint8_t *p_temp_alloc;
822 	uint8_t n_tot_opclss;
823 
824 	*opclass_lst = NULL;
825 	*chansize_lst =  NULL;
826 	*channel_lists = NULL;
827 	*num_opclasses = 0;
828 
829 	op_class_tbl = global_op_class;
830 	n_tot_opclss = reg_dmn_get_num_6g_opclasses(pdev);
831 	opcls_lst_size = n_tot_opclss * sizeof(uint8_t);
832 	chansize_lst_size = n_tot_opclss * sizeof(uint8_t);
833 	arr_chan_lists_size = n_tot_opclss * sizeof(uint8_t *);
834 
835 	total_alloc_size = 0;
836 	total_alloc_size += opcls_lst_size
837 		+ chansize_lst_size
838 		+ arr_chan_lists_size;
839 
840 	if (!total_alloc_size) {
841 		reg_err("Number of Opclasses is zero");
842 		return QDF_STATUS_E_INVAL;
843 	}
844 
845 	p_total_alloc1 = qdf_mem_malloc(total_alloc_size);
846 	if (!p_total_alloc1) {
847 		return QDF_STATUS_E_NOMEM;
848 	}
849 
850 	 /* Assign memory locations to each pointers */
851 	p_temp_alloc = p_total_alloc1;
852 
853 	l_opcls_lst = p_temp_alloc;
854 	p_temp_alloc += opcls_lst_size;
855 
856 	l_chansize_lst = p_temp_alloc;
857 	p_temp_alloc += chansize_lst_size;
858 
859 	arr_chan_lists = (uint8_t **)p_temp_alloc;
860 
861 	/* Fill arrays with opclasses and chanlist sizes */
862 	count = 0;
863 	while (op_class_tbl && op_class_tbl->op_class) {
864 		const struct c_freq_lst *p_lst;
865 		uint8_t op_class = op_class_tbl->op_class;
866 
867 		p_lst = op_class_tbl->p_cfi_lst_obj;
868 		if (p_lst &&
869 		    reg_is_6ghz_op_class(pdev, op_class)) {
870 			uint8_t n_supp_cfis = 0;
871 			uint8_t j;
872 
873 			if (reg_is_unsupported_opclass(pdev, op_class)) {
874 				op_class_tbl++;
875 				continue;
876 			}
877 
878 			for (j = 0; j < p_lst->num_cfis; j++) {
879 				uint8_t cfi;
880 				qdf_freq_t cfi_freq;
881 				qdf_freq_t start_freq = op_class_tbl->start_freq;
882 				uint16_t bw = op_class_tbl->chan_spacing;
883 
884 				cfi = p_lst->p_cfis_arr[j];
885 				cfi_freq = start_freq +
886 					FREQ_TO_CHAN_SCALE * cfi;
887 				if (reg_is_cfi_freq_in_ranges(cfi_freq,
888 							      bw,
889 							      p_frange_lst)) {
890 					n_supp_cfis++;
891 				}
892 			}
893 			/* Fill opclass number, num cfis and increment
894 			 * num_opclasses only if the cfi of the opclass
895 			 * is within the frequency range of interest.
896 			 */
897 			if (n_supp_cfis) {
898 				l_chansize_lst[count] = n_supp_cfis;
899 				l_opcls_lst[count] = op_class;
900 				(*num_opclasses)++;
901 				count++;
902 			}
903 		}
904 		op_class_tbl++;
905 	}
906 
907 	/* Calculate total allocation size for the array */
908 	total_alloc_size = 0;
909 	for (i = 0; i < *num_opclasses; i++)
910 		total_alloc_size += l_chansize_lst[i] * sizeof(uint8_t *);
911 
912 	if (!total_alloc_size) {
913 		reg_err("Number of Opclasses is zero");
914 		qdf_mem_free(p_total_alloc1);
915 		return QDF_STATUS_E_INVAL;
916 	}
917 
918 	p_total_alloc2 = qdf_mem_malloc(total_alloc_size);
919 	if (!p_total_alloc2) {
920 		qdf_mem_free(p_total_alloc1);
921 		return QDF_STATUS_E_NOMEM;
922 	}
923 
924 	/* Assign memory locations to each list pointers */
925 	p_temp_alloc = p_total_alloc2;
926 	for (i = 0; i < *num_opclasses; i++) {
927 		if (!l_chansize_lst[i])
928 			arr_chan_lists[i] = NULL;
929 		else
930 			arr_chan_lists[i] = p_temp_alloc;
931 
932 		p_temp_alloc += l_chansize_lst[i] * sizeof(uint8_t *);
933 	}
934 
935 	/* Fill the array with channel lists */
936 	reg_dmn_fill_6g_opcls_chan_lists(pdev, p_frange_lst, l_chansize_lst, arr_chan_lists);
937 
938 	*opclass_lst = l_opcls_lst;
939 	*chansize_lst = l_chansize_lst;
940 	*channel_lists = arr_chan_lists;
941 
942 	return QDF_STATUS_SUCCESS;
943 }
944 #endif /* CONFIG_AFC_SUPPORT */
945 
reg_dmn_get_chanwidth_from_opclass(uint8_t * country,uint8_t channel,uint8_t opclass)946 uint16_t reg_dmn_get_chanwidth_from_opclass(uint8_t *country, uint8_t channel,
947 					    uint8_t opclass)
948 {
949 	const struct reg_dmn_op_class_map_t *class;
950 	uint16_t i;
951 
952 	class = reg_get_class_from_country(country);
953 
954 	while (class->op_class) {
955 		if (opclass == class->op_class) {
956 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
957 				     class->channels[i]); i++) {
958 				if (channel == class->channels[i])
959 					return class->chan_spacing;
960 			}
961 		}
962 		class++;
963 	}
964 
965 	return 0;
966 }
967 
reg_dmn_get_chanwidth_from_opclass_auto(uint8_t * country,uint8_t channel,uint8_t opclass)968 uint16_t reg_dmn_get_chanwidth_from_opclass_auto(uint8_t *country,
969 						 uint8_t channel,
970 						 uint8_t opclass)
971 {
972 	uint16_t ret;
973 	uint8_t global_country[REG_ALPHA2_LEN + 1];
974 
975 	ret = reg_dmn_get_chanwidth_from_opclass(country, channel, opclass);
976 
977 	if (!ret) {
978 		global_country[2] = OP_CLASS_GLOBAL;
979 		ret = reg_dmn_get_chanwidth_from_opclass(global_country,
980 							 channel, opclass);
981 	}
982 
983 	return ret;
984 }
985 
reg_dmn_get_opclass_from_channel(uint8_t * country,uint8_t channel,uint8_t offset)986 uint16_t reg_dmn_get_opclass_from_channel(uint8_t *country, uint8_t channel,
987 					  uint8_t offset)
988 {
989 	const struct reg_dmn_op_class_map_t *class = NULL;
990 	uint16_t i = 0;
991 
992 	class = reg_get_class_from_country(country);
993 	while (class && class->op_class) {
994 		if ((offset == class->offset) || (offset == BWALL)) {
995 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
996 				     class->channels[i]); i++) {
997 				if (channel == class->channels[i])
998 					return class->op_class;
999 			}
1000 		}
1001 		class++;
1002 	}
1003 
1004 	return 0;
1005 }
1006 
reg_dmn_get_opclass_from_freq_width(uint8_t * country,qdf_freq_t freq,uint16_t ch_width,uint16_t behav_limit)1007 uint8_t reg_dmn_get_opclass_from_freq_width(uint8_t *country,
1008 					    qdf_freq_t freq,
1009 					    uint16_t ch_width,
1010 					    uint16_t behav_limit)
1011 {
1012 	const struct reg_dmn_op_class_map_t *op_class_tbl = NULL;
1013 	uint16_t i = 0;
1014 
1015 	op_class_tbl = reg_get_class_from_country(country);
1016 
1017 	while (op_class_tbl && op_class_tbl->op_class) {
1018 		if (op_class_tbl->chan_spacing == ch_width) {
1019 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1020 				     op_class_tbl->channels[i]); i++) {
1021 				if ((op_class_tbl->start_freq +
1022 				     (FREQ_TO_CHAN_SCALE *
1023 				      op_class_tbl->channels[i]) == freq) &&
1024 				    (behav_limit & op_class_tbl->behav_limit)) {
1025 					return op_class_tbl->op_class;
1026 				}
1027 			}
1028 		}
1029 		op_class_tbl++;
1030 	}
1031 
1032 	return 0;
1033 }
1034 
1035 static void
reg_get_band_cap_from_chan_set(const struct reg_dmn_op_class_map_t * op_class_tbl,uint8_t * supported_band)1036 reg_get_band_cap_from_chan_set(const struct reg_dmn_op_class_map_t
1037 			       *op_class_tbl,
1038 			       uint8_t *supported_band)
1039 {
1040 	qdf_freq_t chan_freq = op_class_tbl->start_freq +
1041 						(op_class_tbl->channels[0] *
1042 						 FREQ_TO_CHAN_SCALE);
1043 
1044 	if (reg_is_24ghz_ch_freq(chan_freq))
1045 		*supported_band |= BIT(REG_BAND_2G);
1046 	else if (reg_is_5ghz_ch_freq(chan_freq))
1047 		*supported_band |= BIT(REG_BAND_5G);
1048 	else if (reg_is_6ghz_chan_freq(chan_freq))
1049 		*supported_band |= BIT(REG_BAND_6G);
1050 	else
1051 		reg_err_rl("Unknown band");
1052 }
1053 
reg_get_band_cap_from_op_class(const uint8_t * country,uint8_t num_of_opclass,const uint8_t * opclass)1054 uint8_t reg_get_band_cap_from_op_class(const uint8_t *country,
1055 				       uint8_t num_of_opclass,
1056 				       const uint8_t *opclass)
1057 {
1058 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1059 	uint8_t supported_band = 0, opclassidx;
1060 
1061 	op_class_tbl = reg_get_class_from_country(country);
1062 
1063 	while (op_class_tbl && op_class_tbl->op_class) {
1064 		for (opclassidx = 0; opclassidx < num_of_opclass;
1065 		     opclassidx++) {
1066 			if (op_class_tbl->op_class == opclass[opclassidx]) {
1067 				reg_get_band_cap_from_chan_set(op_class_tbl,
1068 							       &supported_band);
1069 			}
1070 		}
1071 		op_class_tbl++;
1072 	}
1073 
1074 	if (!supported_band)
1075 		reg_err_rl("None of the operating classes is found");
1076 
1077 	return supported_band;
1078 }
1079 
reg_dmn_print_channels_in_opclass(uint8_t * country,uint8_t op_class)1080 void reg_dmn_print_channels_in_opclass(uint8_t *country, uint8_t op_class)
1081 {
1082 	const struct reg_dmn_op_class_map_t *class = NULL;
1083 	uint16_t i = 0;
1084 
1085 	class = reg_get_class_from_country(country);
1086 
1087 	if (!class) {
1088 		reg_err("class is NULL");
1089 		return;
1090 	}
1091 
1092 	while (class->op_class) {
1093 		if (class->op_class == op_class) {
1094 			for (i = 0;
1095 			     (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1096 			      class->channels[i]); i++) {
1097 				reg_debug("Valid channel(%d) in requested RC(%d)",
1098 					  class->channels[i], op_class);
1099 			}
1100 			break;
1101 		}
1102 		class++;
1103 	}
1104 	if (!class->op_class)
1105 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
1106 			  "Invalid requested RC (%d)", op_class);
1107 }
1108 
reg_dmn_set_curr_opclasses(uint8_t num_classes,uint8_t * class)1109 uint16_t reg_dmn_set_curr_opclasses(uint8_t num_classes, uint8_t *class)
1110 {
1111 	uint8_t i;
1112 
1113 	if (num_classes > REG_MAX_SUPP_OPER_CLASSES) {
1114 		reg_err("invalid num classes %d", num_classes);
1115 		return 0;
1116 	}
1117 
1118 	for (i = 0; i < num_classes; i++)
1119 		reg_dmn_curr_supp_opp_classes.classes[i] = class[i];
1120 
1121 	reg_dmn_curr_supp_opp_classes.num_classes = num_classes;
1122 
1123 	return 0;
1124 }
1125 
reg_dmn_get_curr_opclasses(uint8_t * num_classes,uint8_t * class)1126 uint16_t reg_dmn_get_curr_opclasses(uint8_t *num_classes, uint8_t *class)
1127 {
1128 	uint8_t i;
1129 
1130 	if (!num_classes || !class) {
1131 		reg_err("either num_classes or class is null");
1132 		return 0;
1133 	}
1134 
1135 	for (i = 0; i < reg_dmn_curr_supp_opp_classes.num_classes; i++)
1136 		class[i] = reg_dmn_curr_supp_opp_classes.classes[i];
1137 
1138 	*num_classes = reg_dmn_curr_supp_opp_classes.num_classes;
1139 
1140 	return 0;
1141 }
1142 
1143 #ifdef CONFIG_CHAN_FREQ_API
1144 /**
1145  * reg_find_opclass_absent_in_ctry_opclss_tables() - Check Global Opclass table
1146  * when Opclass is not present in specific country.
1147  * @pdev: Pointer to pdev
1148  * @freq: Destination Frequency
1149  * @chan_width: Channel Width
1150  * @global_tbl_lookup: Global Table Lookup
1151  * @behav_limit: Behav Limit
1152  * @op_class: Pointer to Opclass
1153  * @chan_num: Pointer to Channel
1154  *
1155  * Return: Void
1156  */
1157 static void
reg_find_opclass_absent_in_ctry_opclss_tables(struct wlan_objmgr_pdev * pdev,qdf_freq_t freq,uint16_t chan_width,bool global_tbl_lookup,uint16_t behav_limit,uint8_t * op_class,uint8_t * chan_num)1158 reg_find_opclass_absent_in_ctry_opclss_tables(struct wlan_objmgr_pdev *pdev,
1159 					      qdf_freq_t freq,
1160 					      uint16_t chan_width,
1161 					      bool global_tbl_lookup,
1162 					      uint16_t behav_limit,
1163 					      uint8_t *op_class,
1164 					      uint8_t *chan_num)
1165 {
1166 	if (!global_tbl_lookup && !*op_class) {
1167 		global_tbl_lookup = true;
1168 		reg_freq_width_to_chan_op_class(pdev, freq,
1169 						chan_width,
1170 						global_tbl_lookup,
1171 						behav_limit,
1172 						op_class,
1173 						chan_num);
1174 	}
1175 }
1176 
1177 static bool
reg_is_country_opclass_global(struct wlan_objmgr_pdev * pdev)1178 reg_is_country_opclass_global(struct wlan_objmgr_pdev *pdev)
1179 {
1180 	struct wlan_lmac_if_reg_tx_ops *reg_tx_ops;
1181 	struct wlan_objmgr_psoc *psoc;
1182 	uint8_t opclass_tbl_idx;
1183 
1184 	psoc = wlan_pdev_get_psoc(pdev);
1185 	if (!psoc) {
1186 		reg_err("psoc is NULL");
1187 		return false;
1188 	}
1189 
1190 	reg_tx_ops = reg_get_psoc_tx_ops(psoc);
1191 	if (!reg_tx_ops) {
1192 		reg_err("reg_tx_ops is NULL");
1193 		return false;
1194 	}
1195 
1196 	if (reg_tx_ops->get_opclass_tbl_idx) {
1197 		reg_tx_ops->get_opclass_tbl_idx(pdev, &opclass_tbl_idx);
1198 
1199 		if (opclass_tbl_idx == OP_CLASS_GLOBAL)
1200 			return true;
1201 	}
1202 
1203 	return false;
1204 }
1205 
reg_freq_width_to_chan_op_class_auto(struct wlan_objmgr_pdev * pdev,qdf_freq_t freq,uint16_t chan_width,bool global_tbl_lookup,uint16_t behav_limit,uint8_t * op_class,uint8_t * chan_num)1206 void reg_freq_width_to_chan_op_class_auto(struct wlan_objmgr_pdev *pdev,
1207 					  qdf_freq_t freq,
1208 					  uint16_t chan_width,
1209 					  bool global_tbl_lookup,
1210 					  uint16_t behav_limit,
1211 					  uint8_t *op_class,
1212 					  uint8_t *chan_num)
1213 {
1214 	if (reg_freq_to_band(freq) == REG_BAND_6G) {
1215 		global_tbl_lookup = true;
1216 		if (chan_width == BW_40_MHZ)
1217 			behav_limit = BIT(BEHAV_NONE);
1218 	} else if (reg_is_5dot9_ghz_freq(pdev, freq)) {
1219 		global_tbl_lookup = true;
1220 	} else {
1221 		global_tbl_lookup = reg_is_country_opclass_global(pdev);
1222 	}
1223 
1224 	*op_class = 0;
1225 	reg_freq_width_to_chan_op_class(pdev, freq,
1226 					chan_width,
1227 					global_tbl_lookup,
1228 					behav_limit,
1229 					op_class,
1230 					chan_num);
1231 	reg_find_opclass_absent_in_ctry_opclss_tables(pdev, freq,
1232 						      chan_width,
1233 						      global_tbl_lookup,
1234 						      behav_limit,
1235 						      op_class,
1236 						      chan_num);
1237 }
1238 
reg_freq_width_to_chan_op_class(struct wlan_objmgr_pdev * pdev,qdf_freq_t freq,uint16_t chan_width,bool global_tbl_lookup,uint16_t behav_limit,uint8_t * op_class,uint8_t * chan_num)1239 void reg_freq_width_to_chan_op_class(struct wlan_objmgr_pdev *pdev,
1240 				     qdf_freq_t freq,
1241 				     uint16_t chan_width,
1242 				     bool global_tbl_lookup,
1243 				     uint16_t behav_limit,
1244 				     uint8_t *op_class,
1245 				     uint8_t *chan_num)
1246 {
1247 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1248 	enum channel_enum chan_enum;
1249 	uint16_t i;
1250 
1251 	chan_enum = reg_get_chan_enum_for_freq(freq);
1252 
1253 	if (reg_is_chan_enum_invalid(chan_enum)) {
1254 		reg_err_rl("Invalid chan enum %d", chan_enum);
1255 		return;
1256 	}
1257 
1258 	if (global_tbl_lookup) {
1259 		op_class_tbl = global_op_class;
1260 	} else {
1261 		if (channel_map == channel_map_us)
1262 			op_class_tbl = us_op_class;
1263 		else if (channel_map == channel_map_eu)
1264 			op_class_tbl = euro_op_class;
1265 		else if (channel_map == channel_map_china)
1266 			op_class_tbl = china_op_class;
1267 		else if (channel_map == channel_map_jp)
1268 			op_class_tbl = japan_op_class;
1269 		else
1270 			op_class_tbl = global_op_class;
1271 	}
1272 
1273 	while (op_class_tbl->op_class) {
1274 		if (op_class_tbl->chan_spacing >= chan_width) {
1275 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1276 				     op_class_tbl->channels[i]); i++) {
1277 				if ((op_class_tbl->start_freq +
1278 				     FREQ_TO_CHAN_SCALE *
1279 				     op_class_tbl->channels[i] == freq) &&
1280 				    (behav_limit & op_class_tbl->behav_limit ||
1281 				     behav_limit == BIT(BEHAV_NONE))) {
1282 					*chan_num = op_class_tbl->channels[i];
1283 					*op_class = op_class_tbl->op_class;
1284 					return;
1285 				}
1286 			}
1287 		}
1288 		op_class_tbl++;
1289 	}
1290 
1291 	reg_err_rl("no op class for frequency %d", freq);
1292 }
1293 
reg_freq_to_chan_op_class(struct wlan_objmgr_pdev * pdev,qdf_freq_t freq,bool global_tbl_lookup,uint16_t behav_limit,uint8_t * op_class,uint8_t * chan_num)1294 void reg_freq_to_chan_op_class(struct wlan_objmgr_pdev *pdev,
1295 			       qdf_freq_t freq,
1296 			       bool global_tbl_lookup,
1297 			       uint16_t behav_limit,
1298 			       uint8_t *op_class,
1299 			       uint8_t *chan_num)
1300 {
1301 	enum channel_enum chan_enum;
1302 	struct regulatory_channel *cur_chan_list;
1303 	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
1304 	struct ch_params chan_params = {0};
1305 
1306 	pdev_priv_obj = reg_get_pdev_obj(pdev);
1307 
1308 	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
1309 		reg_err_rl("NULL pdev reg obj");
1310 		return;
1311 	}
1312 
1313 	cur_chan_list = pdev_priv_obj->cur_chan_list;
1314 
1315 	chan_enum = reg_get_chan_enum_for_freq(freq);
1316 
1317 	if (reg_is_chan_enum_invalid(chan_enum)) {
1318 		reg_err_rl("Invalid chan enum %d", chan_enum);
1319 		return;
1320 	}
1321 
1322 	chan_params.ch_width = CH_WIDTH_MAX;
1323 	reg_set_channel_params_for_pwrmode(pdev, freq,
1324 					   0,
1325 					   &chan_params,
1326 					   REG_CURRENT_PWR_MODE, true);
1327 
1328 	reg_freq_width_to_chan_op_class(pdev, freq,
1329 					reg_get_bw_value(chan_params.ch_width),
1330 					global_tbl_lookup,
1331 					behav_limit,
1332 					op_class,
1333 					chan_num);
1334 }
1335 
reg_is_freq_in_country_opclass(struct wlan_objmgr_pdev * pdev,const uint8_t country[3],uint8_t op_class,qdf_freq_t chan_freq)1336 bool reg_is_freq_in_country_opclass(struct wlan_objmgr_pdev *pdev,
1337 				    const uint8_t country[3],
1338 				    uint8_t op_class,
1339 				    qdf_freq_t chan_freq)
1340 {
1341 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1342 	uint8_t i;
1343 
1344 	op_class_tbl = reg_get_class_from_country((uint8_t *)country);
1345 
1346 	while (op_class_tbl && op_class_tbl->op_class) {
1347 		if  (op_class_tbl->op_class == op_class) {
1348 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1349 				     op_class_tbl->channels[i]); i++) {
1350 				if (op_class_tbl->channels[i] *
1351 				    FREQ_TO_CHAN_SCALE +
1352 				    op_class_tbl->start_freq == chan_freq)
1353 					return true;
1354 			}
1355 		}
1356 		op_class_tbl++;
1357 	}
1358 	return false;
1359 }
1360 
1361 #endif
1362 
reg_get_op_class_width(struct wlan_objmgr_pdev * pdev,uint8_t op_class,bool global_tbl_lookup)1363 uint16_t reg_get_op_class_width(struct wlan_objmgr_pdev *pdev,
1364 				uint8_t op_class,
1365 				bool global_tbl_lookup)
1366 {
1367 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1368 
1369 	if (global_tbl_lookup) {
1370 		op_class_tbl = global_op_class;
1371 	} else {
1372 		if (channel_map == channel_map_us)
1373 			op_class_tbl = us_op_class;
1374 		else if (channel_map == channel_map_eu)
1375 			op_class_tbl = euro_op_class;
1376 		else if (channel_map == channel_map_china)
1377 			op_class_tbl = china_op_class;
1378 		else if (channel_map == channel_map_jp)
1379 			op_class_tbl = japan_op_class;
1380 		else
1381 			op_class_tbl = global_op_class;
1382 	}
1383 
1384 	while (op_class_tbl->op_class) {
1385 		if  (op_class_tbl->op_class == op_class)
1386 			return op_class_tbl->chan_spacing;
1387 		op_class_tbl++;
1388 	}
1389 
1390 	return 0;
1391 }
1392 
reg_chan_opclass_to_freq(uint8_t chan,uint8_t op_class,bool global_tbl_lookup)1393 uint16_t reg_chan_opclass_to_freq(uint8_t chan,
1394 				  uint8_t op_class,
1395 				  bool global_tbl_lookup)
1396 {
1397 	const struct reg_dmn_op_class_map_t *op_class_tbl = NULL;
1398 	uint8_t i = 0;
1399 
1400 	if (global_tbl_lookup) {
1401 		op_class_tbl = global_op_class;
1402 	} else {
1403 		if (channel_map == channel_map_global) {
1404 			op_class_tbl = global_op_class;
1405 		} else if (channel_map == channel_map_us) {
1406 			op_class_tbl = us_op_class;
1407 		} else if (channel_map == channel_map_eu) {
1408 			op_class_tbl = euro_op_class;
1409 		} else if (channel_map == channel_map_china) {
1410 			op_class_tbl = china_op_class;
1411 		} else if (channel_map == channel_map_jp) {
1412 			op_class_tbl = japan_op_class;
1413 		} else {
1414 			reg_err_rl("Invalid channel map");
1415 			return 0;
1416 		}
1417 	}
1418 
1419 	while (op_class_tbl->op_class) {
1420 		if  (op_class_tbl->op_class == op_class) {
1421 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1422 				     op_class_tbl->channels[i]); i++) {
1423 				if (op_class_tbl->channels[i] == chan) {
1424 					chan = op_class_tbl->channels[i];
1425 					return op_class_tbl->start_freq +
1426 						(chan * FREQ_TO_CHAN_SCALE);
1427 				}
1428 			}
1429 			reg_err_rl("Channel not found");
1430 			return 0;
1431 		}
1432 		op_class_tbl++;
1433 	}
1434 	reg_err_rl("Invalid opclass");
1435 	return 0;
1436 }
1437 
reg_chan_opclass_to_freq_auto(uint8_t chan,uint8_t op_class,bool global_tbl_lookup)1438 qdf_freq_t reg_chan_opclass_to_freq_auto(uint8_t chan, uint8_t op_class,
1439 					 bool global_tbl_lookup)
1440 {
1441 	if ((op_class >= MIN_6GHZ_OPER_CLASS) &&
1442 	    (op_class <= MAX_6GHZ_OPER_CLASS)) {
1443 		global_tbl_lookup = true;
1444 	} else {
1445 		qdf_freq_t freq = reg_chan_opclass_to_freq(chan,
1446 				op_class,
1447 				global_tbl_lookup);
1448 		if (freq)
1449 			return freq;
1450 		global_tbl_lookup = true;
1451 	}
1452 
1453 	return reg_chan_opclass_to_freq(chan, op_class, global_tbl_lookup);
1454 }
1455 
1456 #ifdef HOST_OPCLASS_EXT
reg_country_chan_opclass_to_freq(struct wlan_objmgr_pdev * pdev,const uint8_t country[3],uint8_t chan,uint8_t op_class,bool strict)1457 qdf_freq_t reg_country_chan_opclass_to_freq(struct wlan_objmgr_pdev *pdev,
1458 					    const uint8_t country[3],
1459 					    uint8_t chan, uint8_t op_class,
1460 					    bool strict)
1461 {
1462 	const struct reg_dmn_op_class_map_t *op_class_tbl, *op_class_tbl_org;
1463 	uint16_t i;
1464 
1465 	if (reg_is_6ghz_op_class(pdev, op_class))
1466 		op_class_tbl_org = global_op_class;
1467 	else
1468 		op_class_tbl_org =
1469 			reg_get_class_from_country((uint8_t *)country);
1470 	op_class_tbl = op_class_tbl_org;
1471 	while (op_class_tbl && op_class_tbl->op_class) {
1472 		if  (op_class_tbl->op_class == op_class) {
1473 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1474 				     op_class_tbl->channels[i]); i++) {
1475 				if (op_class_tbl->channels[i] == chan)
1476 					return op_class_tbl->start_freq +
1477 						(chan * FREQ_TO_CHAN_SCALE);
1478 			}
1479 		}
1480 		op_class_tbl++;
1481 	}
1482 	reg_debug_rl("Not found ch %d in op class %d ch list, strict %d",
1483 		     chan, op_class, strict);
1484 	if (strict)
1485 		return 0;
1486 
1487 	op_class_tbl = op_class_tbl_org;
1488 	while (op_class_tbl && op_class_tbl->op_class) {
1489 		for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1490 			     op_class_tbl->channels[i]); i++) {
1491 			if (op_class_tbl->channels[i] == chan)
1492 				return op_class_tbl->start_freq +
1493 					(chan * FREQ_TO_CHAN_SCALE);
1494 		}
1495 		op_class_tbl++;
1496 	}
1497 	reg_debug_rl("Got invalid freq 0 for ch %d", chan);
1498 
1499 	return 0;
1500 }
1501 #endif
1502 
1503 static void
reg_get_op_class_tbl_by_chan_map(const struct reg_dmn_op_class_map_t ** op_class_tbl)1504 reg_get_op_class_tbl_by_chan_map(const struct
1505 				 reg_dmn_op_class_map_t **op_class_tbl)
1506 {
1507 	if (channel_map == channel_map_us)
1508 		*op_class_tbl = us_op_class;
1509 	else if (channel_map == channel_map_eu)
1510 		*op_class_tbl = euro_op_class;
1511 	else if (channel_map == channel_map_china)
1512 		*op_class_tbl = china_op_class;
1513 	else if (channel_map == channel_map_jp)
1514 		*op_class_tbl = japan_op_class;
1515 	else
1516 		*op_class_tbl = global_op_class;
1517 }
1518 
1519 /**
1520  * reg_get_channel_cen - Calculate central channel in the channel set.
1521  *
1522  * @op_class_tbl: Pointer to op_class_tbl.
1523  * @idx: Pointer to channel index.
1524  * @num_channels: Number of channels.
1525  * @center_chan: Pointer to center channel number
1526  *
1527  * Return : void
1528  */
reg_get_channel_cen(const struct reg_dmn_op_class_map_t * op_class_tbl,uint8_t * idx,uint8_t num_channels,uint8_t * center_chan)1529 static void reg_get_channel_cen(const struct
1530 				reg_dmn_op_class_map_t *op_class_tbl,
1531 				uint8_t *idx,
1532 				uint8_t num_channels,
1533 				uint8_t *center_chan)
1534 {
1535 	uint8_t i;
1536 	uint16_t new_chan = 0;
1537 
1538 	for (i = *idx; i < (*idx + num_channels); i++)
1539 		new_chan += op_class_tbl->channels[i];
1540 
1541 	new_chan = new_chan / num_channels;
1542 	*center_chan = new_chan;
1543 	*idx = *idx + num_channels;
1544 }
1545 
1546 /**
1547  * reg_is_chan_320mhz() - Return true if the chan width is 320MHZ,
1548  * false otherwise.
1549  * @chan_spacing: Channel spacing in MHZ.
1550  *
1551  * Return: true if chan_width is 320, false otherwise.
1552  */
1553 #ifdef WLAN_FEATURE_11BE
reg_is_chan_320mhz(uint16_t chan_spacing)1554 static bool reg_is_chan_320mhz(uint16_t chan_spacing)
1555 {
1556 	if (chan_spacing == BW_320_MHZ)
1557 		return true;
1558 	return false;
1559 }
1560 #else
reg_is_chan_320mhz(uint16_t chan_spacing)1561 static bool reg_is_chan_320mhz(uint16_t chan_spacing)
1562 {
1563 	return false;
1564 }
1565 #endif
1566 
1567 /**
1568  * reg_get_chan_or_chan_center - Calculate central channel in the channel set.
1569  *
1570  * @op_class_tbl: Pointer to op_class_tbl.
1571  * @idx: Pointer to channel index.
1572  *
1573  * Return : Center channel number
1574  */
reg_get_chan_or_chan_center(const struct reg_dmn_op_class_map_t * op_class_tbl,uint8_t * idx)1575 static uint8_t reg_get_chan_or_chan_center(const struct
1576 					   reg_dmn_op_class_map_t *op_class_tbl,
1577 					   uint8_t *idx)
1578 {
1579 	uint8_t center_chan;
1580 
1581 	if (((op_class_tbl->chan_spacing == BW_80_MHZ) &&
1582 	     (op_class_tbl->behav_limit == BIT(BEHAV_NONE))) ||
1583 	    ((op_class_tbl->chan_spacing == BW_80_MHZ) &&
1584 	     (op_class_tbl->behav_limit == BIT(BEHAV_BW80_PLUS)))) {
1585 		reg_get_channel_cen(op_class_tbl,
1586 				    idx,
1587 				    NUM_20_MHZ_CHAN_IN_80_MHZ_CHAN,
1588 				    &center_chan);
1589 	} else if (op_class_tbl->chan_spacing == BW_160_MHZ) {
1590 		reg_get_channel_cen(op_class_tbl,
1591 				    idx,
1592 				    NUM_20_MHZ_CHAN_IN_160_MHZ_CHAN,
1593 				    &center_chan);
1594 	} else if (reg_is_chan_320mhz(op_class_tbl->chan_spacing)) {
1595 		reg_get_channel_cen(op_class_tbl,
1596 				    idx,
1597 				    NUM_20_MHZ_CHAN_IN_320_MHZ_CHAN,
1598 				    &center_chan);
1599 	} else {
1600 		center_chan = op_class_tbl->channels[*idx];
1601 		*idx = *idx + 1;
1602 	}
1603 
1604 	return center_chan;
1605 }
1606 
reg_get_nearest_primary_freq(uint16_t bw,qdf_freq_t cfi_freq,uint8_t op_class)1607 static inline qdf_freq_t reg_get_nearest_primary_freq(uint16_t bw,
1608 						      qdf_freq_t cfi_freq,
1609 						      uint8_t op_class)
1610 {
1611 	qdf_freq_t pri_freq;
1612 
1613 	if (bw <= BW_40_MHZ && op_class != OPCLS_132) {
1614 		pri_freq = cfi_freq;
1615 	} else {
1616 		if (cfi_freq >= BW_10_MHZ)
1617 			pri_freq = cfi_freq - BW_10_MHZ;
1618 		else
1619 			pri_freq = 0;
1620 	}
1621 
1622 	return pri_freq;
1623 }
1624 
1625 #if defined(QCA_DFS_BW_PUNCTURE) && defined(WLAN_FEATURE_11BE) && \
1626 	!defined(CONFIG_REG_CLIENT)
1627 /**
1628  * reg_get_radar_puncture_bmap() - If DFS puncturing feature is enabled,
1629  * puncture the NOL channels and retrieve the radar puncture bitmap.
1630  * For non-puncturable bandwidths (bandwidths less than 80), puncturing is not
1631  * applicable.
1632  * @pdev: Pointer to struct wlan_objmgr_pdev
1633  * @pri_freq: Primary frequency in MHz
1634  * @ch_width: channel width
1635  * @center_320: 320 MHz center frequency
1636  */
1637 static uint16_t
reg_get_radar_puncture_bmap(struct wlan_objmgr_pdev * pdev,qdf_freq_t pri_freq,enum phy_ch_width ch_width,qdf_freq_t center_320)1638 reg_get_radar_puncture_bmap(struct wlan_objmgr_pdev *pdev,
1639 			    qdf_freq_t pri_freq,
1640 			    enum phy_ch_width ch_width,
1641 			    qdf_freq_t center_320)
1642 {
1643 	const struct bonded_channel_freq *bonded_chan_ptr;
1644 	uint16_t chan_cfreq, radar_punc_bitmap = NO_SCHANS_PUNC;
1645 	uint8_t i = 0;
1646 	bool is_dfs_punc_en, is_5g_freq_and_punc_en;
1647 	bool is_chanwidth_puncturable = ch_width > CH_WIDTH_40MHZ ? true : false;
1648 
1649 	ucfg_dfs_get_dfs_puncture(pdev, &is_dfs_punc_en);
1650 	is_5g_freq_and_punc_en = reg_is_5ghz_ch_freq(pri_freq) && is_dfs_punc_en;
1651 
1652 	if (!(is_5g_freq_and_punc_en && is_chanwidth_puncturable))
1653 		return radar_punc_bitmap;
1654 
1655 	bonded_chan_ptr = reg_get_bonded_chan_entry(pri_freq, ch_width,
1656 						    center_320);
1657 	if (!bonded_chan_ptr)
1658 		return radar_punc_bitmap;
1659 
1660 	chan_cfreq = bonded_chan_ptr->start_freq;
1661 	while (chan_cfreq <= bonded_chan_ptr->end_freq) {
1662 		if (wlan_reg_is_nol_for_freq(pdev, chan_cfreq))
1663 			radar_punc_bitmap |=  1 << i;
1664 		i++;
1665 		chan_cfreq = chan_cfreq + BW_20_MHZ;
1666 	}
1667 
1668 	return radar_punc_bitmap;
1669 }
1670 #else
1671 static inline uint16_t
reg_get_radar_puncture_bmap(struct wlan_objmgr_pdev * pdev,qdf_freq_t pri_freq,enum phy_ch_width ch_width,qdf_freq_t center_320)1672 reg_get_radar_puncture_bmap(struct wlan_objmgr_pdev *pdev,
1673 			    qdf_freq_t pri_freq,
1674 			    enum phy_ch_width ch_width,
1675 			    qdf_freq_t center_320)
1676 {
1677 	return NO_SCHANS_PUNC;
1678 }
1679 #endif
1680 
1681 #ifdef WLAN_FEATURE_11BE
1682 /**
1683  * reg_is_chan_supported()- Check if given channel is supported based on its
1684  * freq provided
1685  * @pdev: Pointer to pdev
1686  * @pri_freq: Primary frequency of the input channel
1687  * @cfi_freq: cfi frequency of the input channel
1688  * @ch_width: Input channel width
1689  * @in_6g_pwr_mode: 6g power type which decides 6G channel list lookup.
1690  *
1691  * Return: True if the channel is supported, else false
1692  */
reg_is_chan_supported(struct wlan_objmgr_pdev * pdev,qdf_freq_t pri_freq,qdf_freq_t cfi_freq,enum phy_ch_width ch_width,enum supported_6g_pwr_types in_6g_pwr_mode)1693 static bool reg_is_chan_supported(struct wlan_objmgr_pdev *pdev,
1694 				  qdf_freq_t pri_freq,
1695 				  qdf_freq_t cfi_freq,
1696 				  enum phy_ch_width ch_width,
1697 				  enum supported_6g_pwr_types in_6g_pwr_mode)
1698 {
1699 	struct reg_channel_list chan_list = {0};
1700 	qdf_freq_t center_320;
1701 	struct ch_params ch_params = {0};
1702 	uint16_t radar_punc_bitmap;
1703 
1704 	center_320 = (ch_width == CH_WIDTH_320MHZ) ? cfi_freq : 0;
1705 
1706 	/* Determine if there are any NOL subchannels in the given freq/BW
1707 	 * combination and if so, calculate the dfs puncture pattern and then
1708 	 * invoke reg_fill_channel_list.
1709 	 */
1710 	radar_punc_bitmap = reg_get_radar_puncture_bmap(pdev, pri_freq,
1711 							ch_width,
1712 							center_320);
1713 	chan_list.chan_param[0].input_punc_bitmap = radar_punc_bitmap;
1714 	reg_fill_channel_list_for_pwrmode(pdev, pri_freq, 0,
1715 					  ch_width, center_320,
1716 					  &chan_list, in_6g_pwr_mode,
1717 					  true);
1718 	ch_params = chan_list.chan_param[0];
1719 
1720 	if (ch_params.ch_width == ch_width)
1721 		return true;
1722 
1723 	return false;
1724 }
1725 #else
reg_is_chan_supported(struct wlan_objmgr_pdev * pdev,qdf_freq_t pri_freq,qdf_freq_t cfi_freq,enum phy_ch_width ch_width,enum supported_6g_pwr_types in_6g_pwr_mode)1726 static bool reg_is_chan_supported(struct wlan_objmgr_pdev *pdev,
1727 				  qdf_freq_t pri_freq,
1728 				  qdf_freq_t cfi_freq,
1729 				  enum phy_ch_width ch_width,
1730 				  enum supported_6g_pwr_types in_6g_pwr_mode)
1731 {
1732 	struct ch_params ch_params = {0};
1733 
1734 	ch_params.ch_width = ch_width;
1735 	reg_set_channel_params_for_pwrmode(pdev, pri_freq, 0, &ch_params,
1736 					   in_6g_pwr_mode, true);
1737 	if (ch_params.ch_width == ch_width)
1738 		return true;
1739 
1740 	return false;
1741 }
1742 #endif
1743 
1744 /**
1745  * reg_is_cfi_supported()- Check if given cfi is supported
1746  * @pdev: Pointer to pdev
1747  * @cfi_freq: cfi frequency
1748  * @bw: bandwidth
1749  * @op_class: op_class
1750  * @in_6g_pwr_mode: 6g power type which decides 6G channel list lookup.
1751  *
1752  * Return: True if the cfi is supported, else false
1753  */
reg_is_cfi_supported(struct wlan_objmgr_pdev * pdev,qdf_freq_t cfi_freq,uint16_t bw,uint8_t op_class,enum supported_6g_pwr_types in_6g_pwr_mode)1754 static bool reg_is_cfi_supported(struct wlan_objmgr_pdev *pdev,
1755 				 qdf_freq_t cfi_freq,
1756 				 uint16_t bw,
1757 				 uint8_t op_class,
1758 				 enum supported_6g_pwr_types in_6g_pwr_mode)
1759 {
1760 	enum phy_ch_width ch_width;
1761 	qdf_freq_t pri_freq;
1762 	bool is_cfi_supported;
1763 
1764 	ch_width = reg_find_chwidth_from_bw(bw);
1765 	pri_freq = reg_get_nearest_primary_freq(bw, cfi_freq, op_class);
1766 	is_cfi_supported = reg_is_chan_supported(pdev,
1767 						 pri_freq,
1768 						 cfi_freq,
1769 						 ch_width,
1770 						 in_6g_pwr_mode);
1771 
1772 	return is_cfi_supported;
1773 }
1774 
1775 /**
1776  * reg_is_opclass_entry_80p80() - Return true if the opclass entry is
1777  * 80P80 false otherwise.
1778  * @op_class_tbl: Pointer to struct reg_dmn_op_class_map_t
1779  */
1780 static bool
reg_is_opclass_entry_80p80(const struct reg_dmn_op_class_map_t * op_class_tbl)1781 reg_is_opclass_entry_80p80(const struct reg_dmn_op_class_map_t *op_class_tbl)
1782 {
1783 	return (op_class_tbl->chan_spacing == BW_80_MHZ &&
1784 		op_class_tbl->behav_limit == BIT(BEHAV_BW80_PLUS));
1785 }
1786 
1787 /**
1788  * reg_get_cfis_from_opclassmap_for_6g()- Get channels from the opclass map
1789  * for 6GHz
1790  * @pdev: Pointer to pdev
1791  * @cap: Pointer to regdmn_ap_cap_opclass_t
1792  * @op_class_tbl: Pointer to op_class_tbl
1793  * @in_opclass_conf: input opclass configuration
1794  * Supported or not-supported by current HW mode
1795  * @in_6g_pwr_mode: 6g power type which decides 6G channel list lookup.
1796  *
1797  * Populate channels from opclass map to regdmn_ap_cap_opclass_t as supported
1798  * and non-supported channels for 6Ghz.
1799  *
1800  * Return: void.
1801  */
reg_get_cfis_from_opclassmap_for_6g(struct wlan_objmgr_pdev * pdev,struct regdmn_ap_cap_opclass_t * cap,const struct reg_dmn_op_class_map_t * op_class_tbl,enum opclass_config in_opclass_conf,enum supported_6g_pwr_types in_6g_pwr_mode)1802 static void reg_get_cfis_from_opclassmap_for_6g(
1803 			struct wlan_objmgr_pdev *pdev,
1804 			struct regdmn_ap_cap_opclass_t *cap,
1805 			const struct reg_dmn_op_class_map_t *op_class_tbl,
1806 			enum opclass_config in_opclass_conf,
1807 			enum supported_6g_pwr_types in_6g_pwr_mode)
1808 {
1809 	uint8_t n_sup_chans = 0, n_unsup_chans = 0, j;
1810 	const struct c_freq_lst *p_cfi_lst = op_class_tbl->p_cfi_lst_obj;
1811 	qdf_freq_t cfi_freq;
1812 	qdf_freq_t start_freq = op_class_tbl->start_freq;
1813 	uint16_t bw = op_class_tbl->chan_spacing;
1814 
1815 	for (j = 0; j < p_cfi_lst->num_cfis; j++) {
1816 		uint8_t cfi = p_cfi_lst->p_cfis_arr[j];
1817 		bool is_cfi_supported;
1818 
1819 		cfi_freq = start_freq + FREQ_TO_CHAN_SCALE * cfi;
1820 		/* 6 Ghz band does not support 80P80 mode of operation.*/
1821 		if (reg_is_opclass_entry_80p80(op_class_tbl))
1822 			is_cfi_supported = false;
1823 		else
1824 			is_cfi_supported = reg_is_cfi_supported(pdev,
1825 								cfi_freq,
1826 								bw,
1827 								op_class_tbl->op_class,
1828 								in_6g_pwr_mode);
1829 		if (is_cfi_supported &&
1830 		    (in_opclass_conf == OPCLASSES_SUPPORTED_BY_CUR_HWMODE ||
1831 		     in_opclass_conf == OPCLASSES_SUPPORTED_BY_DOMAIN)) {
1832 			cap->sup_chan_list[n_sup_chans++] = cfi;
1833 			cap->num_supported_chan++;
1834 		} else {
1835 			cap->non_sup_chan_list[n_unsup_chans++] = cfi;
1836 			cap->num_non_supported_chan++;
1837 		}
1838 	}
1839 }
1840 
reg_find_nearest_ieee_bw(uint16_t spacing)1841 static uint16_t reg_find_nearest_ieee_bw(uint16_t spacing)
1842 {
1843 	#define SMALLEST_BW 20
1844 	return (spacing / SMALLEST_BW) * SMALLEST_BW;
1845 }
1846 
1847 /**
1848  * reg_is_freq_80p80_supported() - Return true if the given input frequency
1849  * supports 80P80, false otherwise.
1850  * @pdev: Pointer to struct wlan_objmgr_pdev
1851  * @primary_freq: Primary frequency in MHz
1852  *
1853  * Return: True if the frequency supports 80P80 mode of operation, false
1854  * otherwise.
1855  */
1856 static bool
reg_is_freq_80p80_supported(struct wlan_objmgr_pdev * pdev,qdf_freq_t primary_freq)1857 reg_is_freq_80p80_supported(struct wlan_objmgr_pdev *pdev,
1858 			    qdf_freq_t primary_freq)
1859 {
1860 	struct wlan_lmac_if_reg_tx_ops *reg_tx_ops;
1861 	struct wlan_objmgr_psoc *psoc;
1862 
1863 	psoc = wlan_pdev_get_psoc(pdev);
1864 	if (!psoc)
1865 		return false;
1866 
1867 	reg_tx_ops = reg_get_psoc_tx_ops(psoc);
1868 	if (!reg_tx_ops)
1869 		return false;
1870 
1871 	if (reg_tx_ops->is_freq_80p80_supported &&
1872 	    reg_tx_ops->is_freq_80p80_supported(pdev, primary_freq))
1873 		return true;
1874 
1875 	return false;
1876 }
1877 
1878 /**
1879  * reg_get_cfis_from_opclassmap_for_non6g()- Get channels from the opclass map
1880  * for non-6GHz
1881  * @pdev: Pointer to pdev
1882  * @cap: Pointer to regdmn_ap_cap_opclass_t
1883  * @op_class_tbl: Pointer to op_class_tbl
1884  * @in_opclass_conf: input opclass configuration
1885  * Supported or not-supported by current HW mode
1886  * @in_6g_pwr_mode: 6g power type which decides 6G channel list lookup.
1887  *
1888  * Populate channels from opclass map to regdmn_ap_cap_opclass_t as supported
1889  * and non-supported channels for non-6Ghz.
1890  *
1891  * Return: void.
1892  */
reg_get_cfis_from_opclassmap_for_non6g(struct wlan_objmgr_pdev * pdev,struct regdmn_ap_cap_opclass_t * cap,const struct reg_dmn_op_class_map_t * op_class_tbl,enum opclass_config in_opclass_conf,enum supported_6g_pwr_types in_6g_pwr_mode)1893 static void reg_get_cfis_from_opclassmap_for_non6g(
1894 			struct wlan_objmgr_pdev *pdev,
1895 			struct regdmn_ap_cap_opclass_t *cap,
1896 			const struct reg_dmn_op_class_map_t *op_class_tbl,
1897 			enum opclass_config in_opclass_conf,
1898 			enum supported_6g_pwr_types in_6g_pwr_mode)
1899 {
1900 	qdf_freq_t start_freq = op_class_tbl->start_freq;
1901 	uint8_t chan_idx = 0, n_sup_chans = 0, n_unsup_chans = 0;
1902 
1903 	while (op_class_tbl->channels[chan_idx]) {
1904 		uint8_t op_cls_chan;
1905 		qdf_freq_t pri_freq;
1906 		enum phy_ch_width ch_width;
1907 		bool is_supported;
1908 		uint16_t opcls_bw;
1909 
1910 		op_cls_chan = reg_get_chan_or_chan_center(op_class_tbl,
1911 							  &chan_idx);
1912 		pri_freq = start_freq + FREQ_TO_CHAN_SCALE * op_cls_chan;
1913 		opcls_bw = reg_find_nearest_ieee_bw(op_class_tbl->chan_spacing);
1914 		ch_width = reg_find_chwidth_from_bw(opcls_bw);
1915 		pri_freq = reg_get_nearest_primary_freq(opcls_bw,
1916 							pri_freq,
1917 							op_class_tbl->op_class);
1918 
1919 		if (reg_is_opclass_entry_80p80(op_class_tbl))
1920 			is_supported = reg_is_freq_80p80_supported(pdev, pri_freq);
1921 		else
1922 			is_supported = reg_is_chan_supported(pdev,
1923 							     pri_freq,
1924 							     0,
1925 							     ch_width,
1926 							     in_6g_pwr_mode);
1927 		if (is_supported &&
1928 		    (in_opclass_conf == OPCLASSES_SUPPORTED_BY_CUR_HWMODE ||
1929 		     in_opclass_conf == OPCLASSES_SUPPORTED_BY_DOMAIN)) {
1930 			cap->sup_chan_list[n_sup_chans++] = op_cls_chan;
1931 			cap->num_supported_chan++;
1932 		} else {
1933 			cap->non_sup_chan_list[n_unsup_chans++] = op_cls_chan;
1934 			cap->num_non_supported_chan++;
1935 		}
1936 	}
1937 }
1938 
1939 /**
1940  * reg_get_channels_from_opclassmap()- Get channels from the opclass map
1941  * @pdev: Pointer to pdev
1942  * @reg_ap_cap: Pointer to reg_ap_cap
1943  * @index: Pointer to index of reg_ap_cap
1944  * @op_class_tbl: Pointer to op_class_tbl
1945  * @is_opclass_operable: Set true if opclass is operable, else set false
1946  * @in_opclass_conf: input opclass configuration
1947  * Supported or not-supported by current HW mode
1948  * @in_6g_pwr_mode: 6g power type which decides 6G channel list lookup.
1949  *
1950  * Populate channels from opclass map to reg_ap_cap as supported and
1951  * non-supported channels.
1952  *
1953  * Return: void.
1954  */
1955 static void
reg_get_channels_from_opclassmap(struct wlan_objmgr_pdev * pdev,struct regdmn_ap_cap_opclass_t * reg_ap_cap,uint8_t index,const struct reg_dmn_op_class_map_t * op_class_tbl,bool * is_opclass_operable,enum opclass_config in_opclass_conf,enum supported_6g_pwr_types in_6g_pwr_mode)1956 reg_get_channels_from_opclassmap(
1957 		struct wlan_objmgr_pdev *pdev,
1958 		struct regdmn_ap_cap_opclass_t *reg_ap_cap,
1959 		uint8_t index,
1960 		const struct reg_dmn_op_class_map_t *op_class_tbl,
1961 		bool *is_opclass_operable,
1962 		enum opclass_config in_opclass_conf,
1963 		enum supported_6g_pwr_types in_6g_pwr_mode)
1964 {
1965 	struct regdmn_ap_cap_opclass_t *cap = &reg_ap_cap[index];
1966 
1967 	if (reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) {
1968 		reg_get_cfis_from_opclassmap_for_6g(pdev,
1969 						    cap,
1970 						    op_class_tbl,
1971 						    in_opclass_conf,
1972 						    in_6g_pwr_mode);
1973 	} else {
1974 		reg_get_cfis_from_opclassmap_for_non6g(pdev,
1975 						       cap,
1976 						       op_class_tbl,
1977 						       in_opclass_conf,
1978 						       in_6g_pwr_mode);
1979 	}
1980 
1981 	if (cap->num_supported_chan >= 1)
1982 		*is_opclass_operable = true;
1983 }
1984 
reg_get_opclass_details(struct wlan_objmgr_pdev * pdev,struct regdmn_ap_cap_opclass_t * reg_ap_cap,uint8_t * n_opclasses,uint8_t max_supp_op_class,bool global_tbl_lookup,enum supported_6g_pwr_types in_6g_pwr_mode)1985 QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
1986 				   struct regdmn_ap_cap_opclass_t *reg_ap_cap,
1987 				   uint8_t *n_opclasses,
1988 				   uint8_t max_supp_op_class,
1989 				   bool global_tbl_lookup,
1990 				   enum supported_6g_pwr_types in_6g_pwr_mode)
1991 {
1992 	uint8_t max_reg_power = 0;
1993 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1994 	uint8_t index = 0;
1995 	enum opclass_config opclass_conf = OPCLASSES_SUPPORTED_BY_DOMAIN;
1996 
1997 	if (global_tbl_lookup)
1998 		op_class_tbl = global_op_class;
1999 	else
2000 		reg_get_op_class_tbl_by_chan_map(&op_class_tbl);
2001 
2002 	max_reg_power = reg_get_max_tx_power(pdev);
2003 
2004 	while (op_class_tbl->op_class && (index < max_supp_op_class)) {
2005 		bool is_opclass_operable = false;
2006 
2007 		qdf_mem_zero(reg_ap_cap[index].sup_chan_list,
2008 			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
2009 		reg_ap_cap[index].num_supported_chan = 0;
2010 		qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list,
2011 			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
2012 		reg_ap_cap[index].num_non_supported_chan = 0;
2013 		reg_get_channels_from_opclassmap(pdev,
2014 						 reg_ap_cap,
2015 						 index,
2016 						 op_class_tbl,
2017 						 &is_opclass_operable,
2018 						 opclass_conf,
2019 						 in_6g_pwr_mode);
2020 		if (is_opclass_operable) {
2021 			reg_ap_cap[index].op_class = op_class_tbl->op_class;
2022 			reg_ap_cap[index].ch_width =
2023 						op_class_tbl->chan_spacing;
2024 			reg_ap_cap[index].start_freq =
2025 						op_class_tbl->start_freq;
2026 			reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power;
2027 			reg_ap_cap[index].behav_limit =
2028 						op_class_tbl->behav_limit;
2029 			index++;
2030 		}
2031 
2032 		op_class_tbl++;
2033 	}
2034 
2035 	*n_opclasses = index;
2036 
2037 	return QDF_STATUS_SUCCESS;
2038 }
2039 
reg_is_6ghz_op_class(struct wlan_objmgr_pdev * pdev,uint8_t op_class)2040 bool reg_is_6ghz_op_class(struct wlan_objmgr_pdev *pdev, uint8_t op_class)
2041 {
2042 	return ((op_class >= MIN_6GHZ_OPER_CLASS) &&
2043 		(op_class <= MAX_6GHZ_OPER_CLASS));
2044 }
2045 
2046 /**
2047  * reg_is_opclass_band_found() - Check if the input opclass is 2G or 5G.
2048  * @country: Pointer to country.
2049  * @op_class: Operating class.
2050  * @bandmask: Bitmask for band.
2051  *
2052  * Return : Return true if the input opclass' band (2Ghz or 5Ghz) matches one
2053  * of bandmask's band.
2054  */
reg_is_opclass_band_found(const uint8_t * country,uint8_t op_class,uint8_t bandmask)2055 static bool reg_is_opclass_band_found(const uint8_t *country,
2056 				      uint8_t op_class,
2057 				      uint8_t bandmask)
2058 {
2059 	const struct reg_dmn_op_class_map_t *op_class_tbl;
2060 
2061 	op_class_tbl = reg_get_class_from_country((uint8_t *)country);
2062 
2063 	while (op_class_tbl && op_class_tbl->op_class) {
2064 		if (op_class_tbl->op_class == op_class) {
2065 			qdf_freq_t freq = op_class_tbl->start_freq +
2066 			(op_class_tbl->channels[0] * FREQ_TO_CHAN_SCALE);
2067 
2068 			if ((bandmask & BIT(REG_BAND_5G)) &&
2069 			    REG_IS_5GHZ_FREQ(freq))
2070 				return true;
2071 
2072 			if ((bandmask & BIT(REG_BAND_2G)) &&
2073 			    REG_IS_24GHZ_CH_FREQ(freq))
2074 				return true;
2075 
2076 			return false;
2077 		}
2078 
2079 		op_class_tbl++;
2080 	}
2081 
2082 	reg_err_rl("Opclass %d is not found", op_class);
2083 
2084 	return false;
2085 }
2086 
reg_is_5ghz_op_class(const uint8_t * country,uint8_t op_class)2087 bool reg_is_5ghz_op_class(const uint8_t *country, uint8_t op_class)
2088 {
2089 	return reg_is_opclass_band_found(country, op_class, BIT(REG_BAND_5G));
2090 }
2091 
reg_is_2ghz_op_class(const uint8_t * country,uint8_t op_class)2092 bool reg_is_2ghz_op_class(const uint8_t *country, uint8_t op_class)
2093 {
2094 	return reg_is_opclass_band_found(country, op_class, BIT(REG_BAND_2G));
2095 }
2096 
2097 /**
2098  * reg_convert_chan_spacing_to_width() - Convert channel spacing to
2099  * channel width.
2100  * @chan_spacing: Channel spacing
2101  * @opclass_chwidth: Opclass channel width
2102  *
2103  * Return: None
2104  */
2105 #ifdef WLAN_FEATURE_11BE
reg_convert_chan_spacing_to_width(uint16_t chan_spacing,uint16_t * opclass_chwidth)2106 static void reg_convert_chan_spacing_to_width(uint16_t chan_spacing,
2107 					      uint16_t *opclass_chwidth)
2108 {
2109 	switch (chan_spacing) {
2110 	case BW_20_MHZ:
2111 	case BW_25_MHZ:
2112 		*opclass_chwidth = BW_20_MHZ;
2113 		break;
2114 	case BW_40_MHZ:
2115 		*opclass_chwidth = BW_40_MHZ;
2116 		break;
2117 	case BW_80_MHZ:
2118 		*opclass_chwidth = BW_80_MHZ;
2119 		break;
2120 	case BW_160_MHZ:
2121 		*opclass_chwidth = BW_160_MHZ;
2122 		break;
2123 	case BW_320_MHZ:
2124 		*opclass_chwidth = BW_320_MHZ;
2125 		break;
2126 	default:
2127 		*opclass_chwidth = 0;
2128 	}
2129 }
2130 #else
reg_convert_chan_spacing_to_width(uint16_t chan_spacing,uint16_t * opclass_chwidth)2131 static void reg_convert_chan_spacing_to_width(uint16_t chan_spacing,
2132 					      uint16_t *opclass_chwidth)
2133 {
2134 	switch (chan_spacing) {
2135 	case BW_20_MHZ:
2136 	case BW_25_MHZ:
2137 		*opclass_chwidth = BW_20_MHZ;
2138 		break;
2139 	case BW_40_MHZ:
2140 		*opclass_chwidth = BW_40_MHZ;
2141 		break;
2142 	case BW_80_MHZ:
2143 		*opclass_chwidth = BW_80_MHZ;
2144 		break;
2145 	case BW_160_MHZ:
2146 		*opclass_chwidth = BW_160_MHZ;
2147 		break;
2148 	default:
2149 		*opclass_chwidth = 0;
2150 	}
2151 }
2152 #endif
2153 
2154 QDF_STATUS
reg_get_opclass_for_cur_hwmode(struct wlan_objmgr_pdev * pdev,struct regdmn_ap_cap_opclass_t * reg_ap_cap,uint8_t * n_opclasses,uint8_t max_supp_op_class,bool global_tbl_lookup,enum phy_ch_width max_chwidth,bool is_80p80_supp,enum supported_6g_pwr_types in_6g_pwr_mode)2155 reg_get_opclass_for_cur_hwmode(struct wlan_objmgr_pdev *pdev,
2156 			       struct regdmn_ap_cap_opclass_t *reg_ap_cap,
2157 			       uint8_t *n_opclasses,
2158 			       uint8_t max_supp_op_class,
2159 			       bool global_tbl_lookup,
2160 			       enum phy_ch_width max_chwidth,
2161 			       bool is_80p80_supp,
2162 			       enum supported_6g_pwr_types in_6g_pwr_mode)
2163 {
2164 	uint8_t max_reg_power = 0;
2165 	const struct reg_dmn_op_class_map_t *op_class_tbl;
2166 	uint8_t index = 0;
2167 	uint16_t out_width;
2168 
2169 	if (global_tbl_lookup)
2170 		op_class_tbl = global_op_class;
2171 	else
2172 		reg_get_op_class_tbl_by_chan_map(&op_class_tbl);
2173 
2174 	max_reg_power = reg_get_max_tx_power(pdev);
2175 
2176 	out_width = reg_get_bw_value(max_chwidth);
2177 
2178 	while (op_class_tbl->op_class && (index < max_supp_op_class)) {
2179 		bool is_opclass_operable = false;
2180 		enum opclass_config opclass_in_config =
2181 		    OPCLASSES_SUPPORTED_BY_CUR_HWMODE;
2182 		uint16_t opclass_width;
2183 
2184 		qdf_mem_zero(reg_ap_cap[index].sup_chan_list,
2185 			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
2186 		reg_ap_cap[index].num_supported_chan = 0;
2187 		qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list,
2188 			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
2189 		reg_ap_cap[index].num_non_supported_chan = 0;
2190 
2191 		reg_convert_chan_spacing_to_width(op_class_tbl->chan_spacing,
2192 						  &opclass_width);
2193 
2194 		if ((opclass_width > out_width) ||
2195 		    ((op_class_tbl->behav_limit == BIT(BEHAV_BW80_PLUS)) &&
2196 		     !is_80p80_supp))
2197 			opclass_in_config =
2198 			    OPCLASSES_NOT_SUPPORTED_BY_CUR_HWMODE;
2199 
2200 		reg_get_channels_from_opclassmap(pdev,
2201 						 reg_ap_cap,
2202 						 index,
2203 						 op_class_tbl,
2204 						 &is_opclass_operable,
2205 						 opclass_in_config,
2206 						 in_6g_pwr_mode);
2207 
2208 		if (is_opclass_operable && opclass_in_config ==
2209 		    OPCLASSES_SUPPORTED_BY_CUR_HWMODE) {
2210 			reg_ap_cap[index].op_class = op_class_tbl->op_class;
2211 			reg_ap_cap[index].ch_width =
2212 				op_class_tbl->chan_spacing;
2213 			reg_ap_cap[index].start_freq =
2214 				op_class_tbl->start_freq;
2215 			reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power;
2216 			reg_ap_cap[index].behav_limit =
2217 				op_class_tbl->behav_limit;
2218 			index++;
2219 		}
2220 		op_class_tbl++;
2221 	}
2222 
2223 	*n_opclasses = index;
2224 
2225 	return QDF_STATUS_SUCCESS;
2226 }
2227 
2228 #ifndef CONFIG_REG_CLIENT
2229 /**
2230  * reg_enable_disable_chan_in_mas_chan_list() - Mark the opclass flag of the
2231  * freq/channel as disabled in the master channel list. Then based on that
2232  * regulatory disable/enable the freq/channel in the current channel list
2233  * @pdev_priv_obj: Pointer to regulatory pdev private object
2234  * @chan_num:  2.4 GHz or 5 GHz channel number
2235  * @is_disable: Boolean to disable or enable
2236  *
2237  * Return: void
2238  */
2239 static void
reg_enable_disable_chan_in_mas_chan_list(struct wlan_regulatory_pdev_priv_obj * pdev_priv_obj,uint8_t chan_num,bool is_disable)2240 reg_enable_disable_chan_in_mas_chan_list(struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
2241 					 uint8_t chan_num,
2242 					 bool is_disable)
2243 {
2244 	enum channel_enum chan_enum;
2245 	struct regulatory_channel *mas_chan_list;
2246 	qdf_freq_t freq;
2247 
2248 	freq = reg_legacy_chan_to_freq(pdev_priv_obj->pdev_ptr, chan_num);
2249 
2250 	/*
2251 	 * freq = 0 represent a regulatory disabled channel in master channel
2252 	 * list. Do not apply opclass disable/enable on a channel disabled in
2253 	 * the master channel list.
2254 	 */
2255 	if (!freq) {
2256 		reg_err("Frequency should not be zero");
2257 		return;
2258 	}
2259 
2260 	chan_enum = reg_get_chan_enum_for_freq(freq);
2261 	if (reg_is_chan_enum_invalid(chan_enum)) {
2262 		reg_err("Invalid chan enum %d", chan_enum);
2263 		return;
2264 	}
2265 
2266 	mas_chan_list = pdev_priv_obj->mas_chan_list;
2267 
2268 	if (is_disable) {
2269 		mas_chan_list[chan_enum].opclass_chan_disable = true;
2270 	} else {
2271 		/* A channel can be enabled only if its not in NOL */
2272 		if (!mas_chan_list[chan_enum].nol_chan)
2273 			mas_chan_list[chan_enum].opclass_chan_disable = false;
2274 	}
2275 }
2276 
2277 /**
2278  * reg_enable_disable_chan_freq() - Disable or enable a channel in the master
2279  * channel list, that is present in the operating class table's channel set.
2280  * @pdev: Pointer to pdev.
2281  * @is_disable: Boolean to disable or enable
2282  * @ieee_chan_list: Pointer to ieee_chan_list
2283  * @chan_list_size: Size of ieee_chan_list
2284  *
2285  * Return: void.
2286  */
2287 static void
reg_enable_disable_chan_freq(struct wlan_objmgr_pdev * pdev,bool is_disable,uint8_t * ieee_chan_list,uint8_t chan_list_size)2288 reg_enable_disable_chan_freq(struct wlan_objmgr_pdev *pdev,
2289 			     bool is_disable,
2290 			     uint8_t *ieee_chan_list,
2291 			     uint8_t chan_list_size)
2292 {
2293 	uint8_t i;
2294 	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
2295 
2296 	pdev_priv_obj = reg_get_pdev_obj(pdev);
2297 	if (!pdev_priv_obj) {
2298 		reg_err("pdev priv obj is NULL");
2299 		return;
2300 	}
2301 
2302 	for (i = 0; i < chan_list_size; i++) {
2303 		reg_enable_disable_chan_in_mas_chan_list(pdev_priv_obj,
2304 							 ieee_chan_list[i],
2305 							 is_disable);
2306 	}
2307 
2308 	reg_compute_pdev_current_chan_list(pdev_priv_obj);
2309 }
2310 
2311 /**
2312  * reg_is_chan_in_opclass_chan_list() - Check if a channel is present in the
2313  * operating class table's channel set
2314  * @chan: IEEE channel number
2315  * @opclass_chan_list: Pointer to opclass_chan_list
2316  *
2317  * Return: bool.
2318  */
2319 static bool
reg_is_chan_in_opclass_chan_list(uint8_t chan,const uint8_t * opclass_chan_list)2320 reg_is_chan_in_opclass_chan_list(uint8_t chan, const uint8_t *opclass_chan_list)
2321 {
2322 	uint8_t j;
2323 
2324 	for (j = 0; j < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
2325 	     opclass_chan_list[j]; j++) {
2326 		if (chan == opclass_chan_list[j])
2327 			return true;
2328 	}
2329 
2330 	return false;
2331 }
2332 
2333 /**
2334  * reg_is_inlst_subset_of_opchanlst() - Check if a channel present
2335  * in the input ieee_chan_list, is absent in the operating class table
2336  * channel set.
2337  * @opclass_chan_list: Pointer to opclass_chan_list
2338  * @ieee_chan_list: Pointer to ieee_chan_list
2339  * @ieee_chan_list_size: Size of ieee_chan_list
2340  *
2341  * Return: True if channel is absent in operating class table channel set.
2342  */
2343 static bool
reg_is_inlst_subset_of_opchanlst(const uint8_t * opclass_chan_list,uint8_t * ieee_chan_list,uint8_t ieee_chan_list_size)2344 reg_is_inlst_subset_of_opchanlst(const uint8_t *opclass_chan_list,
2345 				 uint8_t *ieee_chan_list,
2346 				 uint8_t ieee_chan_list_size)
2347 {
2348 	uint8_t i;
2349 
2350 	for (i = 0; i < ieee_chan_list_size; i++) {
2351 		if (!reg_is_chan_in_opclass_chan_list(ieee_chan_list[i],
2352 						      opclass_chan_list))
2353 			return true;
2354 	}
2355 
2356 	return false;
2357 }
2358 
reg_is_chanspacing_20mhz(uint16_t ch_spacing)2359 static bool reg_is_chanspacing_20mhz(uint16_t ch_spacing)
2360 {
2361 	return (ch_spacing >= BW_20_MHZ) && (ch_spacing <= BW_25_MHZ);
2362 }
2363 
reg_enable_disable_opclass_chans(struct wlan_objmgr_pdev * pdev,bool is_disable,uint8_t opclass,uint8_t * ieee_chan_list,uint8_t chan_list_size,bool global_tbl_lookup)2364 QDF_STATUS reg_enable_disable_opclass_chans(struct wlan_objmgr_pdev *pdev,
2365 					    bool is_disable, uint8_t opclass,
2366 					    uint8_t *ieee_chan_list,
2367 					    uint8_t chan_list_size,
2368 					    bool global_tbl_lookup)
2369 {
2370 	const struct reg_dmn_op_class_map_t *op_class_tbl;
2371 	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
2372 
2373 	if (!ieee_chan_list) {
2374 		reg_err("IEEE channel list is empty");
2375 		return QDF_STATUS_E_INVAL;
2376 	}
2377 
2378 	pdev_priv_obj = reg_get_pdev_obj(pdev);
2379 	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
2380 		reg_err("pdev reg obj is NULL");
2381 		return QDF_STATUS_E_FAILURE;
2382 	}
2383 
2384 	if (global_tbl_lookup)
2385 		op_class_tbl = global_op_class;
2386 	else
2387 		reg_get_op_class_tbl_by_chan_map(&op_class_tbl);
2388 
2389 	if (reg_is_6ghz_op_class(pdev, opclass)) {
2390 		reg_err("6GHz operating class is not supported");
2391 		return QDF_STATUS_E_INVAL;
2392 	}
2393 
2394 	while (op_class_tbl->op_class) {
2395 		if (opclass == op_class_tbl->op_class) {
2396 			if (!reg_is_chanspacing_20mhz(op_class_tbl->chan_spacing)) {
2397 				reg_err("Opclass should only be 20 MHz opclass");
2398 				return QDF_STATUS_E_INVAL;
2399 			}
2400 
2401 			if (reg_is_inlst_subset_of_opchanlst(op_class_tbl->channels,
2402 							     ieee_chan_list,
2403 							     chan_list_size)) {
2404 				reg_err("Invalid channel present in chan list");
2405 				return QDF_STATUS_E_INVAL;
2406 			}
2407 
2408 			reg_enable_disable_chan_freq(pdev, is_disable,
2409 						     ieee_chan_list,
2410 						     chan_list_size);
2411 
2412 			return QDF_STATUS_SUCCESS;
2413 		}
2414 
2415 		op_class_tbl++;
2416 	}
2417 
2418 	reg_err("The opclass is not found %d", opclass);
2419 	return QDF_STATUS_E_INVAL;
2420 }
2421 #endif /* #ifndef CONFIG_REG_CLIENT */
2422 
reg_get_opclass_from_map(const struct reg_dmn_op_class_map_t ** map,bool is_global_op_table_needed)2423 QDF_STATUS reg_get_opclass_from_map(const struct reg_dmn_op_class_map_t **map,
2424 				    bool is_global_op_table_needed)
2425 {
2426 	if (is_global_op_table_needed)
2427 		*map = global_op_class;
2428 	else
2429 		reg_get_op_class_tbl_by_chan_map(map);
2430 
2431 	return QDF_STATUS_SUCCESS;
2432 }
2433 
2434 #endif
2435