xref: /wlan-dirver/qca-wifi-host-cmn/umac/regulatory/core/src/reg_opclass.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0) !
1 /*
2  * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: reg_opclass.c
21  * This file defines regulatory opclass functions.
22  */
23 
24 #include <qdf_types.h>
25 #include <wlan_cmn.h>
26 #include <reg_services_public_struct.h>
27 #include <wlan_objmgr_psoc_obj.h>
28 #include "reg_priv_objs.h"
29 #include "reg_utils.h"
30 #include "reg_db.h"
31 #include "reg_db_parser.h"
32 #include "reg_host_11d.h"
33 #include <scheduler_api.h>
34 #include "reg_build_chan_list.h"
35 #include "reg_opclass.h"
36 #include "reg_services_common.h"
37 
38 #ifdef HOST_OPCLASS
39 static struct reg_dmn_supp_op_classes reg_dmn_curr_supp_opp_classes = { 0 };
40 #endif
41 
42 /**
43  * Given a global opclass number create the corresponding  array token.
44  * Examples:
45  *     'CFISARR(132)' expands to  'opcls_132_cfis_arr'
46  *     'CFISARR(133)' expands to  'opcls_133_cfis_arr'
47  */
48 #define CFISARR(_g_opcls)  opcls_ ## _g_opcls ## _cfis_arr
49 
50 /**
51  * Given a global opclass number create the corresponding list token.
52  * Examples:
53  *     'CFISLST(132)' expands to  'opcls_132_cfis_lst'
54  *     'CFISLST(133)' expands to  'opcls_133_cfis_lst'
55  */
56 #define CFISLST(_g_opcls)  opcls_ ## _g_opcls ## _cfis_lst
57 
58 /* The type of the opclass list objects */
59 #define CFISLST_TYPE static const struct c_freq_lst
60 
61 /* The number of elements of the array */
62 #define NELEMS QDF_ARRAY_SIZE
63 
64 /**
65  * Given a global opclass number create the corresponding cfis list and assign
66  * the corresponding cfis array and size of the cfis array
67  * Examples:
68  *     'CREATE_CFIS_LST(132);'
69  *     expands to
70  *     '
71  *     static const struct c_freq_lst opcls_132_cfis_lst =
72  *                   {QDF_ARRAY_SIZE(opcls_132_cfis_arr), opcls_132_cfis_arr};
73  *     '
74  *
75  *     'CREATE_CFIS_LST(133);'
76  *     expands to
77  *     '
78  *     static const struct c_freq_lst opcls_133_cfis_lst =
79  *                   {QDF_ARRAY_SIZE(opcls_133_cfis_arr), opcls_133_cfis_arr};
80  *     '
81  */
82 #define CREATE_CFIS_LST(_gopcls) \
83 CFISLST_TYPE CFISLST(_gopcls) = {NELEMS(CFISARR(_gopcls)), CFISARR(_gopcls)}
84 
85 /* The NULL pointer to a cfis list object */
86 #define NULL_CFIS_LST NULL
87 
88 /* CFIs for global opclass 131: (start Freq=5925 BW=20MHz) */
89 static const uint8_t opcls_131_cfis_arr[] = {
90 #ifdef CONFIG_AFC_SUPPORT
91 	  1, 5, 9, 13, 17, 21, 25, 29, 33,
92 	  37, 41, 45, 49, 53, 57, 61, 65, 69,
93 	  73, 77, 81, 85, 89, 93, 97,
94 	  101, 105, 109, 113, 117, 121, 125,
95 	  129, 133, 137, 141, 145, 149, 153,
96 	  157, 161, 165, 169, 173, 177, 181,
97 	  185, 189, 193, 197, 201, 205, 209,
98 	  213, 217, 221, 225, 229, 233,
99 #endif
100 };
101 
102 /* CFIs for global opclass 132: (start Freq=5925 BW=40MHz) */
103 static const uint8_t opcls_132_cfis_arr[] = {
104 #ifdef CONFIG_AFC_SUPPORT
105 	3, 11, 19, 27, 35, 43, 51, 59, 67, 75,
106 	83, 91, 99, 107, 115, 123, 131, 139, 147, 155,
107 	163, 171, 179, 187, 195, 203, 211, 219, 227,
108 #endif
109 };
110 
111 /* CFIs for global opclass 133: (start Freq=5925 BW=80MHz) */
112 static const uint8_t opcls_133_cfis_arr[] = {
113 #ifdef CONFIG_AFC_SUPPORT
114 	7, 23, 39, 55, 71, 87, 103, 119, 135, 151, 167, 183,
115 	  199, 215,
116 #endif
117 };
118 
119 /* CFIs for global opclass 134: (start Freq=5950 BW=160MHz) */
120 static const uint8_t opcls_134_cfis_arr[] = {
121 #ifdef CONFIG_AFC_SUPPORT
122 	15, 47, 79, 111, 143, 175, 207,
123 #endif
124 };
125 
126 /* CFIs for global opclass 135: (start Freq=5950 BW=80MHz+80MHz) */
127 static const uint8_t opcls_135_cfis_arr[] = {
128 #ifdef CONFIG_AFC_SUPPORT
129 	7, 23, 39, 55, 71, 87, 103, 119, 135, 151, 167, 183,
130 	199, 215,
131 #endif
132 };
133 
134 /* CFIs for global opclass 136: (start Freq=5925 BW=20MHz) */
135 static const uint8_t opcls_136_cfis_arr[] = {
136 #ifdef CONFIG_AFC_SUPPORT
137 	2,
138 #endif
139 };
140 
141 /* CFIs for global opclass 137: (start Freq=5950 BW=320MHz) */
142 #ifdef WLAN_FEATURE_11BE
143 static const uint8_t opcls_137_cfis_arr[] = {
144 #ifdef CONFIG_AFC_SUPPORT
145 	31, 63, 95, 127, 159, 191,
146 #endif
147 };
148 #endif
149 
150 /* Create the CFIS static constant lists */
151 CREATE_CFIS_LST(131);
152 CREATE_CFIS_LST(132);
153 CREATE_CFIS_LST(133);
154 CREATE_CFIS_LST(134);
155 CREATE_CFIS_LST(135);
156 CREATE_CFIS_LST(136);
157 #ifdef WLAN_FEATURE_11BE
158 CREATE_CFIS_LST(137);
159 #endif
160 
161 static const struct reg_dmn_op_class_map_t global_op_class[] = {
162 	{81, 25, BW20, BIT(BEHAV_NONE), 2407,
163 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
164 	 NULL_CFIS_LST },
165 	{82, 25, BW20, BIT(BEHAV_NONE), 2414,
166 	 {14},
167 	 NULL_CFIS_LST },
168 	{83, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407,
169 	 {1, 2, 3, 4, 5, 6, 7, 8, 9},
170 	 NULL_CFIS_LST },
171 	{84, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407,
172 	 {5, 6, 7, 8, 9, 10, 11, 12, 13},
173 	 NULL_CFIS_LST },
174 	{115, 20, BW20, BIT(BEHAV_NONE), 5000,
175 	 {36, 40, 44, 48},
176 	 NULL_CFIS_LST },
177 	{116, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
178 	 {36, 44},
179 	 NULL_CFIS_LST },
180 	{117, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
181 	 {40, 48},
182 	 NULL_CFIS_LST },
183 	{118, 20, BW20, BIT(BEHAV_NONE), 5000,
184 	 {52, 56, 60, 64},
185 	 NULL_CFIS_LST },
186 	{119, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
187 	 {52, 60},
188 	 NULL_CFIS_LST },
189 	{120, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
190 	 {56, 64},
191 	 NULL_CFIS_LST },
192 	{121, 20, BW20, BIT(BEHAV_NONE), 5000,
193 	 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144},
194 	 NULL_CFIS_LST },
195 	{122, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
196 	 {100, 108, 116, 124, 132, 140},
197 	 NULL_CFIS_LST },
198 	{123, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
199 	 {104, 112, 120, 128, 136, 144},
200 	 NULL_CFIS_LST },
201 	{125, 20, BW20, BIT(BEHAV_NONE), 5000,
202 	 {149, 153, 157, 161, 165, 169, 173, 177},
203 	 NULL_CFIS_LST },
204 	{126, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
205 	 {149, 157, 165, 173},
206 	 NULL_CFIS_LST },
207 	{127, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
208 	 {153, 161, 169, 177},
209 	 NULL_CFIS_LST },
210 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
211 	 {36, 40, 44, 48, 52, 56, 60, 64,
212 	  100, 104, 108, 112, 116, 120, 124, 128,
213 	  132, 136, 140, 144, 149, 153, 157, 161,
214 	  165, 169, 173, 177},
215 	  NULL_CFIS_LST },
216 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
217 	 {36, 40, 44, 48, 52, 56, 60, 64,
218 	  100, 104, 108, 112, 116, 120, 124, 128,
219 	  149, 153, 157, 161, 165, 169, 173, 177},
220 	 NULL_CFIS_LST },
221 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
222 	 {36, 40, 44, 48, 52, 56, 60, 64,
223 	  100, 104, 108, 112, 116, 120, 124, 128,
224 	  132, 136, 140, 144, 149, 153, 157, 161,
225 	  165, 169, 173, 177},
226 	 NULL_CFIS_LST },
227 
228 #ifdef CONFIG_BAND_6GHZ
229 	{131, 20, BW20, BIT(BEHAV_NONE), 5950,
230 	 {1, 5, 9, 13, 17, 21, 25, 29, 33,
231 	  37, 41, 45, 49, 53, 57, 61, 65, 69,
232 	  73, 77, 81, 85, 89, 93, 97,
233 	  101, 105, 109, 113, 117, 121, 125,
234 	  129, 133, 137, 141, 145, 149, 153,
235 	  157, 161, 165, 169, 173, 177, 181,
236 	  185, 189, 193, 197, 201, 205, 209,
237 	  213, 217, 221, 225, 229, 233},
238 	&CFISLST(131)},
239 
240 	{132, 40, BW40_LOW_PRIMARY, BIT(BEHAV_NONE), 5950,
241 	 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49,
242 	  53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97,
243 	  101, 105, 109, 113, 117, 121, 125, 129, 133, 137,
244 	  141, 145, 149, 153, 157, 161, 165, 169, 173, 177,
245 	  181, 185, 189, 193, 197, 201, 205, 209, 213, 217,
246 	  221, 225, 229, 233},
247 	&CFISLST(132)},
248 
249 	{133, 80, BW80, BIT(BEHAV_NONE), 5950,
250 	 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49,
251 	  53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97,
252 	  101, 105, 109, 113, 117, 121, 125, 129, 133, 137,
253 	  141, 145, 149, 153, 157, 161, 165, 169, 173,
254 	  177, 181, 185, 189, 193, 197, 201, 205, 209, 213,
255 	  217, 221, 225, 229, 233},
256 	&CFISLST(133)},
257 
258 	{134, 160, BW80, BIT(BEHAV_NONE), 5950,
259 	 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45,
260 	  49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89,
261 	  93, 97, 101, 105, 109, 113, 117, 121, 125,
262 	  129, 133, 137, 141, 145, 149, 153, 157, 161,
263 	  165, 169, 173, 177, 181, 185, 189, 193, 197,
264 	     201, 205, 209, 213, 217, 221, 225, 229, 233},
265 	&CFISLST(134)},
266 
267 	{135, 80, BW80, BIT(BEHAV_BW80_PLUS), 5950,
268 	 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41,
269 	  45, 49, 53, 57, 61, 65, 69, 73, 77, 81,
270 	  85, 89, 93, 97, 101, 105, 109, 113, 117,
271 	  121, 125, 129, 133, 137, 141, 145, 149,
272 	  153, 157, 161, 165, 169, 173, 177, 181,
273 	  185, 189, 193, 197, 201, 205, 209, 213,
274 	  217, 221, 225, 229, 233},
275 	&CFISLST(135)},
276 
277 	{136, 20, BW20, BIT(BEHAV_NONE), 5925,
278 	 {2},
279 	&CFISLST(136)},
280 #ifdef WLAN_FEATURE_11BE
281 	{137, 320, BW20, BIT(BEHAV_NONE), 5950,
282 	 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41,
283 	  45, 49, 53, 57, 61, 65, 69, 73, 77, 81,
284 	  85, 89, 93, 97, 101, 105, 109, 113, 117,
285 	  121, 125, 129, 133, 137, 141, 145, 149,
286 	  153, 157, 161, 165, 169, 173, 177, 181,
287 	  185, 189, 193, 197, 201, 205, 209, 213,
288 	  217, 221, 225, 229, 233},
289 	&CFISLST(137)},
290 #endif
291 #endif
292 	{0, 0, 0, 0, 0, {0},
293 	NULL_CFIS_LST },
294 };
295 
296 static const struct reg_dmn_op_class_map_t us_op_class[] = {
297 	{1, 20, BW20, BIT(BEHAV_NONE), 5000,
298 	 {36, 40, 44, 48},
299 	 NULL_CFIS_LST },
300 	{2, 20, BW20, BIT(BEHAV_NONE), 5000,
301 	 {52, 56, 60, 64},
302 	 NULL_CFIS_LST },
303 	{4, 20, BW20, BIT(BEHAV_NONE), 5000,
304 	 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144},
305 	 NULL_CFIS_LST },
306 	{5, 20, BW20, BIT(BEHAV_NONE), 5000,
307 	 {149, 153, 157, 161, 165},
308 	 NULL_CFIS_LST },
309 	{12, 25, BW20, BIT(BEHAV_NONE), 2407,
310 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
311 	 NULL_CFIS_LST },
312 	{22, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
313 	 {36, 44},
314 	 NULL_CFIS_LST },
315 	{23, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
316 	 {52, 60},
317 	 NULL_CFIS_LST },
318 	{24, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
319 	 {100, 108, 116, 124, 132, 140},
320 	 NULL_CFIS_LST },
321 	{26, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
322 	 {149, 157},
323 	 NULL_CFIS_LST },
324 	{27, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
325 	 {40, 48},
326 	 NULL_CFIS_LST },
327 	{28, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
328 	 {56, 64},
329 	 NULL_CFIS_LST },
330 	{29, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
331 	 {104, 112, 120, 128, 136, 144},
332 	 NULL_CFIS_LST },
333 	{30, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
334 	 {153, 161},
335 	 NULL_CFIS_LST },
336 	{31, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
337 	 {153, 161},
338 	 NULL_CFIS_LST },
339 	{32, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407,
340 	 {1, 2, 3, 4, 5, 6, 7},
341 	 NULL_CFIS_LST },
342 	{33, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407,
343 	 {5, 6, 7, 8, 9, 10, 11},
344 	 NULL_CFIS_LST },
345 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
346 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
347 	  104, 108, 112, 116, 120, 124, 128, 132,
348 	  136, 140, 144, 149, 153, 157, 161},
349 	 NULL_CFIS_LST },
350 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
351 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
352 	  104, 108, 112, 116, 120, 124, 128},
353 	 NULL_CFIS_LST },
354 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
355 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
356 	  104, 108, 112, 116, 120, 124, 128, 132,
357 	  136, 140, 144, 149, 153, 157, 161},
358 	 NULL_CFIS_LST },
359 	{0, 0, 0, 0, 0, {0},
360 	 NULL_CFIS_LST },
361 };
362 
363 static const struct reg_dmn_op_class_map_t euro_op_class[] = {
364 	{1, 20, BW20, BIT(BEHAV_NONE), 5000,
365 	 {36, 40, 44, 48},
366 	 NULL_CFIS_LST },
367 	{2, 20, BW20, BIT(BEHAV_NONE), 5000,
368 	 {52, 56, 60, 64},
369 	 NULL_CFIS_LST },
370 	{3, 20, BW20, BIT(BEHAV_NONE), 5000,
371 	 {100, 104, 108, 112, 116, 120,
372 	  124, 128, 132, 136, 140},
373 	 NULL_CFIS_LST },
374 	{4, 25, BW20, BIT(BEHAV_NONE), 2407,
375 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
376 	 NULL_CFIS_LST },
377 	{5, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
378 	 {36, 44},
379 	 NULL_CFIS_LST },
380 	{6, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
381 	 {52, 60},
382 	 NULL_CFIS_LST },
383 	{7, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
384 	 {100, 108, 116, 124, 132},
385 	 NULL_CFIS_LST },
386 	{8, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
387 	 {40, 48},
388 	 NULL_CFIS_LST },
389 	{9, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
390 	 {56, 64},
391 	 NULL_CFIS_LST },
392 	{10, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
393 	 {104, 112, 120, 128, 136},
394 	 NULL_CFIS_LST },
395 	{11, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407,
396 	 {1, 2, 3, 4, 5, 6, 7, 8, 9},
397 	 NULL_CFIS_LST },
398 	{12, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407,
399 	 {5, 6, 7, 8, 9, 10, 11, 12, 13},
400 	 NULL_CFIS_LST },
401 	{17, 20, BW20, BIT(BEHAV_NONE), 5000,
402 	 {149, 153, 157, 161, 165, 169},
403 	 NULL_CFIS_LST },
404 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
405 	 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
406 	  124, 128},
407 	 NULL_CFIS_LST },
408 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
409 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
410 	  104, 108, 112, 116, 120, 124, 128},
411 	 NULL_CFIS_LST },
412 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
413 	 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
414 	  124, 128},
415 	 NULL_CFIS_LST },
416 	{0, 0, 0, 0, 0, {0},
417 	 NULL_CFIS_LST },
418 };
419 
420 static const struct reg_dmn_op_class_map_t japan_op_class[] = {
421 	{1, 20, BW20, BIT(BEHAV_NONE), 5000,
422 	 {36, 40, 44, 48},
423 	 NULL_CFIS_LST },
424 	{30, 25, BW20, BIT(BEHAV_NONE), 2407,
425 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
426 	 NULL_CFIS_LST },
427 	{31, 25, BW20, BIT(BEHAV_NONE), 2414,
428 	 {14},
429 	 NULL_CFIS_LST },
430 	{32, 20, BW20, BIT(BEHAV_NONE), 5000,
431 	 {52, 56, 60, 64},
432 	 NULL_CFIS_LST },
433 	{34, 20, BW20, BIT(BEHAV_NONE), 5000,
434 	 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140},
435 	 NULL_CFIS_LST },
436 	{36, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
437 	 {36, 44},
438 	 NULL_CFIS_LST },
439 	{37, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
440 	 {52, 60},
441 	 NULL_CFIS_LST },
442 	{39, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
443 	 {100, 108, 116, 124, 132},
444 	 NULL_CFIS_LST },
445 	{41, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
446 	 {40, 48},
447 	 NULL_CFIS_LST },
448 	{42, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
449 	 {56, 64},
450 	 NULL_CFIS_LST },
451 	{44, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
452 	 {104, 112, 120, 128, 136},
453 	 NULL_CFIS_LST },
454 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
455 	 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
456 	  124, 128, 132, 136, 140, 144},
457 	 NULL_CFIS_LST },
458 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
459 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
460 	  104, 108, 112, 116, 120, 124, 128},
461 	 NULL_CFIS_LST },
462 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
463 	 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
464 	  124, 128, 132, 136, 140, 144},
465 	 NULL_CFIS_LST },
466 	{0, 0, 0, 0, 0, {0},
467 	 NULL_CFIS_LST },
468 };
469 
470 static const struct reg_dmn_op_class_map_t china_op_class[] = {
471 	{7, 25, BW20, BIT(BEHAV_NONE), 2407,
472 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
473 	 NULL_CFIS_LST },
474 	{8, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407,
475 	 {1, 2, 3, 4, 5, 6, 7, 8, 9},
476 	 NULL_CFIS_LST },
477 	{9, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407,
478 	 {5, 6, 7, 8, 9, 10, 11, 12, 13},
479 	 NULL_CFIS_LST },
480 	{1, 20, BW20, BIT(BEHAV_NONE), 5000,
481 	 {36, 40, 44, 48},
482 	 NULL_CFIS_LST },
483 	{4, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
484 	 {36, 44},
485 	 NULL_CFIS_LST },
486 	{117, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
487 	 {40, 48},
488 	 NULL_CFIS_LST },
489 	{2, 20, BW20, BIT(BEHAV_NONE), 5000,
490 	 {52, 56, 60, 64},
491 	 NULL_CFIS_LST },
492 	{5, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
493 	 {52, 60},
494 	 NULL_CFIS_LST },
495 	{3, 20, BW20, BIT(BEHAV_NONE), 5000,
496 	 {149, 153, 157, 161, 165},
497 	 NULL_CFIS_LST },
498 	{6, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
499 	 {149, 157},
500 	 NULL_CFIS_LST },
501 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
502 	 {36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161},
503 	 NULL_CFIS_LST },
504 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
505 	 {36, 40, 44, 48, 52, 56, 60, 64,},
506 	 NULL_CFIS_LST },
507 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
508 	 {36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161},
509 	 NULL_CFIS_LST },
510 	{0, 0, 0, 0, 0, {0},
511 	 NULL_CFIS_LST },
512 };
513 #ifdef HOST_OPCLASS
514 /**
515  * reg_get_class_from_country()- Get Class from country
516  * @country- Country
517  *
518  * Return: class.
519  */
520 static const struct reg_dmn_op_class_map_t
521 *reg_get_class_from_country(const uint8_t *country)
522 {
523 	const struct reg_dmn_op_class_map_t *class = NULL;
524 
525 	reg_debug_rl("Country %c%c 0x%x", country[0], country[1], country[2]);
526 
527 	switch (country[2]) {
528 	case OP_CLASS_US:
529 		class = us_op_class;
530 		break;
531 
532 	case OP_CLASS_EU:
533 		class = euro_op_class;
534 		break;
535 
536 	case OP_CLASS_JAPAN:
537 		class = japan_op_class;
538 		break;
539 
540 	case OP_CLASS_GLOBAL:
541 		class = global_op_class;
542 		break;
543 
544 	case OP_CLASS_CHINA:
545 		class = china_op_class;
546 		break;
547 	default:
548 		if (!qdf_mem_cmp(country, "US", 2))
549 			class = us_op_class;
550 		else if (!qdf_mem_cmp(country, "EU", 2))
551 			class = euro_op_class;
552 		else if (!qdf_mem_cmp(country, "JP", 2))
553 			class = japan_op_class;
554 		else if (!qdf_mem_cmp(country, "CN", 2))
555 			class = china_op_class;
556 		else
557 			class = global_op_class;
558 	}
559 	return class;
560 }
561 
562 #ifdef CONFIG_AFC_SUPPORT
563 static bool reg_is_range_valid(struct freq_range *range)
564 {
565 	return (range->right > range->left);
566 }
567 
568 /**
569  * reg_is_subrange() - Check if range_first is a subrange of range_second
570  * @range_first: Pointer to first range
571  * @range_second: Pointer to first range
572  *
573  * Return: True if the range_first is a subrange range_second, else false
574  */
575 static bool reg_is_subrange(struct freq_range *range_first,
576 			    struct freq_range *range_second)
577 {
578 	bool is_subrange;
579 	bool is_valid;
580 
581 	is_valid = reg_is_range_valid(range_first) &&
582 		   reg_is_range_valid(range_second);
583 
584 	if (!is_valid)
585 		return false;
586 
587 	is_subrange = (range_first->left >= range_second->left) &&
588 		      (range_first->right <= range_second->right);
589 
590 	return is_subrange;
591 }
592 
593 /**
594  * reg_is_cfi_freq_in_ranges() - Check if the given 'cfi' in the any of the
595  * frequency ranges
596  * @cfi_freq: The center frequency index frequency
597  * @bw: bandwidth of the band with center freq cfi_freq
598  * @p_frange_lst: Pointer to frequency range list (AFC)
599  *
600  * return: True if the cfi is in the ranges, else false
601  */
602 static bool reg_is_cfi_freq_in_ranges(qdf_freq_t cfi_freq,
603 				      uint16_t bw,
604 				      struct wlan_afc_frange_list *p_frange_lst)
605 {
606 	uint32_t num_ranges;
607 	struct wlan_afc_freq_range_obj *p_range_objs;
608 	uint8_t i;
609 	bool is_cfi_supported = false;
610 
611 	num_ranges = p_frange_lst->num_ranges;
612 	p_range_objs = &p_frange_lst->range_objs[0];
613 	for (i = 0; i <  num_ranges; i++) {
614 		qdf_freq_t cfi_band_left;
615 		qdf_freq_t cfi_band_right;
616 		struct freq_range range_cfi;
617 		struct freq_range range_chip;
618 
619 		cfi_band_left = cfi_freq - bw / 2;
620 		cfi_band_right = cfi_freq + bw / 2;
621 
622 		range_cfi = reg_init_freq_range(cfi_band_left,
623 						cfi_band_right);
624 		range_chip = reg_init_freq_range(p_range_objs->lowfreq,
625 						 p_range_objs->highfreq);
626 		is_cfi_supported = reg_is_subrange(&range_cfi, &range_chip);
627 
628 		if (is_cfi_supported)
629 			return true;
630 
631 		p_range_objs++;
632 	}
633 
634 	return is_cfi_supported;
635 }
636 
637 void reg_dmn_free_6g_opclasses_and_channels(struct wlan_objmgr_pdev *pdev,
638 					    uint8_t num_opclasses,
639 					    uint8_t *opclass_lst,
640 					    uint8_t *chansize_lst,
641 					    uint8_t *channel_lists[])
642 {
643 	/*
644 	 * All the elements of channel_lists were allocated as a single
645 	 * allocation with 'channel_lists[0]' holding the first location of the
646 	 * allocation. Therefore, freeing only 'channel_lists[0]' is enough.
647 	 * Freeing any other 'channel_lists[i]' will result in error of freeing
648 	 * unallocated memory.
649 
650 	 */
651 	if (channel_lists)
652 		qdf_mem_free(channel_lists[0]);
653 
654 	/*
655 	 * opclass_lst, chansize_lst and channel_lists were allocated as a
656 	 * single allocation with 'opclass_lst' holding the first location of
657 	 * allocation. Therefore, freeing only 'opclass_lst' is enough.
658 	 * Freeing chansize_lst, channel_lists will result in error of freeing
659 	 * unallocated memory.
660 	 */
661 	qdf_mem_free(opclass_lst);
662 }
663 
664 /**
665  * reg_dmn_get_num_6g_opclasses() - Calculate the number of opclasses in the
666  * 6GHz band.
667  * Return: The number of opclasses
668  */
669 static uint8_t reg_dmn_get_num_6g_opclasses(struct wlan_objmgr_pdev *pdev)
670 {
671 	const struct reg_dmn_op_class_map_t *op_class_tbl;
672 	uint8_t count;
673 
674 	op_class_tbl = global_op_class;
675 
676 	count = 0;
677 	while (op_class_tbl && op_class_tbl->op_class) {
678 		const struct c_freq_lst *p_lst;
679 
680 		p_lst = op_class_tbl->p_cfi_lst_obj;
681 		if (p_lst &&
682 		    reg_is_6ghz_op_class(pdev, op_class_tbl->op_class))
683 			count++;
684 
685 		op_class_tbl++;
686 	}
687 
688 	return count;
689 }
690 
691 /**
692  * reg_dmn_fill_6g_opcls_chan_lists() - Copy the channel lists for 6g opclasses
693  * to the output argument list ('channel_lists')
694  * @pdev: Pointer to pdev.
695  * @p_frange_lst: Pointer to frequencey range list (AFC)
696  * @chansize_lst: Array of sizes of channel lists
697  * @channel_lists: The array list pointers where the channel lists are to be
698  *                 copied.
699  *
700  * Return: Void
701  */
702 static void reg_dmn_fill_6g_opcls_chan_lists(struct wlan_objmgr_pdev *pdev,
703 					     struct wlan_afc_frange_list *p_frange_lst,
704 					     uint8_t chansize_lst[],
705 					     uint8_t *channel_lists[])
706 {
707 	uint8_t i = 0;
708 	const struct reg_dmn_op_class_map_t *op_class_tbl;
709 
710 	op_class_tbl = global_op_class;
711 
712 	while (op_class_tbl && op_class_tbl->op_class) {
713 		const struct c_freq_lst *p_lst;
714 
715 		p_lst = op_class_tbl->p_cfi_lst_obj;
716 		if (p_lst &&
717 		    reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) {
718 			uint8_t j;
719 			uint8_t cfi_idx = 0;
720 			uint8_t *dst;
721 
722 			dst = channel_lists[i];
723 			for (j = 0; j < p_lst->num_cfis; j++) {
724 				uint8_t cfi;
725 				qdf_freq_t cfi_freq;
726 				qdf_freq_t start_freq = op_class_tbl->start_freq;
727 				uint16_t bw = op_class_tbl->chan_spacing;
728 
729 				cfi = p_lst->p_cfis_arr[j];
730 				cfi_freq = start_freq +
731 					FREQ_TO_CHAN_SCALE * cfi;
732 
733 				if (reg_is_cfi_freq_in_ranges(cfi_freq,
734 							      bw,
735 							      p_frange_lst)) {
736 					dst[cfi_idx++] = cfi;
737 				}
738 			}
739 			i++;
740 		}
741 		op_class_tbl++;
742 	}
743 }
744 
745 static bool reg_is_val_within_range(qdf_freq_t val,
746 				    qdf_freq_t left,
747 				    qdf_freq_t right)
748 {
749 	bool is_within = false;
750 
751 	if (val >= left && val <= right)
752 		is_within = true;
753 
754 	return is_within;
755 }
756 
757 QDF_STATUS reg_dmn_get_6g_opclasses_and_channels(struct wlan_objmgr_pdev *pdev,
758 						 struct wlan_afc_frange_list *p_frange_lst,
759 						 uint8_t *num_opclasses,
760 						 uint8_t **opclass_lst,
761 						 uint8_t **chansize_lst,
762 						 uint8_t **channel_lists[])
763 {
764 	const struct reg_dmn_op_class_map_t *op_class_tbl;
765 	uint8_t *l_opcls_lst;
766 	uint8_t *l_chansize_lst;
767 	uint8_t count;
768 	uint8_t i;
769 	uint8_t **arr_chan_lists;
770 	uint16_t total_alloc_size;
771 	uint16_t opcls_lst_size;
772 	uint16_t chansize_lst_size;
773 	uint16_t arr_chan_lists_size;
774 	uint8_t *p_total_alloc1;
775 	uint8_t *p_total_alloc2;
776 	uint8_t *p_temp_alloc;
777 
778 	*opclass_lst = NULL;
779 	*chansize_lst =  NULL;
780 	*channel_lists = NULL;
781 
782 	op_class_tbl = global_op_class;
783 
784 	*num_opclasses = reg_dmn_get_num_6g_opclasses(pdev);
785 	opcls_lst_size = *num_opclasses * sizeof(uint8_t);
786 	chansize_lst_size = *num_opclasses * sizeof(uint8_t);
787 	arr_chan_lists_size = *num_opclasses * sizeof(uint8_t *);
788 
789 	total_alloc_size = 0;
790 	total_alloc_size += opcls_lst_size
791 		+ chansize_lst_size
792 		+ arr_chan_lists_size;
793 
794 	p_total_alloc1 = qdf_mem_malloc(total_alloc_size);
795 	if (!p_total_alloc1) {
796 		reg_err("out-of-memory");
797 		return QDF_STATUS_E_NOMEM;
798 	}
799 
800 	 /* Assign memory locations to each pointers */
801 	p_temp_alloc = p_total_alloc1;
802 
803 	l_opcls_lst = p_temp_alloc;
804 	p_temp_alloc += opcls_lst_size;
805 
806 	l_chansize_lst = p_temp_alloc;
807 	p_temp_alloc += chansize_lst_size;
808 
809 	arr_chan_lists = (uint8_t **)p_temp_alloc;
810 
811 	/* Fill arrays with opclasses and chanlist sizes */
812 	count = 0;
813 	while (op_class_tbl && op_class_tbl->op_class) {
814 		const struct c_freq_lst *p_lst;
815 
816 		p_lst = op_class_tbl->p_cfi_lst_obj;
817 		if (p_lst &&
818 		    reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) {
819 			uint8_t n_supp_cfis = 0;
820 			uint8_t j;
821 
822 			l_opcls_lst[count] = op_class_tbl->op_class;
823 			for (j = 0; j < p_lst->num_cfis; j++) {
824 				uint8_t cfi;
825 				qdf_freq_t cfi_freq;
826 				qdf_freq_t start_freq = op_class_tbl->start_freq;
827 				uint16_t bw = op_class_tbl->chan_spacing;
828 
829 				cfi = p_lst->p_cfis_arr[j];
830 				cfi_freq = start_freq +
831 					FREQ_TO_CHAN_SCALE * cfi;
832 				if (reg_is_cfi_freq_in_ranges(cfi_freq,
833 							      bw,
834 							      p_frange_lst)) {
835 					n_supp_cfis++;
836 				}
837 			}
838 			l_chansize_lst[count] = n_supp_cfis;
839 			count++;
840 		}
841 		op_class_tbl++;
842 	}
843 
844 	/* Calculate total alloction size for the array */
845 	total_alloc_size = 0;
846 	for (i = 0; i < *num_opclasses; i++)
847 		total_alloc_size += l_chansize_lst[i] * sizeof(uint8_t *);
848 
849 	p_total_alloc2 = qdf_mem_malloc(total_alloc_size);
850 	if (!p_total_alloc2) {
851 		reg_err("out-of-memory");
852 		qdf_mem_free(p_total_alloc1);
853 		return QDF_STATUS_E_NOMEM;
854 	}
855 
856 	/* Assign memory locations to each list pointers */
857 	p_temp_alloc = p_total_alloc2;
858 	for (i = 0; i < *num_opclasses; i++) {
859 		if (!l_chansize_lst[i])
860 			arr_chan_lists[i] = NULL;
861 		else
862 			arr_chan_lists[i] = p_temp_alloc;
863 
864 		p_temp_alloc += l_chansize_lst[i] * sizeof(uint8_t *);
865 	}
866 
867 	/* Fill the array with channl lists */
868 	reg_dmn_fill_6g_opcls_chan_lists(pdev, p_frange_lst, l_chansize_lst, arr_chan_lists);
869 
870 	*opclass_lst = l_opcls_lst;
871 	*chansize_lst = l_chansize_lst;
872 	*channel_lists = arr_chan_lists;
873 
874 	return QDF_STATUS_SUCCESS;
875 }
876 #endif /* CONFIG_AFC_SUPPORT */
877 
878 uint16_t reg_dmn_get_chanwidth_from_opclass(uint8_t *country, uint8_t channel,
879 					    uint8_t opclass)
880 {
881 	const struct reg_dmn_op_class_map_t *class;
882 	uint16_t i;
883 
884 	class = reg_get_class_from_country(country);
885 
886 	while (class->op_class) {
887 		if (opclass == class->op_class) {
888 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
889 				     class->channels[i]); i++) {
890 				if (channel == class->channels[i])
891 					return class->chan_spacing;
892 			}
893 		}
894 		class++;
895 	}
896 
897 	return 0;
898 }
899 
900 uint16_t reg_dmn_get_chanwidth_from_opclass_auto(uint8_t *country,
901 						 uint8_t channel,
902 						 uint8_t opclass)
903 {
904 	uint16_t ret;
905 	uint8_t global_country[REG_ALPHA2_LEN + 1];
906 
907 	ret = reg_dmn_get_chanwidth_from_opclass(country, channel, opclass);
908 
909 	if (!ret) {
910 		global_country[2] = OP_CLASS_GLOBAL;
911 		ret = reg_dmn_get_chanwidth_from_opclass(global_country,
912 							 channel, opclass);
913 	}
914 
915 	return ret;
916 }
917 
918 uint16_t reg_dmn_get_opclass_from_channel(uint8_t *country, uint8_t channel,
919 					  uint8_t offset)
920 {
921 	const struct reg_dmn_op_class_map_t *class = NULL;
922 	uint16_t i = 0;
923 
924 	class = reg_get_class_from_country(country);
925 	while (class && class->op_class) {
926 		if ((offset == class->offset) || (offset == BWALL)) {
927 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
928 				     class->channels[i]); i++) {
929 				if (channel == class->channels[i])
930 					return class->op_class;
931 			}
932 		}
933 		class++;
934 	}
935 
936 	return 0;
937 }
938 
939 uint8_t reg_dmn_get_opclass_from_freq_width(uint8_t *country,
940 					    qdf_freq_t freq,
941 					    uint16_t ch_width,
942 					    uint16_t behav_limit)
943 {
944 	const struct reg_dmn_op_class_map_t *op_class_tbl = NULL;
945 	uint16_t i = 0;
946 
947 	op_class_tbl = reg_get_class_from_country(country);
948 
949 	while (op_class_tbl && op_class_tbl->op_class) {
950 		if (op_class_tbl->chan_spacing == ch_width) {
951 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
952 				     op_class_tbl->channels[i]); i++) {
953 				if ((op_class_tbl->start_freq +
954 				     (FREQ_TO_CHAN_SCALE *
955 				      op_class_tbl->channels[i]) == freq) &&
956 				    (behav_limit & op_class_tbl->behav_limit)) {
957 					return op_class_tbl->op_class;
958 				}
959 			}
960 		}
961 		op_class_tbl++;
962 	}
963 
964 	return 0;
965 }
966 
967 static void
968 reg_get_band_cap_from_chan_set(const struct reg_dmn_op_class_map_t
969 			       *op_class_tbl,
970 			       uint8_t *supported_band)
971 {
972 	qdf_freq_t chan_freq = op_class_tbl->start_freq +
973 						(op_class_tbl->channels[0] *
974 						 FREQ_TO_CHAN_SCALE);
975 
976 	if (reg_is_24ghz_ch_freq(chan_freq))
977 		*supported_band |= BIT(REG_BAND_2G);
978 	else if (reg_is_5ghz_ch_freq(chan_freq))
979 		*supported_band |= BIT(REG_BAND_5G);
980 	else if (reg_is_6ghz_chan_freq(chan_freq))
981 		*supported_band |= BIT(REG_BAND_6G);
982 	else
983 		reg_err_rl("Unknown band");
984 }
985 
986 uint8_t reg_get_band_cap_from_op_class(const uint8_t *country,
987 				       uint8_t num_of_opclass,
988 				       const uint8_t *opclass)
989 {
990 	const struct reg_dmn_op_class_map_t *op_class_tbl;
991 	uint8_t supported_band = 0, opclassidx;
992 
993 	op_class_tbl = reg_get_class_from_country(country);
994 
995 	while (op_class_tbl && op_class_tbl->op_class) {
996 		for (opclassidx = 0; opclassidx < num_of_opclass;
997 		     opclassidx++) {
998 			if (op_class_tbl->op_class == opclass[opclassidx]) {
999 				reg_get_band_cap_from_chan_set(op_class_tbl,
1000 							       &supported_band);
1001 			}
1002 		}
1003 		op_class_tbl++;
1004 	}
1005 
1006 	if (!supported_band)
1007 		reg_err_rl("None of the operating classes is found");
1008 
1009 	return supported_band;
1010 }
1011 
1012 void reg_dmn_print_channels_in_opclass(uint8_t *country, uint8_t op_class)
1013 {
1014 	const struct reg_dmn_op_class_map_t *class = NULL;
1015 	uint16_t i = 0;
1016 
1017 	class = reg_get_class_from_country(country);
1018 
1019 	if (!class) {
1020 		reg_err("class is NULL");
1021 		return;
1022 	}
1023 
1024 	while (class->op_class) {
1025 		if (class->op_class == op_class) {
1026 			for (i = 0;
1027 			     (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1028 			      class->channels[i]); i++) {
1029 				reg_debug("Valid channel(%d) in requested RC(%d)",
1030 					  class->channels[i], op_class);
1031 			}
1032 			break;
1033 		}
1034 		class++;
1035 	}
1036 	if (!class->op_class)
1037 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
1038 			  "Invalid requested RC (%d)", op_class);
1039 }
1040 
1041 uint16_t reg_dmn_set_curr_opclasses(uint8_t num_classes, uint8_t *class)
1042 {
1043 	uint8_t i;
1044 
1045 	if (num_classes > REG_MAX_SUPP_OPER_CLASSES) {
1046 		reg_err("invalid num classes %d", num_classes);
1047 		return 0;
1048 	}
1049 
1050 	for (i = 0; i < num_classes; i++)
1051 		reg_dmn_curr_supp_opp_classes.classes[i] = class[i];
1052 
1053 	reg_dmn_curr_supp_opp_classes.num_classes = num_classes;
1054 
1055 	return 0;
1056 }
1057 
1058 uint16_t reg_dmn_get_curr_opclasses(uint8_t *num_classes, uint8_t *class)
1059 {
1060 	uint8_t i;
1061 
1062 	if (!num_classes || !class) {
1063 		reg_err("either num_classes or class is null");
1064 		return 0;
1065 	}
1066 
1067 	for (i = 0; i < reg_dmn_curr_supp_opp_classes.num_classes; i++)
1068 		class[i] = reg_dmn_curr_supp_opp_classes.classes[i];
1069 
1070 	*num_classes = reg_dmn_curr_supp_opp_classes.num_classes;
1071 
1072 	return 0;
1073 }
1074 
1075 #ifdef CONFIG_CHAN_FREQ_API
1076 /**
1077  * reg_find_opclass_absent_in_ctry_opclss_tables() - Check Global Opclass table
1078  * when Opclass is not present in specific country.
1079  * @pdev - Pointer to pdev
1080  * @freq - Destination Frequency
1081  * @chan_width- Channel Width
1082  * @global_tbl_lookup - Global Table Lookup
1083  * @behav_limit - Behav Limit
1084  * @op_class - Pointer to Opclass
1085  * @chan_num - Pointer to Channel
1086  *
1087  * Return: Void
1088  */
1089 static void
1090 reg_find_opclass_absent_in_ctry_opclss_tables(struct wlan_objmgr_pdev *pdev,
1091 					      qdf_freq_t freq,
1092 					      uint16_t chan_width,
1093 					      bool global_tbl_lookup,
1094 					      uint16_t behav_limit,
1095 					      uint8_t *op_class,
1096 					      uint8_t *chan_num)
1097 {
1098 	if (!global_tbl_lookup && !*op_class) {
1099 		global_tbl_lookup = true;
1100 		reg_freq_width_to_chan_op_class(pdev, freq,
1101 						chan_width,
1102 						global_tbl_lookup,
1103 						behav_limit,
1104 						op_class,
1105 						chan_num);
1106 	}
1107 }
1108 
1109 void reg_freq_width_to_chan_op_class_auto(struct wlan_objmgr_pdev *pdev,
1110 					  qdf_freq_t freq,
1111 					  uint16_t chan_width,
1112 					  bool global_tbl_lookup,
1113 					  uint16_t behav_limit,
1114 					  uint8_t *op_class,
1115 					  uint8_t *chan_num)
1116 {
1117 	if (reg_freq_to_band(freq) == REG_BAND_6G) {
1118 		global_tbl_lookup = true;
1119 		if (chan_width == BW_40_MHZ)
1120 			behav_limit = BIT(BEHAV_NONE);
1121 	} else if (reg_is_5dot9_ghz_freq(pdev, freq)) {
1122 		global_tbl_lookup = true;
1123 	} else {
1124 		global_tbl_lookup = false;
1125 	}
1126 
1127 	*op_class = 0;
1128 	reg_freq_width_to_chan_op_class(pdev, freq,
1129 					chan_width,
1130 					global_tbl_lookup,
1131 					behav_limit,
1132 					op_class,
1133 					chan_num);
1134 	reg_find_opclass_absent_in_ctry_opclss_tables(pdev, freq,
1135 						      chan_width,
1136 						      global_tbl_lookup,
1137 						      behav_limit,
1138 						      op_class,
1139 						      chan_num);
1140 }
1141 
1142 void reg_freq_width_to_chan_op_class(struct wlan_objmgr_pdev *pdev,
1143 				     qdf_freq_t freq,
1144 				     uint16_t chan_width,
1145 				     bool global_tbl_lookup,
1146 				     uint16_t behav_limit,
1147 				     uint8_t *op_class,
1148 				     uint8_t *chan_num)
1149 {
1150 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1151 	enum channel_enum chan_enum;
1152 	uint16_t i;
1153 
1154 	chan_enum = reg_get_chan_enum_for_freq(freq);
1155 
1156 	if (chan_enum == INVALID_CHANNEL) {
1157 		reg_err_rl("Invalid chan enum %d", chan_enum);
1158 		return;
1159 	}
1160 
1161 	if (global_tbl_lookup) {
1162 		op_class_tbl = global_op_class;
1163 	} else {
1164 		if (channel_map == channel_map_us)
1165 			op_class_tbl = us_op_class;
1166 		else if (channel_map == channel_map_eu)
1167 			op_class_tbl = euro_op_class;
1168 		else if (channel_map == channel_map_china)
1169 			op_class_tbl = china_op_class;
1170 		else if (channel_map == channel_map_jp)
1171 			op_class_tbl = japan_op_class;
1172 		else
1173 			op_class_tbl = global_op_class;
1174 	}
1175 
1176 	while (op_class_tbl->op_class) {
1177 		if (op_class_tbl->chan_spacing >= chan_width) {
1178 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1179 				     op_class_tbl->channels[i]); i++) {
1180 				if ((op_class_tbl->start_freq +
1181 				     FREQ_TO_CHAN_SCALE *
1182 				     op_class_tbl->channels[i] == freq) &&
1183 				    (behav_limit & op_class_tbl->behav_limit ||
1184 				     behav_limit == BIT(BEHAV_NONE))) {
1185 					*chan_num = op_class_tbl->channels[i];
1186 					*op_class = op_class_tbl->op_class;
1187 					return;
1188 				}
1189 			}
1190 		}
1191 		op_class_tbl++;
1192 	}
1193 
1194 	reg_err_rl("no op class for frequency %d", freq);
1195 }
1196 
1197 void reg_freq_to_chan_op_class(struct wlan_objmgr_pdev *pdev,
1198 			       qdf_freq_t freq,
1199 			       bool global_tbl_lookup,
1200 			       uint16_t behav_limit,
1201 			       uint8_t *op_class,
1202 			       uint8_t *chan_num)
1203 {
1204 	enum channel_enum chan_enum;
1205 	struct regulatory_channel *cur_chan_list;
1206 	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
1207 	struct ch_params chan_params;
1208 
1209 	pdev_priv_obj = reg_get_pdev_obj(pdev);
1210 
1211 	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
1212 		reg_err_rl("NULL pdev reg obj");
1213 		return;
1214 	}
1215 
1216 	cur_chan_list = pdev_priv_obj->cur_chan_list;
1217 
1218 	chan_enum = reg_get_chan_enum_for_freq(freq);
1219 
1220 	if (chan_enum == INVALID_CHANNEL) {
1221 		reg_err_rl("Invalid chan enum %d", chan_enum);
1222 		return;
1223 	}
1224 
1225 	chan_params.ch_width = CH_WIDTH_MAX;
1226 	reg_set_channel_params_for_freq(pdev, freq, 0, &chan_params);
1227 
1228 	reg_freq_width_to_chan_op_class(pdev, freq,
1229 					reg_get_bw_value(chan_params.ch_width),
1230 					global_tbl_lookup,
1231 					behav_limit,
1232 					op_class,
1233 					chan_num);
1234 }
1235 
1236 bool reg_is_freq_in_country_opclass(struct wlan_objmgr_pdev *pdev,
1237 				    const uint8_t country[3],
1238 				    uint8_t op_class,
1239 				    qdf_freq_t chan_freq)
1240 {
1241 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1242 	uint8_t i;
1243 
1244 	op_class_tbl = reg_get_class_from_country((uint8_t *)country);
1245 
1246 	while (op_class_tbl && op_class_tbl->op_class) {
1247 		if  (op_class_tbl->op_class == op_class) {
1248 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1249 				     op_class_tbl->channels[i]); i++) {
1250 				if (op_class_tbl->channels[i] *
1251 				    FREQ_TO_CHAN_SCALE +
1252 				    op_class_tbl->start_freq == chan_freq)
1253 					return true;
1254 			}
1255 		}
1256 		op_class_tbl++;
1257 	}
1258 	return false;
1259 }
1260 
1261 #endif
1262 
1263 uint16_t reg_get_op_class_width(struct wlan_objmgr_pdev *pdev,
1264 				uint8_t op_class,
1265 				bool global_tbl_lookup)
1266 {
1267 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1268 
1269 	if (global_tbl_lookup) {
1270 		op_class_tbl = global_op_class;
1271 	} else {
1272 		if (channel_map == channel_map_us)
1273 			op_class_tbl = us_op_class;
1274 		else if (channel_map == channel_map_eu)
1275 			op_class_tbl = euro_op_class;
1276 		else if (channel_map == channel_map_china)
1277 			op_class_tbl = china_op_class;
1278 		else if (channel_map == channel_map_jp)
1279 			op_class_tbl = japan_op_class;
1280 		else
1281 			op_class_tbl = global_op_class;
1282 	}
1283 
1284 	while (op_class_tbl->op_class) {
1285 		if  (op_class_tbl->op_class == op_class)
1286 			return op_class_tbl->chan_spacing;
1287 		op_class_tbl++;
1288 	}
1289 
1290 	return 0;
1291 }
1292 
1293 uint16_t reg_chan_opclass_to_freq(uint8_t chan,
1294 				  uint8_t op_class,
1295 				  bool global_tbl_lookup)
1296 {
1297 	const struct reg_dmn_op_class_map_t *op_class_tbl = NULL;
1298 	uint8_t i = 0;
1299 
1300 	if (global_tbl_lookup) {
1301 		op_class_tbl = global_op_class;
1302 	} else {
1303 		if (channel_map == channel_map_global) {
1304 			op_class_tbl = global_op_class;
1305 		} else if (channel_map == channel_map_us) {
1306 			op_class_tbl = us_op_class;
1307 		} else if (channel_map == channel_map_eu) {
1308 			op_class_tbl = euro_op_class;
1309 		} else if (channel_map == channel_map_china) {
1310 			op_class_tbl = china_op_class;
1311 		} else if (channel_map == channel_map_jp) {
1312 			op_class_tbl = japan_op_class;
1313 		} else {
1314 			reg_err_rl("Invalid channel map");
1315 			return 0;
1316 		}
1317 	}
1318 
1319 	while (op_class_tbl->op_class) {
1320 		if  (op_class_tbl->op_class == op_class) {
1321 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1322 				     op_class_tbl->channels[i]); i++) {
1323 				if (op_class_tbl->channels[i] == chan) {
1324 					chan = op_class_tbl->channels[i];
1325 					return op_class_tbl->start_freq +
1326 						(chan * FREQ_TO_CHAN_SCALE);
1327 				}
1328 			}
1329 			reg_err_rl("Channel not found");
1330 			return 0;
1331 		}
1332 		op_class_tbl++;
1333 	}
1334 	reg_err_rl("Invalid opclass");
1335 	return 0;
1336 }
1337 
1338 qdf_freq_t reg_chan_opclass_to_freq_auto(uint8_t chan, uint8_t op_class,
1339 					 bool global_tbl_lookup)
1340 {
1341 	if ((op_class >= MIN_6GHZ_OPER_CLASS) &&
1342 	    (op_class <= MAX_6GHZ_OPER_CLASS)) {
1343 		global_tbl_lookup = true;
1344 	} else {
1345 		qdf_freq_t freq = reg_chan_opclass_to_freq(chan,
1346 				op_class,
1347 				global_tbl_lookup);
1348 		if (freq)
1349 			return freq;
1350 		global_tbl_lookup = true;
1351 	}
1352 
1353 	return reg_chan_opclass_to_freq(chan, op_class, global_tbl_lookup);
1354 }
1355 
1356 #ifdef HOST_OPCLASS_EXT
1357 qdf_freq_t reg_country_chan_opclass_to_freq(struct wlan_objmgr_pdev *pdev,
1358 					    const uint8_t country[3],
1359 					    uint8_t chan, uint8_t op_class,
1360 					    bool strict)
1361 {
1362 	const struct reg_dmn_op_class_map_t *op_class_tbl, *op_class_tbl_org;
1363 	uint16_t i;
1364 
1365 	if (reg_is_6ghz_op_class(pdev, op_class))
1366 		op_class_tbl_org = global_op_class;
1367 	else
1368 		op_class_tbl_org =
1369 			reg_get_class_from_country((uint8_t *)country);
1370 	op_class_tbl = op_class_tbl_org;
1371 	while (op_class_tbl && op_class_tbl->op_class) {
1372 		if  (op_class_tbl->op_class == op_class) {
1373 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1374 				     op_class_tbl->channels[i]); i++) {
1375 				if (op_class_tbl->channels[i] == chan)
1376 					return op_class_tbl->start_freq +
1377 						(chan * FREQ_TO_CHAN_SCALE);
1378 			}
1379 		}
1380 		op_class_tbl++;
1381 	}
1382 	reg_debug_rl("Not found ch %d in op class %d ch list, strict %d",
1383 		     chan, op_class, strict);
1384 	if (strict)
1385 		return 0;
1386 
1387 	op_class_tbl = op_class_tbl_org;
1388 	while (op_class_tbl && op_class_tbl->op_class) {
1389 		for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
1390 			     op_class_tbl->channels[i]); i++) {
1391 			if (op_class_tbl->channels[i] == chan)
1392 				return op_class_tbl->start_freq +
1393 					(chan * FREQ_TO_CHAN_SCALE);
1394 		}
1395 		op_class_tbl++;
1396 	}
1397 	reg_debug_rl("Got invalid freq 0 for ch %d", chan);
1398 
1399 	return 0;
1400 }
1401 #endif
1402 
1403 static void
1404 reg_get_op_class_tbl_by_chan_map(const struct
1405 				 reg_dmn_op_class_map_t **op_class_tbl)
1406 {
1407 	if (channel_map == channel_map_us)
1408 		*op_class_tbl = us_op_class;
1409 	else if (channel_map == channel_map_eu)
1410 		*op_class_tbl = euro_op_class;
1411 	else if (channel_map == channel_map_china)
1412 		*op_class_tbl = china_op_class;
1413 	else if (channel_map == channel_map_jp)
1414 		*op_class_tbl = japan_op_class;
1415 	else
1416 		*op_class_tbl = global_op_class;
1417 }
1418 
1419 /**
1420  * reg_get_channel_cen - Calculate central channel in the channel set.
1421  *
1422  * @op_class_tbl - Pointer to op_class_tbl.
1423  * @idx - Pointer to channel index.
1424  * @num_channels - Number of channels.
1425  * @center_chan - Pointer to center channel number
1426  *
1427  * Return : void
1428  */
1429 static void reg_get_channel_cen(const struct
1430 				reg_dmn_op_class_map_t *op_class_tbl,
1431 				uint8_t *idx,
1432 				uint8_t num_channels,
1433 				uint8_t *center_chan)
1434 {
1435 	uint8_t i;
1436 	uint16_t new_chan = 0;
1437 
1438 	for (i = *idx; i < (*idx + num_channels); i++)
1439 		new_chan += op_class_tbl->channels[i];
1440 
1441 	new_chan = new_chan / num_channels;
1442 	*center_chan = new_chan;
1443 	*idx = *idx + num_channels;
1444 }
1445 
1446 /**
1447  * reg_get_chan_or_chan_center - Calculate central channel in the channel set.
1448  *
1449  * @op_class_tbl - Pointer to op_class_tbl.
1450  * @idx - Pointer to channel index.
1451  *
1452  * Return : Center channel number
1453  */
1454 static uint8_t reg_get_chan_or_chan_center(const struct
1455 					   reg_dmn_op_class_map_t *op_class_tbl,
1456 					   uint8_t *idx)
1457 {
1458 	uint8_t center_chan;
1459 
1460 	if (((op_class_tbl->chan_spacing == BW_80_MHZ) &&
1461 	     (op_class_tbl->behav_limit == BIT(BEHAV_NONE))) ||
1462 	    ((op_class_tbl->chan_spacing == BW_80_MHZ) &&
1463 	     (op_class_tbl->behav_limit == BIT(BEHAV_BW80_PLUS)))) {
1464 		reg_get_channel_cen(op_class_tbl,
1465 				    idx,
1466 				    NUM_20_MHZ_CHAN_IN_80_MHZ_CHAN,
1467 				    &center_chan);
1468 	} else if (op_class_tbl->chan_spacing == BW_160_MHZ) {
1469 		reg_get_channel_cen(op_class_tbl,
1470 				    idx,
1471 				    NUM_20_MHZ_CHAN_IN_160_MHZ_CHAN,
1472 				    &center_chan);
1473 	} else {
1474 		center_chan = op_class_tbl->channels[*idx];
1475 		*idx = *idx + 1;
1476 	}
1477 
1478 	return center_chan;
1479 }
1480 
1481 /**
1482  * reg_get_channels_from_opclassmap()- Get channels from the opclass map
1483  * @pdev: Pointer to pdev
1484  * @reg_ap_cap: Pointer to reg_ap_cap
1485  * @index: Pointer to index of reg_ap_cap
1486  * @op_class_tbl: Pointer to op_class_tbl
1487  * @is_opclass_operable: Set true if opclass is operable, else set false
1488  *
1489  * Populate channels from opclass map to reg_ap_cap as supported and
1490  * non-supported channels.
1491  *
1492  * Return: void.
1493  */
1494 static void
1495 reg_get_channels_from_opclassmap(
1496 		struct wlan_objmgr_pdev *pdev,
1497 		struct regdmn_ap_cap_opclass_t *reg_ap_cap,
1498 		uint8_t index,
1499 		const struct reg_dmn_op_class_map_t *op_class_tbl,
1500 		bool *is_opclass_operable)
1501 {
1502 	uint8_t op_cls_chan;
1503 	qdf_freq_t search_freq;
1504 	bool is_freq_present;
1505 	uint8_t chan_idx = 0, n_sup_chans = 0, n_unsup_chans = 0;
1506 
1507 	while (op_class_tbl->channels[chan_idx]) {
1508 		op_cls_chan = op_class_tbl->channels[chan_idx];
1509 		search_freq = op_class_tbl->start_freq +
1510 					(FREQ_TO_CHAN_SCALE * op_cls_chan);
1511 		is_freq_present =
1512 			reg_is_freq_present_in_cur_chan_list(pdev, search_freq);
1513 
1514 		if (!is_freq_present) {
1515 			reg_ap_cap[index].non_sup_chan_list[n_unsup_chans++] =
1516 				reg_get_chan_or_chan_center(op_class_tbl,
1517 							    &chan_idx);
1518 			reg_ap_cap[index].num_non_supported_chan++;
1519 		} else {
1520 			reg_ap_cap[index].sup_chan_list[n_sup_chans++] =
1521 				reg_get_chan_or_chan_center(op_class_tbl,
1522 							    &chan_idx);
1523 			reg_ap_cap[index].num_supported_chan++;
1524 		}
1525 	}
1526 
1527 	if (reg_ap_cap[index].num_supported_chan >= 1)
1528 		*is_opclass_operable = true;
1529 }
1530 
1531 QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
1532 				   struct regdmn_ap_cap_opclass_t *reg_ap_cap,
1533 				   uint8_t *n_opclasses,
1534 				   uint8_t max_supp_op_class,
1535 				   bool global_tbl_lookup)
1536 {
1537 	uint8_t max_reg_power = 0;
1538 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1539 	uint8_t index = 0;
1540 
1541 	if (global_tbl_lookup)
1542 		op_class_tbl = global_op_class;
1543 	else
1544 		reg_get_op_class_tbl_by_chan_map(&op_class_tbl);
1545 
1546 	max_reg_power = reg_get_max_tx_power(pdev);
1547 
1548 	while (op_class_tbl->op_class && (index < max_supp_op_class)) {
1549 		bool is_opclass_operable = false;
1550 
1551 		qdf_mem_zero(reg_ap_cap[index].sup_chan_list,
1552 			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
1553 		reg_ap_cap[index].num_supported_chan = 0;
1554 		qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list,
1555 			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
1556 		reg_ap_cap[index].num_non_supported_chan = 0;
1557 		reg_get_channels_from_opclassmap(pdev,
1558 						 reg_ap_cap,
1559 						 index,
1560 						 op_class_tbl,
1561 						 &is_opclass_operable);
1562 		if (is_opclass_operable) {
1563 			reg_ap_cap[index].op_class = op_class_tbl->op_class;
1564 			reg_ap_cap[index].ch_width =
1565 						op_class_tbl->chan_spacing;
1566 			reg_ap_cap[index].start_freq =
1567 						op_class_tbl->start_freq;
1568 			reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power;
1569 			reg_ap_cap[index].behav_limit =
1570 						op_class_tbl->behav_limit;
1571 			index++;
1572 		}
1573 
1574 		op_class_tbl++;
1575 	}
1576 
1577 	*n_opclasses = index;
1578 
1579 	return QDF_STATUS_SUCCESS;
1580 }
1581 
1582 bool reg_is_6ghz_op_class(struct wlan_objmgr_pdev *pdev, uint8_t op_class)
1583 {
1584 	return ((op_class >= MIN_6GHZ_OPER_CLASS) &&
1585 		(op_class <= MAX_6GHZ_OPER_CLASS));
1586 }
1587 
1588 /**
1589  * reg_is_opclass_band_found - Check if the input opclass is 2G or 5G.
1590  *
1591  * @country - Pointer to country.
1592  * @op_class - Operating class.
1593  * @bandmask = Bitmask for band.
1594  *
1595  * Return : Return true if the input opclass' band (2Ghz or 5Ghz) matches one
1596  * of bandmask's band.
1597  */
1598 static bool reg_is_opclass_band_found(const uint8_t *country,
1599 				      uint8_t op_class,
1600 				      uint8_t bandmask)
1601 {
1602 	const struct reg_dmn_op_class_map_t *op_class_tbl;
1603 
1604 	op_class_tbl = reg_get_class_from_country((uint8_t *)country);
1605 
1606 	while (op_class_tbl && op_class_tbl->op_class) {
1607 		if (op_class_tbl->op_class == op_class) {
1608 			qdf_freq_t freq = op_class_tbl->start_freq +
1609 			(op_class_tbl->channels[0] * FREQ_TO_CHAN_SCALE);
1610 
1611 			if ((bandmask & BIT(REG_BAND_5G)) &&
1612 			    REG_IS_5GHZ_FREQ(freq))
1613 				return true;
1614 
1615 			if ((bandmask & BIT(REG_BAND_2G)) &&
1616 			    REG_IS_24GHZ_CH_FREQ(freq))
1617 				return true;
1618 
1619 			return false;
1620 		}
1621 
1622 		op_class_tbl++;
1623 	}
1624 
1625 	reg_err_rl("Opclass %d is not found", op_class);
1626 
1627 	return false;
1628 }
1629 
1630 bool reg_is_5ghz_op_class(const uint8_t *country, uint8_t op_class)
1631 {
1632 	return reg_is_opclass_band_found(country, op_class, BIT(REG_BAND_5G));
1633 }
1634 
1635 bool reg_is_2ghz_op_class(const uint8_t *country, uint8_t op_class)
1636 {
1637 	return reg_is_opclass_band_found(country, op_class, BIT(REG_BAND_2G));
1638 }
1639 #endif
1640