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