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