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