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 ¢er_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 ¢er_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