1 /* 2 * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 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 p_total_alloc1 = qdf_mem_malloc(total_alloc_size); 789 if (!p_total_alloc1) { 790 reg_err("out-of-memory"); 791 return QDF_STATUS_E_NOMEM; 792 } 793 794 /* Assign memory locations to each pointers */ 795 p_temp_alloc = p_total_alloc1; 796 797 l_opcls_lst = p_temp_alloc; 798 p_temp_alloc += opcls_lst_size; 799 800 l_chansize_lst = p_temp_alloc; 801 p_temp_alloc += chansize_lst_size; 802 803 arr_chan_lists = (uint8_t **)p_temp_alloc; 804 805 /* Fill arrays with opclasses and chanlist sizes */ 806 count = 0; 807 while (op_class_tbl && op_class_tbl->op_class) { 808 const struct c_freq_lst *p_lst; 809 810 p_lst = op_class_tbl->p_cfi_lst_obj; 811 if (p_lst && 812 reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) { 813 uint8_t n_supp_cfis = 0; 814 uint8_t j; 815 816 l_opcls_lst[count] = op_class_tbl->op_class; 817 for (j = 0; j < p_lst->num_cfis; j++) { 818 uint8_t cfi; 819 qdf_freq_t cfi_freq; 820 qdf_freq_t start_freq = op_class_tbl->start_freq; 821 uint16_t bw = op_class_tbl->chan_spacing; 822 823 cfi = p_lst->p_cfis_arr[j]; 824 cfi_freq = start_freq + 825 FREQ_TO_CHAN_SCALE * cfi; 826 if (reg_is_cfi_freq_in_ranges(cfi_freq, 827 bw, 828 p_frange_lst)) { 829 n_supp_cfis++; 830 } 831 } 832 l_chansize_lst[count] = n_supp_cfis; 833 count++; 834 } 835 op_class_tbl++; 836 } 837 838 /* Calculate total alloction size for the array */ 839 total_alloc_size = 0; 840 for (i = 0; i < *num_opclasses; i++) 841 total_alloc_size += l_chansize_lst[i] * sizeof(uint8_t *); 842 843 p_total_alloc2 = qdf_mem_malloc(total_alloc_size); 844 if (!p_total_alloc2) { 845 reg_err("out-of-memory"); 846 qdf_mem_free(p_total_alloc1); 847 return QDF_STATUS_E_NOMEM; 848 } 849 850 /* Assign memory locations to each list pointers */ 851 p_temp_alloc = p_total_alloc2; 852 for (i = 0; i < *num_opclasses; i++) { 853 if (!l_chansize_lst[i]) 854 arr_chan_lists[i] = NULL; 855 else 856 arr_chan_lists[i] = p_temp_alloc; 857 858 p_temp_alloc += l_chansize_lst[i] * sizeof(uint8_t *); 859 } 860 861 /* Fill the array with channel lists */ 862 reg_dmn_fill_6g_opcls_chan_lists(pdev, p_frange_lst, l_chansize_lst, arr_chan_lists); 863 864 *opclass_lst = l_opcls_lst; 865 *chansize_lst = l_chansize_lst; 866 *channel_lists = arr_chan_lists; 867 868 return QDF_STATUS_SUCCESS; 869 } 870 #endif /* CONFIG_AFC_SUPPORT */ 871 872 uint16_t reg_dmn_get_chanwidth_from_opclass(uint8_t *country, uint8_t channel, 873 uint8_t opclass) 874 { 875 const struct reg_dmn_op_class_map_t *class; 876 uint16_t i; 877 878 class = reg_get_class_from_country(country); 879 880 while (class->op_class) { 881 if (opclass == class->op_class) { 882 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 883 class->channels[i]); i++) { 884 if (channel == class->channels[i]) 885 return class->chan_spacing; 886 } 887 } 888 class++; 889 } 890 891 return 0; 892 } 893 894 uint16_t reg_dmn_get_chanwidth_from_opclass_auto(uint8_t *country, 895 uint8_t channel, 896 uint8_t opclass) 897 { 898 uint16_t ret; 899 uint8_t global_country[REG_ALPHA2_LEN + 1]; 900 901 ret = reg_dmn_get_chanwidth_from_opclass(country, channel, opclass); 902 903 if (!ret) { 904 global_country[2] = OP_CLASS_GLOBAL; 905 ret = reg_dmn_get_chanwidth_from_opclass(global_country, 906 channel, opclass); 907 } 908 909 return ret; 910 } 911 912 uint16_t reg_dmn_get_opclass_from_channel(uint8_t *country, uint8_t channel, 913 uint8_t offset) 914 { 915 const struct reg_dmn_op_class_map_t *class = NULL; 916 uint16_t i = 0; 917 918 class = reg_get_class_from_country(country); 919 while (class && class->op_class) { 920 if ((offset == class->offset) || (offset == BWALL)) { 921 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 922 class->channels[i]); i++) { 923 if (channel == class->channels[i]) 924 return class->op_class; 925 } 926 } 927 class++; 928 } 929 930 return 0; 931 } 932 933 uint8_t reg_dmn_get_opclass_from_freq_width(uint8_t *country, 934 qdf_freq_t freq, 935 uint16_t ch_width, 936 uint16_t behav_limit) 937 { 938 const struct reg_dmn_op_class_map_t *op_class_tbl = NULL; 939 uint16_t i = 0; 940 941 op_class_tbl = reg_get_class_from_country(country); 942 943 while (op_class_tbl && op_class_tbl->op_class) { 944 if (op_class_tbl->chan_spacing == ch_width) { 945 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 946 op_class_tbl->channels[i]); i++) { 947 if ((op_class_tbl->start_freq + 948 (FREQ_TO_CHAN_SCALE * 949 op_class_tbl->channels[i]) == freq) && 950 (behav_limit & op_class_tbl->behav_limit)) { 951 return op_class_tbl->op_class; 952 } 953 } 954 } 955 op_class_tbl++; 956 } 957 958 return 0; 959 } 960 961 static void 962 reg_get_band_cap_from_chan_set(const struct reg_dmn_op_class_map_t 963 *op_class_tbl, 964 uint8_t *supported_band) 965 { 966 qdf_freq_t chan_freq = op_class_tbl->start_freq + 967 (op_class_tbl->channels[0] * 968 FREQ_TO_CHAN_SCALE); 969 970 if (reg_is_24ghz_ch_freq(chan_freq)) 971 *supported_band |= BIT(REG_BAND_2G); 972 else if (reg_is_5ghz_ch_freq(chan_freq)) 973 *supported_band |= BIT(REG_BAND_5G); 974 else if (reg_is_6ghz_chan_freq(chan_freq)) 975 *supported_band |= BIT(REG_BAND_6G); 976 else 977 reg_err_rl("Unknown band"); 978 } 979 980 uint8_t reg_get_band_cap_from_op_class(const uint8_t *country, 981 uint8_t num_of_opclass, 982 const uint8_t *opclass) 983 { 984 const struct reg_dmn_op_class_map_t *op_class_tbl; 985 uint8_t supported_band = 0, opclassidx; 986 987 op_class_tbl = reg_get_class_from_country(country); 988 989 while (op_class_tbl && op_class_tbl->op_class) { 990 for (opclassidx = 0; opclassidx < num_of_opclass; 991 opclassidx++) { 992 if (op_class_tbl->op_class == opclass[opclassidx]) { 993 reg_get_band_cap_from_chan_set(op_class_tbl, 994 &supported_band); 995 } 996 } 997 op_class_tbl++; 998 } 999 1000 if (!supported_band) 1001 reg_err_rl("None of the operating classes is found"); 1002 1003 return supported_band; 1004 } 1005 1006 void reg_dmn_print_channels_in_opclass(uint8_t *country, uint8_t op_class) 1007 { 1008 const struct reg_dmn_op_class_map_t *class = NULL; 1009 uint16_t i = 0; 1010 1011 class = reg_get_class_from_country(country); 1012 1013 if (!class) { 1014 reg_err("class is NULL"); 1015 return; 1016 } 1017 1018 while (class->op_class) { 1019 if (class->op_class == op_class) { 1020 for (i = 0; 1021 (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1022 class->channels[i]); i++) { 1023 reg_debug("Valid channel(%d) in requested RC(%d)", 1024 class->channels[i], op_class); 1025 } 1026 break; 1027 } 1028 class++; 1029 } 1030 if (!class->op_class) 1031 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 1032 "Invalid requested RC (%d)", op_class); 1033 } 1034 1035 uint16_t reg_dmn_set_curr_opclasses(uint8_t num_classes, uint8_t *class) 1036 { 1037 uint8_t i; 1038 1039 if (num_classes > REG_MAX_SUPP_OPER_CLASSES) { 1040 reg_err("invalid num classes %d", num_classes); 1041 return 0; 1042 } 1043 1044 for (i = 0; i < num_classes; i++) 1045 reg_dmn_curr_supp_opp_classes.classes[i] = class[i]; 1046 1047 reg_dmn_curr_supp_opp_classes.num_classes = num_classes; 1048 1049 return 0; 1050 } 1051 1052 uint16_t reg_dmn_get_curr_opclasses(uint8_t *num_classes, uint8_t *class) 1053 { 1054 uint8_t i; 1055 1056 if (!num_classes || !class) { 1057 reg_err("either num_classes or class is null"); 1058 return 0; 1059 } 1060 1061 for (i = 0; i < reg_dmn_curr_supp_opp_classes.num_classes; i++) 1062 class[i] = reg_dmn_curr_supp_opp_classes.classes[i]; 1063 1064 *num_classes = reg_dmn_curr_supp_opp_classes.num_classes; 1065 1066 return 0; 1067 } 1068 1069 #ifdef CONFIG_CHAN_FREQ_API 1070 /** 1071 * reg_find_opclass_absent_in_ctry_opclss_tables() - Check Global Opclass table 1072 * when Opclass is not present in specific country. 1073 * @pdev - Pointer to pdev 1074 * @freq - Destination Frequency 1075 * @chan_width- Channel Width 1076 * @global_tbl_lookup - Global Table Lookup 1077 * @behav_limit - Behav Limit 1078 * @op_class - Pointer to Opclass 1079 * @chan_num - Pointer to Channel 1080 * 1081 * Return: Void 1082 */ 1083 static void 1084 reg_find_opclass_absent_in_ctry_opclss_tables(struct wlan_objmgr_pdev *pdev, 1085 qdf_freq_t freq, 1086 uint16_t chan_width, 1087 bool global_tbl_lookup, 1088 uint16_t behav_limit, 1089 uint8_t *op_class, 1090 uint8_t *chan_num) 1091 { 1092 if (!global_tbl_lookup && !*op_class) { 1093 global_tbl_lookup = true; 1094 reg_freq_width_to_chan_op_class(pdev, freq, 1095 chan_width, 1096 global_tbl_lookup, 1097 behav_limit, 1098 op_class, 1099 chan_num); 1100 } 1101 } 1102 1103 static bool 1104 reg_is_country_opclass_global(struct wlan_objmgr_pdev *pdev) 1105 { 1106 struct wlan_lmac_if_reg_tx_ops *reg_tx_ops; 1107 struct wlan_objmgr_psoc *psoc; 1108 uint8_t opclass_tbl_idx; 1109 1110 psoc = wlan_pdev_get_psoc(pdev); 1111 if (!psoc) { 1112 reg_err("psoc is NULL"); 1113 return false; 1114 } 1115 1116 reg_tx_ops = reg_get_psoc_tx_ops(psoc); 1117 if (!reg_tx_ops) { 1118 reg_err("reg_tx_ops is NULL"); 1119 return false; 1120 } 1121 1122 if (reg_tx_ops->get_opclass_tbl_idx) { 1123 reg_tx_ops->get_opclass_tbl_idx(pdev, &opclass_tbl_idx); 1124 1125 if (opclass_tbl_idx == OP_CLASS_GLOBAL) 1126 return true; 1127 } 1128 1129 return false; 1130 } 1131 1132 void reg_freq_width_to_chan_op_class_auto(struct wlan_objmgr_pdev *pdev, 1133 qdf_freq_t freq, 1134 uint16_t chan_width, 1135 bool global_tbl_lookup, 1136 uint16_t behav_limit, 1137 uint8_t *op_class, 1138 uint8_t *chan_num) 1139 { 1140 if (reg_freq_to_band(freq) == REG_BAND_6G) { 1141 global_tbl_lookup = true; 1142 if (chan_width == BW_40_MHZ) 1143 behav_limit = BIT(BEHAV_NONE); 1144 } else if (reg_is_5dot9_ghz_freq(pdev, freq)) { 1145 global_tbl_lookup = true; 1146 } else { 1147 global_tbl_lookup = reg_is_country_opclass_global(pdev); 1148 } 1149 1150 *op_class = 0; 1151 reg_freq_width_to_chan_op_class(pdev, freq, 1152 chan_width, 1153 global_tbl_lookup, 1154 behav_limit, 1155 op_class, 1156 chan_num); 1157 reg_find_opclass_absent_in_ctry_opclss_tables(pdev, freq, 1158 chan_width, 1159 global_tbl_lookup, 1160 behav_limit, 1161 op_class, 1162 chan_num); 1163 } 1164 1165 void reg_freq_width_to_chan_op_class(struct wlan_objmgr_pdev *pdev, 1166 qdf_freq_t freq, 1167 uint16_t chan_width, 1168 bool global_tbl_lookup, 1169 uint16_t behav_limit, 1170 uint8_t *op_class, 1171 uint8_t *chan_num) 1172 { 1173 const struct reg_dmn_op_class_map_t *op_class_tbl; 1174 enum channel_enum chan_enum; 1175 uint16_t i; 1176 1177 chan_enum = reg_get_chan_enum_for_freq(freq); 1178 1179 if (reg_is_chan_enum_invalid(chan_enum)) { 1180 reg_err_rl("Invalid chan enum %d", chan_enum); 1181 return; 1182 } 1183 1184 if (global_tbl_lookup) { 1185 op_class_tbl = global_op_class; 1186 } else { 1187 if (channel_map == channel_map_us) 1188 op_class_tbl = us_op_class; 1189 else if (channel_map == channel_map_eu) 1190 op_class_tbl = euro_op_class; 1191 else if (channel_map == channel_map_china) 1192 op_class_tbl = china_op_class; 1193 else if (channel_map == channel_map_jp) 1194 op_class_tbl = japan_op_class; 1195 else 1196 op_class_tbl = global_op_class; 1197 } 1198 1199 while (op_class_tbl->op_class) { 1200 if (op_class_tbl->chan_spacing >= chan_width) { 1201 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1202 op_class_tbl->channels[i]); i++) { 1203 if ((op_class_tbl->start_freq + 1204 FREQ_TO_CHAN_SCALE * 1205 op_class_tbl->channels[i] == freq) && 1206 (behav_limit & op_class_tbl->behav_limit || 1207 behav_limit == BIT(BEHAV_NONE))) { 1208 *chan_num = op_class_tbl->channels[i]; 1209 *op_class = op_class_tbl->op_class; 1210 return; 1211 } 1212 } 1213 } 1214 op_class_tbl++; 1215 } 1216 1217 reg_err_rl("no op class for frequency %d", freq); 1218 } 1219 1220 void reg_freq_to_chan_op_class(struct wlan_objmgr_pdev *pdev, 1221 qdf_freq_t freq, 1222 bool global_tbl_lookup, 1223 uint16_t behav_limit, 1224 uint8_t *op_class, 1225 uint8_t *chan_num) 1226 { 1227 enum channel_enum chan_enum; 1228 struct regulatory_channel *cur_chan_list; 1229 struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj; 1230 struct ch_params chan_params = {0}; 1231 1232 pdev_priv_obj = reg_get_pdev_obj(pdev); 1233 1234 if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) { 1235 reg_err_rl("NULL pdev reg obj"); 1236 return; 1237 } 1238 1239 cur_chan_list = pdev_priv_obj->cur_chan_list; 1240 1241 chan_enum = reg_get_chan_enum_for_freq(freq); 1242 1243 if (reg_is_chan_enum_invalid(chan_enum)) { 1244 reg_err_rl("Invalid chan enum %d", chan_enum); 1245 return; 1246 } 1247 1248 chan_params.ch_width = CH_WIDTH_MAX; 1249 reg_set_channel_params_for_pwrmode(pdev, freq, 1250 0, 1251 &chan_params, 1252 REG_CURRENT_PWR_MODE, true); 1253 1254 reg_freq_width_to_chan_op_class(pdev, freq, 1255 reg_get_bw_value(chan_params.ch_width), 1256 global_tbl_lookup, 1257 behav_limit, 1258 op_class, 1259 chan_num); 1260 } 1261 1262 bool reg_is_freq_in_country_opclass(struct wlan_objmgr_pdev *pdev, 1263 const uint8_t country[3], 1264 uint8_t op_class, 1265 qdf_freq_t chan_freq) 1266 { 1267 const struct reg_dmn_op_class_map_t *op_class_tbl; 1268 uint8_t i; 1269 1270 op_class_tbl = reg_get_class_from_country((uint8_t *)country); 1271 1272 while (op_class_tbl && op_class_tbl->op_class) { 1273 if (op_class_tbl->op_class == op_class) { 1274 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1275 op_class_tbl->channels[i]); i++) { 1276 if (op_class_tbl->channels[i] * 1277 FREQ_TO_CHAN_SCALE + 1278 op_class_tbl->start_freq == chan_freq) 1279 return true; 1280 } 1281 } 1282 op_class_tbl++; 1283 } 1284 return false; 1285 } 1286 1287 #endif 1288 1289 uint16_t reg_get_op_class_width(struct wlan_objmgr_pdev *pdev, 1290 uint8_t op_class, 1291 bool global_tbl_lookup) 1292 { 1293 const struct reg_dmn_op_class_map_t *op_class_tbl; 1294 1295 if (global_tbl_lookup) { 1296 op_class_tbl = global_op_class; 1297 } else { 1298 if (channel_map == channel_map_us) 1299 op_class_tbl = us_op_class; 1300 else if (channel_map == channel_map_eu) 1301 op_class_tbl = euro_op_class; 1302 else if (channel_map == channel_map_china) 1303 op_class_tbl = china_op_class; 1304 else if (channel_map == channel_map_jp) 1305 op_class_tbl = japan_op_class; 1306 else 1307 op_class_tbl = global_op_class; 1308 } 1309 1310 while (op_class_tbl->op_class) { 1311 if (op_class_tbl->op_class == op_class) 1312 return op_class_tbl->chan_spacing; 1313 op_class_tbl++; 1314 } 1315 1316 return 0; 1317 } 1318 1319 uint16_t reg_chan_opclass_to_freq(uint8_t chan, 1320 uint8_t op_class, 1321 bool global_tbl_lookup) 1322 { 1323 const struct reg_dmn_op_class_map_t *op_class_tbl = NULL; 1324 uint8_t i = 0; 1325 1326 if (global_tbl_lookup) { 1327 op_class_tbl = global_op_class; 1328 } else { 1329 if (channel_map == channel_map_global) { 1330 op_class_tbl = global_op_class; 1331 } else if (channel_map == channel_map_us) { 1332 op_class_tbl = us_op_class; 1333 } else if (channel_map == channel_map_eu) { 1334 op_class_tbl = euro_op_class; 1335 } else if (channel_map == channel_map_china) { 1336 op_class_tbl = china_op_class; 1337 } else if (channel_map == channel_map_jp) { 1338 op_class_tbl = japan_op_class; 1339 } else { 1340 reg_err_rl("Invalid channel map"); 1341 return 0; 1342 } 1343 } 1344 1345 while (op_class_tbl->op_class) { 1346 if (op_class_tbl->op_class == op_class) { 1347 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1348 op_class_tbl->channels[i]); i++) { 1349 if (op_class_tbl->channels[i] == chan) { 1350 chan = op_class_tbl->channels[i]; 1351 return op_class_tbl->start_freq + 1352 (chan * FREQ_TO_CHAN_SCALE); 1353 } 1354 } 1355 reg_err_rl("Channel not found"); 1356 return 0; 1357 } 1358 op_class_tbl++; 1359 } 1360 reg_err_rl("Invalid opclass"); 1361 return 0; 1362 } 1363 1364 qdf_freq_t reg_chan_opclass_to_freq_auto(uint8_t chan, uint8_t op_class, 1365 bool global_tbl_lookup) 1366 { 1367 if ((op_class >= MIN_6GHZ_OPER_CLASS) && 1368 (op_class <= MAX_6GHZ_OPER_CLASS)) { 1369 global_tbl_lookup = true; 1370 } else { 1371 qdf_freq_t freq = reg_chan_opclass_to_freq(chan, 1372 op_class, 1373 global_tbl_lookup); 1374 if (freq) 1375 return freq; 1376 global_tbl_lookup = true; 1377 } 1378 1379 return reg_chan_opclass_to_freq(chan, op_class, global_tbl_lookup); 1380 } 1381 1382 #ifdef HOST_OPCLASS_EXT 1383 qdf_freq_t reg_country_chan_opclass_to_freq(struct wlan_objmgr_pdev *pdev, 1384 const uint8_t country[3], 1385 uint8_t chan, uint8_t op_class, 1386 bool strict) 1387 { 1388 const struct reg_dmn_op_class_map_t *op_class_tbl, *op_class_tbl_org; 1389 uint16_t i; 1390 1391 if (reg_is_6ghz_op_class(pdev, op_class)) 1392 op_class_tbl_org = global_op_class; 1393 else 1394 op_class_tbl_org = 1395 reg_get_class_from_country((uint8_t *)country); 1396 op_class_tbl = op_class_tbl_org; 1397 while (op_class_tbl && op_class_tbl->op_class) { 1398 if (op_class_tbl->op_class == op_class) { 1399 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1400 op_class_tbl->channels[i]); i++) { 1401 if (op_class_tbl->channels[i] == chan) 1402 return op_class_tbl->start_freq + 1403 (chan * FREQ_TO_CHAN_SCALE); 1404 } 1405 } 1406 op_class_tbl++; 1407 } 1408 reg_debug_rl("Not found ch %d in op class %d ch list, strict %d", 1409 chan, op_class, strict); 1410 if (strict) 1411 return 0; 1412 1413 op_class_tbl = op_class_tbl_org; 1414 while (op_class_tbl && op_class_tbl->op_class) { 1415 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1416 op_class_tbl->channels[i]); i++) { 1417 if (op_class_tbl->channels[i] == chan) 1418 return op_class_tbl->start_freq + 1419 (chan * FREQ_TO_CHAN_SCALE); 1420 } 1421 op_class_tbl++; 1422 } 1423 reg_debug_rl("Got invalid freq 0 for ch %d", chan); 1424 1425 return 0; 1426 } 1427 #endif 1428 1429 static void 1430 reg_get_op_class_tbl_by_chan_map(const struct 1431 reg_dmn_op_class_map_t **op_class_tbl) 1432 { 1433 if (channel_map == channel_map_us) 1434 *op_class_tbl = us_op_class; 1435 else if (channel_map == channel_map_eu) 1436 *op_class_tbl = euro_op_class; 1437 else if (channel_map == channel_map_china) 1438 *op_class_tbl = china_op_class; 1439 else if (channel_map == channel_map_jp) 1440 *op_class_tbl = japan_op_class; 1441 else 1442 *op_class_tbl = global_op_class; 1443 } 1444 1445 /** 1446 * reg_get_channel_cen - Calculate central channel in the channel set. 1447 * 1448 * @op_class_tbl - Pointer to op_class_tbl. 1449 * @idx - Pointer to channel index. 1450 * @num_channels - Number of channels. 1451 * @center_chan - Pointer to center channel number 1452 * 1453 * Return : void 1454 */ 1455 static void reg_get_channel_cen(const struct 1456 reg_dmn_op_class_map_t *op_class_tbl, 1457 uint8_t *idx, 1458 uint8_t num_channels, 1459 uint8_t *center_chan) 1460 { 1461 uint8_t i; 1462 uint16_t new_chan = 0; 1463 1464 for (i = *idx; i < (*idx + num_channels); i++) 1465 new_chan += op_class_tbl->channels[i]; 1466 1467 new_chan = new_chan / num_channels; 1468 *center_chan = new_chan; 1469 *idx = *idx + num_channels; 1470 } 1471 1472 /** 1473 * reg_is_chan_320mhz() - Return true if the chan width is 320MHZ, 1474 * false otherwise. 1475 * @chan_spacing: Channel spacing in MHZ. 1476 * 1477 * Return: true if chan_width is 320, false otherwise. 1478 */ 1479 #ifdef WLAN_FEATURE_11BE 1480 static bool reg_is_chan_320mhz(uint16_t chan_spacing) 1481 { 1482 if (chan_spacing == BW_320_MHZ) 1483 return true; 1484 return false; 1485 } 1486 #else 1487 static bool reg_is_chan_320mhz(uint16_t chan_spacing) 1488 { 1489 return false; 1490 } 1491 #endif 1492 1493 /** 1494 * reg_get_chan_or_chan_center - Calculate central channel in the channel set. 1495 * 1496 * @op_class_tbl - Pointer to op_class_tbl. 1497 * @idx - Pointer to channel index. 1498 * 1499 * Return : Center channel number 1500 */ 1501 static uint8_t reg_get_chan_or_chan_center(const struct 1502 reg_dmn_op_class_map_t *op_class_tbl, 1503 uint8_t *idx) 1504 { 1505 uint8_t center_chan; 1506 1507 if (((op_class_tbl->chan_spacing == BW_80_MHZ) && 1508 (op_class_tbl->behav_limit == BIT(BEHAV_NONE))) || 1509 ((op_class_tbl->chan_spacing == BW_80_MHZ) && 1510 (op_class_tbl->behav_limit == BIT(BEHAV_BW80_PLUS)))) { 1511 reg_get_channel_cen(op_class_tbl, 1512 idx, 1513 NUM_20_MHZ_CHAN_IN_80_MHZ_CHAN, 1514 ¢er_chan); 1515 } else if (op_class_tbl->chan_spacing == BW_160_MHZ) { 1516 reg_get_channel_cen(op_class_tbl, 1517 idx, 1518 NUM_20_MHZ_CHAN_IN_160_MHZ_CHAN, 1519 ¢er_chan); 1520 } else if (reg_is_chan_320mhz(op_class_tbl->chan_spacing)) { 1521 reg_get_channel_cen(op_class_tbl, 1522 idx, 1523 NUM_20_MHZ_CHAN_IN_320_MHZ_CHAN, 1524 ¢er_chan); 1525 } else { 1526 center_chan = op_class_tbl->channels[*idx]; 1527 *idx = *idx + 1; 1528 } 1529 1530 return center_chan; 1531 } 1532 1533 static inline qdf_freq_t reg_get_nearest_primary_freq(uint16_t bw, 1534 qdf_freq_t cfi_freq, 1535 uint8_t op_class) 1536 { 1537 qdf_freq_t pri_freq; 1538 1539 if (bw <= BW_40_MHZ && op_class != OPCLS_132) { 1540 pri_freq = cfi_freq; 1541 } else { 1542 if (cfi_freq >= BW_10_MHZ) 1543 pri_freq = cfi_freq - BW_10_MHZ; 1544 else 1545 pri_freq = 0; 1546 } 1547 1548 return pri_freq; 1549 } 1550 1551 #ifdef WLAN_FEATURE_11BE 1552 /** 1553 * reg_is_chan_supported()- Check if given channel is supported based on its 1554 * freq provided 1555 * @pdev: Pointer to pdev 1556 * @pri_freq: Primary frequency of the input channel 1557 * @cfi_freq: cfi frequency of the input channel 1558 * @ch_width: Input channel width 1559 * 1560 * Return: True if the channel is supported, else false 1561 */ 1562 static bool reg_is_chan_supported(struct wlan_objmgr_pdev *pdev, 1563 qdf_freq_t pri_freq, 1564 qdf_freq_t cfi_freq, 1565 enum phy_ch_width ch_width) 1566 { 1567 struct reg_channel_list chan_list; 1568 qdf_freq_t center_320; 1569 struct ch_params ch_params = {0}; 1570 1571 center_320 = (ch_width == CH_WIDTH_320MHZ) ? cfi_freq : 0; 1572 reg_fill_channel_list(pdev, 1573 pri_freq, 1574 0, 1575 ch_width, 1576 center_320, 1577 &chan_list, true); 1578 ch_params = chan_list.chan_param[0]; 1579 1580 if (ch_params.ch_width == ch_width) 1581 return true; 1582 1583 return false; 1584 } 1585 #else 1586 static bool reg_is_chan_supported(struct wlan_objmgr_pdev *pdev, 1587 qdf_freq_t pri_freq, 1588 qdf_freq_t cfi_freq, 1589 enum phy_ch_width ch_width) 1590 { 1591 struct ch_params ch_params = {0}; 1592 1593 ch_params.ch_width = ch_width; 1594 reg_set_channel_params_for_freq(pdev, pri_freq, 0, &ch_params, true); 1595 if (ch_params.ch_width == ch_width) 1596 return true; 1597 1598 return false; 1599 } 1600 #endif 1601 1602 /** 1603 * reg_is_cfi_supported()- Check if given cfi is supported 1604 * @pdev: Pointer to pdev 1605 * @cfi_freq: cfi frequency 1606 * @bw: bandwidth 1607 * 1608 * Return: True if the cfi is supported, else false 1609 */ 1610 static bool reg_is_cfi_supported(struct wlan_objmgr_pdev *pdev, 1611 qdf_freq_t cfi_freq, 1612 uint16_t bw, 1613 uint8_t op_class) 1614 { 1615 enum phy_ch_width ch_width; 1616 qdf_freq_t pri_freq; 1617 bool is_cfi_supported; 1618 1619 ch_width = reg_find_chwidth_from_bw(bw); 1620 pri_freq = reg_get_nearest_primary_freq(bw, cfi_freq, op_class); 1621 is_cfi_supported = reg_is_chan_supported(pdev, 1622 pri_freq, 1623 cfi_freq, 1624 ch_width); 1625 1626 return is_cfi_supported; 1627 } 1628 1629 /** 1630 * reg_get_cfis_from_opclassmap_for_6g()- Get channels from the opclass map 1631 * for 6GHz 1632 * @pdev: Pointer to pdev 1633 * @cap: Pointer to regdmn_ap_cap_opclass_t 1634 * @op_class_tbl: Pointer to op_class_tbl 1635 * @in_opclass_conf: input opclass configuration 1636 * Supported or not-supported by current HW mode 1637 * 1638 * Populate channels from opclass map to regdmn_ap_cap_opclass_t as supported 1639 * and non-supported channels for 6Ghz. 1640 * 1641 * Return: void. 1642 */ 1643 static void reg_get_cfis_from_opclassmap_for_6g( 1644 struct wlan_objmgr_pdev *pdev, 1645 struct regdmn_ap_cap_opclass_t *cap, 1646 const struct reg_dmn_op_class_map_t *op_class_tbl, 1647 enum opclass_config in_opclass_conf) 1648 { 1649 uint8_t n_sup_chans = 0, n_unsup_chans = 0, j; 1650 const struct c_freq_lst *p_cfi_lst = op_class_tbl->p_cfi_lst_obj; 1651 qdf_freq_t cfi_freq; 1652 qdf_freq_t start_freq = op_class_tbl->start_freq; 1653 uint16_t bw = op_class_tbl->chan_spacing; 1654 1655 for (j = 0; j < p_cfi_lst->num_cfis; j++) { 1656 uint8_t cfi = p_cfi_lst->p_cfis_arr[j]; 1657 bool is_cfi_supported; 1658 1659 cfi_freq = start_freq + FREQ_TO_CHAN_SCALE * cfi; 1660 is_cfi_supported = reg_is_cfi_supported(pdev, 1661 cfi_freq, 1662 bw, 1663 op_class_tbl->op_class); 1664 if (is_cfi_supported && 1665 (in_opclass_conf == OPCLASSES_SUPPORTED_BY_CUR_HWMODE || 1666 in_opclass_conf == OPCLASSES_SUPPORTED_BY_DOMAIN)) { 1667 cap->sup_chan_list[n_sup_chans++] = cfi; 1668 cap->num_supported_chan++; 1669 } else { 1670 cap->non_sup_chan_list[n_unsup_chans++] = cfi; 1671 cap->num_non_supported_chan++; 1672 } 1673 } 1674 } 1675 1676 static uint16_t reg_find_nearest_ieee_bw(uint16_t spacing) 1677 { 1678 #define SMALLEST_BW 20 1679 return (spacing / SMALLEST_BW) * SMALLEST_BW; 1680 } 1681 1682 /** 1683 * reg_get_cfis_from_opclassmap_for_non6g()- Get channels from the opclass map 1684 * for non-6GHz 1685 * @pdev: Pointer to pdev 1686 * @cap: Pointer to regdmn_ap_cap_opclass_t 1687 * @op_class_tbl: Pointer to op_class_tbl 1688 * @in_opclass_conf: input opclass configuration 1689 * Supported or not-supported by current HW mode 1690 * 1691 * Populate channels from opclass map to regdmn_ap_cap_opclass_t as supported 1692 * and non-supported channels for non-6Ghz. 1693 * 1694 * Return: void. 1695 */ 1696 static void reg_get_cfis_from_opclassmap_for_non6g( 1697 struct wlan_objmgr_pdev *pdev, 1698 struct regdmn_ap_cap_opclass_t *cap, 1699 const struct reg_dmn_op_class_map_t *op_class_tbl, 1700 enum opclass_config in_opclass_conf) 1701 { 1702 qdf_freq_t start_freq = op_class_tbl->start_freq; 1703 uint8_t chan_idx = 0, n_sup_chans = 0, n_unsup_chans = 0; 1704 1705 while (op_class_tbl->channels[chan_idx]) { 1706 uint8_t op_cls_chan; 1707 qdf_freq_t pri_freq; 1708 enum phy_ch_width ch_width; 1709 bool is_supported; 1710 uint16_t opcls_bw; 1711 1712 op_cls_chan = reg_get_chan_or_chan_center(op_class_tbl, 1713 &chan_idx); 1714 pri_freq = start_freq + FREQ_TO_CHAN_SCALE * op_cls_chan; 1715 opcls_bw = reg_find_nearest_ieee_bw(op_class_tbl->chan_spacing); 1716 ch_width = reg_find_chwidth_from_bw(opcls_bw); 1717 pri_freq = reg_get_nearest_primary_freq(opcls_bw, 1718 pri_freq, 1719 op_class_tbl->op_class); 1720 is_supported = reg_is_chan_supported(pdev, 1721 pri_freq, 1722 0, 1723 ch_width); 1724 1725 if (is_supported && 1726 (in_opclass_conf == OPCLASSES_SUPPORTED_BY_CUR_HWMODE || 1727 in_opclass_conf == OPCLASSES_SUPPORTED_BY_DOMAIN)) { 1728 cap->sup_chan_list[n_sup_chans++] = op_cls_chan; 1729 cap->num_supported_chan++; 1730 } else { 1731 cap->non_sup_chan_list[n_unsup_chans++] = op_cls_chan; 1732 cap->num_non_supported_chan++; 1733 } 1734 } 1735 } 1736 1737 /** 1738 * reg_get_channels_from_opclassmap()- Get channels from the opclass map 1739 * @pdev: Pointer to pdev 1740 * @reg_ap_cap: Pointer to reg_ap_cap 1741 * @index: Pointer to index of reg_ap_cap 1742 * @op_class_tbl: Pointer to op_class_tbl 1743 * @is_opclass_operable: Set true if opclass is operable, else set false 1744 * @in_opclass_conf: input opclass configuration 1745 * Supported or not-supported by current HW mode 1746 * 1747 * Populate channels from opclass map to reg_ap_cap as supported and 1748 * non-supported channels. 1749 * 1750 * Return: void. 1751 */ 1752 static void 1753 reg_get_channels_from_opclassmap( 1754 struct wlan_objmgr_pdev *pdev, 1755 struct regdmn_ap_cap_opclass_t *reg_ap_cap, 1756 uint8_t index, 1757 const struct reg_dmn_op_class_map_t *op_class_tbl, 1758 bool *is_opclass_operable, 1759 enum opclass_config in_opclass_conf) 1760 { 1761 struct regdmn_ap_cap_opclass_t *cap = ®_ap_cap[index]; 1762 1763 if (reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) { 1764 reg_get_cfis_from_opclassmap_for_6g(pdev, 1765 cap, 1766 op_class_tbl, 1767 in_opclass_conf); 1768 } else { 1769 reg_get_cfis_from_opclassmap_for_non6g(pdev, 1770 cap, 1771 op_class_tbl, 1772 in_opclass_conf); 1773 } 1774 1775 if (cap->num_supported_chan >= 1) 1776 *is_opclass_operable = true; 1777 } 1778 1779 QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev, 1780 struct regdmn_ap_cap_opclass_t *reg_ap_cap, 1781 uint8_t *n_opclasses, 1782 uint8_t max_supp_op_class, 1783 bool global_tbl_lookup) 1784 { 1785 uint8_t max_reg_power = 0; 1786 const struct reg_dmn_op_class_map_t *op_class_tbl; 1787 uint8_t index = 0; 1788 enum opclass_config opclass_conf = OPCLASSES_SUPPORTED_BY_DOMAIN; 1789 1790 if (global_tbl_lookup) 1791 op_class_tbl = global_op_class; 1792 else 1793 reg_get_op_class_tbl_by_chan_map(&op_class_tbl); 1794 1795 max_reg_power = reg_get_max_tx_power(pdev); 1796 1797 while (op_class_tbl->op_class && (index < max_supp_op_class)) { 1798 bool is_opclass_operable = false; 1799 1800 qdf_mem_zero(reg_ap_cap[index].sup_chan_list, 1801 REG_MAX_CHANNELS_PER_OPERATING_CLASS); 1802 reg_ap_cap[index].num_supported_chan = 0; 1803 qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list, 1804 REG_MAX_CHANNELS_PER_OPERATING_CLASS); 1805 reg_ap_cap[index].num_non_supported_chan = 0; 1806 reg_get_channels_from_opclassmap(pdev, 1807 reg_ap_cap, 1808 index, 1809 op_class_tbl, 1810 &is_opclass_operable, 1811 opclass_conf); 1812 if (is_opclass_operable) { 1813 reg_ap_cap[index].op_class = op_class_tbl->op_class; 1814 reg_ap_cap[index].ch_width = 1815 op_class_tbl->chan_spacing; 1816 reg_ap_cap[index].start_freq = 1817 op_class_tbl->start_freq; 1818 reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power; 1819 reg_ap_cap[index].behav_limit = 1820 op_class_tbl->behav_limit; 1821 index++; 1822 } 1823 1824 op_class_tbl++; 1825 } 1826 1827 *n_opclasses = index; 1828 1829 return QDF_STATUS_SUCCESS; 1830 } 1831 1832 bool reg_is_6ghz_op_class(struct wlan_objmgr_pdev *pdev, uint8_t op_class) 1833 { 1834 return ((op_class >= MIN_6GHZ_OPER_CLASS) && 1835 (op_class <= MAX_6GHZ_OPER_CLASS)); 1836 } 1837 1838 /** 1839 * reg_is_opclass_band_found - Check if the input opclass is 2G or 5G. 1840 * 1841 * @country - Pointer to country. 1842 * @op_class - Operating class. 1843 * @bandmask = Bitmask for band. 1844 * 1845 * Return : Return true if the input opclass' band (2Ghz or 5Ghz) matches one 1846 * of bandmask's band. 1847 */ 1848 static bool reg_is_opclass_band_found(const uint8_t *country, 1849 uint8_t op_class, 1850 uint8_t bandmask) 1851 { 1852 const struct reg_dmn_op_class_map_t *op_class_tbl; 1853 1854 op_class_tbl = reg_get_class_from_country((uint8_t *)country); 1855 1856 while (op_class_tbl && op_class_tbl->op_class) { 1857 if (op_class_tbl->op_class == op_class) { 1858 qdf_freq_t freq = op_class_tbl->start_freq + 1859 (op_class_tbl->channels[0] * FREQ_TO_CHAN_SCALE); 1860 1861 if ((bandmask & BIT(REG_BAND_5G)) && 1862 REG_IS_5GHZ_FREQ(freq)) 1863 return true; 1864 1865 if ((bandmask & BIT(REG_BAND_2G)) && 1866 REG_IS_24GHZ_CH_FREQ(freq)) 1867 return true; 1868 1869 return false; 1870 } 1871 1872 op_class_tbl++; 1873 } 1874 1875 reg_err_rl("Opclass %d is not found", op_class); 1876 1877 return false; 1878 } 1879 1880 bool reg_is_5ghz_op_class(const uint8_t *country, uint8_t op_class) 1881 { 1882 return reg_is_opclass_band_found(country, op_class, BIT(REG_BAND_5G)); 1883 } 1884 1885 bool reg_is_2ghz_op_class(const uint8_t *country, uint8_t op_class) 1886 { 1887 return reg_is_opclass_band_found(country, op_class, BIT(REG_BAND_2G)); 1888 } 1889 1890 /** 1891 * reg_convert_chan_spacing_to_width() - Convert channel spacing to 1892 * channel width. 1893 * @chan_spacing: Channel spacing 1894 * @opclass_chwidth: Opclass channel width 1895 * Return - None 1896 */ 1897 #ifdef WLAN_FEATURE_11BE 1898 static void reg_convert_chan_spacing_to_width(uint16_t chan_spacing, 1899 uint16_t *opclass_chwidth) 1900 { 1901 switch (chan_spacing) { 1902 case BW_20_MHZ: 1903 case BW_25_MHZ: 1904 *opclass_chwidth = BW_20_MHZ; 1905 break; 1906 case BW_40_MHZ: 1907 *opclass_chwidth = BW_40_MHZ; 1908 break; 1909 case BW_80_MHZ: 1910 *opclass_chwidth = BW_80_MHZ; 1911 break; 1912 case BW_160_MHZ: 1913 *opclass_chwidth = BW_160_MHZ; 1914 break; 1915 case BW_320_MHZ: 1916 *opclass_chwidth = BW_320_MHZ; 1917 break; 1918 default: 1919 *opclass_chwidth = 0; 1920 } 1921 } 1922 #else 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 default: 1941 *opclass_chwidth = 0; 1942 } 1943 } 1944 #endif 1945 1946 QDF_STATUS 1947 reg_get_opclass_for_cur_hwmode(struct wlan_objmgr_pdev *pdev, 1948 struct regdmn_ap_cap_opclass_t *reg_ap_cap, 1949 uint8_t *n_opclasses, 1950 uint8_t max_supp_op_class, 1951 bool global_tbl_lookup, 1952 enum phy_ch_width max_chwidth, 1953 bool is_80p80_supp) 1954 { 1955 uint8_t max_reg_power = 0; 1956 const struct reg_dmn_op_class_map_t *op_class_tbl; 1957 uint8_t index = 0; 1958 uint16_t out_width; 1959 1960 if (global_tbl_lookup) 1961 op_class_tbl = global_op_class; 1962 else 1963 reg_get_op_class_tbl_by_chan_map(&op_class_tbl); 1964 1965 max_reg_power = reg_get_max_tx_power(pdev); 1966 1967 out_width = reg_get_bw_value(max_chwidth); 1968 1969 while (op_class_tbl->op_class && (index < max_supp_op_class)) { 1970 bool is_opclass_operable = false; 1971 enum opclass_config opclass_in_config = 1972 OPCLASSES_SUPPORTED_BY_CUR_HWMODE; 1973 uint16_t opclass_width; 1974 1975 qdf_mem_zero(reg_ap_cap[index].sup_chan_list, 1976 REG_MAX_CHANNELS_PER_OPERATING_CLASS); 1977 reg_ap_cap[index].num_supported_chan = 0; 1978 qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list, 1979 REG_MAX_CHANNELS_PER_OPERATING_CLASS); 1980 reg_ap_cap[index].num_non_supported_chan = 0; 1981 1982 reg_convert_chan_spacing_to_width(op_class_tbl->chan_spacing, 1983 &opclass_width); 1984 1985 if ((opclass_width > out_width) || 1986 ((op_class_tbl->behav_limit == BIT(BEHAV_BW80_PLUS)) && 1987 !is_80p80_supp)) 1988 opclass_in_config = 1989 OPCLASSES_NOT_SUPPORTED_BY_CUR_HWMODE; 1990 1991 reg_get_channels_from_opclassmap(pdev, 1992 reg_ap_cap, 1993 index, 1994 op_class_tbl, 1995 &is_opclass_operable, 1996 opclass_in_config); 1997 1998 if (is_opclass_operable && opclass_in_config == 1999 OPCLASSES_SUPPORTED_BY_CUR_HWMODE) { 2000 reg_ap_cap[index].op_class = op_class_tbl->op_class; 2001 reg_ap_cap[index].ch_width = 2002 op_class_tbl->chan_spacing; 2003 reg_ap_cap[index].start_freq = 2004 op_class_tbl->start_freq; 2005 reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power; 2006 reg_ap_cap[index].behav_limit = 2007 op_class_tbl->behav_limit; 2008 index++; 2009 } 2010 op_class_tbl++; 2011 } 2012 2013 *n_opclasses = index; 2014 2015 return QDF_STATUS_SUCCESS; 2016 } 2017 #endif 2018