xref: /wlan-dirver/qca-wifi-host-cmn/umac/regulatory/core/src/reg_opclass.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
1 /*
2  * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 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 	p_total_alloc1 = qdf_mem_malloc(total_alloc_size);
789 	if (!p_total_alloc1) {
790 		reg_err("out-of-memory");
791 		return QDF_STATUS_E_NOMEM;
792 	}
793 
794 	 /* Assign memory locations to each pointers */
795 	p_temp_alloc = p_total_alloc1;
796 
797 	l_opcls_lst = p_temp_alloc;
798 	p_temp_alloc += opcls_lst_size;
799 
800 	l_chansize_lst = p_temp_alloc;
801 	p_temp_alloc += chansize_lst_size;
802 
803 	arr_chan_lists = (uint8_t **)p_temp_alloc;
804 
805 	/* Fill arrays with opclasses and chanlist sizes */
806 	count = 0;
807 	while (op_class_tbl && op_class_tbl->op_class) {
808 		const struct c_freq_lst *p_lst;
809 
810 		p_lst = op_class_tbl->p_cfi_lst_obj;
811 		if (p_lst &&
812 		    reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) {
813 			uint8_t n_supp_cfis = 0;
814 			uint8_t j;
815 
816 			l_opcls_lst[count] = op_class_tbl->op_class;
817 			for (j = 0; j < p_lst->num_cfis; j++) {
818 				uint8_t cfi;
819 				qdf_freq_t cfi_freq;
820 				qdf_freq_t start_freq = op_class_tbl->start_freq;
821 				uint16_t bw = op_class_tbl->chan_spacing;
822 
823 				cfi = p_lst->p_cfis_arr[j];
824 				cfi_freq = start_freq +
825 					FREQ_TO_CHAN_SCALE * cfi;
826 				if (reg_is_cfi_freq_in_ranges(cfi_freq,
827 							      bw,
828 							      p_frange_lst)) {
829 					n_supp_cfis++;
830 				}
831 			}
832 			l_chansize_lst[count] = n_supp_cfis;
833 			count++;
834 		}
835 		op_class_tbl++;
836 	}
837 
838 	/* Calculate total alloction size for the array */
839 	total_alloc_size = 0;
840 	for (i = 0; i < *num_opclasses; i++)
841 		total_alloc_size += l_chansize_lst[i] * sizeof(uint8_t *);
842 
843 	p_total_alloc2 = qdf_mem_malloc(total_alloc_size);
844 	if (!p_total_alloc2) {
845 		reg_err("out-of-memory");
846 		qdf_mem_free(p_total_alloc1);
847 		return QDF_STATUS_E_NOMEM;
848 	}
849 
850 	/* Assign memory locations to each list pointers */
851 	p_temp_alloc = p_total_alloc2;
852 	for (i = 0; i < *num_opclasses; i++) {
853 		if (!l_chansize_lst[i])
854 			arr_chan_lists[i] = NULL;
855 		else
856 			arr_chan_lists[i] = p_temp_alloc;
857 
858 		p_temp_alloc += l_chansize_lst[i] * sizeof(uint8_t *);
859 	}
860 
861 	/* Fill the array with channel lists */
862 	reg_dmn_fill_6g_opcls_chan_lists(pdev, p_frange_lst, l_chansize_lst, arr_chan_lists);
863 
864 	*opclass_lst = l_opcls_lst;
865 	*chansize_lst = l_chansize_lst;
866 	*channel_lists = arr_chan_lists;
867 
868 	return QDF_STATUS_SUCCESS;
869 }
870 #endif /* CONFIG_AFC_SUPPORT */
871 
872 uint16_t reg_dmn_get_chanwidth_from_opclass(uint8_t *country, uint8_t channel,
873 					    uint8_t opclass)
874 {
875 	const struct reg_dmn_op_class_map_t *class;
876 	uint16_t i;
877 
878 	class = reg_get_class_from_country(country);
879 
880 	while (class->op_class) {
881 		if (opclass == class->op_class) {
882 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
883 				     class->channels[i]); i++) {
884 				if (channel == class->channels[i])
885 					return class->chan_spacing;
886 			}
887 		}
888 		class++;
889 	}
890 
891 	return 0;
892 }
893 
894 uint16_t reg_dmn_get_chanwidth_from_opclass_auto(uint8_t *country,
895 						 uint8_t channel,
896 						 uint8_t opclass)
897 {
898 	uint16_t ret;
899 	uint8_t global_country[REG_ALPHA2_LEN + 1];
900 
901 	ret = reg_dmn_get_chanwidth_from_opclass(country, channel, opclass);
902 
903 	if (!ret) {
904 		global_country[2] = OP_CLASS_GLOBAL;
905 		ret = reg_dmn_get_chanwidth_from_opclass(global_country,
906 							 channel, opclass);
907 	}
908 
909 	return ret;
910 }
911 
912 uint16_t reg_dmn_get_opclass_from_channel(uint8_t *country, uint8_t channel,
913 					  uint8_t offset)
914 {
915 	const struct reg_dmn_op_class_map_t *class = NULL;
916 	uint16_t i = 0;
917 
918 	class = reg_get_class_from_country(country);
919 	while (class && class->op_class) {
920 		if ((offset == class->offset) || (offset == BWALL)) {
921 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
922 				     class->channels[i]); i++) {
923 				if (channel == class->channels[i])
924 					return class->op_class;
925 			}
926 		}
927 		class++;
928 	}
929 
930 	return 0;
931 }
932 
933 uint8_t reg_dmn_get_opclass_from_freq_width(uint8_t *country,
934 					    qdf_freq_t freq,
935 					    uint16_t ch_width,
936 					    uint16_t behav_limit)
937 {
938 	const struct reg_dmn_op_class_map_t *op_class_tbl = NULL;
939 	uint16_t i = 0;
940 
941 	op_class_tbl = reg_get_class_from_country(country);
942 
943 	while (op_class_tbl && op_class_tbl->op_class) {
944 		if (op_class_tbl->chan_spacing == ch_width) {
945 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
946 				     op_class_tbl->channels[i]); i++) {
947 				if ((op_class_tbl->start_freq +
948 				     (FREQ_TO_CHAN_SCALE *
949 				      op_class_tbl->channels[i]) == freq) &&
950 				    (behav_limit & op_class_tbl->behav_limit)) {
951 					return op_class_tbl->op_class;
952 				}
953 			}
954 		}
955 		op_class_tbl++;
956 	}
957 
958 	return 0;
959 }
960 
961 static void
962 reg_get_band_cap_from_chan_set(const struct reg_dmn_op_class_map_t
963 			       *op_class_tbl,
964 			       uint8_t *supported_band)
965 {
966 	qdf_freq_t chan_freq = op_class_tbl->start_freq +
967 						(op_class_tbl->channels[0] *
968 						 FREQ_TO_CHAN_SCALE);
969 
970 	if (reg_is_24ghz_ch_freq(chan_freq))
971 		*supported_band |= BIT(REG_BAND_2G);
972 	else if (reg_is_5ghz_ch_freq(chan_freq))
973 		*supported_band |= BIT(REG_BAND_5G);
974 	else if (reg_is_6ghz_chan_freq(chan_freq))
975 		*supported_band |= BIT(REG_BAND_6G);
976 	else
977 		reg_err_rl("Unknown band");
978 }
979 
980 uint8_t reg_get_band_cap_from_op_class(const uint8_t *country,
981 				       uint8_t num_of_opclass,
982 				       const uint8_t *opclass)
983 {
984 	const struct reg_dmn_op_class_map_t *op_class_tbl;
985 	uint8_t supported_band = 0, opclassidx;
986 
987 	op_class_tbl = reg_get_class_from_country(country);
988 
989 	while (op_class_tbl && op_class_tbl->op_class) {
990 		for (opclassidx = 0; opclassidx < num_of_opclass;
991 		     opclassidx++) {
992 			if (op_class_tbl->op_class == opclass[opclassidx]) {
993 				reg_get_band_cap_from_chan_set(op_class_tbl,
994 							       &supported_band);
995 			}
996 		}
997 		op_class_tbl++;
998 	}
999 
1000 	if (!supported_band)
1001 		reg_err_rl("None of the operating classes is found");
1002 
1003 	return supported_band;
1004 }
1005 
1006 void reg_dmn_print_channels_in_opclass(uint8_t *country, uint8_t op_class)
1007 {
1008 	const struct reg_dmn_op_class_map_t *class = NULL;
1009 	uint16_t i = 0;
1010 
1011 	class = reg_get_class_from_country(country);
1012 
1013 	if (!class) {
1014 		reg_err("class is NULL");
1015 		return;
1016 	}
1017 
1018 	while (class->op_class) {
1019 		if (class->op_class == op_class) {
1020 			for (i = 0;
1021 			     (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1022 			      class->channels[i]); i++) {
1023 				reg_debug("Valid channel(%d) in requested RC(%d)",
1024 					  class->channels[i], op_class);
1025 			}
1026 			break;
1027 		}
1028 		class++;
1029 	}
1030 	if (!class->op_class)
1031 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
1032 			  "Invalid requested RC (%d)", op_class);
1033 }
1034 
1035 uint16_t reg_dmn_set_curr_opclasses(uint8_t num_classes, uint8_t *class)
1036 {
1037 	uint8_t i;
1038 
1039 	if (num_classes > REG_MAX_SUPP_OPER_CLASSES) {
1040 		reg_err("invalid num classes %d", num_classes);
1041 		return 0;
1042 	}
1043 
1044 	for (i = 0; i < num_classes; i++)
1045 		reg_dmn_curr_supp_opp_classes.classes[i] = class[i];
1046 
1047 	reg_dmn_curr_supp_opp_classes.num_classes = num_classes;
1048 
1049 	return 0;
1050 }
1051 
1052 uint16_t reg_dmn_get_curr_opclasses(uint8_t *num_classes, uint8_t *class)
1053 {
1054 	uint8_t i;
1055 
1056 	if (!num_classes || !class) {
1057 		reg_err("either num_classes or class is null");
1058 		return 0;
1059 	}
1060 
1061 	for (i = 0; i < reg_dmn_curr_supp_opp_classes.num_classes; i++)
1062 		class[i] = reg_dmn_curr_supp_opp_classes.classes[i];
1063 
1064 	*num_classes = reg_dmn_curr_supp_opp_classes.num_classes;
1065 
1066 	return 0;
1067 }
1068 
1069 #ifdef CONFIG_CHAN_FREQ_API
1070 /**
1071  * reg_find_opclass_absent_in_ctry_opclss_tables() - Check Global Opclass table
1072  * when Opclass is not present in specific country.
1073  * @pdev - Pointer to pdev
1074  * @freq - Destination Frequency
1075  * @chan_width- Channel Width
1076  * @global_tbl_lookup - Global Table Lookup
1077  * @behav_limit - Behav Limit
1078  * @op_class - Pointer to Opclass
1079  * @chan_num - Pointer to Channel
1080  *
1081  * Return: Void
1082  */
1083 static void
1084 reg_find_opclass_absent_in_ctry_opclss_tables(struct wlan_objmgr_pdev *pdev,
1085 					      qdf_freq_t freq,
1086 					      uint16_t chan_width,
1087 					      bool global_tbl_lookup,
1088 					      uint16_t behav_limit,
1089 					      uint8_t *op_class,
1090 					      uint8_t *chan_num)
1091 {
1092 	if (!global_tbl_lookup && !*op_class) {
1093 		global_tbl_lookup = true;
1094 		reg_freq_width_to_chan_op_class(pdev, freq,
1095 						chan_width,
1096 						global_tbl_lookup,
1097 						behav_limit,
1098 						op_class,
1099 						chan_num);
1100 	}
1101 }
1102 
1103 static bool
1104 reg_is_country_opclass_global(struct wlan_objmgr_pdev *pdev)
1105 {
1106 	struct wlan_lmac_if_reg_tx_ops *reg_tx_ops;
1107 	struct wlan_objmgr_psoc *psoc;
1108 	uint8_t opclass_tbl_idx;
1109 
1110 	psoc = wlan_pdev_get_psoc(pdev);
1111 	if (!psoc) {
1112 		reg_err("psoc is NULL");
1113 		return false;
1114 	}
1115 
1116 	reg_tx_ops = reg_get_psoc_tx_ops(psoc);
1117 	if (!reg_tx_ops) {
1118 		reg_err("reg_tx_ops is NULL");
1119 		return false;
1120 	}
1121 
1122 	if (reg_tx_ops->get_opclass_tbl_idx) {
1123 		reg_tx_ops->get_opclass_tbl_idx(pdev, &opclass_tbl_idx);
1124 
1125 		if (opclass_tbl_idx == OP_CLASS_GLOBAL)
1126 			return true;
1127 	}
1128 
1129 	return false;
1130 }
1131 
1132 void reg_freq_width_to_chan_op_class_auto(struct wlan_objmgr_pdev *pdev,
1133 					  qdf_freq_t freq,
1134 					  uint16_t chan_width,
1135 					  bool global_tbl_lookup,
1136 					  uint16_t behav_limit,
1137 					  uint8_t *op_class,
1138 					  uint8_t *chan_num)
1139 {
1140 	if (reg_freq_to_band(freq) == REG_BAND_6G) {
1141 		global_tbl_lookup = true;
1142 		if (chan_width == BW_40_MHZ)
1143 			behav_limit = BIT(BEHAV_NONE);
1144 	} else if (reg_is_5dot9_ghz_freq(pdev, freq)) {
1145 		global_tbl_lookup = true;
1146 	} else {
1147 		global_tbl_lookup = reg_is_country_opclass_global(pdev);
1148 	}
1149 
1150 	*op_class = 0;
1151 	reg_freq_width_to_chan_op_class(pdev, freq,
1152 					chan_width,
1153 					global_tbl_lookup,
1154 					behav_limit,
1155 					op_class,
1156 					chan_num);
1157 	reg_find_opclass_absent_in_ctry_opclss_tables(pdev, freq,
1158 						      chan_width,
1159 						      global_tbl_lookup,
1160 						      behav_limit,
1161 						      op_class,
1162 						      chan_num);
1163 }
1164 
1165 void reg_freq_width_to_chan_op_class(struct wlan_objmgr_pdev *pdev,
1166 				     qdf_freq_t freq,
1167 				     uint16_t chan_width,
1168 				     bool global_tbl_lookup,
1169 				     uint16_t behav_limit,
1170 				     uint8_t *op_class,
1171 				     uint8_t *chan_num)
1172 {
1173 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1174 	enum channel_enum chan_enum;
1175 	uint16_t i;
1176 
1177 	chan_enum = reg_get_chan_enum_for_freq(freq);
1178 
1179 	if (reg_is_chan_enum_invalid(chan_enum)) {
1180 		reg_err_rl("Invalid chan enum %d", chan_enum);
1181 		return;
1182 	}
1183 
1184 	if (global_tbl_lookup) {
1185 		op_class_tbl = global_op_class;
1186 	} else {
1187 		if (channel_map == channel_map_us)
1188 			op_class_tbl = us_op_class;
1189 		else if (channel_map == channel_map_eu)
1190 			op_class_tbl = euro_op_class;
1191 		else if (channel_map == channel_map_china)
1192 			op_class_tbl = china_op_class;
1193 		else if (channel_map == channel_map_jp)
1194 			op_class_tbl = japan_op_class;
1195 		else
1196 			op_class_tbl = global_op_class;
1197 	}
1198 
1199 	while (op_class_tbl->op_class) {
1200 		if (op_class_tbl->chan_spacing >= chan_width) {
1201 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1202 				     op_class_tbl->channels[i]); i++) {
1203 				if ((op_class_tbl->start_freq +
1204 				     FREQ_TO_CHAN_SCALE *
1205 				     op_class_tbl->channels[i] == freq) &&
1206 				    (behav_limit & op_class_tbl->behav_limit ||
1207 				     behav_limit == BIT(BEHAV_NONE))) {
1208 					*chan_num = op_class_tbl->channels[i];
1209 					*op_class = op_class_tbl->op_class;
1210 					return;
1211 				}
1212 			}
1213 		}
1214 		op_class_tbl++;
1215 	}
1216 
1217 	reg_err_rl("no op class for frequency %d", freq);
1218 }
1219 
1220 void reg_freq_to_chan_op_class(struct wlan_objmgr_pdev *pdev,
1221 			       qdf_freq_t freq,
1222 			       bool global_tbl_lookup,
1223 			       uint16_t behav_limit,
1224 			       uint8_t *op_class,
1225 			       uint8_t *chan_num)
1226 {
1227 	enum channel_enum chan_enum;
1228 	struct regulatory_channel *cur_chan_list;
1229 	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
1230 	struct ch_params chan_params = {0};
1231 
1232 	pdev_priv_obj = reg_get_pdev_obj(pdev);
1233 
1234 	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
1235 		reg_err_rl("NULL pdev reg obj");
1236 		return;
1237 	}
1238 
1239 	cur_chan_list = pdev_priv_obj->cur_chan_list;
1240 
1241 	chan_enum = reg_get_chan_enum_for_freq(freq);
1242 
1243 	if (reg_is_chan_enum_invalid(chan_enum)) {
1244 		reg_err_rl("Invalid chan enum %d", chan_enum);
1245 		return;
1246 	}
1247 
1248 	chan_params.ch_width = CH_WIDTH_MAX;
1249 	reg_set_channel_params_for_pwrmode(pdev, freq,
1250 					   0,
1251 					   &chan_params,
1252 					   REG_CURRENT_PWR_MODE, true);
1253 
1254 	reg_freq_width_to_chan_op_class(pdev, freq,
1255 					reg_get_bw_value(chan_params.ch_width),
1256 					global_tbl_lookup,
1257 					behav_limit,
1258 					op_class,
1259 					chan_num);
1260 }
1261 
1262 bool reg_is_freq_in_country_opclass(struct wlan_objmgr_pdev *pdev,
1263 				    const uint8_t country[3],
1264 				    uint8_t op_class,
1265 				    qdf_freq_t chan_freq)
1266 {
1267 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1268 	uint8_t i;
1269 
1270 	op_class_tbl = reg_get_class_from_country((uint8_t *)country);
1271 
1272 	while (op_class_tbl && op_class_tbl->op_class) {
1273 		if  (op_class_tbl->op_class == op_class) {
1274 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1275 				     op_class_tbl->channels[i]); i++) {
1276 				if (op_class_tbl->channels[i] *
1277 				    FREQ_TO_CHAN_SCALE +
1278 				    op_class_tbl->start_freq == chan_freq)
1279 					return true;
1280 			}
1281 		}
1282 		op_class_tbl++;
1283 	}
1284 	return false;
1285 }
1286 
1287 #endif
1288 
1289 uint16_t reg_get_op_class_width(struct wlan_objmgr_pdev *pdev,
1290 				uint8_t op_class,
1291 				bool global_tbl_lookup)
1292 {
1293 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1294 
1295 	if (global_tbl_lookup) {
1296 		op_class_tbl = global_op_class;
1297 	} else {
1298 		if (channel_map == channel_map_us)
1299 			op_class_tbl = us_op_class;
1300 		else if (channel_map == channel_map_eu)
1301 			op_class_tbl = euro_op_class;
1302 		else if (channel_map == channel_map_china)
1303 			op_class_tbl = china_op_class;
1304 		else if (channel_map == channel_map_jp)
1305 			op_class_tbl = japan_op_class;
1306 		else
1307 			op_class_tbl = global_op_class;
1308 	}
1309 
1310 	while (op_class_tbl->op_class) {
1311 		if  (op_class_tbl->op_class == op_class)
1312 			return op_class_tbl->chan_spacing;
1313 		op_class_tbl++;
1314 	}
1315 
1316 	return 0;
1317 }
1318 
1319 uint16_t reg_chan_opclass_to_freq(uint8_t chan,
1320 				  uint8_t op_class,
1321 				  bool global_tbl_lookup)
1322 {
1323 	const struct reg_dmn_op_class_map_t *op_class_tbl = NULL;
1324 	uint8_t i = 0;
1325 
1326 	if (global_tbl_lookup) {
1327 		op_class_tbl = global_op_class;
1328 	} else {
1329 		if (channel_map == channel_map_global) {
1330 			op_class_tbl = global_op_class;
1331 		} else if (channel_map == channel_map_us) {
1332 			op_class_tbl = us_op_class;
1333 		} else if (channel_map == channel_map_eu) {
1334 			op_class_tbl = euro_op_class;
1335 		} else if (channel_map == channel_map_china) {
1336 			op_class_tbl = china_op_class;
1337 		} else if (channel_map == channel_map_jp) {
1338 			op_class_tbl = japan_op_class;
1339 		} else {
1340 			reg_err_rl("Invalid channel map");
1341 			return 0;
1342 		}
1343 	}
1344 
1345 	while (op_class_tbl->op_class) {
1346 		if  (op_class_tbl->op_class == op_class) {
1347 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1348 				     op_class_tbl->channels[i]); i++) {
1349 				if (op_class_tbl->channels[i] == chan) {
1350 					chan = op_class_tbl->channels[i];
1351 					return op_class_tbl->start_freq +
1352 						(chan * FREQ_TO_CHAN_SCALE);
1353 				}
1354 			}
1355 			reg_err_rl("Channel not found");
1356 			return 0;
1357 		}
1358 		op_class_tbl++;
1359 	}
1360 	reg_err_rl("Invalid opclass");
1361 	return 0;
1362 }
1363 
1364 qdf_freq_t reg_chan_opclass_to_freq_auto(uint8_t chan, uint8_t op_class,
1365 					 bool global_tbl_lookup)
1366 {
1367 	if ((op_class >= MIN_6GHZ_OPER_CLASS) &&
1368 	    (op_class <= MAX_6GHZ_OPER_CLASS)) {
1369 		global_tbl_lookup = true;
1370 	} else {
1371 		qdf_freq_t freq = reg_chan_opclass_to_freq(chan,
1372 				op_class,
1373 				global_tbl_lookup);
1374 		if (freq)
1375 			return freq;
1376 		global_tbl_lookup = true;
1377 	}
1378 
1379 	return reg_chan_opclass_to_freq(chan, op_class, global_tbl_lookup);
1380 }
1381 
1382 #ifdef HOST_OPCLASS_EXT
1383 qdf_freq_t reg_country_chan_opclass_to_freq(struct wlan_objmgr_pdev *pdev,
1384 					    const uint8_t country[3],
1385 					    uint8_t chan, uint8_t op_class,
1386 					    bool strict)
1387 {
1388 	const struct reg_dmn_op_class_map_t *op_class_tbl, *op_class_tbl_org;
1389 	uint16_t i;
1390 
1391 	if (reg_is_6ghz_op_class(pdev, op_class))
1392 		op_class_tbl_org = global_op_class;
1393 	else
1394 		op_class_tbl_org =
1395 			reg_get_class_from_country((uint8_t *)country);
1396 	op_class_tbl = op_class_tbl_org;
1397 	while (op_class_tbl && op_class_tbl->op_class) {
1398 		if  (op_class_tbl->op_class == op_class) {
1399 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1400 				     op_class_tbl->channels[i]); i++) {
1401 				if (op_class_tbl->channels[i] == chan)
1402 					return op_class_tbl->start_freq +
1403 						(chan * FREQ_TO_CHAN_SCALE);
1404 			}
1405 		}
1406 		op_class_tbl++;
1407 	}
1408 	reg_debug_rl("Not found ch %d in op class %d ch list, strict %d",
1409 		     chan, op_class, strict);
1410 	if (strict)
1411 		return 0;
1412 
1413 	op_class_tbl = op_class_tbl_org;
1414 	while (op_class_tbl && op_class_tbl->op_class) {
1415 		for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1416 			     op_class_tbl->channels[i]); i++) {
1417 			if (op_class_tbl->channels[i] == chan)
1418 				return op_class_tbl->start_freq +
1419 					(chan * FREQ_TO_CHAN_SCALE);
1420 		}
1421 		op_class_tbl++;
1422 	}
1423 	reg_debug_rl("Got invalid freq 0 for ch %d", chan);
1424 
1425 	return 0;
1426 }
1427 #endif
1428 
1429 static void
1430 reg_get_op_class_tbl_by_chan_map(const struct
1431 				 reg_dmn_op_class_map_t **op_class_tbl)
1432 {
1433 	if (channel_map == channel_map_us)
1434 		*op_class_tbl = us_op_class;
1435 	else if (channel_map == channel_map_eu)
1436 		*op_class_tbl = euro_op_class;
1437 	else if (channel_map == channel_map_china)
1438 		*op_class_tbl = china_op_class;
1439 	else if (channel_map == channel_map_jp)
1440 		*op_class_tbl = japan_op_class;
1441 	else
1442 		*op_class_tbl = global_op_class;
1443 }
1444 
1445 /**
1446  * reg_get_channel_cen - Calculate central channel in the channel set.
1447  *
1448  * @op_class_tbl - Pointer to op_class_tbl.
1449  * @idx - Pointer to channel index.
1450  * @num_channels - Number of channels.
1451  * @center_chan - Pointer to center channel number
1452  *
1453  * Return : void
1454  */
1455 static void reg_get_channel_cen(const struct
1456 				reg_dmn_op_class_map_t *op_class_tbl,
1457 				uint8_t *idx,
1458 				uint8_t num_channels,
1459 				uint8_t *center_chan)
1460 {
1461 	uint8_t i;
1462 	uint16_t new_chan = 0;
1463 
1464 	for (i = *idx; i < (*idx + num_channels); i++)
1465 		new_chan += op_class_tbl->channels[i];
1466 
1467 	new_chan = new_chan / num_channels;
1468 	*center_chan = new_chan;
1469 	*idx = *idx + num_channels;
1470 }
1471 
1472 /**
1473  * reg_is_chan_320mhz() - Return true if the chan width is 320MHZ,
1474  * false otherwise.
1475  * @chan_spacing: Channel spacing in MHZ.
1476  *
1477  * Return: true if chan_width is 320, false otherwise.
1478  */
1479 #ifdef WLAN_FEATURE_11BE
1480 static bool reg_is_chan_320mhz(uint16_t chan_spacing)
1481 {
1482 	if (chan_spacing == BW_320_MHZ)
1483 		return true;
1484 	return false;
1485 }
1486 #else
1487 static bool reg_is_chan_320mhz(uint16_t chan_spacing)
1488 {
1489 	return false;
1490 }
1491 #endif
1492 
1493 /**
1494  * reg_get_chan_or_chan_center - Calculate central channel in the channel set.
1495  *
1496  * @op_class_tbl - Pointer to op_class_tbl.
1497  * @idx - Pointer to channel index.
1498  *
1499  * Return : Center channel number
1500  */
1501 static uint8_t reg_get_chan_or_chan_center(const struct
1502 					   reg_dmn_op_class_map_t *op_class_tbl,
1503 					   uint8_t *idx)
1504 {
1505 	uint8_t center_chan;
1506 
1507 	if (((op_class_tbl->chan_spacing == BW_80_MHZ) &&
1508 	     (op_class_tbl->behav_limit == BIT(BEHAV_NONE))) ||
1509 	    ((op_class_tbl->chan_spacing == BW_80_MHZ) &&
1510 	     (op_class_tbl->behav_limit == BIT(BEHAV_BW80_PLUS)))) {
1511 		reg_get_channel_cen(op_class_tbl,
1512 				    idx,
1513 				    NUM_20_MHZ_CHAN_IN_80_MHZ_CHAN,
1514 				    &center_chan);
1515 	} else if (op_class_tbl->chan_spacing == BW_160_MHZ) {
1516 		reg_get_channel_cen(op_class_tbl,
1517 				    idx,
1518 				    NUM_20_MHZ_CHAN_IN_160_MHZ_CHAN,
1519 				    &center_chan);
1520 	} else if (reg_is_chan_320mhz(op_class_tbl->chan_spacing)) {
1521 		reg_get_channel_cen(op_class_tbl,
1522 				    idx,
1523 				    NUM_20_MHZ_CHAN_IN_320_MHZ_CHAN,
1524 				    &center_chan);
1525 	} else {
1526 		center_chan = op_class_tbl->channels[*idx];
1527 		*idx = *idx + 1;
1528 	}
1529 
1530 	return center_chan;
1531 }
1532 
1533 static inline qdf_freq_t reg_get_nearest_primary_freq(uint16_t bw,
1534 						      qdf_freq_t cfi_freq,
1535 						      uint8_t op_class)
1536 {
1537 	qdf_freq_t pri_freq;
1538 
1539 	if (bw <= BW_40_MHZ && op_class != OPCLS_132) {
1540 		pri_freq = cfi_freq;
1541 	} else {
1542 		if (cfi_freq >= BW_10_MHZ)
1543 			pri_freq = cfi_freq - BW_10_MHZ;
1544 		else
1545 			pri_freq = 0;
1546 	}
1547 
1548 	return pri_freq;
1549 }
1550 
1551 #ifdef WLAN_FEATURE_11BE
1552 /**
1553  * reg_is_chan_supported()- Check if given channel is supported based on its
1554  * freq provided
1555  * @pdev: Pointer to pdev
1556  * @pri_freq: Primary frequency of the input channel
1557  * @cfi_freq: cfi frequency of the input channel
1558  * @ch_width: Input channel width
1559  *
1560  * Return: True if the channel is supported, else false
1561  */
1562 static bool reg_is_chan_supported(struct wlan_objmgr_pdev *pdev,
1563 				  qdf_freq_t pri_freq,
1564 				  qdf_freq_t cfi_freq,
1565 				  enum phy_ch_width ch_width)
1566 {
1567 	struct reg_channel_list chan_list;
1568 	qdf_freq_t center_320;
1569 	struct ch_params ch_params = {0};
1570 
1571 	center_320 = (ch_width == CH_WIDTH_320MHZ) ? cfi_freq : 0;
1572 	reg_fill_channel_list(pdev,
1573 			      pri_freq,
1574 			      0,
1575 			      ch_width,
1576 			      center_320,
1577 			      &chan_list, true);
1578 	ch_params = chan_list.chan_param[0];
1579 
1580 	if (ch_params.ch_width == ch_width)
1581 		return true;
1582 
1583 	return false;
1584 }
1585 #else
1586 static bool reg_is_chan_supported(struct wlan_objmgr_pdev *pdev,
1587 				  qdf_freq_t pri_freq,
1588 				  qdf_freq_t cfi_freq,
1589 				  enum phy_ch_width ch_width)
1590 {
1591 	struct ch_params ch_params = {0};
1592 
1593 	ch_params.ch_width = ch_width;
1594 	reg_set_channel_params_for_freq(pdev, pri_freq, 0, &ch_params, true);
1595 	if (ch_params.ch_width == ch_width)
1596 		return true;
1597 
1598 	return false;
1599 }
1600 #endif
1601 
1602 /**
1603  * reg_is_cfi_supported()- Check if given cfi is supported
1604  * @pdev: Pointer to pdev
1605  * @cfi_freq: cfi frequency
1606  * @bw: bandwidth
1607  *
1608  * Return: True if the cfi is supported, else false
1609  */
1610 static bool reg_is_cfi_supported(struct wlan_objmgr_pdev *pdev,
1611 				 qdf_freq_t cfi_freq,
1612 				 uint16_t bw,
1613 				 uint8_t op_class)
1614 {
1615 	enum phy_ch_width ch_width;
1616 	qdf_freq_t pri_freq;
1617 	bool is_cfi_supported;
1618 
1619 	ch_width = reg_find_chwidth_from_bw(bw);
1620 	pri_freq = reg_get_nearest_primary_freq(bw, cfi_freq, op_class);
1621 	is_cfi_supported = reg_is_chan_supported(pdev,
1622 						 pri_freq,
1623 						 cfi_freq,
1624 						 ch_width);
1625 
1626 	return is_cfi_supported;
1627 }
1628 
1629 /**
1630  * reg_get_cfis_from_opclassmap_for_6g()- Get channels from the opclass map
1631  * for 6GHz
1632  * @pdev: Pointer to pdev
1633  * @cap: Pointer to regdmn_ap_cap_opclass_t
1634  * @op_class_tbl: Pointer to op_class_tbl
1635  * @in_opclass_conf: input opclass configuration
1636  * Supported or not-supported by current HW mode
1637  *
1638  * Populate channels from opclass map to regdmn_ap_cap_opclass_t as supported
1639  * and non-supported channels for 6Ghz.
1640  *
1641  * Return: void.
1642  */
1643 static void reg_get_cfis_from_opclassmap_for_6g(
1644 			struct wlan_objmgr_pdev *pdev,
1645 			struct regdmn_ap_cap_opclass_t *cap,
1646 			const struct reg_dmn_op_class_map_t *op_class_tbl,
1647 			enum opclass_config in_opclass_conf)
1648 {
1649 	uint8_t n_sup_chans = 0, n_unsup_chans = 0, j;
1650 	const struct c_freq_lst *p_cfi_lst = op_class_tbl->p_cfi_lst_obj;
1651 	qdf_freq_t cfi_freq;
1652 	qdf_freq_t start_freq = op_class_tbl->start_freq;
1653 	uint16_t bw = op_class_tbl->chan_spacing;
1654 
1655 	for (j = 0; j < p_cfi_lst->num_cfis; j++) {
1656 		uint8_t cfi = p_cfi_lst->p_cfis_arr[j];
1657 		bool is_cfi_supported;
1658 
1659 		cfi_freq = start_freq + FREQ_TO_CHAN_SCALE * cfi;
1660 		is_cfi_supported = reg_is_cfi_supported(pdev,
1661 							cfi_freq,
1662 							bw,
1663 							op_class_tbl->op_class);
1664 		if (is_cfi_supported &&
1665 		    (in_opclass_conf == OPCLASSES_SUPPORTED_BY_CUR_HWMODE ||
1666 		     in_opclass_conf == OPCLASSES_SUPPORTED_BY_DOMAIN)) {
1667 			cap->sup_chan_list[n_sup_chans++] = cfi;
1668 			cap->num_supported_chan++;
1669 		} else {
1670 			cap->non_sup_chan_list[n_unsup_chans++] = cfi;
1671 			cap->num_non_supported_chan++;
1672 		}
1673 	}
1674 }
1675 
1676 static uint16_t reg_find_nearest_ieee_bw(uint16_t spacing)
1677 {
1678 	#define SMALLEST_BW 20
1679 	return (spacing / SMALLEST_BW) * SMALLEST_BW;
1680 }
1681 
1682 /**
1683  * reg_get_cfis_from_opclassmap_for_non6g()- Get channels from the opclass map
1684  * for non-6GHz
1685  * @pdev: Pointer to pdev
1686  * @cap: Pointer to regdmn_ap_cap_opclass_t
1687  * @op_class_tbl: Pointer to op_class_tbl
1688  * @in_opclass_conf: input opclass configuration
1689  * Supported or not-supported by current HW mode
1690  *
1691  * Populate channels from opclass map to regdmn_ap_cap_opclass_t as supported
1692  * and non-supported channels for non-6Ghz.
1693  *
1694  * Return: void.
1695  */
1696 static void reg_get_cfis_from_opclassmap_for_non6g(
1697 			struct wlan_objmgr_pdev *pdev,
1698 			struct regdmn_ap_cap_opclass_t *cap,
1699 			const struct reg_dmn_op_class_map_t *op_class_tbl,
1700 			enum opclass_config in_opclass_conf)
1701 {
1702 	qdf_freq_t start_freq = op_class_tbl->start_freq;
1703 	uint8_t chan_idx = 0, n_sup_chans = 0, n_unsup_chans = 0;
1704 
1705 	while (op_class_tbl->channels[chan_idx]) {
1706 		uint8_t op_cls_chan;
1707 		qdf_freq_t pri_freq;
1708 		enum phy_ch_width ch_width;
1709 		bool is_supported;
1710 		uint16_t opcls_bw;
1711 
1712 		op_cls_chan = reg_get_chan_or_chan_center(op_class_tbl,
1713 							  &chan_idx);
1714 		pri_freq = start_freq + FREQ_TO_CHAN_SCALE * op_cls_chan;
1715 		opcls_bw = reg_find_nearest_ieee_bw(op_class_tbl->chan_spacing);
1716 		ch_width = reg_find_chwidth_from_bw(opcls_bw);
1717 		pri_freq = reg_get_nearest_primary_freq(opcls_bw,
1718 							pri_freq,
1719 							op_class_tbl->op_class);
1720 		is_supported = reg_is_chan_supported(pdev,
1721 						     pri_freq,
1722 						     0,
1723 						     ch_width);
1724 
1725 		if (is_supported &&
1726 		    (in_opclass_conf == OPCLASSES_SUPPORTED_BY_CUR_HWMODE ||
1727 		     in_opclass_conf == OPCLASSES_SUPPORTED_BY_DOMAIN)) {
1728 			cap->sup_chan_list[n_sup_chans++] = op_cls_chan;
1729 			cap->num_supported_chan++;
1730 		} else {
1731 			cap->non_sup_chan_list[n_unsup_chans++] = op_cls_chan;
1732 			cap->num_non_supported_chan++;
1733 		}
1734 	}
1735 }
1736 
1737 /**
1738  * reg_get_channels_from_opclassmap()- Get channels from the opclass map
1739  * @pdev: Pointer to pdev
1740  * @reg_ap_cap: Pointer to reg_ap_cap
1741  * @index: Pointer to index of reg_ap_cap
1742  * @op_class_tbl: Pointer to op_class_tbl
1743  * @is_opclass_operable: Set true if opclass is operable, else set false
1744  * @in_opclass_conf: input opclass configuration
1745  * Supported or not-supported by current HW mode
1746  *
1747  * Populate channels from opclass map to reg_ap_cap as supported and
1748  * non-supported channels.
1749  *
1750  * Return: void.
1751  */
1752 static void
1753 reg_get_channels_from_opclassmap(
1754 		struct wlan_objmgr_pdev *pdev,
1755 		struct regdmn_ap_cap_opclass_t *reg_ap_cap,
1756 		uint8_t index,
1757 		const struct reg_dmn_op_class_map_t *op_class_tbl,
1758 		bool *is_opclass_operable,
1759 		enum opclass_config in_opclass_conf)
1760 {
1761 	struct regdmn_ap_cap_opclass_t *cap = &reg_ap_cap[index];
1762 
1763 	if (reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) {
1764 		reg_get_cfis_from_opclassmap_for_6g(pdev,
1765 						    cap,
1766 						    op_class_tbl,
1767 						    in_opclass_conf);
1768 	} else {
1769 		reg_get_cfis_from_opclassmap_for_non6g(pdev,
1770 						       cap,
1771 						       op_class_tbl,
1772 						       in_opclass_conf);
1773 	}
1774 
1775 	if (cap->num_supported_chan >= 1)
1776 		*is_opclass_operable = true;
1777 }
1778 
1779 QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
1780 				   struct regdmn_ap_cap_opclass_t *reg_ap_cap,
1781 				   uint8_t *n_opclasses,
1782 				   uint8_t max_supp_op_class,
1783 				   bool global_tbl_lookup)
1784 {
1785 	uint8_t max_reg_power = 0;
1786 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1787 	uint8_t index = 0;
1788 	enum opclass_config opclass_conf = OPCLASSES_SUPPORTED_BY_DOMAIN;
1789 
1790 	if (global_tbl_lookup)
1791 		op_class_tbl = global_op_class;
1792 	else
1793 		reg_get_op_class_tbl_by_chan_map(&op_class_tbl);
1794 
1795 	max_reg_power = reg_get_max_tx_power(pdev);
1796 
1797 	while (op_class_tbl->op_class && (index < max_supp_op_class)) {
1798 		bool is_opclass_operable = false;
1799 
1800 		qdf_mem_zero(reg_ap_cap[index].sup_chan_list,
1801 			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
1802 		reg_ap_cap[index].num_supported_chan = 0;
1803 		qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list,
1804 			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
1805 		reg_ap_cap[index].num_non_supported_chan = 0;
1806 		reg_get_channels_from_opclassmap(pdev,
1807 						 reg_ap_cap,
1808 						 index,
1809 						 op_class_tbl,
1810 						 &is_opclass_operable,
1811 						 opclass_conf);
1812 		if (is_opclass_operable) {
1813 			reg_ap_cap[index].op_class = op_class_tbl->op_class;
1814 			reg_ap_cap[index].ch_width =
1815 						op_class_tbl->chan_spacing;
1816 			reg_ap_cap[index].start_freq =
1817 						op_class_tbl->start_freq;
1818 			reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power;
1819 			reg_ap_cap[index].behav_limit =
1820 						op_class_tbl->behav_limit;
1821 			index++;
1822 		}
1823 
1824 		op_class_tbl++;
1825 	}
1826 
1827 	*n_opclasses = index;
1828 
1829 	return QDF_STATUS_SUCCESS;
1830 }
1831 
1832 bool reg_is_6ghz_op_class(struct wlan_objmgr_pdev *pdev, uint8_t op_class)
1833 {
1834 	return ((op_class >= MIN_6GHZ_OPER_CLASS) &&
1835 		(op_class <= MAX_6GHZ_OPER_CLASS));
1836 }
1837 
1838 /**
1839  * reg_is_opclass_band_found - Check if the input opclass is 2G or 5G.
1840  *
1841  * @country - Pointer to country.
1842  * @op_class - Operating class.
1843  * @bandmask = Bitmask for band.
1844  *
1845  * Return : Return true if the input opclass' band (2Ghz or 5Ghz) matches one
1846  * of bandmask's band.
1847  */
1848 static bool reg_is_opclass_band_found(const uint8_t *country,
1849 				      uint8_t op_class,
1850 				      uint8_t bandmask)
1851 {
1852 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1853 
1854 	op_class_tbl = reg_get_class_from_country((uint8_t *)country);
1855 
1856 	while (op_class_tbl && op_class_tbl->op_class) {
1857 		if (op_class_tbl->op_class == op_class) {
1858 			qdf_freq_t freq = op_class_tbl->start_freq +
1859 			(op_class_tbl->channels[0] * FREQ_TO_CHAN_SCALE);
1860 
1861 			if ((bandmask & BIT(REG_BAND_5G)) &&
1862 			    REG_IS_5GHZ_FREQ(freq))
1863 				return true;
1864 
1865 			if ((bandmask & BIT(REG_BAND_2G)) &&
1866 			    REG_IS_24GHZ_CH_FREQ(freq))
1867 				return true;
1868 
1869 			return false;
1870 		}
1871 
1872 		op_class_tbl++;
1873 	}
1874 
1875 	reg_err_rl("Opclass %d is not found", op_class);
1876 
1877 	return false;
1878 }
1879 
1880 bool reg_is_5ghz_op_class(const uint8_t *country, uint8_t op_class)
1881 {
1882 	return reg_is_opclass_band_found(country, op_class, BIT(REG_BAND_5G));
1883 }
1884 
1885 bool reg_is_2ghz_op_class(const uint8_t *country, uint8_t op_class)
1886 {
1887 	return reg_is_opclass_band_found(country, op_class, BIT(REG_BAND_2G));
1888 }
1889 
1890 /**
1891  * reg_convert_chan_spacing_to_width() - Convert channel spacing to
1892  * channel width.
1893  * @chan_spacing: Channel spacing
1894  * @opclass_chwidth: Opclass channel width
1895  * Return - None
1896  */
1897 #ifdef WLAN_FEATURE_11BE
1898 static void reg_convert_chan_spacing_to_width(uint16_t chan_spacing,
1899 					      uint16_t *opclass_chwidth)
1900 {
1901 	switch (chan_spacing) {
1902 	case BW_20_MHZ:
1903 	case BW_25_MHZ:
1904 		*opclass_chwidth = BW_20_MHZ;
1905 		break;
1906 	case BW_40_MHZ:
1907 		*opclass_chwidth = BW_40_MHZ;
1908 		break;
1909 	case BW_80_MHZ:
1910 		*opclass_chwidth = BW_80_MHZ;
1911 		break;
1912 	case BW_160_MHZ:
1913 		*opclass_chwidth = BW_160_MHZ;
1914 		break;
1915 	case BW_320_MHZ:
1916 		*opclass_chwidth = BW_320_MHZ;
1917 		break;
1918 	default:
1919 		*opclass_chwidth = 0;
1920 	}
1921 }
1922 #else
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 	default:
1941 		*opclass_chwidth = 0;
1942 	}
1943 }
1944 #endif
1945 
1946 QDF_STATUS
1947 reg_get_opclass_for_cur_hwmode(struct wlan_objmgr_pdev *pdev,
1948 			       struct regdmn_ap_cap_opclass_t *reg_ap_cap,
1949 			       uint8_t *n_opclasses,
1950 			       uint8_t max_supp_op_class,
1951 			       bool global_tbl_lookup,
1952 			       enum phy_ch_width max_chwidth,
1953 			       bool is_80p80_supp)
1954 {
1955 	uint8_t max_reg_power = 0;
1956 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1957 	uint8_t index = 0;
1958 	uint16_t out_width;
1959 
1960 	if (global_tbl_lookup)
1961 		op_class_tbl = global_op_class;
1962 	else
1963 		reg_get_op_class_tbl_by_chan_map(&op_class_tbl);
1964 
1965 	max_reg_power = reg_get_max_tx_power(pdev);
1966 
1967 	out_width = reg_get_bw_value(max_chwidth);
1968 
1969 	while (op_class_tbl->op_class && (index < max_supp_op_class)) {
1970 		bool is_opclass_operable = false;
1971 		enum opclass_config opclass_in_config =
1972 		    OPCLASSES_SUPPORTED_BY_CUR_HWMODE;
1973 		uint16_t opclass_width;
1974 
1975 		qdf_mem_zero(reg_ap_cap[index].sup_chan_list,
1976 			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
1977 		reg_ap_cap[index].num_supported_chan = 0;
1978 		qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list,
1979 			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
1980 		reg_ap_cap[index].num_non_supported_chan = 0;
1981 
1982 		reg_convert_chan_spacing_to_width(op_class_tbl->chan_spacing,
1983 						  &opclass_width);
1984 
1985 		if ((opclass_width > out_width) ||
1986 		    ((op_class_tbl->behav_limit == BIT(BEHAV_BW80_PLUS)) &&
1987 		     !is_80p80_supp))
1988 			opclass_in_config =
1989 			    OPCLASSES_NOT_SUPPORTED_BY_CUR_HWMODE;
1990 
1991 		reg_get_channels_from_opclassmap(pdev,
1992 						 reg_ap_cap,
1993 						 index,
1994 						 op_class_tbl,
1995 						 &is_opclass_operable,
1996 						 opclass_in_config);
1997 
1998 		if (is_opclass_operable && opclass_in_config ==
1999 		    OPCLASSES_SUPPORTED_BY_CUR_HWMODE) {
2000 			reg_ap_cap[index].op_class = op_class_tbl->op_class;
2001 			reg_ap_cap[index].ch_width =
2002 				op_class_tbl->chan_spacing;
2003 			reg_ap_cap[index].start_freq =
2004 				op_class_tbl->start_freq;
2005 			reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power;
2006 			reg_ap_cap[index].behav_limit =
2007 				op_class_tbl->behav_limit;
2008 			index++;
2009 		}
2010 		op_class_tbl++;
2011 	}
2012 
2013 	*n_opclasses = index;
2014 
2015 	return QDF_STATUS_SUCCESS;
2016 }
2017 #endif
2018