1 /* 2 * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /** 21 * DOC: reg_opclass.c 22 * This file defines regulatory opclass functions. 23 */ 24 25 #include <qdf_types.h> 26 #include <wlan_cmn.h> 27 #include <reg_services_public_struct.h> 28 #include <wlan_objmgr_psoc_obj.h> 29 #include <wlan_objmgr_pdev_obj.h> 30 #include "reg_priv_objs.h" 31 #include "reg_utils.h" 32 #include "reg_db.h" 33 #include "reg_db_parser.h" 34 #include "reg_host_11d.h" 35 #include <scheduler_api.h> 36 #include "reg_build_chan_list.h" 37 #include "reg_opclass.h" 38 #include "reg_services_common.h" 39 #include <wlan_objmgr_pdev_obj.h> 40 41 #ifdef HOST_OPCLASS 42 static struct reg_dmn_supp_op_classes reg_dmn_curr_supp_opp_classes = { 0 }; 43 #endif 44 45 /** 46 * Given a global opclass number create the corresponding array token. 47 * Examples: 48 * 'CFISARR(132)' expands to 'opcls_132_cfis_arr' 49 * 'CFISARR(133)' expands to 'opcls_133_cfis_arr' 50 */ 51 #define CFISARR(_g_opcls) opcls_ ## _g_opcls ## _cfis_arr 52 53 /** 54 * Given a global opclass number create the corresponding list token. 55 * Examples: 56 * 'CFISLST(132)' expands to 'opcls_132_cfis_lst' 57 * 'CFISLST(133)' expands to 'opcls_133_cfis_lst' 58 */ 59 #define CFISLST(_g_opcls) opcls_ ## _g_opcls ## _cfis_lst 60 61 /* The type of the opclass list objects */ 62 #define CFISLST_TYPE static const struct c_freq_lst 63 64 /* The number of elements of the array */ 65 #define NELEMS QDF_ARRAY_SIZE 66 67 /** 68 * Given a global opclass number create the corresponding cfis list and assign 69 * the corresponding cfis array and size of the cfis array 70 * Examples: 71 * 'CREATE_CFIS_LST(132);' 72 * expands to 73 * ' 74 * static const struct c_freq_lst opcls_132_cfis_lst = 75 * {QDF_ARRAY_SIZE(opcls_132_cfis_arr), opcls_132_cfis_arr}; 76 * ' 77 * 78 * 'CREATE_CFIS_LST(133);' 79 * expands to 80 * ' 81 * static const struct c_freq_lst opcls_133_cfis_lst = 82 * {QDF_ARRAY_SIZE(opcls_133_cfis_arr), opcls_133_cfis_arr}; 83 * ' 84 */ 85 #define CREATE_CFIS_LST(_gopcls) \ 86 CFISLST_TYPE CFISLST(_gopcls) = {NELEMS(CFISARR(_gopcls)), CFISARR(_gopcls)} 87 88 /* The NULL pointer to a cfis list object */ 89 #define NULL_CFIS_LST NULL 90 91 /* CFIs for global opclass 131: (start Freq=5925 BW=20MHz) */ 92 static const uint8_t opcls_131_cfis_arr[] = { 93 #ifdef CONFIG_AFC_SUPPORT 94 1, 5, 9, 13, 17, 21, 25, 29, 33, 95 37, 41, 45, 49, 53, 57, 61, 65, 69, 96 73, 77, 81, 85, 89, 93, 97, 97 101, 105, 109, 113, 117, 121, 125, 98 129, 133, 137, 141, 145, 149, 153, 99 157, 161, 165, 169, 173, 177, 181, 100 185, 189, 193, 197, 201, 205, 209, 101 213, 217, 221, 225, 229, 233, 102 #endif 103 }; 104 105 /* CFIs for global opclass 132: (start Freq=5925 BW=40MHz) */ 106 static const uint8_t opcls_132_cfis_arr[] = { 107 #ifdef CONFIG_AFC_SUPPORT 108 3, 11, 19, 27, 35, 43, 51, 59, 67, 75, 109 83, 91, 99, 107, 115, 123, 131, 139, 147, 155, 110 163, 171, 179, 187, 195, 203, 211, 219, 227, 111 #endif 112 }; 113 114 /* CFIs for global opclass 133: (start Freq=5925 BW=80MHz) */ 115 static const uint8_t opcls_133_cfis_arr[] = { 116 #ifdef CONFIG_AFC_SUPPORT 117 7, 23, 39, 55, 71, 87, 103, 119, 135, 151, 167, 183, 118 199, 215, 119 #endif 120 }; 121 122 /* CFIs for global opclass 134: (start Freq=5950 BW=160MHz) */ 123 static const uint8_t opcls_134_cfis_arr[] = { 124 #ifdef CONFIG_AFC_SUPPORT 125 15, 47, 79, 111, 143, 175, 207, 126 #endif 127 }; 128 129 /* CFIs for global opclass 135: (start Freq=5950 BW=80MHz+80MHz) */ 130 static const uint8_t opcls_135_cfis_arr[] = { 131 #ifdef CONFIG_AFC_SUPPORT 132 7, 23, 39, 55, 71, 87, 103, 119, 135, 151, 167, 183, 133 199, 215, 134 #endif 135 }; 136 137 /* CFIs for global opclass 136: (start Freq=5925 BW=20MHz) */ 138 static const uint8_t opcls_136_cfis_arr[] = { 139 #ifdef CONFIG_AFC_SUPPORT 140 2, 141 #endif 142 }; 143 144 /* CFIs for global opclass 137: (start Freq=5950 BW=320MHz) */ 145 #ifdef WLAN_FEATURE_11BE 146 static const uint8_t opcls_137_cfis_arr[] = { 147 #ifdef CONFIG_AFC_SUPPORT 148 31, 63, 95, 127, 159, 191, 149 #endif 150 }; 151 #endif 152 153 /* Create the CFIS static constant lists */ 154 CREATE_CFIS_LST(131); 155 CREATE_CFIS_LST(132); 156 CREATE_CFIS_LST(133); 157 CREATE_CFIS_LST(134); 158 CREATE_CFIS_LST(135); 159 CREATE_CFIS_LST(136); 160 #ifdef WLAN_FEATURE_11BE 161 CREATE_CFIS_LST(137); 162 #endif 163 164 static const struct reg_dmn_op_class_map_t global_op_class[] = { 165 {81, 25, BW20, BIT(BEHAV_NONE), 2407, 166 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 167 NULL_CFIS_LST }, 168 {82, 25, BW20, BIT(BEHAV_NONE), 2414, 169 {14}, 170 NULL_CFIS_LST }, 171 {83, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407, 172 {1, 2, 3, 4, 5, 6, 7, 8, 9}, 173 NULL_CFIS_LST }, 174 {84, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407, 175 {5, 6, 7, 8, 9, 10, 11, 12, 13}, 176 NULL_CFIS_LST }, 177 {115, 20, BW20, BIT(BEHAV_NONE), 5000, 178 {36, 40, 44, 48}, 179 NULL_CFIS_LST }, 180 {116, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 181 {36, 44}, 182 NULL_CFIS_LST }, 183 {117, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 184 {40, 48}, 185 NULL_CFIS_LST }, 186 {118, 20, BW20, BIT(BEHAV_NONE), 5000, 187 {52, 56, 60, 64}, 188 NULL_CFIS_LST }, 189 {119, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 190 {52, 60}, 191 NULL_CFIS_LST }, 192 {120, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 193 {56, 64}, 194 NULL_CFIS_LST }, 195 {121, 20, BW20, BIT(BEHAV_NONE), 5000, 196 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144}, 197 NULL_CFIS_LST }, 198 {122, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 199 {100, 108, 116, 124, 132, 140}, 200 NULL_CFIS_LST }, 201 {123, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 202 {104, 112, 120, 128, 136, 144}, 203 NULL_CFIS_LST }, 204 {125, 20, BW20, BIT(BEHAV_NONE), 5000, 205 {149, 153, 157, 161, 165, 169, 173, 177}, 206 NULL_CFIS_LST }, 207 {126, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 208 {149, 157, 165, 173}, 209 NULL_CFIS_LST }, 210 {127, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 211 {153, 161, 169, 177}, 212 NULL_CFIS_LST }, 213 {128, 80, BW80, BIT(BEHAV_NONE), 5000, 214 {36, 40, 44, 48, 52, 56, 60, 64, 215 100, 104, 108, 112, 116, 120, 124, 128, 216 132, 136, 140, 144, 149, 153, 157, 161, 217 165, 169, 173, 177}, 218 NULL_CFIS_LST }, 219 {129, 160, BW80, BIT(BEHAV_NONE), 5000, 220 {36, 40, 44, 48, 52, 56, 60, 64, 221 100, 104, 108, 112, 116, 120, 124, 128, 222 149, 153, 157, 161, 165, 169, 173, 177}, 223 NULL_CFIS_LST }, 224 {130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000, 225 {36, 40, 44, 48, 52, 56, 60, 64, 226 100, 104, 108, 112, 116, 120, 124, 128, 227 132, 136, 140, 144, 149, 153, 157, 161, 228 165, 169, 173, 177}, 229 NULL_CFIS_LST }, 230 231 #ifdef CONFIG_BAND_6GHZ 232 {131, 20, BW20, BIT(BEHAV_NONE), 5950, 233 {1, 5, 9, 13, 17, 21, 25, 29, 33, 234 37, 41, 45, 49, 53, 57, 61, 65, 69, 235 73, 77, 81, 85, 89, 93, 97, 236 101, 105, 109, 113, 117, 121, 125, 237 129, 133, 137, 141, 145, 149, 153, 238 157, 161, 165, 169, 173, 177, 181, 239 185, 189, 193, 197, 201, 205, 209, 240 213, 217, 221, 225, 229, 233}, 241 &CFISLST(131)}, 242 243 {132, 40, BW40_LOW_PRIMARY, BIT(BEHAV_NONE), 5950, 244 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 245 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 246 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 247 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, 248 181, 185, 189, 193, 197, 201, 205, 209, 213, 217, 249 221, 225, 229, 233}, 250 &CFISLST(132)}, 251 252 {133, 80, BW80, BIT(BEHAV_NONE), 5950, 253 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 254 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 255 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 256 141, 145, 149, 153, 157, 161, 165, 169, 173, 257 177, 181, 185, 189, 193, 197, 201, 205, 209, 213, 258 217, 221, 225, 229, 233}, 259 &CFISLST(133)}, 260 261 {134, 160, BW80, BIT(BEHAV_NONE), 5950, 262 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 263 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 264 93, 97, 101, 105, 109, 113, 117, 121, 125, 265 129, 133, 137, 141, 145, 149, 153, 157, 161, 266 165, 169, 173, 177, 181, 185, 189, 193, 197, 267 201, 205, 209, 213, 217, 221, 225, 229, 233}, 268 &CFISLST(134)}, 269 270 {135, 80, BW80, BIT(BEHAV_BW80_PLUS), 5950, 271 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 272 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 273 85, 89, 93, 97, 101, 105, 109, 113, 117, 274 121, 125, 129, 133, 137, 141, 145, 149, 275 153, 157, 161, 165, 169, 173, 177, 181, 276 185, 189, 193, 197, 201, 205, 209, 213, 277 217, 221, 225, 229, 233}, 278 &CFISLST(135)}, 279 280 {136, 20, BW20, BIT(BEHAV_NONE), 5925, 281 {2}, 282 &CFISLST(136)}, 283 #ifdef WLAN_FEATURE_11BE 284 {137, 320, BW20, BIT(BEHAV_NONE), 5950, 285 {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 286 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 287 85, 89, 93, 97, 101, 105, 109, 113, 117, 288 121, 125, 129, 133, 137, 141, 145, 149, 289 153, 157, 161, 165, 169, 173, 177, 181, 290 185, 189, 193, 197, 201, 205, 209, 213, 291 217, 221, 225, 229, 233}, 292 &CFISLST(137)}, 293 #endif 294 #endif 295 {0, 0, 0, 0, 0, {0}, 296 NULL_CFIS_LST }, 297 }; 298 299 static const struct reg_dmn_op_class_map_t us_op_class[] = { 300 {1, 20, BW20, BIT(BEHAV_NONE), 5000, 301 {36, 40, 44, 48}, 302 NULL_CFIS_LST }, 303 {2, 20, BW20, BIT(BEHAV_NONE), 5000, 304 {52, 56, 60, 64}, 305 NULL_CFIS_LST }, 306 {4, 20, BW20, BIT(BEHAV_NONE), 5000, 307 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144}, 308 NULL_CFIS_LST }, 309 {5, 20, BW20, BIT(BEHAV_NONE), 5000, 310 {149, 153, 157, 161, 165}, 311 NULL_CFIS_LST }, 312 {12, 25, BW20, BIT(BEHAV_NONE), 2407, 313 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 314 NULL_CFIS_LST }, 315 {22, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 316 {36, 44}, 317 NULL_CFIS_LST }, 318 {23, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 319 {52, 60}, 320 NULL_CFIS_LST }, 321 {24, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 322 {100, 108, 116, 124, 132, 140}, 323 NULL_CFIS_LST }, 324 {26, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 325 {149, 157}, 326 NULL_CFIS_LST }, 327 {27, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 328 {40, 48}, 329 NULL_CFIS_LST }, 330 {28, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 331 {56, 64}, 332 NULL_CFIS_LST }, 333 {29, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 334 {104, 112, 120, 128, 136, 144}, 335 NULL_CFIS_LST }, 336 {30, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 337 {153, 161}, 338 NULL_CFIS_LST }, 339 {31, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 340 {153, 161}, 341 NULL_CFIS_LST }, 342 {32, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407, 343 {1, 2, 3, 4, 5, 6, 7}, 344 NULL_CFIS_LST }, 345 {33, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407, 346 {5, 6, 7, 8, 9, 10, 11}, 347 NULL_CFIS_LST }, 348 {128, 80, BW80, BIT(BEHAV_NONE), 5000, 349 {36, 40, 44, 48, 52, 56, 60, 64, 100, 350 104, 108, 112, 116, 120, 124, 128, 132, 351 136, 140, 144, 149, 153, 157, 161}, 352 NULL_CFIS_LST }, 353 {129, 160, BW80, BIT(BEHAV_NONE), 5000, 354 {36, 40, 44, 48, 52, 56, 60, 64, 100, 355 104, 108, 112, 116, 120, 124, 128}, 356 NULL_CFIS_LST }, 357 {130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000, 358 {36, 40, 44, 48, 52, 56, 60, 64, 100, 359 104, 108, 112, 116, 120, 124, 128, 132, 360 136, 140, 144, 149, 153, 157, 161}, 361 NULL_CFIS_LST }, 362 {0, 0, 0, 0, 0, {0}, 363 NULL_CFIS_LST }, 364 }; 365 366 static const struct reg_dmn_op_class_map_t euro_op_class[] = { 367 {1, 20, BW20, BIT(BEHAV_NONE), 5000, 368 {36, 40, 44, 48}, 369 NULL_CFIS_LST }, 370 {2, 20, BW20, BIT(BEHAV_NONE), 5000, 371 {52, 56, 60, 64}, 372 NULL_CFIS_LST }, 373 {3, 20, BW20, BIT(BEHAV_NONE), 5000, 374 {100, 104, 108, 112, 116, 120, 375 124, 128, 132, 136, 140}, 376 NULL_CFIS_LST }, 377 {4, 25, BW20, BIT(BEHAV_NONE), 2407, 378 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 379 NULL_CFIS_LST }, 380 {5, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 381 {36, 44}, 382 NULL_CFIS_LST }, 383 {6, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 384 {52, 60}, 385 NULL_CFIS_LST }, 386 {7, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 387 {100, 108, 116, 124, 132}, 388 NULL_CFIS_LST }, 389 {8, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 390 {40, 48}, 391 NULL_CFIS_LST }, 392 {9, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 393 {56, 64}, 394 NULL_CFIS_LST }, 395 {10, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 396 {104, 112, 120, 128, 136}, 397 NULL_CFIS_LST }, 398 {11, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407, 399 {1, 2, 3, 4, 5, 6, 7, 8, 9}, 400 NULL_CFIS_LST }, 401 {12, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407, 402 {5, 6, 7, 8, 9, 10, 11, 12, 13}, 403 NULL_CFIS_LST }, 404 {17, 20, BW20, BIT(BEHAV_NONE), 5000, 405 {149, 153, 157, 161, 165, 169}, 406 NULL_CFIS_LST }, 407 {128, 80, BW80, BIT(BEHAV_NONE), 5000, 408 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 409 124, 128}, 410 NULL_CFIS_LST }, 411 {129, 160, BW80, BIT(BEHAV_NONE), 5000, 412 {36, 40, 44, 48, 52, 56, 60, 64, 100, 413 104, 108, 112, 116, 120, 124, 128}, 414 NULL_CFIS_LST }, 415 {130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000, 416 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 417 124, 128}, 418 NULL_CFIS_LST }, 419 {0, 0, 0, 0, 0, {0}, 420 NULL_CFIS_LST }, 421 }; 422 423 static const struct reg_dmn_op_class_map_t japan_op_class[] = { 424 {1, 20, BW20, BIT(BEHAV_NONE), 5000, 425 {36, 40, 44, 48}, 426 NULL_CFIS_LST }, 427 {30, 25, BW20, BIT(BEHAV_NONE), 2407, 428 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 429 NULL_CFIS_LST }, 430 {31, 25, BW20, BIT(BEHAV_NONE), 2414, 431 {14}, 432 NULL_CFIS_LST }, 433 {32, 20, BW20, BIT(BEHAV_NONE), 5000, 434 {52, 56, 60, 64}, 435 NULL_CFIS_LST }, 436 {34, 20, BW20, BIT(BEHAV_NONE), 5000, 437 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 438 NULL_CFIS_LST }, 439 {36, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 440 {36, 44}, 441 NULL_CFIS_LST }, 442 {37, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 443 {52, 60}, 444 NULL_CFIS_LST }, 445 {39, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 446 {100, 108, 116, 124, 132}, 447 NULL_CFIS_LST }, 448 {41, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 449 {40, 48}, 450 NULL_CFIS_LST }, 451 {42, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 452 {56, 64}, 453 NULL_CFIS_LST }, 454 {44, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 455 {104, 112, 120, 128, 136}, 456 NULL_CFIS_LST }, 457 {128, 80, BW80, BIT(BEHAV_NONE), 5000, 458 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 459 124, 128, 132, 136, 140, 144}, 460 NULL_CFIS_LST }, 461 {129, 160, BW80, BIT(BEHAV_NONE), 5000, 462 {36, 40, 44, 48, 52, 56, 60, 64, 100, 463 104, 108, 112, 116, 120, 124, 128}, 464 NULL_CFIS_LST }, 465 {130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000, 466 {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 467 124, 128, 132, 136, 140, 144}, 468 NULL_CFIS_LST }, 469 {0, 0, 0, 0, 0, {0}, 470 NULL_CFIS_LST }, 471 }; 472 473 static const struct reg_dmn_op_class_map_t china_op_class[] = { 474 {7, 25, BW20, BIT(BEHAV_NONE), 2407, 475 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 476 NULL_CFIS_LST }, 477 {8, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 2407, 478 {1, 2, 3, 4, 5, 6, 7, 8, 9}, 479 NULL_CFIS_LST }, 480 {9, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 2407, 481 {5, 6, 7, 8, 9, 10, 11, 12, 13}, 482 NULL_CFIS_LST }, 483 {1, 20, BW20, BIT(BEHAV_NONE), 5000, 484 {36, 40, 44, 48}, 485 NULL_CFIS_LST }, 486 {4, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 487 {36, 44}, 488 NULL_CFIS_LST }, 489 {117, 40, BW40_HIGH_PRIMARY, BIT(BEHAV_BW40_HIGH_PRIMARY), 5000, 490 {40, 48}, 491 NULL_CFIS_LST }, 492 {2, 20, BW20, BIT(BEHAV_NONE), 5000, 493 {52, 56, 60, 64}, 494 NULL_CFIS_LST }, 495 {5, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 496 {52, 60}, 497 NULL_CFIS_LST }, 498 {3, 20, BW20, BIT(BEHAV_NONE), 5000, 499 {149, 153, 157, 161, 165}, 500 NULL_CFIS_LST }, 501 {6, 40, BW40_LOW_PRIMARY, BIT(BEHAV_BW40_LOW_PRIMARY), 5000, 502 {149, 157}, 503 NULL_CFIS_LST }, 504 {128, 80, BW80, BIT(BEHAV_NONE), 5000, 505 {36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161}, 506 NULL_CFIS_LST }, 507 {129, 160, BW80, BIT(BEHAV_NONE), 5000, 508 {36, 40, 44, 48, 52, 56, 60, 64,}, 509 NULL_CFIS_LST }, 510 {130, 80, BW80, BIT(BEHAV_BW80_PLUS), 5000, 511 {36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161}, 512 NULL_CFIS_LST }, 513 {0, 0, 0, 0, 0, {0}, 514 NULL_CFIS_LST }, 515 }; 516 #ifdef HOST_OPCLASS 517 /** 518 * reg_get_class_from_country()- Get Class from country 519 * @country- Country 520 * 521 * Return: class. 522 */ 523 static const struct reg_dmn_op_class_map_t 524 *reg_get_class_from_country(const uint8_t *country) 525 { 526 const struct reg_dmn_op_class_map_t *class = NULL; 527 528 if (!country) 529 return global_op_class; 530 531 reg_debug_rl("Country %c%c 0x%x", country[0], country[1], country[2]); 532 533 switch (country[2]) { 534 case OP_CLASS_US: 535 class = us_op_class; 536 break; 537 538 case OP_CLASS_EU: 539 class = euro_op_class; 540 break; 541 542 case OP_CLASS_JAPAN: 543 class = japan_op_class; 544 break; 545 546 case OP_CLASS_GLOBAL: 547 class = global_op_class; 548 break; 549 550 case OP_CLASS_CHINA: 551 class = china_op_class; 552 break; 553 default: 554 if (!qdf_mem_cmp(country, "US", 2)) 555 class = us_op_class; 556 else if (!qdf_mem_cmp(country, "EU", 2)) 557 class = euro_op_class; 558 else if (!qdf_mem_cmp(country, "JP", 2)) 559 class = japan_op_class; 560 else if (!qdf_mem_cmp(country, "CN", 2)) 561 class = china_op_class; 562 else 563 class = global_op_class; 564 } 565 return class; 566 } 567 568 #ifdef CONFIG_AFC_SUPPORT 569 static bool reg_is_range_valid(struct freq_range *range) 570 { 571 return (range->right > range->left); 572 } 573 574 /** 575 * reg_is_subrange() - Check if range_first is a subrange of range_second 576 * @range_first: Pointer to first range 577 * @range_second: Pointer to first range 578 * 579 * Return: True if the range_first is a subrange range_second, else false 580 */ 581 static bool reg_is_subrange(struct freq_range *range_first, 582 struct freq_range *range_second) 583 { 584 bool is_subrange; 585 bool is_valid; 586 587 is_valid = reg_is_range_valid(range_first) && 588 reg_is_range_valid(range_second); 589 590 if (!is_valid) 591 return false; 592 593 is_subrange = (range_first->left >= range_second->left) && 594 (range_first->right <= range_second->right); 595 596 return is_subrange; 597 } 598 599 /** 600 * reg_is_cfi_freq_in_ranges() - Check if the given 'cfi' in the any of the 601 * frequency ranges 602 * @cfi_freq: The center frequency index frequency 603 * @bw: bandwidth of the band with center freq cfi_freq 604 * @p_frange_lst: Pointer to frequency range list (AFC) 605 * 606 * return: True if the cfi is in the ranges, else false 607 */ 608 static bool reg_is_cfi_freq_in_ranges(qdf_freq_t cfi_freq, 609 uint16_t bw, 610 struct wlan_afc_frange_list *p_frange_lst) 611 { 612 uint32_t num_ranges; 613 struct wlan_afc_freq_range_obj *p_range_objs; 614 uint8_t i; 615 bool is_cfi_supported = false; 616 617 num_ranges = p_frange_lst->num_ranges; 618 p_range_objs = &p_frange_lst->range_objs[0]; 619 for (i = 0; i < num_ranges; i++) { 620 qdf_freq_t cfi_band_left; 621 qdf_freq_t cfi_band_right; 622 struct freq_range range_cfi; 623 struct freq_range range_chip; 624 625 cfi_band_left = cfi_freq - bw / 2; 626 cfi_band_right = cfi_freq + bw / 2; 627 628 range_cfi = reg_init_freq_range(cfi_band_left, 629 cfi_band_right); 630 range_chip = reg_init_freq_range(p_range_objs->lowfreq, 631 p_range_objs->highfreq); 632 is_cfi_supported = reg_is_subrange(&range_cfi, &range_chip); 633 634 if (is_cfi_supported) 635 return true; 636 637 p_range_objs++; 638 } 639 640 return is_cfi_supported; 641 } 642 643 void reg_dmn_free_6g_opclasses_and_channels(struct wlan_objmgr_pdev *pdev, 644 uint8_t num_opclasses, 645 uint8_t *opclass_lst, 646 uint8_t *chansize_lst, 647 uint8_t *channel_lists[]) 648 { 649 /* 650 * All the elements of channel_lists were allocated as a single 651 * allocation with 'channel_lists[0]' holding the first location of the 652 * allocation. Therefore, freeing only 'channel_lists[0]' is enough. 653 * Freeing any other 'channel_lists[i]' will result in error of freeing 654 * unallocated memory. 655 656 */ 657 if (channel_lists) 658 qdf_mem_free(channel_lists[0]); 659 660 /* 661 * opclass_lst, chansize_lst and channel_lists were allocated as a 662 * single allocation with 'opclass_lst' holding the first location of 663 * allocation. Therefore, freeing only 'opclass_lst' is enough. 664 * Freeing chansize_lst, channel_lists will result in error of freeing 665 * unallocated memory. 666 */ 667 qdf_mem_free(opclass_lst); 668 } 669 670 /** 671 * reg_dmn_get_num_6g_opclasses() - Calculate the number of opclasses in the 672 * 6GHz band. 673 * Return: The number of opclasses 674 */ 675 static uint8_t reg_dmn_get_num_6g_opclasses(struct wlan_objmgr_pdev *pdev) 676 { 677 const struct reg_dmn_op_class_map_t *op_class_tbl; 678 uint8_t count; 679 680 op_class_tbl = global_op_class; 681 682 count = 0; 683 while (op_class_tbl && op_class_tbl->op_class) { 684 const struct c_freq_lst *p_lst; 685 686 p_lst = op_class_tbl->p_cfi_lst_obj; 687 if (p_lst && 688 reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) 689 count++; 690 691 op_class_tbl++; 692 } 693 694 return count; 695 } 696 697 /** 698 * reg_dmn_fill_6g_opcls_chan_lists() - Copy the channel lists for 6g opclasses 699 * to the output argument list ('channel_lists') 700 * @pdev: Pointer to pdev. 701 * @p_frange_lst: Pointer to frequency range list (AFC) 702 * @chansize_lst: Array of sizes of channel lists 703 * @channel_lists: The array list pointers where the channel lists are to be 704 * copied. 705 * 706 * Return: Void 707 */ 708 static void reg_dmn_fill_6g_opcls_chan_lists(struct wlan_objmgr_pdev *pdev, 709 struct wlan_afc_frange_list *p_frange_lst, 710 uint8_t chansize_lst[], 711 uint8_t *channel_lists[]) 712 { 713 uint8_t i = 0; 714 const struct reg_dmn_op_class_map_t *op_class_tbl; 715 716 op_class_tbl = global_op_class; 717 718 while (op_class_tbl && op_class_tbl->op_class) { 719 const struct c_freq_lst *p_lst; 720 721 p_lst = op_class_tbl->p_cfi_lst_obj; 722 if (p_lst && 723 reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) { 724 uint8_t j; 725 uint8_t cfi_idx = 0; 726 uint8_t *dst; 727 728 dst = channel_lists[i]; 729 for (j = 0; j < p_lst->num_cfis; j++) { 730 uint8_t cfi; 731 qdf_freq_t cfi_freq; 732 qdf_freq_t start_freq = op_class_tbl->start_freq; 733 uint16_t bw = op_class_tbl->chan_spacing; 734 735 cfi = p_lst->p_cfis_arr[j]; 736 cfi_freq = start_freq + 737 FREQ_TO_CHAN_SCALE * cfi; 738 739 if (reg_is_cfi_freq_in_ranges(cfi_freq, 740 bw, 741 p_frange_lst)) { 742 dst[cfi_idx++] = cfi; 743 } 744 } 745 i++; 746 } 747 op_class_tbl++; 748 } 749 } 750 751 QDF_STATUS reg_dmn_get_6g_opclasses_and_channels(struct wlan_objmgr_pdev *pdev, 752 struct wlan_afc_frange_list *p_frange_lst, 753 uint8_t *num_opclasses, 754 uint8_t **opclass_lst, 755 uint8_t **chansize_lst, 756 uint8_t **channel_lists[]) 757 { 758 const struct reg_dmn_op_class_map_t *op_class_tbl; 759 uint8_t *l_opcls_lst; 760 uint8_t *l_chansize_lst; 761 uint8_t count; 762 uint8_t i; 763 uint8_t **arr_chan_lists; 764 uint16_t total_alloc_size; 765 uint16_t opcls_lst_size; 766 uint16_t chansize_lst_size; 767 uint16_t arr_chan_lists_size; 768 uint8_t *p_total_alloc1; 769 uint8_t *p_total_alloc2; 770 uint8_t *p_temp_alloc; 771 772 *opclass_lst = NULL; 773 *chansize_lst = NULL; 774 *channel_lists = NULL; 775 776 op_class_tbl = global_op_class; 777 778 *num_opclasses = reg_dmn_get_num_6g_opclasses(pdev); 779 opcls_lst_size = *num_opclasses * sizeof(uint8_t); 780 chansize_lst_size = *num_opclasses * sizeof(uint8_t); 781 arr_chan_lists_size = *num_opclasses * sizeof(uint8_t *); 782 783 total_alloc_size = 0; 784 total_alloc_size += opcls_lst_size 785 + chansize_lst_size 786 + arr_chan_lists_size; 787 788 if (!total_alloc_size) { 789 reg_err("Number of Opclasses is zero"); 790 return QDF_STATUS_E_INVAL; 791 } 792 793 p_total_alloc1 = qdf_mem_malloc(total_alloc_size); 794 if (!p_total_alloc1) { 795 return QDF_STATUS_E_NOMEM; 796 } 797 798 /* Assign memory locations to each pointers */ 799 p_temp_alloc = p_total_alloc1; 800 801 l_opcls_lst = p_temp_alloc; 802 p_temp_alloc += opcls_lst_size; 803 804 l_chansize_lst = p_temp_alloc; 805 p_temp_alloc += chansize_lst_size; 806 807 arr_chan_lists = (uint8_t **)p_temp_alloc; 808 809 /* Fill arrays with opclasses and chanlist sizes */ 810 count = 0; 811 while (op_class_tbl && op_class_tbl->op_class) { 812 const struct c_freq_lst *p_lst; 813 814 p_lst = op_class_tbl->p_cfi_lst_obj; 815 if (p_lst && 816 reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) { 817 uint8_t n_supp_cfis = 0; 818 uint8_t j; 819 820 l_opcls_lst[count] = op_class_tbl->op_class; 821 for (j = 0; j < p_lst->num_cfis; j++) { 822 uint8_t cfi; 823 qdf_freq_t cfi_freq; 824 qdf_freq_t start_freq = op_class_tbl->start_freq; 825 uint16_t bw = op_class_tbl->chan_spacing; 826 827 cfi = p_lst->p_cfis_arr[j]; 828 cfi_freq = start_freq + 829 FREQ_TO_CHAN_SCALE * cfi; 830 if (reg_is_cfi_freq_in_ranges(cfi_freq, 831 bw, 832 p_frange_lst)) { 833 n_supp_cfis++; 834 } 835 } 836 l_chansize_lst[count] = n_supp_cfis; 837 count++; 838 } 839 op_class_tbl++; 840 } 841 842 /* Calculate total alloction size for the array */ 843 total_alloc_size = 0; 844 for (i = 0; i < *num_opclasses; i++) 845 total_alloc_size += l_chansize_lst[i] * sizeof(uint8_t *); 846 847 if (!total_alloc_size) { 848 reg_err("Number of Opclasses is zero"); 849 qdf_mem_free(p_total_alloc1); 850 return QDF_STATUS_E_INVAL; 851 } 852 853 p_total_alloc2 = qdf_mem_malloc(total_alloc_size); 854 if (!p_total_alloc2) { 855 qdf_mem_free(p_total_alloc1); 856 return QDF_STATUS_E_NOMEM; 857 } 858 859 /* Assign memory locations to each list pointers */ 860 p_temp_alloc = p_total_alloc2; 861 for (i = 0; i < *num_opclasses; i++) { 862 if (!l_chansize_lst[i]) 863 arr_chan_lists[i] = NULL; 864 else 865 arr_chan_lists[i] = p_temp_alloc; 866 867 p_temp_alloc += l_chansize_lst[i] * sizeof(uint8_t *); 868 } 869 870 /* Fill the array with channel lists */ 871 reg_dmn_fill_6g_opcls_chan_lists(pdev, p_frange_lst, l_chansize_lst, arr_chan_lists); 872 873 *opclass_lst = l_opcls_lst; 874 *chansize_lst = l_chansize_lst; 875 *channel_lists = arr_chan_lists; 876 877 return QDF_STATUS_SUCCESS; 878 } 879 #endif /* CONFIG_AFC_SUPPORT */ 880 881 uint16_t reg_dmn_get_chanwidth_from_opclass(uint8_t *country, uint8_t channel, 882 uint8_t opclass) 883 { 884 const struct reg_dmn_op_class_map_t *class; 885 uint16_t i; 886 887 class = reg_get_class_from_country(country); 888 889 while (class->op_class) { 890 if (opclass == class->op_class) { 891 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 892 class->channels[i]); i++) { 893 if (channel == class->channels[i]) 894 return class->chan_spacing; 895 } 896 } 897 class++; 898 } 899 900 return 0; 901 } 902 903 uint16_t reg_dmn_get_chanwidth_from_opclass_auto(uint8_t *country, 904 uint8_t channel, 905 uint8_t opclass) 906 { 907 uint16_t ret; 908 uint8_t global_country[REG_ALPHA2_LEN + 1]; 909 910 ret = reg_dmn_get_chanwidth_from_opclass(country, channel, opclass); 911 912 if (!ret) { 913 global_country[2] = OP_CLASS_GLOBAL; 914 ret = reg_dmn_get_chanwidth_from_opclass(global_country, 915 channel, opclass); 916 } 917 918 return ret; 919 } 920 921 uint16_t reg_dmn_get_opclass_from_channel(uint8_t *country, uint8_t channel, 922 uint8_t offset) 923 { 924 const struct reg_dmn_op_class_map_t *class = NULL; 925 uint16_t i = 0; 926 927 class = reg_get_class_from_country(country); 928 while (class && class->op_class) { 929 if ((offset == class->offset) || (offset == BWALL)) { 930 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 931 class->channels[i]); i++) { 932 if (channel == class->channels[i]) 933 return class->op_class; 934 } 935 } 936 class++; 937 } 938 939 return 0; 940 } 941 942 uint8_t reg_dmn_get_opclass_from_freq_width(uint8_t *country, 943 qdf_freq_t freq, 944 uint16_t ch_width, 945 uint16_t behav_limit) 946 { 947 const struct reg_dmn_op_class_map_t *op_class_tbl = NULL; 948 uint16_t i = 0; 949 950 op_class_tbl = reg_get_class_from_country(country); 951 952 while (op_class_tbl && op_class_tbl->op_class) { 953 if (op_class_tbl->chan_spacing == ch_width) { 954 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 955 op_class_tbl->channels[i]); i++) { 956 if ((op_class_tbl->start_freq + 957 (FREQ_TO_CHAN_SCALE * 958 op_class_tbl->channels[i]) == freq) && 959 (behav_limit & op_class_tbl->behav_limit)) { 960 return op_class_tbl->op_class; 961 } 962 } 963 } 964 op_class_tbl++; 965 } 966 967 return 0; 968 } 969 970 static void 971 reg_get_band_cap_from_chan_set(const struct reg_dmn_op_class_map_t 972 *op_class_tbl, 973 uint8_t *supported_band) 974 { 975 qdf_freq_t chan_freq = op_class_tbl->start_freq + 976 (op_class_tbl->channels[0] * 977 FREQ_TO_CHAN_SCALE); 978 979 if (reg_is_24ghz_ch_freq(chan_freq)) 980 *supported_band |= BIT(REG_BAND_2G); 981 else if (reg_is_5ghz_ch_freq(chan_freq)) 982 *supported_band |= BIT(REG_BAND_5G); 983 else if (reg_is_6ghz_chan_freq(chan_freq)) 984 *supported_band |= BIT(REG_BAND_6G); 985 else 986 reg_err_rl("Unknown band"); 987 } 988 989 uint8_t reg_get_band_cap_from_op_class(const uint8_t *country, 990 uint8_t num_of_opclass, 991 const uint8_t *opclass) 992 { 993 const struct reg_dmn_op_class_map_t *op_class_tbl; 994 uint8_t supported_band = 0, opclassidx; 995 996 op_class_tbl = reg_get_class_from_country(country); 997 998 while (op_class_tbl && op_class_tbl->op_class) { 999 for (opclassidx = 0; opclassidx < num_of_opclass; 1000 opclassidx++) { 1001 if (op_class_tbl->op_class == opclass[opclassidx]) { 1002 reg_get_band_cap_from_chan_set(op_class_tbl, 1003 &supported_band); 1004 } 1005 } 1006 op_class_tbl++; 1007 } 1008 1009 if (!supported_band) 1010 reg_err_rl("None of the operating classes is found"); 1011 1012 return supported_band; 1013 } 1014 1015 void reg_dmn_print_channels_in_opclass(uint8_t *country, uint8_t op_class) 1016 { 1017 const struct reg_dmn_op_class_map_t *class = NULL; 1018 uint16_t i = 0; 1019 1020 class = reg_get_class_from_country(country); 1021 1022 if (!class) { 1023 reg_err("class is NULL"); 1024 return; 1025 } 1026 1027 while (class->op_class) { 1028 if (class->op_class == op_class) { 1029 for (i = 0; 1030 (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1031 class->channels[i]); i++) { 1032 reg_debug("Valid channel(%d) in requested RC(%d)", 1033 class->channels[i], op_class); 1034 } 1035 break; 1036 } 1037 class++; 1038 } 1039 if (!class->op_class) 1040 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 1041 "Invalid requested RC (%d)", op_class); 1042 } 1043 1044 uint16_t reg_dmn_set_curr_opclasses(uint8_t num_classes, uint8_t *class) 1045 { 1046 uint8_t i; 1047 1048 if (num_classes > REG_MAX_SUPP_OPER_CLASSES) { 1049 reg_err("invalid num classes %d", num_classes); 1050 return 0; 1051 } 1052 1053 for (i = 0; i < num_classes; i++) 1054 reg_dmn_curr_supp_opp_classes.classes[i] = class[i]; 1055 1056 reg_dmn_curr_supp_opp_classes.num_classes = num_classes; 1057 1058 return 0; 1059 } 1060 1061 uint16_t reg_dmn_get_curr_opclasses(uint8_t *num_classes, uint8_t *class) 1062 { 1063 uint8_t i; 1064 1065 if (!num_classes || !class) { 1066 reg_err("either num_classes or class is null"); 1067 return 0; 1068 } 1069 1070 for (i = 0; i < reg_dmn_curr_supp_opp_classes.num_classes; i++) 1071 class[i] = reg_dmn_curr_supp_opp_classes.classes[i]; 1072 1073 *num_classes = reg_dmn_curr_supp_opp_classes.num_classes; 1074 1075 return 0; 1076 } 1077 1078 #ifdef CONFIG_CHAN_FREQ_API 1079 /** 1080 * reg_find_opclass_absent_in_ctry_opclss_tables() - Check Global Opclass table 1081 * when Opclass is not present in specific country. 1082 * @pdev - Pointer to pdev 1083 * @freq - Destination Frequency 1084 * @chan_width- Channel Width 1085 * @global_tbl_lookup - Global Table Lookup 1086 * @behav_limit - Behav Limit 1087 * @op_class - Pointer to Opclass 1088 * @chan_num - Pointer to Channel 1089 * 1090 * Return: Void 1091 */ 1092 static void 1093 reg_find_opclass_absent_in_ctry_opclss_tables(struct wlan_objmgr_pdev *pdev, 1094 qdf_freq_t freq, 1095 uint16_t chan_width, 1096 bool global_tbl_lookup, 1097 uint16_t behav_limit, 1098 uint8_t *op_class, 1099 uint8_t *chan_num) 1100 { 1101 if (!global_tbl_lookup && !*op_class) { 1102 global_tbl_lookup = true; 1103 reg_freq_width_to_chan_op_class(pdev, freq, 1104 chan_width, 1105 global_tbl_lookup, 1106 behav_limit, 1107 op_class, 1108 chan_num); 1109 } 1110 } 1111 1112 static bool 1113 reg_is_country_opclass_global(struct wlan_objmgr_pdev *pdev) 1114 { 1115 struct wlan_lmac_if_reg_tx_ops *reg_tx_ops; 1116 struct wlan_objmgr_psoc *psoc; 1117 uint8_t opclass_tbl_idx; 1118 1119 psoc = wlan_pdev_get_psoc(pdev); 1120 if (!psoc) { 1121 reg_err("psoc is NULL"); 1122 return false; 1123 } 1124 1125 reg_tx_ops = reg_get_psoc_tx_ops(psoc); 1126 if (!reg_tx_ops) { 1127 reg_err("reg_tx_ops is NULL"); 1128 return false; 1129 } 1130 1131 if (reg_tx_ops->get_opclass_tbl_idx) { 1132 reg_tx_ops->get_opclass_tbl_idx(pdev, &opclass_tbl_idx); 1133 1134 if (opclass_tbl_idx == OP_CLASS_GLOBAL) 1135 return true; 1136 } 1137 1138 return false; 1139 } 1140 1141 void reg_freq_width_to_chan_op_class_auto(struct wlan_objmgr_pdev *pdev, 1142 qdf_freq_t freq, 1143 uint16_t chan_width, 1144 bool global_tbl_lookup, 1145 uint16_t behav_limit, 1146 uint8_t *op_class, 1147 uint8_t *chan_num) 1148 { 1149 if (reg_freq_to_band(freq) == REG_BAND_6G) { 1150 global_tbl_lookup = true; 1151 if (chan_width == BW_40_MHZ) 1152 behav_limit = BIT(BEHAV_NONE); 1153 } else if (reg_is_5dot9_ghz_freq(pdev, freq)) { 1154 global_tbl_lookup = true; 1155 } else { 1156 global_tbl_lookup = reg_is_country_opclass_global(pdev); 1157 } 1158 1159 *op_class = 0; 1160 reg_freq_width_to_chan_op_class(pdev, freq, 1161 chan_width, 1162 global_tbl_lookup, 1163 behav_limit, 1164 op_class, 1165 chan_num); 1166 reg_find_opclass_absent_in_ctry_opclss_tables(pdev, freq, 1167 chan_width, 1168 global_tbl_lookup, 1169 behav_limit, 1170 op_class, 1171 chan_num); 1172 } 1173 1174 void reg_freq_width_to_chan_op_class(struct wlan_objmgr_pdev *pdev, 1175 qdf_freq_t freq, 1176 uint16_t chan_width, 1177 bool global_tbl_lookup, 1178 uint16_t behav_limit, 1179 uint8_t *op_class, 1180 uint8_t *chan_num) 1181 { 1182 const struct reg_dmn_op_class_map_t *op_class_tbl; 1183 enum channel_enum chan_enum; 1184 uint16_t i; 1185 1186 chan_enum = reg_get_chan_enum_for_freq(freq); 1187 1188 if (reg_is_chan_enum_invalid(chan_enum)) { 1189 reg_err_rl("Invalid chan enum %d", chan_enum); 1190 return; 1191 } 1192 1193 if (global_tbl_lookup) { 1194 op_class_tbl = global_op_class; 1195 } else { 1196 if (channel_map == channel_map_us) 1197 op_class_tbl = us_op_class; 1198 else if (channel_map == channel_map_eu) 1199 op_class_tbl = euro_op_class; 1200 else if (channel_map == channel_map_china) 1201 op_class_tbl = china_op_class; 1202 else if (channel_map == channel_map_jp) 1203 op_class_tbl = japan_op_class; 1204 else 1205 op_class_tbl = global_op_class; 1206 } 1207 1208 while (op_class_tbl->op_class) { 1209 if (op_class_tbl->chan_spacing >= chan_width) { 1210 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1211 op_class_tbl->channels[i]); i++) { 1212 if ((op_class_tbl->start_freq + 1213 FREQ_TO_CHAN_SCALE * 1214 op_class_tbl->channels[i] == freq) && 1215 (behav_limit & op_class_tbl->behav_limit || 1216 behav_limit == BIT(BEHAV_NONE))) { 1217 *chan_num = op_class_tbl->channels[i]; 1218 *op_class = op_class_tbl->op_class; 1219 return; 1220 } 1221 } 1222 } 1223 op_class_tbl++; 1224 } 1225 1226 reg_err_rl("no op class for frequency %d", freq); 1227 } 1228 1229 void reg_freq_to_chan_op_class(struct wlan_objmgr_pdev *pdev, 1230 qdf_freq_t freq, 1231 bool global_tbl_lookup, 1232 uint16_t behav_limit, 1233 uint8_t *op_class, 1234 uint8_t *chan_num) 1235 { 1236 enum channel_enum chan_enum; 1237 struct regulatory_channel *cur_chan_list; 1238 struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj; 1239 struct ch_params chan_params = {0}; 1240 1241 pdev_priv_obj = reg_get_pdev_obj(pdev); 1242 1243 if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) { 1244 reg_err_rl("NULL pdev reg obj"); 1245 return; 1246 } 1247 1248 cur_chan_list = pdev_priv_obj->cur_chan_list; 1249 1250 chan_enum = reg_get_chan_enum_for_freq(freq); 1251 1252 if (reg_is_chan_enum_invalid(chan_enum)) { 1253 reg_err_rl("Invalid chan enum %d", chan_enum); 1254 return; 1255 } 1256 1257 chan_params.ch_width = CH_WIDTH_MAX; 1258 reg_set_channel_params_for_pwrmode(pdev, freq, 1259 0, 1260 &chan_params, 1261 REG_CURRENT_PWR_MODE, true); 1262 1263 reg_freq_width_to_chan_op_class(pdev, freq, 1264 reg_get_bw_value(chan_params.ch_width), 1265 global_tbl_lookup, 1266 behav_limit, 1267 op_class, 1268 chan_num); 1269 } 1270 1271 bool reg_is_freq_in_country_opclass(struct wlan_objmgr_pdev *pdev, 1272 const uint8_t country[3], 1273 uint8_t op_class, 1274 qdf_freq_t chan_freq) 1275 { 1276 const struct reg_dmn_op_class_map_t *op_class_tbl; 1277 uint8_t i; 1278 1279 op_class_tbl = reg_get_class_from_country((uint8_t *)country); 1280 1281 while (op_class_tbl && op_class_tbl->op_class) { 1282 if (op_class_tbl->op_class == op_class) { 1283 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1284 op_class_tbl->channels[i]); i++) { 1285 if (op_class_tbl->channels[i] * 1286 FREQ_TO_CHAN_SCALE + 1287 op_class_tbl->start_freq == chan_freq) 1288 return true; 1289 } 1290 } 1291 op_class_tbl++; 1292 } 1293 return false; 1294 } 1295 1296 #endif 1297 1298 uint16_t reg_get_op_class_width(struct wlan_objmgr_pdev *pdev, 1299 uint8_t op_class, 1300 bool global_tbl_lookup) 1301 { 1302 const struct reg_dmn_op_class_map_t *op_class_tbl; 1303 1304 if (global_tbl_lookup) { 1305 op_class_tbl = global_op_class; 1306 } else { 1307 if (channel_map == channel_map_us) 1308 op_class_tbl = us_op_class; 1309 else if (channel_map == channel_map_eu) 1310 op_class_tbl = euro_op_class; 1311 else if (channel_map == channel_map_china) 1312 op_class_tbl = china_op_class; 1313 else if (channel_map == channel_map_jp) 1314 op_class_tbl = japan_op_class; 1315 else 1316 op_class_tbl = global_op_class; 1317 } 1318 1319 while (op_class_tbl->op_class) { 1320 if (op_class_tbl->op_class == op_class) 1321 return op_class_tbl->chan_spacing; 1322 op_class_tbl++; 1323 } 1324 1325 return 0; 1326 } 1327 1328 uint16_t reg_chan_opclass_to_freq(uint8_t chan, 1329 uint8_t op_class, 1330 bool global_tbl_lookup) 1331 { 1332 const struct reg_dmn_op_class_map_t *op_class_tbl = NULL; 1333 uint8_t i = 0; 1334 1335 if (global_tbl_lookup) { 1336 op_class_tbl = global_op_class; 1337 } else { 1338 if (channel_map == channel_map_global) { 1339 op_class_tbl = global_op_class; 1340 } else if (channel_map == channel_map_us) { 1341 op_class_tbl = us_op_class; 1342 } else if (channel_map == channel_map_eu) { 1343 op_class_tbl = euro_op_class; 1344 } else if (channel_map == channel_map_china) { 1345 op_class_tbl = china_op_class; 1346 } else if (channel_map == channel_map_jp) { 1347 op_class_tbl = japan_op_class; 1348 } else { 1349 reg_err_rl("Invalid channel map"); 1350 return 0; 1351 } 1352 } 1353 1354 while (op_class_tbl->op_class) { 1355 if (op_class_tbl->op_class == op_class) { 1356 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1357 op_class_tbl->channels[i]); i++) { 1358 if (op_class_tbl->channels[i] == chan) { 1359 chan = op_class_tbl->channels[i]; 1360 return op_class_tbl->start_freq + 1361 (chan * FREQ_TO_CHAN_SCALE); 1362 } 1363 } 1364 reg_err_rl("Channel not found"); 1365 return 0; 1366 } 1367 op_class_tbl++; 1368 } 1369 reg_err_rl("Invalid opclass"); 1370 return 0; 1371 } 1372 1373 qdf_freq_t reg_chan_opclass_to_freq_auto(uint8_t chan, uint8_t op_class, 1374 bool global_tbl_lookup) 1375 { 1376 if ((op_class >= MIN_6GHZ_OPER_CLASS) && 1377 (op_class <= MAX_6GHZ_OPER_CLASS)) { 1378 global_tbl_lookup = true; 1379 } else { 1380 qdf_freq_t freq = reg_chan_opclass_to_freq(chan, 1381 op_class, 1382 global_tbl_lookup); 1383 if (freq) 1384 return freq; 1385 global_tbl_lookup = true; 1386 } 1387 1388 return reg_chan_opclass_to_freq(chan, op_class, global_tbl_lookup); 1389 } 1390 1391 #ifdef HOST_OPCLASS_EXT 1392 qdf_freq_t reg_country_chan_opclass_to_freq(struct wlan_objmgr_pdev *pdev, 1393 const uint8_t country[3], 1394 uint8_t chan, uint8_t op_class, 1395 bool strict) 1396 { 1397 const struct reg_dmn_op_class_map_t *op_class_tbl, *op_class_tbl_org; 1398 uint16_t i; 1399 1400 if (reg_is_6ghz_op_class(pdev, op_class)) 1401 op_class_tbl_org = global_op_class; 1402 else 1403 op_class_tbl_org = 1404 reg_get_class_from_country((uint8_t *)country); 1405 op_class_tbl = op_class_tbl_org; 1406 while (op_class_tbl && op_class_tbl->op_class) { 1407 if (op_class_tbl->op_class == op_class) { 1408 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1409 op_class_tbl->channels[i]); i++) { 1410 if (op_class_tbl->channels[i] == chan) 1411 return op_class_tbl->start_freq + 1412 (chan * FREQ_TO_CHAN_SCALE); 1413 } 1414 } 1415 op_class_tbl++; 1416 } 1417 reg_debug_rl("Not found ch %d in op class %d ch list, strict %d", 1418 chan, op_class, strict); 1419 if (strict) 1420 return 0; 1421 1422 op_class_tbl = op_class_tbl_org; 1423 while (op_class_tbl && op_class_tbl->op_class) { 1424 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1425 op_class_tbl->channels[i]); i++) { 1426 if (op_class_tbl->channels[i] == chan) 1427 return op_class_tbl->start_freq + 1428 (chan * FREQ_TO_CHAN_SCALE); 1429 } 1430 op_class_tbl++; 1431 } 1432 reg_debug_rl("Got invalid freq 0 for ch %d", chan); 1433 1434 return 0; 1435 } 1436 #endif 1437 1438 static void 1439 reg_get_op_class_tbl_by_chan_map(const struct 1440 reg_dmn_op_class_map_t **op_class_tbl) 1441 { 1442 if (channel_map == channel_map_us) 1443 *op_class_tbl = us_op_class; 1444 else if (channel_map == channel_map_eu) 1445 *op_class_tbl = euro_op_class; 1446 else if (channel_map == channel_map_china) 1447 *op_class_tbl = china_op_class; 1448 else if (channel_map == channel_map_jp) 1449 *op_class_tbl = japan_op_class; 1450 else 1451 *op_class_tbl = global_op_class; 1452 } 1453 1454 /** 1455 * reg_get_channel_cen - Calculate central channel in the channel set. 1456 * 1457 * @op_class_tbl - Pointer to op_class_tbl. 1458 * @idx - Pointer to channel index. 1459 * @num_channels - Number of channels. 1460 * @center_chan - Pointer to center channel number 1461 * 1462 * Return : void 1463 */ 1464 static void reg_get_channel_cen(const struct 1465 reg_dmn_op_class_map_t *op_class_tbl, 1466 uint8_t *idx, 1467 uint8_t num_channels, 1468 uint8_t *center_chan) 1469 { 1470 uint8_t i; 1471 uint16_t new_chan = 0; 1472 1473 for (i = *idx; i < (*idx + num_channels); i++) 1474 new_chan += op_class_tbl->channels[i]; 1475 1476 new_chan = new_chan / num_channels; 1477 *center_chan = new_chan; 1478 *idx = *idx + num_channels; 1479 } 1480 1481 /** 1482 * reg_is_chan_320mhz() - Return true if the chan width is 320MHZ, 1483 * false otherwise. 1484 * @chan_spacing: Channel spacing in MHZ. 1485 * 1486 * Return: true if chan_width is 320, false otherwise. 1487 */ 1488 #ifdef WLAN_FEATURE_11BE 1489 static bool reg_is_chan_320mhz(uint16_t chan_spacing) 1490 { 1491 if (chan_spacing == BW_320_MHZ) 1492 return true; 1493 return false; 1494 } 1495 #else 1496 static bool reg_is_chan_320mhz(uint16_t chan_spacing) 1497 { 1498 return false; 1499 } 1500 #endif 1501 1502 /** 1503 * reg_get_chan_or_chan_center - Calculate central channel in the channel set. 1504 * 1505 * @op_class_tbl - Pointer to op_class_tbl. 1506 * @idx - Pointer to channel index. 1507 * 1508 * Return : Center channel number 1509 */ 1510 static uint8_t reg_get_chan_or_chan_center(const struct 1511 reg_dmn_op_class_map_t *op_class_tbl, 1512 uint8_t *idx) 1513 { 1514 uint8_t center_chan; 1515 1516 if (((op_class_tbl->chan_spacing == BW_80_MHZ) && 1517 (op_class_tbl->behav_limit == BIT(BEHAV_NONE))) || 1518 ((op_class_tbl->chan_spacing == BW_80_MHZ) && 1519 (op_class_tbl->behav_limit == BIT(BEHAV_BW80_PLUS)))) { 1520 reg_get_channel_cen(op_class_tbl, 1521 idx, 1522 NUM_20_MHZ_CHAN_IN_80_MHZ_CHAN, 1523 ¢er_chan); 1524 } else if (op_class_tbl->chan_spacing == BW_160_MHZ) { 1525 reg_get_channel_cen(op_class_tbl, 1526 idx, 1527 NUM_20_MHZ_CHAN_IN_160_MHZ_CHAN, 1528 ¢er_chan); 1529 } else if (reg_is_chan_320mhz(op_class_tbl->chan_spacing)) { 1530 reg_get_channel_cen(op_class_tbl, 1531 idx, 1532 NUM_20_MHZ_CHAN_IN_320_MHZ_CHAN, 1533 ¢er_chan); 1534 } else { 1535 center_chan = op_class_tbl->channels[*idx]; 1536 *idx = *idx + 1; 1537 } 1538 1539 return center_chan; 1540 } 1541 1542 static inline qdf_freq_t reg_get_nearest_primary_freq(uint16_t bw, 1543 qdf_freq_t cfi_freq, 1544 uint8_t op_class) 1545 { 1546 qdf_freq_t pri_freq; 1547 1548 if (bw <= BW_40_MHZ && op_class != OPCLS_132) { 1549 pri_freq = cfi_freq; 1550 } else { 1551 if (cfi_freq >= BW_10_MHZ) 1552 pri_freq = cfi_freq - BW_10_MHZ; 1553 else 1554 pri_freq = 0; 1555 } 1556 1557 return pri_freq; 1558 } 1559 1560 #ifdef WLAN_FEATURE_11BE 1561 /** 1562 * reg_is_chan_supported()- Check if given channel is supported based on its 1563 * freq provided 1564 * @pdev: Pointer to pdev 1565 * @pri_freq: Primary frequency of the input channel 1566 * @cfi_freq: cfi frequency of the input channel 1567 * @ch_width: Input channel width 1568 * @in_6g_pwr_type: 6g power type which decides 6G channel list lookup. 1569 * 1570 * Return: True if the channel is supported, else false 1571 */ 1572 static bool reg_is_chan_supported(struct wlan_objmgr_pdev *pdev, 1573 qdf_freq_t pri_freq, 1574 qdf_freq_t cfi_freq, 1575 enum phy_ch_width ch_width, 1576 enum supported_6g_pwr_types in_6g_pwr_mode) 1577 { 1578 struct reg_channel_list chan_list; 1579 qdf_freq_t center_320; 1580 struct ch_params ch_params = {0}; 1581 1582 center_320 = (ch_width == CH_WIDTH_320MHZ) ? cfi_freq : 0; 1583 reg_fill_channel_list_for_pwrmode(pdev, pri_freq, 0, 1584 ch_width, center_320, &chan_list, 1585 in_6g_pwr_mode, true); 1586 ch_params = chan_list.chan_param[0]; 1587 1588 if (ch_params.ch_width == ch_width) 1589 return true; 1590 1591 return false; 1592 } 1593 #else 1594 static bool reg_is_chan_supported(struct wlan_objmgr_pdev *pdev, 1595 qdf_freq_t pri_freq, 1596 qdf_freq_t cfi_freq, 1597 enum phy_ch_width ch_width, 1598 enum supported_6g_pwr_types in_6g_pwr_mode) 1599 { 1600 struct ch_params ch_params = {0}; 1601 1602 ch_params.ch_width = ch_width; 1603 reg_set_channel_params_for_freq(pdev, pri_freq, 0, &ch_params, true); 1604 if (ch_params.ch_width == ch_width) 1605 return true; 1606 1607 return false; 1608 } 1609 #endif 1610 1611 /** 1612 * reg_is_cfi_supported()- Check if given cfi is supported 1613 * @pdev: Pointer to pdev 1614 * @cfi_freq: cfi frequency 1615 * @bw: bandwidth 1616 * @op_class: op_class 1617 * @in_6g_pwr_type: 6g power type which decides 6G channel list lookup. 1618 * 1619 * Return: True if the cfi is supported, else false 1620 */ 1621 static bool reg_is_cfi_supported(struct wlan_objmgr_pdev *pdev, 1622 qdf_freq_t cfi_freq, 1623 uint16_t bw, 1624 uint8_t op_class, 1625 enum supported_6g_pwr_types in_6g_pwr_mode) 1626 { 1627 enum phy_ch_width ch_width; 1628 qdf_freq_t pri_freq; 1629 bool is_cfi_supported; 1630 1631 ch_width = reg_find_chwidth_from_bw(bw); 1632 pri_freq = reg_get_nearest_primary_freq(bw, cfi_freq, op_class); 1633 is_cfi_supported = reg_is_chan_supported(pdev, 1634 pri_freq, 1635 cfi_freq, 1636 ch_width, 1637 in_6g_pwr_mode); 1638 1639 return is_cfi_supported; 1640 } 1641 1642 /** 1643 * reg_get_cfis_from_opclassmap_for_6g()- Get channels from the opclass map 1644 * for 6GHz 1645 * @pdev: Pointer to pdev 1646 * @cap: Pointer to regdmn_ap_cap_opclass_t 1647 * @op_class_tbl: Pointer to op_class_tbl 1648 * @in_opclass_conf: input opclass configuration 1649 * Supported or not-supported by current HW mode 1650 * @in_6g_pwr_type: 6g power type which decides 6G channel list lookup. 1651 * 1652 * Populate channels from opclass map to regdmn_ap_cap_opclass_t as supported 1653 * and non-supported channels for 6Ghz. 1654 * 1655 * Return: void. 1656 */ 1657 static void reg_get_cfis_from_opclassmap_for_6g( 1658 struct wlan_objmgr_pdev *pdev, 1659 struct regdmn_ap_cap_opclass_t *cap, 1660 const struct reg_dmn_op_class_map_t *op_class_tbl, 1661 enum opclass_config in_opclass_conf, 1662 enum supported_6g_pwr_types in_6g_pwr_mode) 1663 { 1664 uint8_t n_sup_chans = 0, n_unsup_chans = 0, j; 1665 const struct c_freq_lst *p_cfi_lst = op_class_tbl->p_cfi_lst_obj; 1666 qdf_freq_t cfi_freq; 1667 qdf_freq_t start_freq = op_class_tbl->start_freq; 1668 uint16_t bw = op_class_tbl->chan_spacing; 1669 1670 for (j = 0; j < p_cfi_lst->num_cfis; j++) { 1671 uint8_t cfi = p_cfi_lst->p_cfis_arr[j]; 1672 bool is_cfi_supported; 1673 1674 cfi_freq = start_freq + FREQ_TO_CHAN_SCALE * cfi; 1675 is_cfi_supported = reg_is_cfi_supported(pdev, 1676 cfi_freq, 1677 bw, 1678 op_class_tbl->op_class, 1679 in_6g_pwr_mode); 1680 if (is_cfi_supported && 1681 (in_opclass_conf == OPCLASSES_SUPPORTED_BY_CUR_HWMODE || 1682 in_opclass_conf == OPCLASSES_SUPPORTED_BY_DOMAIN)) { 1683 cap->sup_chan_list[n_sup_chans++] = cfi; 1684 cap->num_supported_chan++; 1685 } else { 1686 cap->non_sup_chan_list[n_unsup_chans++] = cfi; 1687 cap->num_non_supported_chan++; 1688 } 1689 } 1690 } 1691 1692 static uint16_t reg_find_nearest_ieee_bw(uint16_t spacing) 1693 { 1694 #define SMALLEST_BW 20 1695 return (spacing / SMALLEST_BW) * SMALLEST_BW; 1696 } 1697 1698 /** 1699 * reg_get_cfis_from_opclassmap_for_non6g()- Get channels from the opclass map 1700 * for non-6GHz 1701 * @pdev: Pointer to pdev 1702 * @cap: Pointer to regdmn_ap_cap_opclass_t 1703 * @op_class_tbl: Pointer to op_class_tbl 1704 * @in_opclass_conf: input opclass configuration 1705 * Supported or not-supported by current HW mode 1706 * @in_6g_pwr_type: 6g power type which decides 6G channel list lookup. 1707 * 1708 * Populate channels from opclass map to regdmn_ap_cap_opclass_t as supported 1709 * and non-supported channels for non-6Ghz. 1710 * 1711 * Return: void. 1712 */ 1713 static void reg_get_cfis_from_opclassmap_for_non6g( 1714 struct wlan_objmgr_pdev *pdev, 1715 struct regdmn_ap_cap_opclass_t *cap, 1716 const struct reg_dmn_op_class_map_t *op_class_tbl, 1717 enum opclass_config in_opclass_conf, 1718 enum supported_6g_pwr_types in_6g_pwr_mode) 1719 { 1720 qdf_freq_t start_freq = op_class_tbl->start_freq; 1721 uint8_t chan_idx = 0, n_sup_chans = 0, n_unsup_chans = 0; 1722 1723 while (op_class_tbl->channels[chan_idx]) { 1724 uint8_t op_cls_chan; 1725 qdf_freq_t pri_freq; 1726 enum phy_ch_width ch_width; 1727 bool is_supported; 1728 uint16_t opcls_bw; 1729 1730 op_cls_chan = reg_get_chan_or_chan_center(op_class_tbl, 1731 &chan_idx); 1732 pri_freq = start_freq + FREQ_TO_CHAN_SCALE * op_cls_chan; 1733 opcls_bw = reg_find_nearest_ieee_bw(op_class_tbl->chan_spacing); 1734 ch_width = reg_find_chwidth_from_bw(opcls_bw); 1735 pri_freq = reg_get_nearest_primary_freq(opcls_bw, 1736 pri_freq, 1737 op_class_tbl->op_class); 1738 is_supported = reg_is_chan_supported(pdev, 1739 pri_freq, 1740 0, 1741 ch_width, 1742 in_6g_pwr_mode); 1743 1744 if (is_supported && 1745 (in_opclass_conf == OPCLASSES_SUPPORTED_BY_CUR_HWMODE || 1746 in_opclass_conf == OPCLASSES_SUPPORTED_BY_DOMAIN)) { 1747 cap->sup_chan_list[n_sup_chans++] = op_cls_chan; 1748 cap->num_supported_chan++; 1749 } else { 1750 cap->non_sup_chan_list[n_unsup_chans++] = op_cls_chan; 1751 cap->num_non_supported_chan++; 1752 } 1753 } 1754 } 1755 1756 /** 1757 * reg_get_channels_from_opclassmap()- Get channels from the opclass map 1758 * @pdev: Pointer to pdev 1759 * @reg_ap_cap: Pointer to reg_ap_cap 1760 * @index: Pointer to index of reg_ap_cap 1761 * @op_class_tbl: Pointer to op_class_tbl 1762 * @is_opclass_operable: Set true if opclass is operable, else set false 1763 * @in_opclass_conf: input opclass configuration 1764 * Supported or not-supported by current HW mode 1765 * @in_6g_pwr_type: 6g power type which decides 6G channel list lookup. 1766 * 1767 * Populate channels from opclass map to reg_ap_cap as supported and 1768 * non-supported channels. 1769 * 1770 * Return: void. 1771 */ 1772 static void 1773 reg_get_channels_from_opclassmap( 1774 struct wlan_objmgr_pdev *pdev, 1775 struct regdmn_ap_cap_opclass_t *reg_ap_cap, 1776 uint8_t index, 1777 const struct reg_dmn_op_class_map_t *op_class_tbl, 1778 bool *is_opclass_operable, 1779 enum opclass_config in_opclass_conf, 1780 enum supported_6g_pwr_types in_6g_pwr_mode) 1781 { 1782 struct regdmn_ap_cap_opclass_t *cap = ®_ap_cap[index]; 1783 1784 if (reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) { 1785 reg_get_cfis_from_opclassmap_for_6g(pdev, 1786 cap, 1787 op_class_tbl, 1788 in_opclass_conf, 1789 in_6g_pwr_mode); 1790 } else { 1791 reg_get_cfis_from_opclassmap_for_non6g(pdev, 1792 cap, 1793 op_class_tbl, 1794 in_opclass_conf, 1795 in_6g_pwr_mode); 1796 } 1797 1798 if (cap->num_supported_chan >= 1) 1799 *is_opclass_operable = true; 1800 } 1801 1802 QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev, 1803 struct regdmn_ap_cap_opclass_t *reg_ap_cap, 1804 uint8_t *n_opclasses, 1805 uint8_t max_supp_op_class, 1806 bool global_tbl_lookup, 1807 enum supported_6g_pwr_types in_6g_pwr_mode) 1808 { 1809 uint8_t max_reg_power = 0; 1810 const struct reg_dmn_op_class_map_t *op_class_tbl; 1811 uint8_t index = 0; 1812 enum opclass_config opclass_conf = OPCLASSES_SUPPORTED_BY_DOMAIN; 1813 1814 if (global_tbl_lookup) 1815 op_class_tbl = global_op_class; 1816 else 1817 reg_get_op_class_tbl_by_chan_map(&op_class_tbl); 1818 1819 max_reg_power = reg_get_max_tx_power(pdev); 1820 1821 while (op_class_tbl->op_class && (index < max_supp_op_class)) { 1822 bool is_opclass_operable = false; 1823 1824 qdf_mem_zero(reg_ap_cap[index].sup_chan_list, 1825 REG_MAX_CHANNELS_PER_OPERATING_CLASS); 1826 reg_ap_cap[index].num_supported_chan = 0; 1827 qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list, 1828 REG_MAX_CHANNELS_PER_OPERATING_CLASS); 1829 reg_ap_cap[index].num_non_supported_chan = 0; 1830 reg_get_channels_from_opclassmap(pdev, 1831 reg_ap_cap, 1832 index, 1833 op_class_tbl, 1834 &is_opclass_operable, 1835 opclass_conf, 1836 in_6g_pwr_mode); 1837 if (is_opclass_operable) { 1838 reg_ap_cap[index].op_class = op_class_tbl->op_class; 1839 reg_ap_cap[index].ch_width = 1840 op_class_tbl->chan_spacing; 1841 reg_ap_cap[index].start_freq = 1842 op_class_tbl->start_freq; 1843 reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power; 1844 reg_ap_cap[index].behav_limit = 1845 op_class_tbl->behav_limit; 1846 index++; 1847 } 1848 1849 op_class_tbl++; 1850 } 1851 1852 *n_opclasses = index; 1853 1854 return QDF_STATUS_SUCCESS; 1855 } 1856 1857 bool reg_is_6ghz_op_class(struct wlan_objmgr_pdev *pdev, uint8_t op_class) 1858 { 1859 return ((op_class >= MIN_6GHZ_OPER_CLASS) && 1860 (op_class <= MAX_6GHZ_OPER_CLASS)); 1861 } 1862 1863 /** 1864 * reg_is_opclass_band_found - Check if the input opclass is 2G or 5G. 1865 * 1866 * @country - Pointer to country. 1867 * @op_class - Operating class. 1868 * @bandmask = Bitmask for band. 1869 * 1870 * Return : Return true if the input opclass' band (2Ghz or 5Ghz) matches one 1871 * of bandmask's band. 1872 */ 1873 static bool reg_is_opclass_band_found(const uint8_t *country, 1874 uint8_t op_class, 1875 uint8_t bandmask) 1876 { 1877 const struct reg_dmn_op_class_map_t *op_class_tbl; 1878 1879 op_class_tbl = reg_get_class_from_country((uint8_t *)country); 1880 1881 while (op_class_tbl && op_class_tbl->op_class) { 1882 if (op_class_tbl->op_class == op_class) { 1883 qdf_freq_t freq = op_class_tbl->start_freq + 1884 (op_class_tbl->channels[0] * FREQ_TO_CHAN_SCALE); 1885 1886 if ((bandmask & BIT(REG_BAND_5G)) && 1887 REG_IS_5GHZ_FREQ(freq)) 1888 return true; 1889 1890 if ((bandmask & BIT(REG_BAND_2G)) && 1891 REG_IS_24GHZ_CH_FREQ(freq)) 1892 return true; 1893 1894 return false; 1895 } 1896 1897 op_class_tbl++; 1898 } 1899 1900 reg_err_rl("Opclass %d is not found", op_class); 1901 1902 return false; 1903 } 1904 1905 bool reg_is_5ghz_op_class(const uint8_t *country, uint8_t op_class) 1906 { 1907 return reg_is_opclass_band_found(country, op_class, BIT(REG_BAND_5G)); 1908 } 1909 1910 bool reg_is_2ghz_op_class(const uint8_t *country, uint8_t op_class) 1911 { 1912 return reg_is_opclass_band_found(country, op_class, BIT(REG_BAND_2G)); 1913 } 1914 1915 /** 1916 * reg_convert_chan_spacing_to_width() - Convert channel spacing to 1917 * channel width. 1918 * @chan_spacing: Channel spacing 1919 * @opclass_chwidth: Opclass channel width 1920 * Return - None 1921 */ 1922 #ifdef WLAN_FEATURE_11BE 1923 static void reg_convert_chan_spacing_to_width(uint16_t chan_spacing, 1924 uint16_t *opclass_chwidth) 1925 { 1926 switch (chan_spacing) { 1927 case BW_20_MHZ: 1928 case BW_25_MHZ: 1929 *opclass_chwidth = BW_20_MHZ; 1930 break; 1931 case BW_40_MHZ: 1932 *opclass_chwidth = BW_40_MHZ; 1933 break; 1934 case BW_80_MHZ: 1935 *opclass_chwidth = BW_80_MHZ; 1936 break; 1937 case BW_160_MHZ: 1938 *opclass_chwidth = BW_160_MHZ; 1939 break; 1940 case BW_320_MHZ: 1941 *opclass_chwidth = BW_320_MHZ; 1942 break; 1943 default: 1944 *opclass_chwidth = 0; 1945 } 1946 } 1947 #else 1948 static void reg_convert_chan_spacing_to_width(uint16_t chan_spacing, 1949 uint16_t *opclass_chwidth) 1950 { 1951 switch (chan_spacing) { 1952 case BW_20_MHZ: 1953 case BW_25_MHZ: 1954 *opclass_chwidth = BW_20_MHZ; 1955 break; 1956 case BW_40_MHZ: 1957 *opclass_chwidth = BW_40_MHZ; 1958 break; 1959 case BW_80_MHZ: 1960 *opclass_chwidth = BW_80_MHZ; 1961 break; 1962 case BW_160_MHZ: 1963 *opclass_chwidth = BW_160_MHZ; 1964 break; 1965 default: 1966 *opclass_chwidth = 0; 1967 } 1968 } 1969 #endif 1970 1971 QDF_STATUS 1972 reg_get_opclass_for_cur_hwmode(struct wlan_objmgr_pdev *pdev, 1973 struct regdmn_ap_cap_opclass_t *reg_ap_cap, 1974 uint8_t *n_opclasses, 1975 uint8_t max_supp_op_class, 1976 bool global_tbl_lookup, 1977 enum phy_ch_width max_chwidth, 1978 bool is_80p80_supp, 1979 enum supported_6g_pwr_types in_6g_pwr_mode) 1980 { 1981 uint8_t max_reg_power = 0; 1982 const struct reg_dmn_op_class_map_t *op_class_tbl; 1983 uint8_t index = 0; 1984 uint16_t out_width; 1985 1986 if (global_tbl_lookup) 1987 op_class_tbl = global_op_class; 1988 else 1989 reg_get_op_class_tbl_by_chan_map(&op_class_tbl); 1990 1991 max_reg_power = reg_get_max_tx_power(pdev); 1992 1993 out_width = reg_get_bw_value(max_chwidth); 1994 1995 while (op_class_tbl->op_class && (index < max_supp_op_class)) { 1996 bool is_opclass_operable = false; 1997 enum opclass_config opclass_in_config = 1998 OPCLASSES_SUPPORTED_BY_CUR_HWMODE; 1999 uint16_t opclass_width; 2000 2001 qdf_mem_zero(reg_ap_cap[index].sup_chan_list, 2002 REG_MAX_CHANNELS_PER_OPERATING_CLASS); 2003 reg_ap_cap[index].num_supported_chan = 0; 2004 qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list, 2005 REG_MAX_CHANNELS_PER_OPERATING_CLASS); 2006 reg_ap_cap[index].num_non_supported_chan = 0; 2007 2008 reg_convert_chan_spacing_to_width(op_class_tbl->chan_spacing, 2009 &opclass_width); 2010 2011 if ((opclass_width > out_width) || 2012 ((op_class_tbl->behav_limit == BIT(BEHAV_BW80_PLUS)) && 2013 !is_80p80_supp)) 2014 opclass_in_config = 2015 OPCLASSES_NOT_SUPPORTED_BY_CUR_HWMODE; 2016 2017 reg_get_channels_from_opclassmap(pdev, 2018 reg_ap_cap, 2019 index, 2020 op_class_tbl, 2021 &is_opclass_operable, 2022 opclass_in_config, 2023 in_6g_pwr_mode); 2024 2025 if (is_opclass_operable && opclass_in_config == 2026 OPCLASSES_SUPPORTED_BY_CUR_HWMODE) { 2027 reg_ap_cap[index].op_class = op_class_tbl->op_class; 2028 reg_ap_cap[index].ch_width = 2029 op_class_tbl->chan_spacing; 2030 reg_ap_cap[index].start_freq = 2031 op_class_tbl->start_freq; 2032 reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power; 2033 reg_ap_cap[index].behav_limit = 2034 op_class_tbl->behav_limit; 2035 index++; 2036 } 2037 op_class_tbl++; 2038 } 2039 2040 *n_opclasses = index; 2041 2042 return QDF_STATUS_SUCCESS; 2043 } 2044 #endif 2045