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