xref: /wlan-dirver/qca-wifi-host-cmn/umac/regulatory/core/src/reg_opclass.c (revision f28396d060cff5c6519f883cb28ae0116ce479f1)
1 /*
2  * Copyright (c) 2014-2019 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} },
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} },
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), 2407,
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 #ifdef HOST_OPCLASS
258 /**
259  * reg_get_class_from_country()- Get Class from country
260  * @country- Country
261  *
262  * Return: class.
263  */
264 static const
265 struct reg_dmn_op_class_map_t *reg_get_class_from_country(uint8_t *country)
266 {
267 	const struct reg_dmn_op_class_map_t *class = NULL;
268 
269 	qdf_debug("Country %c%c 0x%x",
270 		  country[0], country[1], country[2]);
271 
272 	switch (country[2]) {
273 	case OP_CLASS_US:
274 		class = us_op_class;
275 		break;
276 
277 	case OP_CLASS_EU:
278 		class = euro_op_class;
279 		break;
280 
281 	case OP_CLASS_JAPAN:
282 		class = japan_op_class;
283 		break;
284 
285 	case OP_CLASS_GLOBAL:
286 		class = global_op_class;
287 		break;
288 
289 	default:
290 		if (!qdf_mem_cmp(country, "US", 2))
291 			class = us_op_class;
292 		else if (!qdf_mem_cmp(country, "EU", 2))
293 			class = euro_op_class;
294 		else if (!qdf_mem_cmp(country, "JP", 2))
295 			class = japan_op_class;
296 		else
297 			class = global_op_class;
298 	}
299 	return class;
300 }
301 
302 uint16_t reg_dmn_get_chanwidth_from_opclass(uint8_t *country, uint8_t channel,
303 					    uint8_t opclass)
304 {
305 	const struct reg_dmn_op_class_map_t *class;
306 	uint16_t i;
307 
308 	class = reg_get_class_from_country(country);
309 
310 	while (class->op_class) {
311 		if (opclass == class->op_class) {
312 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
313 				     class->channels[i]); i++) {
314 				if (channel == class->channels[i])
315 					return class->chan_spacing;
316 			}
317 		}
318 		class++;
319 	}
320 
321 	return 0;
322 }
323 
324 uint16_t reg_dmn_get_opclass_from_channel(uint8_t *country, uint8_t channel,
325 					  uint8_t offset)
326 {
327 	const struct reg_dmn_op_class_map_t *class = NULL;
328 	uint16_t i = 0;
329 
330 	class = reg_get_class_from_country(country);
331 	while (class && class->op_class) {
332 		if ((offset == class->offset) || (offset == BWALL)) {
333 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
334 				     class->channels[i]); i++) {
335 				if (channel == class->channels[i])
336 					return class->op_class;
337 			}
338 		}
339 		class++;
340 	}
341 
342 	return 0;
343 }
344 
345 uint8_t reg_dmn_get_opclass_from_freq_width(uint8_t *country,
346 					    qdf_freq_t freq,
347 					    uint8_t ch_width,
348 					    uint16_t behav_limit)
349 {
350 	const struct reg_dmn_op_class_map_t *op_class_tbl = NULL;
351 	uint16_t i = 0;
352 
353 	op_class_tbl = reg_get_class_from_country(country);
354 
355 	while (op_class_tbl && op_class_tbl->op_class) {
356 		if (op_class_tbl->chan_spacing == ch_width) {
357 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
358 				     op_class_tbl->channels[i]); i++) {
359 				if ((op_class_tbl->start_freq +
360 				     (FREQ_TO_CHAN_SCALE *
361 				      op_class_tbl->channels[i]) == freq) &&
362 				    (behav_limit & op_class_tbl->behav_limit)) {
363 					return op_class_tbl->op_class;
364 				}
365 			}
366 		}
367 		op_class_tbl++;
368 	}
369 
370 	return 0;
371 }
372 
373 void reg_dmn_print_channels_in_opclass(uint8_t *country, uint8_t op_class)
374 {
375 	const struct reg_dmn_op_class_map_t *class = NULL;
376 	uint16_t i = 0;
377 
378 	class = reg_get_class_from_country(country);
379 
380 	if (!class) {
381 		reg_err("class is NULL");
382 		return;
383 	}
384 
385 	while (class->op_class) {
386 		if (class->op_class == op_class) {
387 			for (i = 0;
388 			     (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
389 			      class->channels[i]); i++) {
390 				reg_debug("Valid channel(%d) in requested RC(%d)",
391 					  class->channels[i], op_class);
392 			}
393 			break;
394 		}
395 		class++;
396 	}
397 	if (!class->op_class)
398 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
399 			  "Invalid requested RC (%d)", op_class);
400 }
401 
402 uint16_t reg_dmn_set_curr_opclasses(uint8_t num_classes, uint8_t *class)
403 {
404 	uint8_t i;
405 
406 	if (num_classes > REG_MAX_SUPP_OPER_CLASSES) {
407 		reg_err("invalid num classes %d", num_classes);
408 		return 0;
409 	}
410 
411 	for (i = 0; i < num_classes; i++)
412 		reg_dmn_curr_supp_opp_classes.classes[i] = class[i];
413 
414 	reg_dmn_curr_supp_opp_classes.num_classes = num_classes;
415 
416 	return 0;
417 }
418 
419 uint16_t reg_dmn_get_curr_opclasses(uint8_t *num_classes, uint8_t *class)
420 {
421 	uint8_t i;
422 
423 	if (!num_classes || !class) {
424 		reg_err("either num_classes or class is null");
425 		return 0;
426 	}
427 
428 	for (i = 0; i < reg_dmn_curr_supp_opp_classes.num_classes; i++)
429 		class[i] = reg_dmn_curr_supp_opp_classes.classes[i];
430 
431 	*num_classes = reg_dmn_curr_supp_opp_classes.num_classes;
432 
433 	return 0;
434 }
435 
436 #ifdef CONFIG_CHAN_FREQ_API
437 void reg_freq_width_to_chan_op_class(struct wlan_objmgr_pdev *pdev,
438 				     qdf_freq_t freq,
439 				     uint16_t chan_width,
440 				     bool global_tbl_lookup,
441 				     uint16_t behav_limit,
442 				     uint8_t *op_class,
443 				     uint8_t *chan_num)
444 {
445 	const struct reg_dmn_op_class_map_t *op_class_tbl;
446 	enum channel_enum chan_enum;
447 	uint16_t i;
448 
449 	chan_enum = reg_get_chan_enum_for_freq(freq);
450 
451 	if (chan_enum == INVALID_CHANNEL) {
452 		reg_err(" channel enumeration is invalid %d", chan_enum);
453 		return;
454 	}
455 
456 	if (global_tbl_lookup) {
457 		op_class_tbl = global_op_class;
458 	} else {
459 		if (channel_map == channel_map_us)
460 			op_class_tbl = us_op_class;
461 		else if (channel_map == channel_map_eu)
462 			op_class_tbl = euro_op_class;
463 		else if (channel_map == channel_map_china)
464 			op_class_tbl = us_op_class;
465 		else if (channel_map == channel_map_jp)
466 			op_class_tbl = japan_op_class;
467 		else
468 			op_class_tbl = global_op_class;
469 	}
470 
471 	while (op_class_tbl->op_class) {
472 		if (op_class_tbl->chan_spacing >= chan_width) {
473 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
474 				     op_class_tbl->channels[i]); i++) {
475 				if ((op_class_tbl->start_freq +
476 				     FREQ_TO_CHAN_SCALE *
477 				     op_class_tbl->channels[i] == freq) &&
478 				    (behav_limit & op_class_tbl->behav_limit ||
479 				     behav_limit == BIT(BEHAV_NONE))) {
480 					*chan_num = op_class_tbl->channels[i];
481 					*op_class = op_class_tbl->op_class;
482 					return;
483 				}
484 			}
485 		}
486 		op_class_tbl++;
487 	}
488 
489 	reg_err_rl("invalid frequency %d", freq);
490 }
491 
492 void reg_freq_to_chan_op_class(struct wlan_objmgr_pdev *pdev,
493 			       qdf_freq_t freq,
494 			       bool global_tbl_lookup,
495 			       uint16_t behav_limit,
496 			       uint8_t *op_class,
497 			       uint8_t *chan_num)
498 {
499 	enum channel_enum chan_enum;
500 	uint16_t chan_width;
501 	struct regulatory_channel *cur_chan_list;
502 	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
503 
504 	pdev_priv_obj = reg_get_pdev_obj(pdev);
505 
506 	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
507 		reg_err("pdev reg obj is NULL");
508 		return;
509 	}
510 
511 	cur_chan_list = pdev_priv_obj->cur_chan_list;
512 
513 	chan_enum = reg_get_chan_enum_for_freq(freq);
514 
515 	if (chan_enum == INVALID_CHANNEL) {
516 		reg_err(" channel enumeration is invalid %d", chan_enum);
517 		return;
518 	}
519 
520 	chan_width = cur_chan_list[chan_enum].max_bw;
521 
522 	reg_freq_width_to_chan_op_class(pdev, freq,
523 					chan_width,
524 					global_tbl_lookup,
525 					behav_limit,
526 					op_class,
527 					chan_num);
528 }
529 #endif
530 
531 uint16_t reg_get_op_class_width(struct wlan_objmgr_pdev *pdev,
532 				uint8_t op_class,
533 				bool global_tbl_lookup)
534 {
535 	const struct reg_dmn_op_class_map_t *op_class_tbl;
536 
537 	if (global_tbl_lookup) {
538 		op_class_tbl = global_op_class;
539 	} else {
540 		if (channel_map == channel_map_us)
541 			op_class_tbl = us_op_class;
542 		else if (channel_map == channel_map_eu)
543 			op_class_tbl = euro_op_class;
544 		else if (channel_map == channel_map_china)
545 			op_class_tbl = us_op_class;
546 		else if (channel_map == channel_map_jp)
547 			op_class_tbl = japan_op_class;
548 		else
549 			op_class_tbl = global_op_class;
550 	}
551 
552 	while (op_class_tbl->op_class) {
553 		if  (op_class_tbl->op_class == op_class)
554 			return op_class_tbl->chan_spacing;
555 		op_class_tbl++;
556 	}
557 
558 	return 0;
559 }
560 
561 uint16_t reg_chan_opclass_to_freq(uint8_t chan,
562 				  uint8_t op_class,
563 				  bool global_tbl_lookup)
564 {
565 	const struct reg_dmn_op_class_map_t *op_class_tbl = NULL;
566 	uint8_t i = 0;
567 
568 	if (global_tbl_lookup) {
569 		op_class_tbl = global_op_class;
570 	} else {
571 		if (channel_map == channel_map_global) {
572 			op_class_tbl = global_op_class;
573 		} else if (channel_map == channel_map_us) {
574 			op_class_tbl = us_op_class;
575 		} else if (channel_map == channel_map_eu) {
576 			op_class_tbl = euro_op_class;
577 		} else if (channel_map == channel_map_china) {
578 			op_class_tbl = us_op_class;
579 		} else if (channel_map == channel_map_jp) {
580 			op_class_tbl = japan_op_class;
581 		} else {
582 			reg_err_rl("Invalid channel map");
583 			return 0;
584 		}
585 	}
586 
587 	while (op_class_tbl->op_class) {
588 		if  (op_class_tbl->op_class == op_class) {
589 			for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
590 				     op_class_tbl->channels[i]); i++) {
591 				if (op_class_tbl->channels[i] == chan) {
592 					chan = op_class_tbl->channels[i];
593 					return op_class_tbl->start_freq +
594 						(chan * FREQ_TO_CHAN_SCALE);
595 				}
596 			}
597 			reg_err_rl("Channel not found");
598 			return 0;
599 		}
600 		op_class_tbl++;
601 	}
602 	reg_err_rl("Invalid opclass given as input");
603 	return 0;
604 }
605 
606 static void
607 reg_get_op_class_tbl_by_chan_map(const struct
608 				 reg_dmn_op_class_map_t **op_class_tbl)
609 {
610 	if (channel_map == channel_map_us)
611 		*op_class_tbl = us_op_class;
612 	else if (channel_map == channel_map_eu)
613 		*op_class_tbl = euro_op_class;
614 	else if (channel_map == channel_map_china)
615 		*op_class_tbl = us_op_class;
616 	else if (channel_map == channel_map_jp)
617 		*op_class_tbl = japan_op_class;
618 	else
619 		*op_class_tbl = global_op_class;
620 }
621 
622 /**
623  * reg_get_channels_from_opclassmap()- Get channels from the opclass map
624  * @pdev: Pointer to pdev
625  * @reg_ap_cap: Pointer to reg_ap_cap
626  * @index: Pointer to index of reg_ap_cap
627  * @op_class_tbl: Pointer to op_class_tbl
628  * @is_opclass_operable: Set true if opclass is operable, else set false
629  *
630  * Populate channels from opclass map to reg_ap_cap as supported and
631  * non-supported channels.
632  *
633  * Return: void.
634  */
635 static void
636 reg_get_channels_from_opclassmap(
637 		struct wlan_objmgr_pdev *pdev,
638 		struct regdmn_ap_cap_opclass_t *reg_ap_cap,
639 		uint8_t index,
640 		const struct reg_dmn_op_class_map_t *op_class_tbl,
641 		bool *is_opclass_operable)
642 {
643 	uint8_t op_cls_chan;
644 	qdf_freq_t search_freq;
645 	bool is_freq_present;
646 	uint8_t chan_idx = 0, n_sup_chans = 0, n_unsup_chans = 0;
647 
648 	while (op_class_tbl->channels[chan_idx]) {
649 		op_cls_chan = op_class_tbl->channels[chan_idx];
650 		search_freq = op_class_tbl->start_freq +
651 					(FREQ_TO_CHAN_SCALE * op_cls_chan);
652 		is_freq_present =
653 			reg_is_freq_present_in_cur_chan_list(pdev, search_freq);
654 
655 		if (!is_freq_present) {
656 			reg_ap_cap[index].
657 					non_sup_chan_list[n_unsup_chans++] =
658 					op_class_tbl->channels[chan_idx];
659 			reg_ap_cap[index].num_non_supported_chan++;
660 		} else {
661 			reg_ap_cap[index].sup_chan_list[n_sup_chans++] =
662 					op_class_tbl->channels[chan_idx];
663 			reg_ap_cap[index].num_supported_chan++;
664 		}
665 
666 		chan_idx++;
667 	}
668 
669 	if (reg_ap_cap[index].num_supported_chan >= 1)
670 		*is_opclass_operable = true;
671 }
672 
673 QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
674 				   struct regdmn_ap_cap_opclass_t *reg_ap_cap,
675 				   uint8_t *n_opclasses,
676 				   uint8_t max_supp_op_class,
677 				   bool global_tbl_lookup)
678 {
679 	uint8_t max_reg_power = 0;
680 	const struct reg_dmn_op_class_map_t *op_class_tbl;
681 	uint8_t index = 0;
682 
683 	if (global_tbl_lookup)
684 		op_class_tbl = global_op_class;
685 	else
686 		reg_get_op_class_tbl_by_chan_map(&op_class_tbl);
687 
688 	max_reg_power = reg_get_max_tx_power(pdev);
689 
690 	while (op_class_tbl->op_class && (index < max_supp_op_class)) {
691 		bool is_opclass_operable = false;
692 
693 		qdf_mem_zero(reg_ap_cap[index].sup_chan_list,
694 			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
695 		reg_ap_cap[index].num_supported_chan = 0;
696 		qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list,
697 			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
698 		reg_ap_cap[index].num_non_supported_chan = 0;
699 		reg_get_channels_from_opclassmap(pdev,
700 						 reg_ap_cap,
701 						 index,
702 						 op_class_tbl,
703 						 &is_opclass_operable);
704 		if (is_opclass_operable) {
705 			reg_ap_cap[index].op_class = op_class_tbl->op_class;
706 			reg_ap_cap[index].ch_width =
707 						op_class_tbl->chan_spacing;
708 			reg_ap_cap[index].start_freq =
709 						op_class_tbl->start_freq;
710 			reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power;
711 			reg_ap_cap[index].behav_limit =
712 						op_class_tbl->behav_limit;
713 			index++;
714 		}
715 
716 		op_class_tbl++;
717 	}
718 
719 	*n_opclasses = index;
720 
721 	return QDF_STATUS_SUCCESS;
722 }
723 #endif
724