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