xref: /wlan-dirver/qca-wifi-host-cmn/umac/regulatory/core/src/reg_opclass.c (revision 6d768494e5ce14eb1603a695c86739d12ecc6ec2)
1 /*
2  * Copyright (c) 2014-2020 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 static const struct reg_dmn_op_class_map_t global_op_class[] = {
43 	{81, 25, BW20, BIT(BEHAV_NONE), 2407,
44 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} },
45 	{82, 25, BW20, BIT(BEHAV_NONE), 2414,
46 	 {14} },
47 	{83, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407,
48 	 {1, 2, 3, 4, 5, 6, 7, 8, 9} },
49 	{84, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407,
50 	 {5, 6, 7, 8, 9, 10, 11, 12, 13} },
51 	{115, 20, BW20, BIT(BEHAV_NONE), 5000,
52 	 {36, 40, 44, 48} },
53 	{116, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
54 	 {36, 44} },
55 	{117, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
56 	 {40, 48} },
57 	{118, 20, BW20, BIT(BEHAV_NONE), 5000,
58 	 {52, 56, 60, 64} },
59 	{119, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
60 	 {52, 60} },
61 	{120, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
62 	 {56, 64} },
63 	{121, 20, BW20, BIT(BEHAV_NONE), 5000,
64 	 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144} },
65 	{122, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
66 	 {100, 108, 116, 124, 132, 140} },
67 	{123, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
68 	 {104, 112, 120, 128, 136, 144} },
69 	{125, 20, BW20, BIT(BEHAV_NONE), 5000,
70 	 {149, 153, 157, 161, 165, 169} },
71 	{126, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
72 	 {149, 157} },
73 	{127, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
74 	 {153, 161} },
75 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
76 	 {36, 40, 44, 48, 52, 56, 60, 64,
77 	  100, 104, 108, 112, 116, 120, 124,
78 	  128, 132, 136, 140, 144,
79 	  149, 153, 157, 161} },
80 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
81 	 {36, 40, 44, 48, 52, 56, 60, 64,
82 	  100, 104, 108, 112, 116, 120, 124, 128} },
83 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
84 	 {36, 40, 44, 48, 52, 56, 60, 64,
85 	  100, 104, 108, 112, 116, 120, 124, 128,
86 	  132, 136, 140, 144, 149, 153, 157, 161} },
87 
88 #ifdef CONFIG_BAND_6GHZ
89 	{131, 20, BW20, BIT(BEHAV_NONE), 5940,
90 	 {1, 5, 9, 13, 17, 21, 25, 29, 33,
91 	  37, 41, 45, 49, 53, 57, 61, 65, 69,
92 	  73, 77, 81, 85, 89, 93, 97,
93 	  101, 105, 109, 113, 117, 121, 125,
94 	  129, 133, 137, 141, 145, 149, 153,
95 	  157, 161, 165, 169, 173, 177, 181,
96 	  185, 189, 193, 197, 201, 205, 209,
97 	  213, 217, 221, 225, 229, 233} },
98 
99 	{132, 40, BW40_LOW_PRIMARY, BIT(BEHAV_NONE), 5940,
100 	 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49,
101 	  53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97,
102 	  101, 105, 109, 113, 117, 121, 125, 129, 133, 137,
103 	  141, 145, 149, 153, 157, 161, 165, 169, 173, 177,
104 	  181, 185, 189, 193, 197, 201, 205, 209, 213, 217,
105 	  221, 225, 229, 233} },
106 
107 	{133, 80, BW80, BIT(BEHAV_NONE), 5940,
108 	 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49,
109 	  53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97,
110 	  101, 105, 109, 113, 117, 121, 125, 129, 133, 137,
111 	  141, 145, 149, 153, 157, 161, 165, 169, 173,
112 	  177, 181, 185, 189, 193, 197, 201, 205, 209, 213,
113 	  217, 221, 225, 229, 233} },
114 
115 	{134, 160, BW80, BIT(BEHAV_NONE), 5940,
116 	 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45,
117 	  49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89,
118 	  93, 97, 101, 105, 109, 113, 117, 121, 125,
119 	  129, 133, 137, 141, 145, 149, 153, 157, 161,
120 	  165, 169, 173, 177, 181, 185, 189, 193, 197,
121 	  201, 205, 209, 213, 217, 221, 225, 229, 233} },
122 
123 	{135, 80, BW80, BIT(BEHAV_BW80_PLUS), 5940,
124 	 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41,
125 	  45, 49, 53, 57, 61, 65, 69, 73, 77, 81,
126 	  85, 89, 93, 97, 101, 105, 109, 113, 117,
127 	  121, 125, 129, 133, 137, 141, 145, 149,
128 	  153, 157, 161, 165, 169, 173, 177, 181,
129 	  185, 189, 193, 197, 201, 205, 209, 213,
130 	  217, 221, 225, 229, 233} },
131 #endif
132 	{0, 0, 0, 0, 0, {0} },
133 };
134 
135 static const struct reg_dmn_op_class_map_t us_op_class[] = {
136 	{1, 20, BW20, BIT(BEHAV_NONE), 5000,
137 	 {36, 40, 44, 48} },
138 	{2, 20, BW20, BIT(BEHAV_NONE), 5000,
139 	 {52, 56, 60, 64} },
140 	{4, 20, BW20, BIT(BEHAV_NONE), 5000,
141 	 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144} },
142 	{5, 20, BW20, BIT(BEHAV_NONE), 5000,
143 	 {149, 153, 157, 161, 165} },
144 	{12, 25, BW20, BIT(BEHAV_NONE), 2407,
145 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} },
146 	{22, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
147 	 {36, 44} },
148 	{23, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
149 	 {52, 60} },
150 	{24, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
151 	 {100, 108, 116, 124, 132, 140} },
152 	{26, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
153 	 {149, 157} },
154 	{27, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
155 	 {40, 48} },
156 	{28, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
157 	 {56, 64} },
158 	{29, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
159 	 {104, 112, 120, 128, 136, 144} },
160 	{30, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
161 	 {153, 161} },
162 	{31, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
163 	 {153, 161} },
164 	{32, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407,
165 	 {1, 2, 3, 4, 5, 6, 7} },
166 	{33, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407,
167 	 {5, 6, 7, 8, 9, 10, 11} },
168 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
169 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
170 	  104, 108, 112, 116, 120, 124, 128, 132,
171 	  136, 140, 144, 149, 153, 157, 161} },
172 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
173 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
174 	  104, 108, 112, 116, 120, 124, 128} },
175 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
176 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
177 	  104, 108, 112, 116, 120, 124, 128, 132,
178 	  136, 140, 144, 149, 153, 157, 161} },
179 	{0, 0, 0, 0, 0, {0} },
180 };
181 
182 static const struct reg_dmn_op_class_map_t euro_op_class[] = {
183 	{1, 20, BW20, BIT(BEHAV_NONE), 5000,
184 	 {36, 40, 44, 48} },
185 	{2, 20, BW20, BIT(BEHAV_NONE), 5000,
186 	 {52, 56, 60, 64} },
187 	{3, 20, BW20, BIT(BEHAV_NONE), 5000,
188 	 {100, 104, 108, 112, 116, 120,
189 	  124, 128, 132, 136, 140} },
190 	{4, 25, BW20, BIT(BEHAV_NONE), 2407,
191 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} },
192 	{5, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
193 	 {36, 44} },
194 	{6, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
195 	 {52, 60} },
196 	{7, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
197 	 {100, 108, 116, 124, 132} },
198 	{8, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
199 	 {40, 48} },
200 	{9, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
201 	 {56, 64} },
202 	{10, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
203 	 {104, 112, 120, 128, 136} },
204 	{11, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407,
205 	 {1, 2, 3, 4, 5, 6, 7, 8, 9} },
206 	{12, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407,
207 	 {5, 6, 7, 8, 9, 10, 11, 12, 13} },
208 	{17, 20, BW20, BIT(BEHAV_NONE), 5000,
209 	 {149, 153, 157, 161, 165, 169} },
210 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
211 	 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
212 	  124, 128} },
213 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
214 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
215 	  104, 108, 112, 116, 120, 124, 128} },
216 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
217 	 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
218 	  124, 128} },
219 	{0, 0, 0, 0, 0, {0} },
220 };
221 
222 static const struct reg_dmn_op_class_map_t japan_op_class[] = {
223 	{1, 20, BW20, BIT(BEHAV_NONE), 5000,
224 	 {36, 40, 44, 48} },
225 	{30, 25, BW20, BIT(BEHAV_NONE), 2407,
226 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} },
227 	{31, 25, BW20, BIT(BEHAV_NONE), 2414,
228 	 {14} },
229 	{32, 20, BW20, BIT(BEHAV_NONE), 5000,
230 	 {52, 56, 60, 64} },
231 	{34, 20, BW20, BIT(BEHAV_NONE), 5000,
232 	 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140} },
233 	{36, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
234 	 {36, 44} },
235 	{37, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
236 	 {52, 60} },
237 	{39, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
238 	 {100, 108, 116, 124, 132} },
239 	{41, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
240 	 {40, 48} },
241 	{42, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
242 	 {56, 64} },
243 	{44, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
244 	 {104, 112, 120, 128, 136} },
245 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
246 	 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
247 	  124, 128} },
248 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
249 	 {36, 40, 44, 48, 52, 56, 60, 64, 100,
250 	  104, 108, 112, 116, 120, 124, 128} },
251 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
252 	 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
253 	  124, 128} },
254 	{0, 0, 0, 0, 0, {0} },
255 };
256 
257 static const struct reg_dmn_op_class_map_t china_op_class[] = {
258 	{7, 25, BW20, BIT(BEHAV_NONE), 2407,
259 	 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} },
260 	{8, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407,
261 	 {1, 2, 3, 4, 5, 6, 7, 8, 9} },
262 	{9, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407,
263 	 {5, 6, 7, 8, 9, 10, 11, 12, 13} },
264 	{1, 20, BW20, BIT(BEHAV_NONE), 5000,
265 	 {36, 40, 44, 48} },
266 	{4, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
267 	 {36, 44} },
268 	{117, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000,
269 	 {40, 48} },
270 	{2, 20, BW20, BIT(BEHAV_NONE), 5000,
271 	 {52, 56, 60, 64} },
272 	{5, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
273 	 {52, 60} },
274 	{3, 20, BW20, BIT(BEHAV_NONE), 5000,
275 	 {149, 153, 157, 161, 165} },
276 	{6, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000,
277 	 {149, 157} },
278 	{128, 80, BW80, BIT(BEHAV_NONE), 5000,
279 	 {36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161} },
280 	{129, 160, BW80, BIT(BEHAV_NONE), 5000,
281 	 {36, 40, 44, 48, 52, 56, 60, 64,} },
282 	{130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000,
283 	 {36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161} },
284 	{0, 0, 0, 0, 0, {0} },
285 };
286 #ifdef HOST_OPCLASS
287 /**
288  * reg_get_class_from_country()- Get Class from country
289  * @country- Country
290  *
291  * Return: class.
292  */
293 static const struct reg_dmn_op_class_map_t
294 *reg_get_class_from_country(const uint8_t *country)
295 {
296 	const struct reg_dmn_op_class_map_t *class = NULL;
297 
298 	reg_debug_rl("Country %c%c 0x%x", country[0], country[1], country[2]);
299 
300 	switch (country[2]) {
301 	case OP_CLASS_US:
302 		class = us_op_class;
303 		break;
304 
305 	case OP_CLASS_EU:
306 		class = euro_op_class;
307 		break;
308 
309 	case OP_CLASS_JAPAN:
310 		class = japan_op_class;
311 		break;
312 
313 	case OP_CLASS_GLOBAL:
314 		class = global_op_class;
315 		break;
316 
317 	case OP_CLASS_CHINA:
318 		class = china_op_class;
319 		break;
320 	default:
321 		if (!qdf_mem_cmp(country, "US", 2))
322 			class = us_op_class;
323 		else if (!qdf_mem_cmp(country, "EU", 2))
324 			class = euro_op_class;
325 		else if (!qdf_mem_cmp(country, "JP", 2))
326 			class = japan_op_class;
327 		else if (!qdf_mem_cmp(country, "CN", 2))
328 			class = china_op_class;
329 		else
330 			class = global_op_class;
331 	}
332 	return class;
333 }
334 
335 uint16_t reg_dmn_get_chanwidth_from_opclass(uint8_t *country, uint8_t channel,
336 					    uint8_t opclass)
337 {
338 	const struct reg_dmn_op_class_map_t *class;
339 	uint16_t i;
340 
341 	class = reg_get_class_from_country(country);
342 
343 	while (class->op_class) {
344 		if (opclass == class->op_class) {
345 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
346 				     class->channels[i]); i++) {
347 				if (channel == class->channels[i])
348 					return class->chan_spacing;
349 			}
350 		}
351 		class++;
352 	}
353 
354 	return 0;
355 }
356 
357 uint16_t reg_dmn_get_opclass_from_channel(uint8_t *country, uint8_t channel,
358 					  uint8_t offset)
359 {
360 	const struct reg_dmn_op_class_map_t *class = NULL;
361 	uint16_t i = 0;
362 
363 	class = reg_get_class_from_country(country);
364 	while (class && class->op_class) {
365 		if ((offset == class->offset) || (offset == BWALL)) {
366 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
367 				     class->channels[i]); i++) {
368 				if (channel == class->channels[i])
369 					return class->op_class;
370 			}
371 		}
372 		class++;
373 	}
374 
375 	return 0;
376 }
377 
378 uint8_t reg_dmn_get_opclass_from_freq_width(uint8_t *country,
379 					    qdf_freq_t freq,
380 					    uint8_t ch_width,
381 					    uint16_t behav_limit)
382 {
383 	const struct reg_dmn_op_class_map_t *op_class_tbl = NULL;
384 	uint16_t i = 0;
385 
386 	op_class_tbl = reg_get_class_from_country(country);
387 
388 	while (op_class_tbl && op_class_tbl->op_class) {
389 		if (op_class_tbl->chan_spacing == ch_width) {
390 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
391 				     op_class_tbl->channels[i]); i++) {
392 				if ((op_class_tbl->start_freq +
393 				     (FREQ_TO_CHAN_SCALE *
394 				      op_class_tbl->channels[i]) == freq) &&
395 				    (behav_limit & op_class_tbl->behav_limit)) {
396 					return op_class_tbl->op_class;
397 				}
398 			}
399 		}
400 		op_class_tbl++;
401 	}
402 
403 	return 0;
404 }
405 
406 static void
407 reg_get_band_cap_from_chan_set(const struct reg_dmn_op_class_map_t
408 			       *op_class_tbl,
409 			       uint8_t *supported_band)
410 {
411 	qdf_freq_t chan_freq = op_class_tbl->start_freq +
412 						(op_class_tbl->channels[0] *
413 						 FREQ_TO_CHAN_SCALE);
414 
415 	if (reg_is_24ghz_ch_freq(chan_freq))
416 		*supported_band |= BIT(REG_BAND_2G);
417 	else if (reg_is_5ghz_ch_freq(chan_freq))
418 		*supported_band |= BIT(REG_BAND_5G);
419 	else if (reg_is_6ghz_chan_freq(chan_freq))
420 		*supported_band |= BIT(REG_BAND_6G);
421 	else
422 		reg_err_rl("Unknown band");
423 }
424 
425 uint8_t reg_get_band_cap_from_op_class(const uint8_t *country,
426 				       uint8_t num_of_opclass,
427 				       const uint8_t *opclass)
428 {
429 	const struct reg_dmn_op_class_map_t *op_class_tbl;
430 	uint8_t supported_band = 0, opclassidx;
431 
432 	op_class_tbl = reg_get_class_from_country(country);
433 
434 	while (op_class_tbl && op_class_tbl->op_class) {
435 		for (opclassidx = 0; opclassidx < num_of_opclass;
436 		     opclassidx++) {
437 			if (op_class_tbl->op_class == opclass[opclassidx]) {
438 				reg_get_band_cap_from_chan_set(op_class_tbl,
439 							       &supported_band);
440 			}
441 		}
442 		op_class_tbl++;
443 	}
444 
445 	if (!supported_band)
446 		reg_err_rl("None of the operating classes is found");
447 
448 	return supported_band;
449 }
450 
451 void reg_dmn_print_channels_in_opclass(uint8_t *country, uint8_t op_class)
452 {
453 	const struct reg_dmn_op_class_map_t *class = NULL;
454 	uint16_t i = 0;
455 
456 	class = reg_get_class_from_country(country);
457 
458 	if (!class) {
459 		reg_err("class is NULL");
460 		return;
461 	}
462 
463 	while (class->op_class) {
464 		if (class->op_class == op_class) {
465 			for (i = 0;
466 			     (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
467 			      class->channels[i]); i++) {
468 				reg_debug("Valid channel(%d) in requested RC(%d)",
469 					  class->channels[i], op_class);
470 			}
471 			break;
472 		}
473 		class++;
474 	}
475 	if (!class->op_class)
476 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
477 			  "Invalid requested RC (%d)", op_class);
478 }
479 
480 uint16_t reg_dmn_set_curr_opclasses(uint8_t num_classes, uint8_t *class)
481 {
482 	uint8_t i;
483 
484 	if (num_classes > REG_MAX_SUPP_OPER_CLASSES) {
485 		reg_err("invalid num classes %d", num_classes);
486 		return 0;
487 	}
488 
489 	for (i = 0; i < num_classes; i++)
490 		reg_dmn_curr_supp_opp_classes.classes[i] = class[i];
491 
492 	reg_dmn_curr_supp_opp_classes.num_classes = num_classes;
493 
494 	return 0;
495 }
496 
497 uint16_t reg_dmn_get_curr_opclasses(uint8_t *num_classes, uint8_t *class)
498 {
499 	uint8_t i;
500 
501 	if (!num_classes || !class) {
502 		reg_err("either num_classes or class is null");
503 		return 0;
504 	}
505 
506 	for (i = 0; i < reg_dmn_curr_supp_opp_classes.num_classes; i++)
507 		class[i] = reg_dmn_curr_supp_opp_classes.classes[i];
508 
509 	*num_classes = reg_dmn_curr_supp_opp_classes.num_classes;
510 
511 	return 0;
512 }
513 
514 #ifdef CONFIG_CHAN_FREQ_API
515 void reg_freq_width_to_chan_op_class_auto(struct wlan_objmgr_pdev *pdev,
516 					  qdf_freq_t freq,
517 					  uint16_t chan_width,
518 					  bool global_tbl_lookup,
519 					  uint16_t behav_limit,
520 					  uint8_t *op_class,
521 					  uint8_t *chan_num)
522 {
523 	if (reg_freq_to_band(freq) == REG_BAND_6G) {
524 		global_tbl_lookup = true;
525 		if (chan_width == BW_40_MHZ)
526 			behav_limit = BIT(BEHAV_NONE);
527 	} else {
528 		global_tbl_lookup = false;
529 	}
530 
531 	reg_freq_width_to_chan_op_class(pdev, freq,
532 					chan_width,
533 					global_tbl_lookup,
534 					behav_limit,
535 					op_class,
536 					chan_num);
537 }
538 
539 void reg_freq_width_to_chan_op_class(struct wlan_objmgr_pdev *pdev,
540 				     qdf_freq_t freq,
541 				     uint16_t chan_width,
542 				     bool global_tbl_lookup,
543 				     uint16_t behav_limit,
544 				     uint8_t *op_class,
545 				     uint8_t *chan_num)
546 {
547 	const struct reg_dmn_op_class_map_t *op_class_tbl;
548 	enum channel_enum chan_enum;
549 	uint16_t i;
550 
551 	chan_enum = reg_get_chan_enum_for_freq(freq);
552 
553 	if (chan_enum == INVALID_CHANNEL) {
554 		reg_err_rl("Invalid chan enum %d", chan_enum);
555 		return;
556 	}
557 
558 	if (global_tbl_lookup) {
559 		op_class_tbl = global_op_class;
560 	} else {
561 		if (channel_map == channel_map_us)
562 			op_class_tbl = us_op_class;
563 		else if (channel_map == channel_map_eu)
564 			op_class_tbl = euro_op_class;
565 		else if (channel_map == channel_map_china)
566 			op_class_tbl = china_op_class;
567 		else if (channel_map == channel_map_jp)
568 			op_class_tbl = japan_op_class;
569 		else
570 			op_class_tbl = global_op_class;
571 	}
572 
573 	while (op_class_tbl->op_class) {
574 		if (op_class_tbl->chan_spacing >= chan_width) {
575 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
576 				     op_class_tbl->channels[i]); i++) {
577 				if ((op_class_tbl->start_freq +
578 				     FREQ_TO_CHAN_SCALE *
579 				     op_class_tbl->channels[i] == freq) &&
580 				    (behav_limit & op_class_tbl->behav_limit ||
581 				     behav_limit == BIT(BEHAV_NONE))) {
582 					*chan_num = op_class_tbl->channels[i];
583 					*op_class = op_class_tbl->op_class;
584 					return;
585 				}
586 			}
587 		}
588 		op_class_tbl++;
589 	}
590 
591 	reg_err_rl("invalid frequency %d", freq);
592 }
593 
594 void reg_freq_to_chan_op_class(struct wlan_objmgr_pdev *pdev,
595 			       qdf_freq_t freq,
596 			       bool global_tbl_lookup,
597 			       uint16_t behav_limit,
598 			       uint8_t *op_class,
599 			       uint8_t *chan_num)
600 {
601 	enum channel_enum chan_enum;
602 	uint16_t chan_width;
603 	struct regulatory_channel *cur_chan_list;
604 	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
605 
606 	pdev_priv_obj = reg_get_pdev_obj(pdev);
607 
608 	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
609 		reg_err_rl("NULL pdev reg obj");
610 		return;
611 	}
612 
613 	cur_chan_list = pdev_priv_obj->cur_chan_list;
614 
615 	chan_enum = reg_get_chan_enum_for_freq(freq);
616 
617 	if (chan_enum == INVALID_CHANNEL) {
618 		reg_err_rl("Invalid chan enum %d", chan_enum);
619 		return;
620 	}
621 
622 	chan_width = cur_chan_list[chan_enum].max_bw;
623 
624 	reg_freq_width_to_chan_op_class(pdev, freq,
625 					chan_width,
626 					global_tbl_lookup,
627 					behav_limit,
628 					op_class,
629 					chan_num);
630 }
631 
632 bool reg_is_freq_in_country_opclass(struct wlan_objmgr_pdev *pdev,
633 				    const uint8_t country[3],
634 				    uint8_t op_class,
635 				    qdf_freq_t chan_freq)
636 {
637 	const struct reg_dmn_op_class_map_t *op_class_tbl;
638 	uint8_t i;
639 
640 	op_class_tbl = reg_get_class_from_country((uint8_t *)country);
641 
642 	while (op_class_tbl && op_class_tbl->op_class) {
643 		if  (op_class_tbl->op_class == op_class) {
644 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
645 				     op_class_tbl->channels[i]); i++) {
646 				if (op_class_tbl->channels[i] *
647 				    FREQ_TO_CHAN_SCALE +
648 				    op_class_tbl->start_freq == chan_freq)
649 					return true;
650 			}
651 		}
652 		op_class_tbl++;
653 	}
654 	return false;
655 }
656 
657 #endif
658 
659 uint16_t reg_get_op_class_width(struct wlan_objmgr_pdev *pdev,
660 				uint8_t op_class,
661 				bool global_tbl_lookup)
662 {
663 	const struct reg_dmn_op_class_map_t *op_class_tbl;
664 
665 	if (global_tbl_lookup) {
666 		op_class_tbl = global_op_class;
667 	} else {
668 		if (channel_map == channel_map_us)
669 			op_class_tbl = us_op_class;
670 		else if (channel_map == channel_map_eu)
671 			op_class_tbl = euro_op_class;
672 		else if (channel_map == channel_map_china)
673 			op_class_tbl = china_op_class;
674 		else if (channel_map == channel_map_jp)
675 			op_class_tbl = japan_op_class;
676 		else
677 			op_class_tbl = global_op_class;
678 	}
679 
680 	while (op_class_tbl->op_class) {
681 		if  (op_class_tbl->op_class == op_class)
682 			return op_class_tbl->chan_spacing;
683 		op_class_tbl++;
684 	}
685 
686 	return 0;
687 }
688 
689 uint16_t reg_chan_opclass_to_freq(uint8_t chan,
690 				  uint8_t op_class,
691 				  bool global_tbl_lookup)
692 {
693 	const struct reg_dmn_op_class_map_t *op_class_tbl = NULL;
694 	uint8_t i = 0;
695 
696 	if (global_tbl_lookup) {
697 		op_class_tbl = global_op_class;
698 	} else {
699 		if (channel_map == channel_map_global) {
700 			op_class_tbl = global_op_class;
701 		} else if (channel_map == channel_map_us) {
702 			op_class_tbl = us_op_class;
703 		} else if (channel_map == channel_map_eu) {
704 			op_class_tbl = euro_op_class;
705 		} else if (channel_map == channel_map_china) {
706 			op_class_tbl = china_op_class;
707 		} else if (channel_map == channel_map_jp) {
708 			op_class_tbl = japan_op_class;
709 		} else {
710 			reg_err_rl("Invalid channel map");
711 			return 0;
712 		}
713 	}
714 
715 	while (op_class_tbl->op_class) {
716 		if  (op_class_tbl->op_class == op_class) {
717 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
718 				     op_class_tbl->channels[i]); i++) {
719 				if (op_class_tbl->channels[i] == chan) {
720 					chan = op_class_tbl->channels[i];
721 					return op_class_tbl->start_freq +
722 						(chan * FREQ_TO_CHAN_SCALE);
723 				}
724 			}
725 			reg_err_rl("Channel not found");
726 			return 0;
727 		}
728 		op_class_tbl++;
729 	}
730 	reg_err_rl("Invalid opclass");
731 	return 0;
732 }
733 
734 qdf_freq_t reg_chan_opclass_to_freq_auto(uint8_t chan, uint8_t op_class,
735 					 bool global_tbl_lookup)
736 {
737 	if ((op_class >= MIN_6GHZ_OPER_CLASS) &&
738 	    (op_class <= MAX_6GHZ_OPER_CLASS)) {
739 		global_tbl_lookup = true;
740 	}
741 
742 	return reg_chan_opclass_to_freq(chan, op_class, global_tbl_lookup);
743 }
744 
745 #ifdef HOST_OPCLASS_EXT
746 qdf_freq_t reg_country_chan_opclass_to_freq(struct wlan_objmgr_pdev *pdev,
747 					    const uint8_t country[3],
748 					    uint8_t chan, uint8_t op_class,
749 					    bool strict)
750 {
751 	const struct reg_dmn_op_class_map_t *op_class_tbl, *op_class_tbl_org;
752 	uint16_t i;
753 
754 	if (reg_is_6ghz_op_class(pdev, op_class))
755 		op_class_tbl_org = global_op_class;
756 	else
757 		op_class_tbl_org =
758 			reg_get_class_from_country((uint8_t *)country);
759 	op_class_tbl = op_class_tbl_org;
760 	while (op_class_tbl && op_class_tbl->op_class) {
761 		if  (op_class_tbl->op_class == op_class) {
762 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
763 				     op_class_tbl->channels[i]); i++) {
764 				if (op_class_tbl->channels[i] == chan)
765 					return op_class_tbl->start_freq +
766 						(chan * FREQ_TO_CHAN_SCALE);
767 			}
768 		}
769 		op_class_tbl++;
770 	}
771 	reg_debug_rl("Not found ch %d in op class %d ch list, strict %d",
772 		     chan, op_class, strict);
773 	if (strict)
774 		return 0;
775 
776 	op_class_tbl = op_class_tbl_org;
777 	while (op_class_tbl && op_class_tbl->op_class) {
778 		for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
779 			     op_class_tbl->channels[i]); i++) {
780 			if (op_class_tbl->channels[i] == chan)
781 				return op_class_tbl->start_freq +
782 					(chan * FREQ_TO_CHAN_SCALE);
783 		}
784 		op_class_tbl++;
785 	}
786 	reg_debug_rl("Got invalid freq 0 for ch %d", chan);
787 
788 	return 0;
789 }
790 #endif
791 
792 static void
793 reg_get_op_class_tbl_by_chan_map(const struct
794 				 reg_dmn_op_class_map_t **op_class_tbl)
795 {
796 	if (channel_map == channel_map_us)
797 		*op_class_tbl = us_op_class;
798 	else if (channel_map == channel_map_eu)
799 		*op_class_tbl = euro_op_class;
800 	else if (channel_map == channel_map_china)
801 		*op_class_tbl = china_op_class;
802 	else if (channel_map == channel_map_jp)
803 		*op_class_tbl = japan_op_class;
804 	else
805 		*op_class_tbl = global_op_class;
806 }
807 
808 /**
809  * reg_get_channel_cen - Calculate central channel in the channel set.
810  *
811  * @op_class_tbl - Pointer to op_class_tbl.
812  * @idx - Pointer to channel index.
813  * @num_channels - Number of channels.
814  * @center_chan - Pointer to center channel number
815  *
816  * Return : void
817  */
818 static void reg_get_channel_cen(const struct
819 				reg_dmn_op_class_map_t *op_class_tbl,
820 				uint8_t *idx,
821 				uint8_t num_channels,
822 				uint8_t *center_chan)
823 {
824 	uint8_t i;
825 	uint16_t new_chan = 0;
826 
827 	for (i = *idx; i < (*idx + num_channels); i++)
828 		new_chan += op_class_tbl->channels[i];
829 
830 	new_chan = new_chan / num_channels;
831 	*center_chan = new_chan;
832 	*idx = *idx + num_channels;
833 }
834 
835 /**
836  * reg_get_chan_or_chan_center - Calculate central channel in the channel set.
837  *
838  * @op_class_tbl - Pointer to op_class_tbl.
839  * @idx - Pointer to channel index.
840  *
841  * Return : Center channel number
842  */
843 static uint8_t reg_get_chan_or_chan_center(const struct
844 					   reg_dmn_op_class_map_t *op_class_tbl,
845 					   uint8_t *idx)
846 {
847 	uint8_t center_chan;
848 
849 	if (((op_class_tbl->chan_spacing == BW_80_MHZ) &&
850 	     (op_class_tbl->behav_limit == BIT(BEHAV_NONE))) ||
851 	    ((op_class_tbl->chan_spacing == BW_80_MHZ) &&
852 	     (op_class_tbl->behav_limit == BIT(BEHAV_BW80_PLUS)))) {
853 		reg_get_channel_cen(op_class_tbl,
854 				    idx,
855 				    NUM_20_MHZ_CHAN_IN_80_MHZ_CHAN,
856 				    &center_chan);
857 	} else if (op_class_tbl->chan_spacing == BW_160_MHZ) {
858 		reg_get_channel_cen(op_class_tbl,
859 				    idx,
860 				    NUM_20_MHZ_CHAN_IN_160_MHZ_CHAN,
861 				    &center_chan);
862 	} else {
863 		center_chan = op_class_tbl->channels[*idx];
864 		*idx = *idx + 1;
865 	}
866 
867 	return center_chan;
868 }
869 
870 /**
871  * reg_get_channels_from_opclassmap()- Get channels from the opclass map
872  * @pdev: Pointer to pdev
873  * @reg_ap_cap: Pointer to reg_ap_cap
874  * @index: Pointer to index of reg_ap_cap
875  * @op_class_tbl: Pointer to op_class_tbl
876  * @is_opclass_operable: Set true if opclass is operable, else set false
877  *
878  * Populate channels from opclass map to reg_ap_cap as supported and
879  * non-supported channels.
880  *
881  * Return: void.
882  */
883 static void
884 reg_get_channels_from_opclassmap(
885 		struct wlan_objmgr_pdev *pdev,
886 		struct regdmn_ap_cap_opclass_t *reg_ap_cap,
887 		uint8_t index,
888 		const struct reg_dmn_op_class_map_t *op_class_tbl,
889 		bool *is_opclass_operable)
890 {
891 	uint8_t op_cls_chan;
892 	qdf_freq_t search_freq;
893 	bool is_freq_present;
894 	uint8_t chan_idx = 0, n_sup_chans = 0, n_unsup_chans = 0;
895 
896 	while (op_class_tbl->channels[chan_idx]) {
897 		op_cls_chan = op_class_tbl->channels[chan_idx];
898 		search_freq = op_class_tbl->start_freq +
899 					(FREQ_TO_CHAN_SCALE * op_cls_chan);
900 		is_freq_present =
901 			reg_is_freq_present_in_cur_chan_list(pdev, search_freq);
902 
903 		if (!is_freq_present) {
904 			reg_ap_cap[index].non_sup_chan_list[n_unsup_chans++] =
905 				reg_get_chan_or_chan_center(op_class_tbl,
906 							    &chan_idx);
907 			reg_ap_cap[index].num_non_supported_chan++;
908 		} else {
909 			reg_ap_cap[index].sup_chan_list[n_sup_chans++] =
910 				reg_get_chan_or_chan_center(op_class_tbl,
911 							    &chan_idx);
912 			reg_ap_cap[index].num_supported_chan++;
913 		}
914 	}
915 
916 	if (reg_ap_cap[index].num_supported_chan >= 1)
917 		*is_opclass_operable = true;
918 }
919 
920 QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
921 				   struct regdmn_ap_cap_opclass_t *reg_ap_cap,
922 				   uint8_t *n_opclasses,
923 				   uint8_t max_supp_op_class,
924 				   bool global_tbl_lookup)
925 {
926 	uint8_t max_reg_power = 0;
927 	const struct reg_dmn_op_class_map_t *op_class_tbl;
928 	uint8_t index = 0;
929 
930 	if (global_tbl_lookup)
931 		op_class_tbl = global_op_class;
932 	else
933 		reg_get_op_class_tbl_by_chan_map(&op_class_tbl);
934 
935 	max_reg_power = reg_get_max_tx_power(pdev);
936 
937 	while (op_class_tbl->op_class && (index < max_supp_op_class)) {
938 		bool is_opclass_operable = false;
939 
940 		qdf_mem_zero(reg_ap_cap[index].sup_chan_list,
941 			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
942 		reg_ap_cap[index].num_supported_chan = 0;
943 		qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list,
944 			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
945 		reg_ap_cap[index].num_non_supported_chan = 0;
946 		reg_get_channels_from_opclassmap(pdev,
947 						 reg_ap_cap,
948 						 index,
949 						 op_class_tbl,
950 						 &is_opclass_operable);
951 		if (is_opclass_operable) {
952 			reg_ap_cap[index].op_class = op_class_tbl->op_class;
953 			reg_ap_cap[index].ch_width =
954 						op_class_tbl->chan_spacing;
955 			reg_ap_cap[index].start_freq =
956 						op_class_tbl->start_freq;
957 			reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power;
958 			reg_ap_cap[index].behav_limit =
959 						op_class_tbl->behav_limit;
960 			index++;
961 		}
962 
963 		op_class_tbl++;
964 	}
965 
966 	*n_opclasses = index;
967 
968 	return QDF_STATUS_SUCCESS;
969 }
970 
971 #endif
972