1 /* 2 * Copyright (c) 2014-2021 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 /** 43 * Given a global opclass number create the corresponding array token. 44 * Examples: 45 * 'CFISARR(132)' expands to 'opcls_132_cfis_arr' 46 * 'CFISARR(133)' expands to 'opcls_133_cfis_arr' 47 */ 48 #define CFISARR(_g_opcls) opcls_ ## _g_opcls ## _cfis_arr 49 50 /** 51 * Given a global opclass number create the corresponding list token. 52 * Examples: 53 * 'CFISLST(132)' expands to 'opcls_132_cfis_lst' 54 * 'CFISLST(133)' expands to 'opcls_133_cfis_lst' 55 */ 56 #define CFISLST(_g_opcls) opcls_ ## _g_opcls ## _cfis_lst 57 58 /* The type of the opclass list objects */ 59 #define CFISLST_TYPE static const struct c_freq_lst 60 61 /* The number of elements of the array */ 62 #define NELEMS QDF_ARRAY_SIZE 63 64 /** 65 * Given a global opclass number create the corresponding cfis list and assign 66 * the corresponding cfis array and size of the cfis array 67 * Examples: 68 * 'CREATE_CFIS_LST(132);' 69 * expands to 70 * ' 71 * static const struct c_freq_lst opcls_132_cfis_lst = 72 * {QDF_ARRAY_SIZE(opcls_132_cfis_arr), opcls_132_cfis_arr}; 73 * ' 74 * 75 * 'CREATE_CFIS_LST(133);' 76 * expands to 77 * ' 78 * static const struct c_freq_lst opcls_133_cfis_lst = 79 * {QDF_ARRAY_SIZE(opcls_133_cfis_arr), opcls_133_cfis_arr}; 80 * ' 81 */ 82 #define CREATE_CFIS_LST(_gopcls) \ 83 CFISLST_TYPE CFISLST(_gopcls) = {NELEMS(CFISARR(_gopcls)), CFISARR(_gopcls)} 84 85 /* The NULL pointer to a cfis list object */ 86 #define NULL_CFIS_LST NULL 87 88 /* CFIs for global opclass 131: (start Freq=5925 BW=20MHz) */ 89 static const uint8_t opcls_131_cfis_arr[] = { 90 #ifdef CONFIG_AFC_SUPPORT 91 1, 5, 9, 13, 17, 21, 25, 29, 33, 92 37, 41, 45, 49, 53, 57, 61, 65, 69, 93 73, 77, 81, 85, 89, 93, 97, 94 101, 105, 109, 113, 117, 121, 125, 95 129, 133, 137, 141, 145, 149, 153, 96 157, 161, 165, 169, 173, 177, 181, 97 185, 189, 193, 197, 201, 205, 209, 98 213, 217, 221, 225, 229, 233, 99 #endif 100 }; 101 102 /* CFIs for global opclass 132: (start Freq=5925 BW=40MHz) */ 103 static const uint8_t opcls_132_cfis_arr[] = { 104 #ifdef CONFIG_AFC_SUPPORT 105 3, 11, 19, 27, 35, 43, 51, 59, 67, 75, 106 83, 91, 99, 107, 115, 123, 131, 139, 147, 155, 107 163, 171, 179, 187, 195, 203, 211, 219, 227, 108 #endif 109 }; 110 111 /* CFIs for global opclass 133: (start Freq=5925 BW=80MHz) */ 112 static const uint8_t opcls_133_cfis_arr[] = { 113 #ifdef CONFIG_AFC_SUPPORT 114 7, 23, 39, 55, 71, 87, 103, 119, 135, 151, 167, 183, 115 199, 215, 116 #endif 117 }; 118 119 /* CFIs for global opclass 134: (start Freq=5950 BW=160MHz) */ 120 static const uint8_t opcls_134_cfis_arr[] = { 121 #ifdef CONFIG_AFC_SUPPORT 122 15, 47, 79, 111, 143, 175, 207, 123 #endif 124 }; 125 126 /* CFIs for global opclass 135: (start Freq=5950 BW=80MHz+80MHz) */ 127 static const uint8_t opcls_135_cfis_arr[] = { 128 #ifdef CONFIG_AFC_SUPPORT 129 7, 23, 39, 55, 71, 87, 103, 119, 135, 151, 167, 183, 130 199, 215, 131 #endif 132 }; 133 134 /* CFIs for global opclass 136: (start Freq=5925 BW=20MHz) */ 135 static const uint8_t opcls_136_cfis_arr[] = { 136 #ifdef CONFIG_AFC_SUPPORT 137 2, 138 #endif 139 }; 140 141 /* CFIs for global opclass 137: (start Freq=5950 BW=320MHz) */ 142 #ifdef WLAN_FEATURE_11BE 143 static const uint8_t opcls_137_cfis_arr[] = { 144 #ifdef CONFIG_AFC_SUPPORT 145 31, 63, 95, 127, 159, 191, 146 #endif 147 }; 148 #endif 149 150 /* Create the CFIS static constant lists */ 151 CREATE_CFIS_LST(131); 152 CREATE_CFIS_LST(132); 153 CREATE_CFIS_LST(133); 154 CREATE_CFIS_LST(134); 155 CREATE_CFIS_LST(135); 156 CREATE_CFIS_LST(136); 157 #ifdef WLAN_FEATURE_11BE 158 CREATE_CFIS_LST(137); 159 #endif 160 161 static const struct reg_dmn_op_class_map_t global_op_class[] = { 162 {81, 25, BW20, BIT(BEHAV_NONE), 2407, 163 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 164 NULL_CFIS_LST }, 165 {82, 25, BW20, BIT(BEHAV_NONE), 2414, 166 {14}, 167 NULL_CFIS_LST }, 168 {83, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407, 169 {1, 2, 3, 4, 5, 6, 7, 8, 9}, 170 NULL_CFIS_LST }, 171 {84, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407, 172 {5, 6, 7, 8, 9, 10, 11, 12, 13}, 173 NULL_CFIS_LST }, 174 {115, 20, BW20, BIT(BEHAV_NONE), 5000, 175 {36, 40, 44, 48}, 176 NULL_CFIS_LST }, 177 {116, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 178 {36, 44}, 179 NULL_CFIS_LST }, 180 {117, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 181 {40, 48}, 182 NULL_CFIS_LST }, 183 {118, 20, BW20, BIT(BEHAV_NONE), 5000, 184 {52, 56, 60, 64}, 185 NULL_CFIS_LST }, 186 {119, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 187 {52, 60}, 188 NULL_CFIS_LST }, 189 {120, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 190 {56, 64}, 191 NULL_CFIS_LST }, 192 {121, 20, BW20, BIT(BEHAV_NONE), 5000, 193 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144}, 194 NULL_CFIS_LST }, 195 {122, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 196 {100, 108, 116, 124, 132, 140}, 197 NULL_CFIS_LST }, 198 {123, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 199 {104, 112, 120, 128, 136, 144}, 200 NULL_CFIS_LST }, 201 {125, 20, BW20, BIT(BEHAV_NONE), 5000, 202 {149, 153, 157, 161, 165, 169, 173, 177}, 203 NULL_CFIS_LST }, 204 {126, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 205 {149, 157, 165, 173}, 206 NULL_CFIS_LST }, 207 {127, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 208 {153, 161, 169, 177}, 209 NULL_CFIS_LST }, 210 {128, 80, BW80, BIT(BEHAV_NONE), 5000, 211 {36, 40, 44, 48, 52, 56, 60, 64, 212 100, 104, 108, 112, 116, 120, 124, 128, 213 132, 136, 140, 144, 149, 153, 157, 161, 214 165, 169, 173, 177}, 215 NULL_CFIS_LST }, 216 {129, 160, BW80, BIT(BEHAV_NONE), 5000, 217 {36, 40, 44, 48, 52, 56, 60, 64, 218 100, 104, 108, 112, 116, 120, 124, 128, 219 149, 153, 157, 161, 165, 169, 173, 177}, 220 NULL_CFIS_LST }, 221 {130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000, 222 {36, 40, 44, 48, 52, 56, 60, 64, 223 100, 104, 108, 112, 116, 120, 124, 128, 224 132, 136, 140, 144, 149, 153, 157, 161, 225 165, 169, 173, 177}, 226 NULL_CFIS_LST }, 227 228 #ifdef CONFIG_BAND_6GHZ 229 {131, 20, BW20, BIT(BEHAV_NONE), 5950, 230 {1, 5, 9, 13, 17, 21, 25, 29, 33, 231 37, 41, 45, 49, 53, 57, 61, 65, 69, 232 73, 77, 81, 85, 89, 93, 97, 233 101, 105, 109, 113, 117, 121, 125, 234 129, 133, 137, 141, 145, 149, 153, 235 157, 161, 165, 169, 173, 177, 181, 236 185, 189, 193, 197, 201, 205, 209, 237 213, 217, 221, 225, 229, 233}, 238 &CFISLST(131)}, 239 240 {132, 40, BW40_LOW_PRIMARY, BIT(BEHAV_NONE), 5950, 241 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 242 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 243 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 244 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, 245 181, 185, 189, 193, 197, 201, 205, 209, 213, 217, 246 221, 225, 229, 233}, 247 &CFISLST(132)}, 248 249 {133, 80, BW80, BIT(BEHAV_NONE), 5950, 250 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 251 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 252 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 253 141, 145, 149, 153, 157, 161, 165, 169, 173, 254 177, 181, 185, 189, 193, 197, 201, 205, 209, 213, 255 217, 221, 225, 229, 233}, 256 &CFISLST(133)}, 257 258 {134, 160, BW80, BIT(BEHAV_NONE), 5950, 259 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 260 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 261 93, 97, 101, 105, 109, 113, 117, 121, 125, 262 129, 133, 137, 141, 145, 149, 153, 157, 161, 263 165, 169, 173, 177, 181, 185, 189, 193, 197, 264 201, 205, 209, 213, 217, 221, 225, 229, 233}, 265 &CFISLST(134)}, 266 267 {135, 80, BW80, BIT(BEHAV_BW80_PLUS), 5950, 268 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 269 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 270 85, 89, 93, 97, 101, 105, 109, 113, 117, 271 121, 125, 129, 133, 137, 141, 145, 149, 272 153, 157, 161, 165, 169, 173, 177, 181, 273 185, 189, 193, 197, 201, 205, 209, 213, 274 217, 221, 225, 229, 233}, 275 &CFISLST(135)}, 276 277 {136, 20, BW20, BIT(BEHAV_NONE), 5925, 278 {2}, 279 &CFISLST(136)}, 280 #ifdef WLAN_FEATURE_11BE 281 {137, 320, BW20, BIT(BEHAV_NONE), 5950, 282 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 283 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 284 85, 89, 93, 97, 101, 105, 109, 113, 117, 285 121, 125, 129, 133, 137, 141, 145, 149, 286 153, 157, 161, 165, 169, 173, 177, 181, 287 185, 189, 193, 197, 201, 205, 209, 213, 288 217, 221, 225, 229, 233}, 289 &CFISLST(137)}, 290 #endif 291 #endif 292 {0, 0, 0, 0, 0, {0}, 293 NULL_CFIS_LST }, 294 }; 295 296 static const struct reg_dmn_op_class_map_t us_op_class[] = { 297 {1, 20, BW20, BIT(BEHAV_NONE), 5000, 298 {36, 40, 44, 48}, 299 NULL_CFIS_LST }, 300 {2, 20, BW20, BIT(BEHAV_NONE), 5000, 301 {52, 56, 60, 64}, 302 NULL_CFIS_LST }, 303 {4, 20, BW20, BIT(BEHAV_NONE), 5000, 304 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144}, 305 NULL_CFIS_LST }, 306 {5, 20, BW20, BIT(BEHAV_NONE), 5000, 307 {149, 153, 157, 161, 165}, 308 NULL_CFIS_LST }, 309 {12, 25, BW20, BIT(BEHAV_NONE), 2407, 310 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 311 NULL_CFIS_LST }, 312 {22, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 313 {36, 44}, 314 NULL_CFIS_LST }, 315 {23, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 316 {52, 60}, 317 NULL_CFIS_LST }, 318 {24, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 319 {100, 108, 116, 124, 132, 140}, 320 NULL_CFIS_LST }, 321 {26, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 322 {149, 157}, 323 NULL_CFIS_LST }, 324 {27, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 325 {40, 48}, 326 NULL_CFIS_LST }, 327 {28, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 328 {56, 64}, 329 NULL_CFIS_LST }, 330 {29, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 331 {104, 112, 120, 128, 136, 144}, 332 NULL_CFIS_LST }, 333 {30, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 334 {153, 161}, 335 NULL_CFIS_LST }, 336 {31, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 337 {153, 161}, 338 NULL_CFIS_LST }, 339 {32, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407, 340 {1, 2, 3, 4, 5, 6, 7}, 341 NULL_CFIS_LST }, 342 {33, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407, 343 {5, 6, 7, 8, 9, 10, 11}, 344 NULL_CFIS_LST }, 345 {128, 80, BW80, BIT(BEHAV_NONE), 5000, 346 {36, 40, 44, 48, 52, 56, 60, 64, 100, 347 104, 108, 112, 116, 120, 124, 128, 132, 348 136, 140, 144, 149, 153, 157, 161}, 349 NULL_CFIS_LST }, 350 {129, 160, BW80, BIT(BEHAV_NONE), 5000, 351 {36, 40, 44, 48, 52, 56, 60, 64, 100, 352 104, 108, 112, 116, 120, 124, 128}, 353 NULL_CFIS_LST }, 354 {130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000, 355 {36, 40, 44, 48, 52, 56, 60, 64, 100, 356 104, 108, 112, 116, 120, 124, 128, 132, 357 136, 140, 144, 149, 153, 157, 161}, 358 NULL_CFIS_LST }, 359 {0, 0, 0, 0, 0, {0}, 360 NULL_CFIS_LST }, 361 }; 362 363 static const struct reg_dmn_op_class_map_t euro_op_class[] = { 364 {1, 20, BW20, BIT(BEHAV_NONE), 5000, 365 {36, 40, 44, 48}, 366 NULL_CFIS_LST }, 367 {2, 20, BW20, BIT(BEHAV_NONE), 5000, 368 {52, 56, 60, 64}, 369 NULL_CFIS_LST }, 370 {3, 20, BW20, BIT(BEHAV_NONE), 5000, 371 {100, 104, 108, 112, 116, 120, 372 124, 128, 132, 136, 140}, 373 NULL_CFIS_LST }, 374 {4, 25, BW20, BIT(BEHAV_NONE), 2407, 375 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 376 NULL_CFIS_LST }, 377 {5, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 378 {36, 44}, 379 NULL_CFIS_LST }, 380 {6, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 381 {52, 60}, 382 NULL_CFIS_LST }, 383 {7, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 384 {100, 108, 116, 124, 132}, 385 NULL_CFIS_LST }, 386 {8, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 387 {40, 48}, 388 NULL_CFIS_LST }, 389 {9, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 390 {56, 64}, 391 NULL_CFIS_LST }, 392 {10, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 393 {104, 112, 120, 128, 136}, 394 NULL_CFIS_LST }, 395 {11, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407, 396 {1, 2, 3, 4, 5, 6, 7, 8, 9}, 397 NULL_CFIS_LST }, 398 {12, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407, 399 {5, 6, 7, 8, 9, 10, 11, 12, 13}, 400 NULL_CFIS_LST }, 401 {17, 20, BW20, BIT(BEHAV_NONE), 5000, 402 {149, 153, 157, 161, 165, 169}, 403 NULL_CFIS_LST }, 404 {128, 80, BW80, BIT(BEHAV_NONE), 5000, 405 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 406 124, 128}, 407 NULL_CFIS_LST }, 408 {129, 160, BW80, BIT(BEHAV_NONE), 5000, 409 {36, 40, 44, 48, 52, 56, 60, 64, 100, 410 104, 108, 112, 116, 120, 124, 128}, 411 NULL_CFIS_LST }, 412 {130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000, 413 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 414 124, 128}, 415 NULL_CFIS_LST }, 416 {0, 0, 0, 0, 0, {0}, 417 NULL_CFIS_LST }, 418 }; 419 420 static const struct reg_dmn_op_class_map_t japan_op_class[] = { 421 {1, 20, BW20, BIT(BEHAV_NONE), 5000, 422 {36, 40, 44, 48}, 423 NULL_CFIS_LST }, 424 {30, 25, BW20, BIT(BEHAV_NONE), 2407, 425 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 426 NULL_CFIS_LST }, 427 {31, 25, BW20, BIT(BEHAV_NONE), 2414, 428 {14}, 429 NULL_CFIS_LST }, 430 {32, 20, BW20, BIT(BEHAV_NONE), 5000, 431 {52, 56, 60, 64}, 432 NULL_CFIS_LST }, 433 {34, 20, BW20, BIT(BEHAV_NONE), 5000, 434 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 435 NULL_CFIS_LST }, 436 {36, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 437 {36, 44}, 438 NULL_CFIS_LST }, 439 {37, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 440 {52, 60}, 441 NULL_CFIS_LST }, 442 {39, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 443 {100, 108, 116, 124, 132}, 444 NULL_CFIS_LST }, 445 {41, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 446 {40, 48}, 447 NULL_CFIS_LST }, 448 {42, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 449 {56, 64}, 450 NULL_CFIS_LST }, 451 {44, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 452 {104, 112, 120, 128, 136}, 453 NULL_CFIS_LST }, 454 {128, 80, BW80, BIT(BEHAV_NONE), 5000, 455 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 456 124, 128, 132, 136, 140, 144}, 457 NULL_CFIS_LST }, 458 {129, 160, BW80, BIT(BEHAV_NONE), 5000, 459 {36, 40, 44, 48, 52, 56, 60, 64, 100, 460 104, 108, 112, 116, 120, 124, 128}, 461 NULL_CFIS_LST }, 462 {130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000, 463 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 464 124, 128, 132, 136, 140, 144}, 465 NULL_CFIS_LST }, 466 {0, 0, 0, 0, 0, {0}, 467 NULL_CFIS_LST }, 468 }; 469 470 static const struct reg_dmn_op_class_map_t china_op_class[] = { 471 {7, 25, BW20, BIT(BEHAV_NONE), 2407, 472 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 473 NULL_CFIS_LST }, 474 {8, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407, 475 {1, 2, 3, 4, 5, 6, 7, 8, 9}, 476 NULL_CFIS_LST }, 477 {9, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407, 478 {5, 6, 7, 8, 9, 10, 11, 12, 13}, 479 NULL_CFIS_LST }, 480 {1, 20, BW20, BIT(BEHAV_NONE), 5000, 481 {36, 40, 44, 48}, 482 NULL_CFIS_LST }, 483 {4, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 484 {36, 44}, 485 NULL_CFIS_LST }, 486 {117, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 487 {40, 48}, 488 NULL_CFIS_LST }, 489 {2, 20, BW20, BIT(BEHAV_NONE), 5000, 490 {52, 56, 60, 64}, 491 NULL_CFIS_LST }, 492 {5, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 493 {52, 60}, 494 NULL_CFIS_LST }, 495 {3, 20, BW20, BIT(BEHAV_NONE), 5000, 496 {149, 153, 157, 161, 165}, 497 NULL_CFIS_LST }, 498 {6, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 499 {149, 157}, 500 NULL_CFIS_LST }, 501 {128, 80, BW80, BIT(BEHAV_NONE), 5000, 502 {36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161}, 503 NULL_CFIS_LST }, 504 {129, 160, BW80, BIT(BEHAV_NONE), 5000, 505 {36, 40, 44, 48, 52, 56, 60, 64,}, 506 NULL_CFIS_LST }, 507 {130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000, 508 {36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161}, 509 NULL_CFIS_LST }, 510 {0, 0, 0, 0, 0, {0}, 511 NULL_CFIS_LST }, 512 }; 513 #ifdef HOST_OPCLASS 514 /** 515 * reg_get_class_from_country()- Get Class from country 516 * @country- Country 517 * 518 * Return: class. 519 */ 520 static const struct reg_dmn_op_class_map_t 521 *reg_get_class_from_country(const uint8_t *country) 522 { 523 const struct reg_dmn_op_class_map_t *class = NULL; 524 525 reg_debug_rl("Country %c%c 0x%x", country[0], country[1], country[2]); 526 527 switch (country[2]) { 528 case OP_CLASS_US: 529 class = us_op_class; 530 break; 531 532 case OP_CLASS_EU: 533 class = euro_op_class; 534 break; 535 536 case OP_CLASS_JAPAN: 537 class = japan_op_class; 538 break; 539 540 case OP_CLASS_GLOBAL: 541 class = global_op_class; 542 break; 543 544 case OP_CLASS_CHINA: 545 class = china_op_class; 546 break; 547 default: 548 if (!qdf_mem_cmp(country, "US", 2)) 549 class = us_op_class; 550 else if (!qdf_mem_cmp(country, "EU", 2)) 551 class = euro_op_class; 552 else if (!qdf_mem_cmp(country, "JP", 2)) 553 class = japan_op_class; 554 else if (!qdf_mem_cmp(country, "CN", 2)) 555 class = china_op_class; 556 else 557 class = global_op_class; 558 } 559 return class; 560 } 561 562 #ifdef CONFIG_AFC_SUPPORT 563 static bool reg_is_range_valid(struct freq_range *range) 564 { 565 return (range->right > range->left); 566 } 567 568 /** 569 * reg_is_subrange() - Check if range_first is a subrange of range_second 570 * @range_first: Pointer to first range 571 * @range_second: Pointer to first range 572 * 573 * Return: True if the range_first is a subrange range_second, else false 574 */ 575 static bool reg_is_subrange(struct freq_range *range_first, 576 struct freq_range *range_second) 577 { 578 bool is_subrange; 579 bool is_valid; 580 581 is_valid = reg_is_range_valid(range_first) && 582 reg_is_range_valid(range_second); 583 584 if (!is_valid) 585 return false; 586 587 is_subrange = (range_first->left >= range_second->left) && 588 (range_first->right <= range_second->right); 589 590 return is_subrange; 591 } 592 593 /** 594 * reg_is_cfi_freq_in_ranges() - Check if the given 'cfi' in the any of the 595 * frequency ranges 596 * @cfi_freq: The center frequency index frequency 597 * @bw: bandwidth of the band with center freq cfi_freq 598 * @p_frange_lst: Pointer to frequency range list (AFC) 599 * 600 * return: True if the cfi is in the ranges, else false 601 */ 602 static bool reg_is_cfi_freq_in_ranges(qdf_freq_t cfi_freq, 603 uint16_t bw, 604 struct wlan_afc_frange_list *p_frange_lst) 605 { 606 uint32_t num_ranges; 607 struct wlan_afc_freq_range_obj *p_range_objs; 608 uint8_t i; 609 bool is_cfi_supported = false; 610 611 num_ranges = p_frange_lst->num_ranges; 612 p_range_objs = &p_frange_lst->range_objs[0]; 613 for (i = 0; i < num_ranges; i++) { 614 qdf_freq_t cfi_band_left; 615 qdf_freq_t cfi_band_right; 616 struct freq_range range_cfi; 617 struct freq_range range_chip; 618 619 cfi_band_left = cfi_freq - bw / 2; 620 cfi_band_right = cfi_freq + bw / 2; 621 622 range_cfi = reg_init_freq_range(cfi_band_left, 623 cfi_band_right); 624 range_chip = reg_init_freq_range(p_range_objs->lowfreq, 625 p_range_objs->highfreq); 626 is_cfi_supported = reg_is_subrange(&range_cfi, &range_chip); 627 628 if (is_cfi_supported) 629 return true; 630 631 p_range_objs++; 632 } 633 634 return is_cfi_supported; 635 } 636 637 void reg_dmn_free_6g_opclasses_and_channels(struct wlan_objmgr_pdev *pdev, 638 uint8_t num_opclasses, 639 uint8_t *opclass_lst, 640 uint8_t *chansize_lst, 641 uint8_t *channel_lists[]) 642 { 643 /* 644 * All the elements of channel_lists were allocated as a single 645 * allocation with 'channel_lists[0]' holding the first location of the 646 * allocation. Therefore, freeing only 'channel_lists[0]' is enough. 647 * Freeing any other 'channel_lists[i]' will result in error of freeing 648 * unallocated memory. 649 650 */ 651 if (channel_lists) 652 qdf_mem_free(channel_lists[0]); 653 654 /* 655 * opclass_lst, chansize_lst and channel_lists were allocated as a 656 * single allocation with 'opclass_lst' holding the first location of 657 * allocation. Therefore, freeing only 'opclass_lst' is enough. 658 * Freeing chansize_lst, channel_lists will result in error of freeing 659 * unallocated memory. 660 */ 661 qdf_mem_free(opclass_lst); 662 } 663 664 /** 665 * reg_dmn_get_num_6g_opclasses() - Calculate the number of opclasses in the 666 * 6GHz band. 667 * Return: The number of opclasses 668 */ 669 static uint8_t reg_dmn_get_num_6g_opclasses(struct wlan_objmgr_pdev *pdev) 670 { 671 const struct reg_dmn_op_class_map_t *op_class_tbl; 672 uint8_t count; 673 674 op_class_tbl = global_op_class; 675 676 count = 0; 677 while (op_class_tbl && op_class_tbl->op_class) { 678 const struct c_freq_lst *p_lst; 679 680 p_lst = op_class_tbl->p_cfi_lst_obj; 681 if (p_lst && 682 reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) 683 count++; 684 685 op_class_tbl++; 686 } 687 688 return count; 689 } 690 691 /** 692 * reg_dmn_fill_6g_opcls_chan_lists() - Copy the channel lists for 6g opclasses 693 * to the output argument list ('channel_lists') 694 * @pdev: Pointer to pdev. 695 * @p_frange_lst: Pointer to frequencey range list (AFC) 696 * @chansize_lst: Array of sizes of channel lists 697 * @channel_lists: The array list pointers where the channel lists are to be 698 * copied. 699 * 700 * Return: Void 701 */ 702 static void reg_dmn_fill_6g_opcls_chan_lists(struct wlan_objmgr_pdev *pdev, 703 struct wlan_afc_frange_list *p_frange_lst, 704 uint8_t chansize_lst[], 705 uint8_t *channel_lists[]) 706 { 707 uint8_t i = 0; 708 const struct reg_dmn_op_class_map_t *op_class_tbl; 709 710 op_class_tbl = global_op_class; 711 712 while (op_class_tbl && op_class_tbl->op_class) { 713 const struct c_freq_lst *p_lst; 714 715 p_lst = op_class_tbl->p_cfi_lst_obj; 716 if (p_lst && 717 reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) { 718 uint8_t j; 719 uint8_t cfi_idx = 0; 720 uint8_t *dst; 721 722 dst = channel_lists[i]; 723 for (j = 0; j < p_lst->num_cfis; j++) { 724 uint8_t cfi; 725 qdf_freq_t cfi_freq; 726 qdf_freq_t start_freq = op_class_tbl->start_freq; 727 uint16_t bw = op_class_tbl->chan_spacing; 728 729 cfi = p_lst->p_cfis_arr[j]; 730 cfi_freq = start_freq + 731 FREQ_TO_CHAN_SCALE * cfi; 732 733 if (reg_is_cfi_freq_in_ranges(cfi_freq, 734 bw, 735 p_frange_lst)) { 736 dst[cfi_idx++] = cfi; 737 } 738 } 739 i++; 740 } 741 op_class_tbl++; 742 } 743 } 744 745 static bool reg_is_val_within_range(qdf_freq_t val, 746 qdf_freq_t left, 747 qdf_freq_t right) 748 { 749 bool is_within = false; 750 751 if (val >= left && val <= right) 752 is_within = true; 753 754 return is_within; 755 } 756 757 QDF_STATUS reg_dmn_get_6g_opclasses_and_channels(struct wlan_objmgr_pdev *pdev, 758 struct wlan_afc_frange_list *p_frange_lst, 759 uint8_t *num_opclasses, 760 uint8_t **opclass_lst, 761 uint8_t **chansize_lst, 762 uint8_t **channel_lists[]) 763 { 764 const struct reg_dmn_op_class_map_t *op_class_tbl; 765 uint8_t *l_opcls_lst; 766 uint8_t *l_chansize_lst; 767 uint8_t count; 768 uint8_t i; 769 uint8_t **arr_chan_lists; 770 uint16_t total_alloc_size; 771 uint16_t opcls_lst_size; 772 uint16_t chansize_lst_size; 773 uint16_t arr_chan_lists_size; 774 uint8_t *p_total_alloc1; 775 uint8_t *p_total_alloc2; 776 uint8_t *p_temp_alloc; 777 778 *opclass_lst = NULL; 779 *chansize_lst = NULL; 780 *channel_lists = NULL; 781 782 op_class_tbl = global_op_class; 783 784 *num_opclasses = reg_dmn_get_num_6g_opclasses(pdev); 785 opcls_lst_size = *num_opclasses * sizeof(uint8_t); 786 chansize_lst_size = *num_opclasses * sizeof(uint8_t); 787 arr_chan_lists_size = *num_opclasses * sizeof(uint8_t *); 788 789 total_alloc_size = 0; 790 total_alloc_size += opcls_lst_size 791 + chansize_lst_size 792 + arr_chan_lists_size; 793 794 p_total_alloc1 = qdf_mem_malloc(total_alloc_size); 795 if (!p_total_alloc1) { 796 reg_err("out-of-memory"); 797 return QDF_STATUS_E_NOMEM; 798 } 799 800 /* Assign memory locations to each pointers */ 801 p_temp_alloc = p_total_alloc1; 802 803 l_opcls_lst = p_temp_alloc; 804 p_temp_alloc += opcls_lst_size; 805 806 l_chansize_lst = p_temp_alloc; 807 p_temp_alloc += chansize_lst_size; 808 809 arr_chan_lists = (uint8_t **)p_temp_alloc; 810 811 /* Fill arrays with opclasses and chanlist sizes */ 812 count = 0; 813 while (op_class_tbl && op_class_tbl->op_class) { 814 const struct c_freq_lst *p_lst; 815 816 p_lst = op_class_tbl->p_cfi_lst_obj; 817 if (p_lst && 818 reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) { 819 uint8_t n_supp_cfis = 0; 820 uint8_t j; 821 822 l_opcls_lst[count] = op_class_tbl->op_class; 823 for (j = 0; j < p_lst->num_cfis; j++) { 824 uint8_t cfi; 825 qdf_freq_t cfi_freq; 826 qdf_freq_t start_freq = op_class_tbl->start_freq; 827 uint16_t bw = op_class_tbl->chan_spacing; 828 829 cfi = p_lst->p_cfis_arr[j]; 830 cfi_freq = start_freq + 831 FREQ_TO_CHAN_SCALE * cfi; 832 if (reg_is_cfi_freq_in_ranges(cfi_freq, 833 bw, 834 p_frange_lst)) { 835 n_supp_cfis++; 836 } 837 } 838 l_chansize_lst[count] = n_supp_cfis; 839 count++; 840 } 841 op_class_tbl++; 842 } 843 844 /* Calculate total alloction size for the array */ 845 total_alloc_size = 0; 846 for (i = 0; i < *num_opclasses; i++) 847 total_alloc_size += l_chansize_lst[i] * sizeof(uint8_t *); 848 849 p_total_alloc2 = qdf_mem_malloc(total_alloc_size); 850 if (!p_total_alloc2) { 851 reg_err("out-of-memory"); 852 qdf_mem_free(p_total_alloc1); 853 return QDF_STATUS_E_NOMEM; 854 } 855 856 /* Assign memory locations to each list pointers */ 857 p_temp_alloc = p_total_alloc2; 858 for (i = 0; i < *num_opclasses; i++) { 859 if (!l_chansize_lst[i]) 860 arr_chan_lists[i] = NULL; 861 else 862 arr_chan_lists[i] = p_temp_alloc; 863 864 p_temp_alloc += l_chansize_lst[i] * sizeof(uint8_t *); 865 } 866 867 /* Fill the array with channl lists */ 868 reg_dmn_fill_6g_opcls_chan_lists(pdev, p_frange_lst, l_chansize_lst, arr_chan_lists); 869 870 *opclass_lst = l_opcls_lst; 871 *chansize_lst = l_chansize_lst; 872 *channel_lists = arr_chan_lists; 873 874 return QDF_STATUS_SUCCESS; 875 } 876 #endif /* CONFIG_AFC_SUPPORT */ 877 878 uint16_t reg_dmn_get_chanwidth_from_opclass(uint8_t *country, uint8_t channel, 879 uint8_t opclass) 880 { 881 const struct reg_dmn_op_class_map_t *class; 882 uint16_t i; 883 884 class = reg_get_class_from_country(country); 885 886 while (class->op_class) { 887 if (opclass == class->op_class) { 888 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 889 class->channels[i]); i++) { 890 if (channel == class->channels[i]) 891 return class->chan_spacing; 892 } 893 } 894 class++; 895 } 896 897 return 0; 898 } 899 900 uint16_t reg_dmn_get_chanwidth_from_opclass_auto(uint8_t *country, 901 uint8_t channel, 902 uint8_t opclass) 903 { 904 uint16_t ret; 905 uint8_t global_country[REG_ALPHA2_LEN + 1]; 906 907 ret = reg_dmn_get_chanwidth_from_opclass(country, channel, opclass); 908 909 if (!ret) { 910 global_country[2] = OP_CLASS_GLOBAL; 911 ret = reg_dmn_get_chanwidth_from_opclass(global_country, 912 channel, opclass); 913 } 914 915 return ret; 916 } 917 918 uint16_t reg_dmn_get_opclass_from_channel(uint8_t *country, uint8_t channel, 919 uint8_t offset) 920 { 921 const struct reg_dmn_op_class_map_t *class = NULL; 922 uint16_t i = 0; 923 924 class = reg_get_class_from_country(country); 925 while (class && class->op_class) { 926 if ((offset == class->offset) || (offset == BWALL)) { 927 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 928 class->channels[i]); i++) { 929 if (channel == class->channels[i]) 930 return class->op_class; 931 } 932 } 933 class++; 934 } 935 936 return 0; 937 } 938 939 uint8_t reg_dmn_get_opclass_from_freq_width(uint8_t *country, 940 qdf_freq_t freq, 941 uint16_t ch_width, 942 uint16_t behav_limit) 943 { 944 const struct reg_dmn_op_class_map_t *op_class_tbl = NULL; 945 uint16_t i = 0; 946 947 op_class_tbl = reg_get_class_from_country(country); 948 949 while (op_class_tbl && op_class_tbl->op_class) { 950 if (op_class_tbl->chan_spacing == ch_width) { 951 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 952 op_class_tbl->channels[i]); i++) { 953 if ((op_class_tbl->start_freq + 954 (FREQ_TO_CHAN_SCALE * 955 op_class_tbl->channels[i]) == freq) && 956 (behav_limit & op_class_tbl->behav_limit)) { 957 return op_class_tbl->op_class; 958 } 959 } 960 } 961 op_class_tbl++; 962 } 963 964 return 0; 965 } 966 967 static void 968 reg_get_band_cap_from_chan_set(const struct reg_dmn_op_class_map_t 969 *op_class_tbl, 970 uint8_t *supported_band) 971 { 972 qdf_freq_t chan_freq = op_class_tbl->start_freq + 973 (op_class_tbl->channels[0] * 974 FREQ_TO_CHAN_SCALE); 975 976 if (reg_is_24ghz_ch_freq(chan_freq)) 977 *supported_band |= BIT(REG_BAND_2G); 978 else if (reg_is_5ghz_ch_freq(chan_freq)) 979 *supported_band |= BIT(REG_BAND_5G); 980 else if (reg_is_6ghz_chan_freq(chan_freq)) 981 *supported_band |= BIT(REG_BAND_6G); 982 else 983 reg_err_rl("Unknown band"); 984 } 985 986 uint8_t reg_get_band_cap_from_op_class(const uint8_t *country, 987 uint8_t num_of_opclass, 988 const uint8_t *opclass) 989 { 990 const struct reg_dmn_op_class_map_t *op_class_tbl; 991 uint8_t supported_band = 0, opclassidx; 992 993 op_class_tbl = reg_get_class_from_country(country); 994 995 while (op_class_tbl && op_class_tbl->op_class) { 996 for (opclassidx = 0; opclassidx < num_of_opclass; 997 opclassidx++) { 998 if (op_class_tbl->op_class == opclass[opclassidx]) { 999 reg_get_band_cap_from_chan_set(op_class_tbl, 1000 &supported_band); 1001 } 1002 } 1003 op_class_tbl++; 1004 } 1005 1006 if (!supported_band) 1007 reg_err_rl("None of the operating classes is found"); 1008 1009 return supported_band; 1010 } 1011 1012 void reg_dmn_print_channels_in_opclass(uint8_t *country, uint8_t op_class) 1013 { 1014 const struct reg_dmn_op_class_map_t *class = NULL; 1015 uint16_t i = 0; 1016 1017 class = reg_get_class_from_country(country); 1018 1019 if (!class) { 1020 reg_err("class is NULL"); 1021 return; 1022 } 1023 1024 while (class->op_class) { 1025 if (class->op_class == op_class) { 1026 for (i = 0; 1027 (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1028 class->channels[i]); i++) { 1029 reg_debug("Valid channel(%d) in requested RC(%d)", 1030 class->channels[i], op_class); 1031 } 1032 break; 1033 } 1034 class++; 1035 } 1036 if (!class->op_class) 1037 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 1038 "Invalid requested RC (%d)", op_class); 1039 } 1040 1041 uint16_t reg_dmn_set_curr_opclasses(uint8_t num_classes, uint8_t *class) 1042 { 1043 uint8_t i; 1044 1045 if (num_classes > REG_MAX_SUPP_OPER_CLASSES) { 1046 reg_err("invalid num classes %d", num_classes); 1047 return 0; 1048 } 1049 1050 for (i = 0; i < num_classes; i++) 1051 reg_dmn_curr_supp_opp_classes.classes[i] = class[i]; 1052 1053 reg_dmn_curr_supp_opp_classes.num_classes = num_classes; 1054 1055 return 0; 1056 } 1057 1058 uint16_t reg_dmn_get_curr_opclasses(uint8_t *num_classes, uint8_t *class) 1059 { 1060 uint8_t i; 1061 1062 if (!num_classes || !class) { 1063 reg_err("either num_classes or class is null"); 1064 return 0; 1065 } 1066 1067 for (i = 0; i < reg_dmn_curr_supp_opp_classes.num_classes; i++) 1068 class[i] = reg_dmn_curr_supp_opp_classes.classes[i]; 1069 1070 *num_classes = reg_dmn_curr_supp_opp_classes.num_classes; 1071 1072 return 0; 1073 } 1074 1075 #ifdef CONFIG_CHAN_FREQ_API 1076 /** 1077 * reg_find_opclass_absent_in_ctry_opclss_tables() - Check Global Opclass table 1078 * when Opclass is not present in specific country. 1079 * @pdev - Pointer to pdev 1080 * @freq - Destination Frequency 1081 * @chan_width- Channel Width 1082 * @global_tbl_lookup - Global Table Lookup 1083 * @behav_limit - Behav Limit 1084 * @op_class - Pointer to Opclass 1085 * @chan_num - Pointer to Channel 1086 * 1087 * Return: Void 1088 */ 1089 static void 1090 reg_find_opclass_absent_in_ctry_opclss_tables(struct wlan_objmgr_pdev *pdev, 1091 qdf_freq_t freq, 1092 uint16_t chan_width, 1093 bool global_tbl_lookup, 1094 uint16_t behav_limit, 1095 uint8_t *op_class, 1096 uint8_t *chan_num) 1097 { 1098 if (!global_tbl_lookup && !*op_class) { 1099 global_tbl_lookup = true; 1100 reg_freq_width_to_chan_op_class(pdev, freq, 1101 chan_width, 1102 global_tbl_lookup, 1103 behav_limit, 1104 op_class, 1105 chan_num); 1106 } 1107 } 1108 1109 void reg_freq_width_to_chan_op_class_auto(struct wlan_objmgr_pdev *pdev, 1110 qdf_freq_t freq, 1111 uint16_t chan_width, 1112 bool global_tbl_lookup, 1113 uint16_t behav_limit, 1114 uint8_t *op_class, 1115 uint8_t *chan_num) 1116 { 1117 if (reg_freq_to_band(freq) == REG_BAND_6G) { 1118 global_tbl_lookup = true; 1119 if (chan_width == BW_40_MHZ) 1120 behav_limit = BIT(BEHAV_NONE); 1121 } else if (reg_is_5dot9_ghz_freq(pdev, freq)) { 1122 global_tbl_lookup = true; 1123 } else { 1124 global_tbl_lookup = false; 1125 } 1126 1127 *op_class = 0; 1128 reg_freq_width_to_chan_op_class(pdev, freq, 1129 chan_width, 1130 global_tbl_lookup, 1131 behav_limit, 1132 op_class, 1133 chan_num); 1134 reg_find_opclass_absent_in_ctry_opclss_tables(pdev, freq, 1135 chan_width, 1136 global_tbl_lookup, 1137 behav_limit, 1138 op_class, 1139 chan_num); 1140 } 1141 1142 void reg_freq_width_to_chan_op_class(struct wlan_objmgr_pdev *pdev, 1143 qdf_freq_t freq, 1144 uint16_t chan_width, 1145 bool global_tbl_lookup, 1146 uint16_t behav_limit, 1147 uint8_t *op_class, 1148 uint8_t *chan_num) 1149 { 1150 const struct reg_dmn_op_class_map_t *op_class_tbl; 1151 enum channel_enum chan_enum; 1152 uint16_t i; 1153 1154 chan_enum = reg_get_chan_enum_for_freq(freq); 1155 1156 if (chan_enum == INVALID_CHANNEL) { 1157 reg_err_rl("Invalid chan enum %d", chan_enum); 1158 return; 1159 } 1160 1161 if (global_tbl_lookup) { 1162 op_class_tbl = global_op_class; 1163 } else { 1164 if (channel_map == channel_map_us) 1165 op_class_tbl = us_op_class; 1166 else if (channel_map == channel_map_eu) 1167 op_class_tbl = euro_op_class; 1168 else if (channel_map == channel_map_china) 1169 op_class_tbl = china_op_class; 1170 else if (channel_map == channel_map_jp) 1171 op_class_tbl = japan_op_class; 1172 else 1173 op_class_tbl = global_op_class; 1174 } 1175 1176 while (op_class_tbl->op_class) { 1177 if (op_class_tbl->chan_spacing >= chan_width) { 1178 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1179 op_class_tbl->channels[i]); i++) { 1180 if ((op_class_tbl->start_freq + 1181 FREQ_TO_CHAN_SCALE * 1182 op_class_tbl->channels[i] == freq) && 1183 (behav_limit & op_class_tbl->behav_limit || 1184 behav_limit == BIT(BEHAV_NONE))) { 1185 *chan_num = op_class_tbl->channels[i]; 1186 *op_class = op_class_tbl->op_class; 1187 return; 1188 } 1189 } 1190 } 1191 op_class_tbl++; 1192 } 1193 1194 reg_err_rl("no op class for frequency %d", freq); 1195 } 1196 1197 void reg_freq_to_chan_op_class(struct wlan_objmgr_pdev *pdev, 1198 qdf_freq_t freq, 1199 bool global_tbl_lookup, 1200 uint16_t behav_limit, 1201 uint8_t *op_class, 1202 uint8_t *chan_num) 1203 { 1204 enum channel_enum chan_enum; 1205 struct regulatory_channel *cur_chan_list; 1206 struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj; 1207 struct ch_params chan_params; 1208 1209 pdev_priv_obj = reg_get_pdev_obj(pdev); 1210 1211 if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) { 1212 reg_err_rl("NULL pdev reg obj"); 1213 return; 1214 } 1215 1216 cur_chan_list = pdev_priv_obj->cur_chan_list; 1217 1218 chan_enum = reg_get_chan_enum_for_freq(freq); 1219 1220 if (chan_enum == INVALID_CHANNEL) { 1221 reg_err_rl("Invalid chan enum %d", chan_enum); 1222 return; 1223 } 1224 1225 chan_params.ch_width = CH_WIDTH_MAX; 1226 reg_set_channel_params_for_freq(pdev, freq, 0, &chan_params); 1227 1228 reg_freq_width_to_chan_op_class(pdev, freq, 1229 reg_get_bw_value(chan_params.ch_width), 1230 global_tbl_lookup, 1231 behav_limit, 1232 op_class, 1233 chan_num); 1234 } 1235 1236 bool reg_is_freq_in_country_opclass(struct wlan_objmgr_pdev *pdev, 1237 const uint8_t country[3], 1238 uint8_t op_class, 1239 qdf_freq_t chan_freq) 1240 { 1241 const struct reg_dmn_op_class_map_t *op_class_tbl; 1242 uint8_t i; 1243 1244 op_class_tbl = reg_get_class_from_country((uint8_t *)country); 1245 1246 while (op_class_tbl && op_class_tbl->op_class) { 1247 if (op_class_tbl->op_class == op_class) { 1248 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1249 op_class_tbl->channels[i]); i++) { 1250 if (op_class_tbl->channels[i] * 1251 FREQ_TO_CHAN_SCALE + 1252 op_class_tbl->start_freq == chan_freq) 1253 return true; 1254 } 1255 } 1256 op_class_tbl++; 1257 } 1258 return false; 1259 } 1260 1261 #endif 1262 1263 uint16_t reg_get_op_class_width(struct wlan_objmgr_pdev *pdev, 1264 uint8_t op_class, 1265 bool global_tbl_lookup) 1266 { 1267 const struct reg_dmn_op_class_map_t *op_class_tbl; 1268 1269 if (global_tbl_lookup) { 1270 op_class_tbl = global_op_class; 1271 } else { 1272 if (channel_map == channel_map_us) 1273 op_class_tbl = us_op_class; 1274 else if (channel_map == channel_map_eu) 1275 op_class_tbl = euro_op_class; 1276 else if (channel_map == channel_map_china) 1277 op_class_tbl = china_op_class; 1278 else if (channel_map == channel_map_jp) 1279 op_class_tbl = japan_op_class; 1280 else 1281 op_class_tbl = global_op_class; 1282 } 1283 1284 while (op_class_tbl->op_class) { 1285 if (op_class_tbl->op_class == op_class) 1286 return op_class_tbl->chan_spacing; 1287 op_class_tbl++; 1288 } 1289 1290 return 0; 1291 } 1292 1293 uint16_t reg_chan_opclass_to_freq(uint8_t chan, 1294 uint8_t op_class, 1295 bool global_tbl_lookup) 1296 { 1297 const struct reg_dmn_op_class_map_t *op_class_tbl = NULL; 1298 uint8_t i = 0; 1299 1300 if (global_tbl_lookup) { 1301 op_class_tbl = global_op_class; 1302 } else { 1303 if (channel_map == channel_map_global) { 1304 op_class_tbl = global_op_class; 1305 } else if (channel_map == channel_map_us) { 1306 op_class_tbl = us_op_class; 1307 } else if (channel_map == channel_map_eu) { 1308 op_class_tbl = euro_op_class; 1309 } else if (channel_map == channel_map_china) { 1310 op_class_tbl = china_op_class; 1311 } else if (channel_map == channel_map_jp) { 1312 op_class_tbl = japan_op_class; 1313 } else { 1314 reg_err_rl("Invalid channel map"); 1315 return 0; 1316 } 1317 } 1318 1319 while (op_class_tbl->op_class) { 1320 if (op_class_tbl->op_class == op_class) { 1321 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1322 op_class_tbl->channels[i]); i++) { 1323 if (op_class_tbl->channels[i] == chan) { 1324 chan = op_class_tbl->channels[i]; 1325 return op_class_tbl->start_freq + 1326 (chan * FREQ_TO_CHAN_SCALE); 1327 } 1328 } 1329 reg_err_rl("Channel not found"); 1330 return 0; 1331 } 1332 op_class_tbl++; 1333 } 1334 reg_err_rl("Invalid opclass"); 1335 return 0; 1336 } 1337 1338 qdf_freq_t reg_chan_opclass_to_freq_auto(uint8_t chan, uint8_t op_class, 1339 bool global_tbl_lookup) 1340 { 1341 if ((op_class >= MIN_6GHZ_OPER_CLASS) && 1342 (op_class <= MAX_6GHZ_OPER_CLASS)) { 1343 global_tbl_lookup = true; 1344 } else { 1345 qdf_freq_t freq = reg_chan_opclass_to_freq(chan, 1346 op_class, 1347 global_tbl_lookup); 1348 if (freq) 1349 return freq; 1350 global_tbl_lookup = true; 1351 } 1352 1353 return reg_chan_opclass_to_freq(chan, op_class, global_tbl_lookup); 1354 } 1355 1356 #ifdef HOST_OPCLASS_EXT 1357 qdf_freq_t reg_country_chan_opclass_to_freq(struct wlan_objmgr_pdev *pdev, 1358 const uint8_t country[3], 1359 uint8_t chan, uint8_t op_class, 1360 bool strict) 1361 { 1362 const struct reg_dmn_op_class_map_t *op_class_tbl, *op_class_tbl_org; 1363 uint16_t i; 1364 1365 if (reg_is_6ghz_op_class(pdev, op_class)) 1366 op_class_tbl_org = global_op_class; 1367 else 1368 op_class_tbl_org = 1369 reg_get_class_from_country((uint8_t *)country); 1370 op_class_tbl = op_class_tbl_org; 1371 while (op_class_tbl && op_class_tbl->op_class) { 1372 if (op_class_tbl->op_class == op_class) { 1373 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1374 op_class_tbl->channels[i]); i++) { 1375 if (op_class_tbl->channels[i] == chan) 1376 return op_class_tbl->start_freq + 1377 (chan * FREQ_TO_CHAN_SCALE); 1378 } 1379 } 1380 op_class_tbl++; 1381 } 1382 reg_debug_rl("Not found ch %d in op class %d ch list, strict %d", 1383 chan, op_class, strict); 1384 if (strict) 1385 return 0; 1386 1387 op_class_tbl = op_class_tbl_org; 1388 while (op_class_tbl && op_class_tbl->op_class) { 1389 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1390 op_class_tbl->channels[i]); i++) { 1391 if (op_class_tbl->channels[i] == chan) 1392 return op_class_tbl->start_freq + 1393 (chan * FREQ_TO_CHAN_SCALE); 1394 } 1395 op_class_tbl++; 1396 } 1397 reg_debug_rl("Got invalid freq 0 for ch %d", chan); 1398 1399 return 0; 1400 } 1401 #endif 1402 1403 static void 1404 reg_get_op_class_tbl_by_chan_map(const struct 1405 reg_dmn_op_class_map_t **op_class_tbl) 1406 { 1407 if (channel_map == channel_map_us) 1408 *op_class_tbl = us_op_class; 1409 else if (channel_map == channel_map_eu) 1410 *op_class_tbl = euro_op_class; 1411 else if (channel_map == channel_map_china) 1412 *op_class_tbl = china_op_class; 1413 else if (channel_map == channel_map_jp) 1414 *op_class_tbl = japan_op_class; 1415 else 1416 *op_class_tbl = global_op_class; 1417 } 1418 1419 /** 1420 * reg_get_channel_cen - Calculate central channel in the channel set. 1421 * 1422 * @op_class_tbl - Pointer to op_class_tbl. 1423 * @idx - Pointer to channel index. 1424 * @num_channels - Number of channels. 1425 * @center_chan - Pointer to center channel number 1426 * 1427 * Return : void 1428 */ 1429 static void reg_get_channel_cen(const struct 1430 reg_dmn_op_class_map_t *op_class_tbl, 1431 uint8_t *idx, 1432 uint8_t num_channels, 1433 uint8_t *center_chan) 1434 { 1435 uint8_t i; 1436 uint16_t new_chan = 0; 1437 1438 for (i = *idx; i < (*idx + num_channels); i++) 1439 new_chan += op_class_tbl->channels[i]; 1440 1441 new_chan = new_chan / num_channels; 1442 *center_chan = new_chan; 1443 *idx = *idx + num_channels; 1444 } 1445 1446 /** 1447 * reg_get_chan_or_chan_center - Calculate central channel in the channel set. 1448 * 1449 * @op_class_tbl - Pointer to op_class_tbl. 1450 * @idx - Pointer to channel index. 1451 * 1452 * Return : Center channel number 1453 */ 1454 static uint8_t reg_get_chan_or_chan_center(const struct 1455 reg_dmn_op_class_map_t *op_class_tbl, 1456 uint8_t *idx) 1457 { 1458 uint8_t center_chan; 1459 1460 if (((op_class_tbl->chan_spacing == BW_80_MHZ) && 1461 (op_class_tbl->behav_limit == BIT(BEHAV_NONE))) || 1462 ((op_class_tbl->chan_spacing == BW_80_MHZ) && 1463 (op_class_tbl->behav_limit == BIT(BEHAV_BW80_PLUS)))) { 1464 reg_get_channel_cen(op_class_tbl, 1465 idx, 1466 NUM_20_MHZ_CHAN_IN_80_MHZ_CHAN, 1467 ¢er_chan); 1468 } else if (op_class_tbl->chan_spacing == BW_160_MHZ) { 1469 reg_get_channel_cen(op_class_tbl, 1470 idx, 1471 NUM_20_MHZ_CHAN_IN_160_MHZ_CHAN, 1472 ¢er_chan); 1473 } else { 1474 center_chan = op_class_tbl->channels[*idx]; 1475 *idx = *idx + 1; 1476 } 1477 1478 return center_chan; 1479 } 1480 1481 /** 1482 * reg_get_channels_from_opclassmap()- Get channels from the opclass map 1483 * @pdev: Pointer to pdev 1484 * @reg_ap_cap: Pointer to reg_ap_cap 1485 * @index: Pointer to index of reg_ap_cap 1486 * @op_class_tbl: Pointer to op_class_tbl 1487 * @is_opclass_operable: Set true if opclass is operable, else set false 1488 * 1489 * Populate channels from opclass map to reg_ap_cap as supported and 1490 * non-supported channels. 1491 * 1492 * Return: void. 1493 */ 1494 static void 1495 reg_get_channels_from_opclassmap( 1496 struct wlan_objmgr_pdev *pdev, 1497 struct regdmn_ap_cap_opclass_t *reg_ap_cap, 1498 uint8_t index, 1499 const struct reg_dmn_op_class_map_t *op_class_tbl, 1500 bool *is_opclass_operable) 1501 { 1502 uint8_t op_cls_chan; 1503 qdf_freq_t search_freq; 1504 bool is_freq_present; 1505 uint8_t chan_idx = 0, n_sup_chans = 0, n_unsup_chans = 0; 1506 1507 while (op_class_tbl->channels[chan_idx]) { 1508 op_cls_chan = op_class_tbl->channels[chan_idx]; 1509 search_freq = op_class_tbl->start_freq + 1510 (FREQ_TO_CHAN_SCALE * op_cls_chan); 1511 is_freq_present = 1512 reg_is_freq_present_in_cur_chan_list(pdev, search_freq); 1513 1514 if (!is_freq_present) { 1515 reg_ap_cap[index].non_sup_chan_list[n_unsup_chans++] = 1516 reg_get_chan_or_chan_center(op_class_tbl, 1517 &chan_idx); 1518 reg_ap_cap[index].num_non_supported_chan++; 1519 } else { 1520 reg_ap_cap[index].sup_chan_list[n_sup_chans++] = 1521 reg_get_chan_or_chan_center(op_class_tbl, 1522 &chan_idx); 1523 reg_ap_cap[index].num_supported_chan++; 1524 } 1525 } 1526 1527 if (reg_ap_cap[index].num_supported_chan >= 1) 1528 *is_opclass_operable = true; 1529 } 1530 1531 QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev, 1532 struct regdmn_ap_cap_opclass_t *reg_ap_cap, 1533 uint8_t *n_opclasses, 1534 uint8_t max_supp_op_class, 1535 bool global_tbl_lookup) 1536 { 1537 uint8_t max_reg_power = 0; 1538 const struct reg_dmn_op_class_map_t *op_class_tbl; 1539 uint8_t index = 0; 1540 1541 if (global_tbl_lookup) 1542 op_class_tbl = global_op_class; 1543 else 1544 reg_get_op_class_tbl_by_chan_map(&op_class_tbl); 1545 1546 max_reg_power = reg_get_max_tx_power(pdev); 1547 1548 while (op_class_tbl->op_class && (index < max_supp_op_class)) { 1549 bool is_opclass_operable = false; 1550 1551 qdf_mem_zero(reg_ap_cap[index].sup_chan_list, 1552 REG_MAX_CHANNELS_PER_OPERATING_CLASS); 1553 reg_ap_cap[index].num_supported_chan = 0; 1554 qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list, 1555 REG_MAX_CHANNELS_PER_OPERATING_CLASS); 1556 reg_ap_cap[index].num_non_supported_chan = 0; 1557 reg_get_channels_from_opclassmap(pdev, 1558 reg_ap_cap, 1559 index, 1560 op_class_tbl, 1561 &is_opclass_operable); 1562 if (is_opclass_operable) { 1563 reg_ap_cap[index].op_class = op_class_tbl->op_class; 1564 reg_ap_cap[index].ch_width = 1565 op_class_tbl->chan_spacing; 1566 reg_ap_cap[index].start_freq = 1567 op_class_tbl->start_freq; 1568 reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power; 1569 reg_ap_cap[index].behav_limit = 1570 op_class_tbl->behav_limit; 1571 index++; 1572 } 1573 1574 op_class_tbl++; 1575 } 1576 1577 *n_opclasses = index; 1578 1579 return QDF_STATUS_SUCCESS; 1580 } 1581 1582 bool reg_is_6ghz_op_class(struct wlan_objmgr_pdev *pdev, uint8_t op_class) 1583 { 1584 return ((op_class >= MIN_6GHZ_OPER_CLASS) && 1585 (op_class <= MAX_6GHZ_OPER_CLASS)); 1586 } 1587 1588 /** 1589 * reg_is_opclass_band_found - Check if the input opclass is 2G or 5G. 1590 * 1591 * @country - Pointer to country. 1592 * @op_class - Operating class. 1593 * @bandmask = Bitmask for band. 1594 * 1595 * Return : Return true if the input opclass' band (2Ghz or 5Ghz) matches one 1596 * of bandmask's band. 1597 */ 1598 static bool reg_is_opclass_band_found(const uint8_t *country, 1599 uint8_t op_class, 1600 uint8_t bandmask) 1601 { 1602 const struct reg_dmn_op_class_map_t *op_class_tbl; 1603 1604 op_class_tbl = reg_get_class_from_country((uint8_t *)country); 1605 1606 while (op_class_tbl && op_class_tbl->op_class) { 1607 if (op_class_tbl->op_class == op_class) { 1608 qdf_freq_t freq = op_class_tbl->start_freq + 1609 (op_class_tbl->channels[0] * FREQ_TO_CHAN_SCALE); 1610 1611 if ((bandmask & BIT(REG_BAND_5G)) && 1612 REG_IS_5GHZ_FREQ(freq)) 1613 return true; 1614 1615 if ((bandmask & BIT(REG_BAND_2G)) && 1616 REG_IS_24GHZ_CH_FREQ(freq)) 1617 return true; 1618 1619 return false; 1620 } 1621 1622 op_class_tbl++; 1623 } 1624 1625 reg_err_rl("Opclass %d is not found", op_class); 1626 1627 return false; 1628 } 1629 1630 bool reg_is_5ghz_op_class(const uint8_t *country, uint8_t op_class) 1631 { 1632 return reg_is_opclass_band_found(country, op_class, BIT(REG_BAND_5G)); 1633 } 1634 1635 bool reg_is_2ghz_op_class(const uint8_t *country, uint8_t op_class) 1636 { 1637 return reg_is_opclass_band_found(country, op_class, BIT(REG_BAND_2G)); 1638 } 1639 #endif 1640