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