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 * 6 GHz band. 673 * @pdev: Pointer to pdev. 674 * 675 * Return: The number of opclasses 676 */ 677 static uint8_t reg_dmn_get_num_6g_opclasses(struct wlan_objmgr_pdev *pdev) 678 { 679 const struct reg_dmn_op_class_map_t *op_class_tbl; 680 uint8_t count; 681 682 op_class_tbl = global_op_class; 683 684 count = 0; 685 while (op_class_tbl && op_class_tbl->op_class) { 686 const struct c_freq_lst *p_lst; 687 688 p_lst = op_class_tbl->p_cfi_lst_obj; 689 if (p_lst && 690 reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) 691 count++; 692 693 op_class_tbl++; 694 } 695 696 return count; 697 } 698 699 /** 700 * reg_dmn_fill_cfis() - Fill the cfis for the given 701 * opclass and frequency range. 702 * @op_class_tbl: Pointer to struct reg_dmn_op_class_map_t 703 * @p_lst: Pointer to struct c_freq_lst 704 * @p_frange_lst: Pointer to struct wlan_afc_frange_list 705 * @dst: Pointer to dst buffer 706 * 707 * Return: Number of valid cfis 708 */ 709 static uint8_t 710 reg_dmn_fill_cfis(const struct reg_dmn_op_class_map_t *op_class_tbl, 711 const struct c_freq_lst *p_lst, 712 struct wlan_afc_frange_list *p_frange_lst, 713 uint8_t *dst) 714 { 715 uint8_t j; 716 uint8_t cfi_idx = 0; 717 718 for (j = 0; j < p_lst->num_cfis; j++) { 719 uint8_t cfi; 720 qdf_freq_t cfi_freq; 721 qdf_freq_t start_freq = op_class_tbl->start_freq; 722 uint16_t bw = op_class_tbl->chan_spacing; 723 724 cfi = p_lst->p_cfis_arr[j]; 725 cfi_freq = start_freq + FREQ_TO_CHAN_SCALE * cfi; 726 727 if (reg_is_cfi_freq_in_ranges(cfi_freq, bw, p_frange_lst)) 728 dst[cfi_idx++] = cfi; 729 } 730 return cfi_idx; 731 } 732 733 /** 734 * reg_dmn_fill_6g_opcls_chan_lists() - Copy the channel lists for 6g opclasses 735 * to the output argument list ('channel_lists') 736 * @pdev: Pointer to pdev. 737 * @p_frange_lst: Pointer to frequency range list (AFC) 738 * @chansize_lst: Array of sizes of channel lists 739 * @channel_lists: The array list pointers where the channel lists are to be 740 * copied. 741 * 742 * Return: Void 743 */ 744 static void reg_dmn_fill_6g_opcls_chan_lists(struct wlan_objmgr_pdev *pdev, 745 struct wlan_afc_frange_list *p_frange_lst, 746 uint8_t chansize_lst[], 747 uint8_t *channel_lists[]) 748 { 749 uint8_t i = 0; 750 const struct reg_dmn_op_class_map_t *op_class_tbl; 751 752 op_class_tbl = global_op_class; 753 754 while (op_class_tbl && op_class_tbl->op_class) { 755 const struct c_freq_lst *p_lst; 756 757 p_lst = op_class_tbl->p_cfi_lst_obj; 758 if (p_lst && 759 reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) { 760 uint8_t *dst; 761 uint8_t num_valid_cfi = 0; 762 763 dst = channel_lists[i]; 764 if (!dst) { 765 reg_debug("dest list empty\n"); 766 return; 767 } 768 num_valid_cfi = reg_dmn_fill_cfis(op_class_tbl, p_lst, 769 p_frange_lst, dst); 770 if (num_valid_cfi) 771 i++; 772 773 } 774 op_class_tbl++; 775 } 776 } 777 778 QDF_STATUS reg_dmn_get_6g_opclasses_and_channels(struct wlan_objmgr_pdev *pdev, 779 struct wlan_afc_frange_list *p_frange_lst, 780 uint8_t *num_opclasses, 781 uint8_t **opclass_lst, 782 uint8_t **chansize_lst, 783 uint8_t **channel_lists[]) 784 { 785 const struct reg_dmn_op_class_map_t *op_class_tbl; 786 uint8_t *l_opcls_lst; 787 uint8_t *l_chansize_lst; 788 uint8_t count; 789 uint8_t i; 790 uint8_t **arr_chan_lists; 791 uint16_t total_alloc_size; 792 uint16_t opcls_lst_size; 793 uint16_t chansize_lst_size; 794 uint16_t arr_chan_lists_size; 795 uint8_t *p_total_alloc1; 796 uint8_t *p_total_alloc2; 797 uint8_t *p_temp_alloc; 798 uint8_t n_tot_opclss; 799 800 *opclass_lst = NULL; 801 *chansize_lst = NULL; 802 *channel_lists = NULL; 803 *num_opclasses = 0; 804 805 op_class_tbl = global_op_class; 806 n_tot_opclss = reg_dmn_get_num_6g_opclasses(pdev); 807 opcls_lst_size = n_tot_opclss * sizeof(uint8_t); 808 chansize_lst_size = n_tot_opclss * sizeof(uint8_t); 809 arr_chan_lists_size = n_tot_opclss * sizeof(uint8_t *); 810 811 total_alloc_size = 0; 812 total_alloc_size += opcls_lst_size 813 + chansize_lst_size 814 + arr_chan_lists_size; 815 816 if (!total_alloc_size) { 817 reg_err("Number of Opclasses is zero"); 818 return QDF_STATUS_E_INVAL; 819 } 820 821 p_total_alloc1 = qdf_mem_malloc(total_alloc_size); 822 if (!p_total_alloc1) { 823 return QDF_STATUS_E_NOMEM; 824 } 825 826 /* Assign memory locations to each pointers */ 827 p_temp_alloc = p_total_alloc1; 828 829 l_opcls_lst = p_temp_alloc; 830 p_temp_alloc += opcls_lst_size; 831 832 l_chansize_lst = p_temp_alloc; 833 p_temp_alloc += chansize_lst_size; 834 835 arr_chan_lists = (uint8_t **)p_temp_alloc; 836 837 /* Fill arrays with opclasses and chanlist sizes */ 838 count = 0; 839 while (op_class_tbl && op_class_tbl->op_class) { 840 const struct c_freq_lst *p_lst; 841 842 p_lst = op_class_tbl->p_cfi_lst_obj; 843 if (p_lst && 844 reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) { 845 uint8_t n_supp_cfis = 0; 846 uint8_t j; 847 848 for (j = 0; j < p_lst->num_cfis; j++) { 849 uint8_t cfi; 850 qdf_freq_t cfi_freq; 851 qdf_freq_t start_freq = op_class_tbl->start_freq; 852 uint16_t bw = op_class_tbl->chan_spacing; 853 854 cfi = p_lst->p_cfis_arr[j]; 855 cfi_freq = start_freq + 856 FREQ_TO_CHAN_SCALE * cfi; 857 if (reg_is_cfi_freq_in_ranges(cfi_freq, 858 bw, 859 p_frange_lst)) { 860 n_supp_cfis++; 861 } 862 } 863 /* Fill opclass number, num cfis and increment 864 * num_opclasses only if the cfi of the opclass 865 * is within the frequency range of interest. 866 */ 867 if (n_supp_cfis) { 868 l_chansize_lst[count] = n_supp_cfis; 869 l_opcls_lst[count] = op_class_tbl->op_class; 870 (*num_opclasses)++; 871 count++; 872 } 873 } 874 op_class_tbl++; 875 } 876 877 /* Calculate total allocation size for the array */ 878 total_alloc_size = 0; 879 for (i = 0; i < *num_opclasses; i++) 880 total_alloc_size += l_chansize_lst[i] * sizeof(uint8_t *); 881 882 if (!total_alloc_size) { 883 reg_err("Number of Opclasses is zero"); 884 qdf_mem_free(p_total_alloc1); 885 return QDF_STATUS_E_INVAL; 886 } 887 888 p_total_alloc2 = qdf_mem_malloc(total_alloc_size); 889 if (!p_total_alloc2) { 890 qdf_mem_free(p_total_alloc1); 891 return QDF_STATUS_E_NOMEM; 892 } 893 894 /* Assign memory locations to each list pointers */ 895 p_temp_alloc = p_total_alloc2; 896 for (i = 0; i < *num_opclasses; i++) { 897 if (!l_chansize_lst[i]) 898 arr_chan_lists[i] = NULL; 899 else 900 arr_chan_lists[i] = p_temp_alloc; 901 902 p_temp_alloc += l_chansize_lst[i] * sizeof(uint8_t *); 903 } 904 905 /* Fill the array with channel lists */ 906 reg_dmn_fill_6g_opcls_chan_lists(pdev, p_frange_lst, l_chansize_lst, arr_chan_lists); 907 908 *opclass_lst = l_opcls_lst; 909 *chansize_lst = l_chansize_lst; 910 *channel_lists = arr_chan_lists; 911 912 return QDF_STATUS_SUCCESS; 913 } 914 #endif /* CONFIG_AFC_SUPPORT */ 915 916 uint16_t reg_dmn_get_chanwidth_from_opclass(uint8_t *country, uint8_t channel, 917 uint8_t opclass) 918 { 919 const struct reg_dmn_op_class_map_t *class; 920 uint16_t i; 921 922 class = reg_get_class_from_country(country); 923 924 while (class->op_class) { 925 if (opclass == class->op_class) { 926 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 927 class->channels[i]); i++) { 928 if (channel == class->channels[i]) 929 return class->chan_spacing; 930 } 931 } 932 class++; 933 } 934 935 return 0; 936 } 937 938 uint16_t reg_dmn_get_chanwidth_from_opclass_auto(uint8_t *country, 939 uint8_t channel, 940 uint8_t opclass) 941 { 942 uint16_t ret; 943 uint8_t global_country[REG_ALPHA2_LEN + 1]; 944 945 ret = reg_dmn_get_chanwidth_from_opclass(country, channel, opclass); 946 947 if (!ret) { 948 global_country[2] = OP_CLASS_GLOBAL; 949 ret = reg_dmn_get_chanwidth_from_opclass(global_country, 950 channel, opclass); 951 } 952 953 return ret; 954 } 955 956 uint16_t reg_dmn_get_opclass_from_channel(uint8_t *country, uint8_t channel, 957 uint8_t offset) 958 { 959 const struct reg_dmn_op_class_map_t *class = NULL; 960 uint16_t i = 0; 961 962 class = reg_get_class_from_country(country); 963 while (class && class->op_class) { 964 if ((offset == class->offset) || (offset == BWALL)) { 965 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 966 class->channels[i]); i++) { 967 if (channel == class->channels[i]) 968 return class->op_class; 969 } 970 } 971 class++; 972 } 973 974 return 0; 975 } 976 977 uint8_t reg_dmn_get_opclass_from_freq_width(uint8_t *country, 978 qdf_freq_t freq, 979 uint16_t ch_width, 980 uint16_t behav_limit) 981 { 982 const struct reg_dmn_op_class_map_t *op_class_tbl = NULL; 983 uint16_t i = 0; 984 985 op_class_tbl = reg_get_class_from_country(country); 986 987 while (op_class_tbl && op_class_tbl->op_class) { 988 if (op_class_tbl->chan_spacing == ch_width) { 989 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 990 op_class_tbl->channels[i]); i++) { 991 if ((op_class_tbl->start_freq + 992 (FREQ_TO_CHAN_SCALE * 993 op_class_tbl->channels[i]) == freq) && 994 (behav_limit & op_class_tbl->behav_limit)) { 995 return op_class_tbl->op_class; 996 } 997 } 998 } 999 op_class_tbl++; 1000 } 1001 1002 return 0; 1003 } 1004 1005 static void 1006 reg_get_band_cap_from_chan_set(const struct reg_dmn_op_class_map_t 1007 *op_class_tbl, 1008 uint8_t *supported_band) 1009 { 1010 qdf_freq_t chan_freq = op_class_tbl->start_freq + 1011 (op_class_tbl->channels[0] * 1012 FREQ_TO_CHAN_SCALE); 1013 1014 if (reg_is_24ghz_ch_freq(chan_freq)) 1015 *supported_band |= BIT(REG_BAND_2G); 1016 else if (reg_is_5ghz_ch_freq(chan_freq)) 1017 *supported_band |= BIT(REG_BAND_5G); 1018 else if (reg_is_6ghz_chan_freq(chan_freq)) 1019 *supported_band |= BIT(REG_BAND_6G); 1020 else 1021 reg_err_rl("Unknown band"); 1022 } 1023 1024 uint8_t reg_get_band_cap_from_op_class(const uint8_t *country, 1025 uint8_t num_of_opclass, 1026 const uint8_t *opclass) 1027 { 1028 const struct reg_dmn_op_class_map_t *op_class_tbl; 1029 uint8_t supported_band = 0, opclassidx; 1030 1031 op_class_tbl = reg_get_class_from_country(country); 1032 1033 while (op_class_tbl && op_class_tbl->op_class) { 1034 for (opclassidx = 0; opclassidx < num_of_opclass; 1035 opclassidx++) { 1036 if (op_class_tbl->op_class == opclass[opclassidx]) { 1037 reg_get_band_cap_from_chan_set(op_class_tbl, 1038 &supported_band); 1039 } 1040 } 1041 op_class_tbl++; 1042 } 1043 1044 if (!supported_band) 1045 reg_err_rl("None of the operating classes is found"); 1046 1047 return supported_band; 1048 } 1049 1050 void reg_dmn_print_channels_in_opclass(uint8_t *country, uint8_t op_class) 1051 { 1052 const struct reg_dmn_op_class_map_t *class = NULL; 1053 uint16_t i = 0; 1054 1055 class = reg_get_class_from_country(country); 1056 1057 if (!class) { 1058 reg_err("class is NULL"); 1059 return; 1060 } 1061 1062 while (class->op_class) { 1063 if (class->op_class == op_class) { 1064 for (i = 0; 1065 (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1066 class->channels[i]); i++) { 1067 reg_debug("Valid channel(%d) in requested RC(%d)", 1068 class->channels[i], op_class); 1069 } 1070 break; 1071 } 1072 class++; 1073 } 1074 if (!class->op_class) 1075 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 1076 "Invalid requested RC (%d)", op_class); 1077 } 1078 1079 uint16_t reg_dmn_set_curr_opclasses(uint8_t num_classes, uint8_t *class) 1080 { 1081 uint8_t i; 1082 1083 if (num_classes > REG_MAX_SUPP_OPER_CLASSES) { 1084 reg_err("invalid num classes %d", num_classes); 1085 return 0; 1086 } 1087 1088 for (i = 0; i < num_classes; i++) 1089 reg_dmn_curr_supp_opp_classes.classes[i] = class[i]; 1090 1091 reg_dmn_curr_supp_opp_classes.num_classes = num_classes; 1092 1093 return 0; 1094 } 1095 1096 uint16_t reg_dmn_get_curr_opclasses(uint8_t *num_classes, uint8_t *class) 1097 { 1098 uint8_t i; 1099 1100 if (!num_classes || !class) { 1101 reg_err("either num_classes or class is null"); 1102 return 0; 1103 } 1104 1105 for (i = 0; i < reg_dmn_curr_supp_opp_classes.num_classes; i++) 1106 class[i] = reg_dmn_curr_supp_opp_classes.classes[i]; 1107 1108 *num_classes = reg_dmn_curr_supp_opp_classes.num_classes; 1109 1110 return 0; 1111 } 1112 1113 #ifdef CONFIG_CHAN_FREQ_API 1114 /** 1115 * reg_find_opclass_absent_in_ctry_opclss_tables() - Check Global Opclass table 1116 * when Opclass is not present in specific country. 1117 * @pdev: Pointer to pdev 1118 * @freq: Destination Frequency 1119 * @chan_width: Channel Width 1120 * @global_tbl_lookup: Global Table Lookup 1121 * @behav_limit: Behav Limit 1122 * @op_class: Pointer to Opclass 1123 * @chan_num: Pointer to Channel 1124 * 1125 * Return: Void 1126 */ 1127 static void 1128 reg_find_opclass_absent_in_ctry_opclss_tables(struct wlan_objmgr_pdev *pdev, 1129 qdf_freq_t freq, 1130 uint16_t chan_width, 1131 bool global_tbl_lookup, 1132 uint16_t behav_limit, 1133 uint8_t *op_class, 1134 uint8_t *chan_num) 1135 { 1136 if (!global_tbl_lookup && !*op_class) { 1137 global_tbl_lookup = true; 1138 reg_freq_width_to_chan_op_class(pdev, freq, 1139 chan_width, 1140 global_tbl_lookup, 1141 behav_limit, 1142 op_class, 1143 chan_num); 1144 } 1145 } 1146 1147 static bool 1148 reg_is_country_opclass_global(struct wlan_objmgr_pdev *pdev) 1149 { 1150 struct wlan_lmac_if_reg_tx_ops *reg_tx_ops; 1151 struct wlan_objmgr_psoc *psoc; 1152 uint8_t opclass_tbl_idx; 1153 1154 psoc = wlan_pdev_get_psoc(pdev); 1155 if (!psoc) { 1156 reg_err("psoc is NULL"); 1157 return false; 1158 } 1159 1160 reg_tx_ops = reg_get_psoc_tx_ops(psoc); 1161 if (!reg_tx_ops) { 1162 reg_err("reg_tx_ops is NULL"); 1163 return false; 1164 } 1165 1166 if (reg_tx_ops->get_opclass_tbl_idx) { 1167 reg_tx_ops->get_opclass_tbl_idx(pdev, &opclass_tbl_idx); 1168 1169 if (opclass_tbl_idx == OP_CLASS_GLOBAL) 1170 return true; 1171 } 1172 1173 return false; 1174 } 1175 1176 void reg_freq_width_to_chan_op_class_auto(struct wlan_objmgr_pdev *pdev, 1177 qdf_freq_t freq, 1178 uint16_t chan_width, 1179 bool global_tbl_lookup, 1180 uint16_t behav_limit, 1181 uint8_t *op_class, 1182 uint8_t *chan_num) 1183 { 1184 if (reg_freq_to_band(freq) == REG_BAND_6G) { 1185 global_tbl_lookup = true; 1186 if (chan_width == BW_40_MHZ) 1187 behav_limit = BIT(BEHAV_NONE); 1188 } else if (reg_is_5dot9_ghz_freq(pdev, freq)) { 1189 global_tbl_lookup = true; 1190 } else { 1191 global_tbl_lookup = reg_is_country_opclass_global(pdev); 1192 } 1193 1194 *op_class = 0; 1195 reg_freq_width_to_chan_op_class(pdev, freq, 1196 chan_width, 1197 global_tbl_lookup, 1198 behav_limit, 1199 op_class, 1200 chan_num); 1201 reg_find_opclass_absent_in_ctry_opclss_tables(pdev, freq, 1202 chan_width, 1203 global_tbl_lookup, 1204 behav_limit, 1205 op_class, 1206 chan_num); 1207 } 1208 1209 void reg_freq_width_to_chan_op_class(struct wlan_objmgr_pdev *pdev, 1210 qdf_freq_t freq, 1211 uint16_t chan_width, 1212 bool global_tbl_lookup, 1213 uint16_t behav_limit, 1214 uint8_t *op_class, 1215 uint8_t *chan_num) 1216 { 1217 const struct reg_dmn_op_class_map_t *op_class_tbl; 1218 enum channel_enum chan_enum; 1219 uint16_t i; 1220 1221 chan_enum = reg_get_chan_enum_for_freq(freq); 1222 1223 if (reg_is_chan_enum_invalid(chan_enum)) { 1224 reg_err_rl("Invalid chan enum %d", chan_enum); 1225 return; 1226 } 1227 1228 if (global_tbl_lookup) { 1229 op_class_tbl = global_op_class; 1230 } else { 1231 if (channel_map == channel_map_us) 1232 op_class_tbl = us_op_class; 1233 else if (channel_map == channel_map_eu) 1234 op_class_tbl = euro_op_class; 1235 else if (channel_map == channel_map_china) 1236 op_class_tbl = china_op_class; 1237 else if (channel_map == channel_map_jp) 1238 op_class_tbl = japan_op_class; 1239 else 1240 op_class_tbl = global_op_class; 1241 } 1242 1243 while (op_class_tbl->op_class) { 1244 if (op_class_tbl->chan_spacing >= chan_width) { 1245 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1246 op_class_tbl->channels[i]); i++) { 1247 if ((op_class_tbl->start_freq + 1248 FREQ_TO_CHAN_SCALE * 1249 op_class_tbl->channels[i] == freq) && 1250 (behav_limit & op_class_tbl->behav_limit || 1251 behav_limit == BIT(BEHAV_NONE))) { 1252 *chan_num = op_class_tbl->channels[i]; 1253 *op_class = op_class_tbl->op_class; 1254 return; 1255 } 1256 } 1257 } 1258 op_class_tbl++; 1259 } 1260 1261 reg_err_rl("no op class for frequency %d", freq); 1262 } 1263 1264 void reg_freq_to_chan_op_class(struct wlan_objmgr_pdev *pdev, 1265 qdf_freq_t freq, 1266 bool global_tbl_lookup, 1267 uint16_t behav_limit, 1268 uint8_t *op_class, 1269 uint8_t *chan_num) 1270 { 1271 enum channel_enum chan_enum; 1272 struct regulatory_channel *cur_chan_list; 1273 struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj; 1274 struct ch_params chan_params = {0}; 1275 1276 pdev_priv_obj = reg_get_pdev_obj(pdev); 1277 1278 if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) { 1279 reg_err_rl("NULL pdev reg obj"); 1280 return; 1281 } 1282 1283 cur_chan_list = pdev_priv_obj->cur_chan_list; 1284 1285 chan_enum = reg_get_chan_enum_for_freq(freq); 1286 1287 if (reg_is_chan_enum_invalid(chan_enum)) { 1288 reg_err_rl("Invalid chan enum %d", chan_enum); 1289 return; 1290 } 1291 1292 chan_params.ch_width = CH_WIDTH_MAX; 1293 reg_set_channel_params_for_pwrmode(pdev, freq, 1294 0, 1295 &chan_params, 1296 REG_CURRENT_PWR_MODE, true); 1297 1298 reg_freq_width_to_chan_op_class(pdev, freq, 1299 reg_get_bw_value(chan_params.ch_width), 1300 global_tbl_lookup, 1301 behav_limit, 1302 op_class, 1303 chan_num); 1304 } 1305 1306 bool reg_is_freq_in_country_opclass(struct wlan_objmgr_pdev *pdev, 1307 const uint8_t country[3], 1308 uint8_t op_class, 1309 qdf_freq_t chan_freq) 1310 { 1311 const struct reg_dmn_op_class_map_t *op_class_tbl; 1312 uint8_t i; 1313 1314 op_class_tbl = reg_get_class_from_country((uint8_t *)country); 1315 1316 while (op_class_tbl && op_class_tbl->op_class) { 1317 if (op_class_tbl->op_class == op_class) { 1318 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1319 op_class_tbl->channels[i]); i++) { 1320 if (op_class_tbl->channels[i] * 1321 FREQ_TO_CHAN_SCALE + 1322 op_class_tbl->start_freq == chan_freq) 1323 return true; 1324 } 1325 } 1326 op_class_tbl++; 1327 } 1328 return false; 1329 } 1330 1331 #endif 1332 1333 uint16_t reg_get_op_class_width(struct wlan_objmgr_pdev *pdev, 1334 uint8_t op_class, 1335 bool global_tbl_lookup) 1336 { 1337 const struct reg_dmn_op_class_map_t *op_class_tbl; 1338 1339 if (global_tbl_lookup) { 1340 op_class_tbl = global_op_class; 1341 } else { 1342 if (channel_map == channel_map_us) 1343 op_class_tbl = us_op_class; 1344 else if (channel_map == channel_map_eu) 1345 op_class_tbl = euro_op_class; 1346 else if (channel_map == channel_map_china) 1347 op_class_tbl = china_op_class; 1348 else if (channel_map == channel_map_jp) 1349 op_class_tbl = japan_op_class; 1350 else 1351 op_class_tbl = global_op_class; 1352 } 1353 1354 while (op_class_tbl->op_class) { 1355 if (op_class_tbl->op_class == op_class) 1356 return op_class_tbl->chan_spacing; 1357 op_class_tbl++; 1358 } 1359 1360 return 0; 1361 } 1362 1363 uint16_t reg_chan_opclass_to_freq(uint8_t chan, 1364 uint8_t op_class, 1365 bool global_tbl_lookup) 1366 { 1367 const struct reg_dmn_op_class_map_t *op_class_tbl = NULL; 1368 uint8_t i = 0; 1369 1370 if (global_tbl_lookup) { 1371 op_class_tbl = global_op_class; 1372 } else { 1373 if (channel_map == channel_map_global) { 1374 op_class_tbl = global_op_class; 1375 } else if (channel_map == channel_map_us) { 1376 op_class_tbl = us_op_class; 1377 } else if (channel_map == channel_map_eu) { 1378 op_class_tbl = euro_op_class; 1379 } else if (channel_map == channel_map_china) { 1380 op_class_tbl = china_op_class; 1381 } else if (channel_map == channel_map_jp) { 1382 op_class_tbl = japan_op_class; 1383 } else { 1384 reg_err_rl("Invalid channel map"); 1385 return 0; 1386 } 1387 } 1388 1389 while (op_class_tbl->op_class) { 1390 if (op_class_tbl->op_class == op_class) { 1391 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1392 op_class_tbl->channels[i]); i++) { 1393 if (op_class_tbl->channels[i] == chan) { 1394 chan = op_class_tbl->channels[i]; 1395 return op_class_tbl->start_freq + 1396 (chan * FREQ_TO_CHAN_SCALE); 1397 } 1398 } 1399 reg_err_rl("Channel not found"); 1400 return 0; 1401 } 1402 op_class_tbl++; 1403 } 1404 reg_err_rl("Invalid opclass"); 1405 return 0; 1406 } 1407 1408 qdf_freq_t reg_chan_opclass_to_freq_auto(uint8_t chan, uint8_t op_class, 1409 bool global_tbl_lookup) 1410 { 1411 if ((op_class >= MIN_6GHZ_OPER_CLASS) && 1412 (op_class <= MAX_6GHZ_OPER_CLASS)) { 1413 global_tbl_lookup = true; 1414 } else { 1415 qdf_freq_t freq = reg_chan_opclass_to_freq(chan, 1416 op_class, 1417 global_tbl_lookup); 1418 if (freq) 1419 return freq; 1420 global_tbl_lookup = true; 1421 } 1422 1423 return reg_chan_opclass_to_freq(chan, op_class, global_tbl_lookup); 1424 } 1425 1426 #ifdef HOST_OPCLASS_EXT 1427 qdf_freq_t reg_country_chan_opclass_to_freq(struct wlan_objmgr_pdev *pdev, 1428 const uint8_t country[3], 1429 uint8_t chan, uint8_t op_class, 1430 bool strict) 1431 { 1432 const struct reg_dmn_op_class_map_t *op_class_tbl, *op_class_tbl_org; 1433 uint16_t i; 1434 1435 if (reg_is_6ghz_op_class(pdev, op_class)) 1436 op_class_tbl_org = global_op_class; 1437 else 1438 op_class_tbl_org = 1439 reg_get_class_from_country((uint8_t *)country); 1440 op_class_tbl = op_class_tbl_org; 1441 while (op_class_tbl && op_class_tbl->op_class) { 1442 if (op_class_tbl->op_class == op_class) { 1443 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1444 op_class_tbl->channels[i]); i++) { 1445 if (op_class_tbl->channels[i] == chan) 1446 return op_class_tbl->start_freq + 1447 (chan * FREQ_TO_CHAN_SCALE); 1448 } 1449 } 1450 op_class_tbl++; 1451 } 1452 reg_debug_rl("Not found ch %d in op class %d ch list, strict %d", 1453 chan, op_class, strict); 1454 if (strict) 1455 return 0; 1456 1457 op_class_tbl = op_class_tbl_org; 1458 while (op_class_tbl && op_class_tbl->op_class) { 1459 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 1460 op_class_tbl->channels[i]); i++) { 1461 if (op_class_tbl->channels[i] == chan) 1462 return op_class_tbl->start_freq + 1463 (chan * FREQ_TO_CHAN_SCALE); 1464 } 1465 op_class_tbl++; 1466 } 1467 reg_debug_rl("Got invalid freq 0 for ch %d", chan); 1468 1469 return 0; 1470 } 1471 #endif 1472 1473 static void 1474 reg_get_op_class_tbl_by_chan_map(const struct 1475 reg_dmn_op_class_map_t **op_class_tbl) 1476 { 1477 if (channel_map == channel_map_us) 1478 *op_class_tbl = us_op_class; 1479 else if (channel_map == channel_map_eu) 1480 *op_class_tbl = euro_op_class; 1481 else if (channel_map == channel_map_china) 1482 *op_class_tbl = china_op_class; 1483 else if (channel_map == channel_map_jp) 1484 *op_class_tbl = japan_op_class; 1485 else 1486 *op_class_tbl = global_op_class; 1487 } 1488 1489 /** 1490 * reg_get_channel_cen - Calculate central channel in the channel set. 1491 * 1492 * @op_class_tbl: Pointer to op_class_tbl. 1493 * @idx: Pointer to channel index. 1494 * @num_channels: Number of channels. 1495 * @center_chan: Pointer to center channel number 1496 * 1497 * Return : void 1498 */ 1499 static void reg_get_channel_cen(const struct 1500 reg_dmn_op_class_map_t *op_class_tbl, 1501 uint8_t *idx, 1502 uint8_t num_channels, 1503 uint8_t *center_chan) 1504 { 1505 uint8_t i; 1506 uint16_t new_chan = 0; 1507 1508 for (i = *idx; i < (*idx + num_channels); i++) 1509 new_chan += op_class_tbl->channels[i]; 1510 1511 new_chan = new_chan / num_channels; 1512 *center_chan = new_chan; 1513 *idx = *idx + num_channels; 1514 } 1515 1516 /** 1517 * reg_is_chan_320mhz() - Return true if the chan width is 320MHZ, 1518 * false otherwise. 1519 * @chan_spacing: Channel spacing in MHZ. 1520 * 1521 * Return: true if chan_width is 320, false otherwise. 1522 */ 1523 #ifdef WLAN_FEATURE_11BE 1524 static bool reg_is_chan_320mhz(uint16_t chan_spacing) 1525 { 1526 if (chan_spacing == BW_320_MHZ) 1527 return true; 1528 return false; 1529 } 1530 #else 1531 static bool reg_is_chan_320mhz(uint16_t chan_spacing) 1532 { 1533 return false; 1534 } 1535 #endif 1536 1537 /** 1538 * reg_get_chan_or_chan_center - Calculate central channel in the channel set. 1539 * 1540 * @op_class_tbl: Pointer to op_class_tbl. 1541 * @idx: Pointer to channel index. 1542 * 1543 * Return : Center channel number 1544 */ 1545 static uint8_t reg_get_chan_or_chan_center(const struct 1546 reg_dmn_op_class_map_t *op_class_tbl, 1547 uint8_t *idx) 1548 { 1549 uint8_t center_chan; 1550 1551 if (((op_class_tbl->chan_spacing == BW_80_MHZ) && 1552 (op_class_tbl->behav_limit == BIT(BEHAV_NONE))) || 1553 ((op_class_tbl->chan_spacing == BW_80_MHZ) && 1554 (op_class_tbl->behav_limit == BIT(BEHAV_BW80_PLUS)))) { 1555 reg_get_channel_cen(op_class_tbl, 1556 idx, 1557 NUM_20_MHZ_CHAN_IN_80_MHZ_CHAN, 1558 ¢er_chan); 1559 } else if (op_class_tbl->chan_spacing == BW_160_MHZ) { 1560 reg_get_channel_cen(op_class_tbl, 1561 idx, 1562 NUM_20_MHZ_CHAN_IN_160_MHZ_CHAN, 1563 ¢er_chan); 1564 } else if (reg_is_chan_320mhz(op_class_tbl->chan_spacing)) { 1565 reg_get_channel_cen(op_class_tbl, 1566 idx, 1567 NUM_20_MHZ_CHAN_IN_320_MHZ_CHAN, 1568 ¢er_chan); 1569 } else { 1570 center_chan = op_class_tbl->channels[*idx]; 1571 *idx = *idx + 1; 1572 } 1573 1574 return center_chan; 1575 } 1576 1577 static inline qdf_freq_t reg_get_nearest_primary_freq(uint16_t bw, 1578 qdf_freq_t cfi_freq, 1579 uint8_t op_class) 1580 { 1581 qdf_freq_t pri_freq; 1582 1583 if (bw <= BW_40_MHZ && op_class != OPCLS_132) { 1584 pri_freq = cfi_freq; 1585 } else { 1586 if (cfi_freq >= BW_10_MHZ) 1587 pri_freq = cfi_freq - BW_10_MHZ; 1588 else 1589 pri_freq = 0; 1590 } 1591 1592 return pri_freq; 1593 } 1594 1595 #ifdef WLAN_FEATURE_11BE 1596 /** 1597 * reg_is_chan_supported()- Check if given channel is supported based on its 1598 * freq provided 1599 * @pdev: Pointer to pdev 1600 * @pri_freq: Primary frequency of the input channel 1601 * @cfi_freq: cfi frequency of the input channel 1602 * @ch_width: Input channel width 1603 * @in_6g_pwr_mode: 6g power type which decides 6G channel list lookup. 1604 * 1605 * Return: True if the channel is supported, else false 1606 */ 1607 static bool reg_is_chan_supported(struct wlan_objmgr_pdev *pdev, 1608 qdf_freq_t pri_freq, 1609 qdf_freq_t cfi_freq, 1610 enum phy_ch_width ch_width, 1611 enum supported_6g_pwr_types in_6g_pwr_mode) 1612 { 1613 struct reg_channel_list chan_list = {0}; 1614 qdf_freq_t center_320; 1615 struct ch_params ch_params = {0}; 1616 1617 center_320 = (ch_width == CH_WIDTH_320MHZ) ? cfi_freq : 0; 1618 reg_fill_channel_list_for_pwrmode(pdev, pri_freq, 0, 1619 ch_width, center_320, &chan_list, 1620 in_6g_pwr_mode, true); 1621 ch_params = chan_list.chan_param[0]; 1622 1623 if (ch_params.ch_width == ch_width) 1624 return true; 1625 1626 return false; 1627 } 1628 #else 1629 static bool reg_is_chan_supported(struct wlan_objmgr_pdev *pdev, 1630 qdf_freq_t pri_freq, 1631 qdf_freq_t cfi_freq, 1632 enum phy_ch_width ch_width, 1633 enum supported_6g_pwr_types in_6g_pwr_mode) 1634 { 1635 struct ch_params ch_params = {0}; 1636 1637 ch_params.ch_width = ch_width; 1638 reg_set_channel_params_for_pwrmode(pdev, pri_freq, 0, &ch_params, 1639 in_6g_pwr_mode, true); 1640 if (ch_params.ch_width == ch_width) 1641 return true; 1642 1643 return false; 1644 } 1645 #endif 1646 1647 /** 1648 * reg_is_cfi_supported()- Check if given cfi is supported 1649 * @pdev: Pointer to pdev 1650 * @cfi_freq: cfi frequency 1651 * @bw: bandwidth 1652 * @op_class: op_class 1653 * @in_6g_pwr_mode: 6g power type which decides 6G channel list lookup. 1654 * 1655 * Return: True if the cfi is supported, else false 1656 */ 1657 static bool reg_is_cfi_supported(struct wlan_objmgr_pdev *pdev, 1658 qdf_freq_t cfi_freq, 1659 uint16_t bw, 1660 uint8_t op_class, 1661 enum supported_6g_pwr_types in_6g_pwr_mode) 1662 { 1663 enum phy_ch_width ch_width; 1664 qdf_freq_t pri_freq; 1665 bool is_cfi_supported; 1666 1667 ch_width = reg_find_chwidth_from_bw(bw); 1668 pri_freq = reg_get_nearest_primary_freq(bw, cfi_freq, op_class); 1669 is_cfi_supported = reg_is_chan_supported(pdev, 1670 pri_freq, 1671 cfi_freq, 1672 ch_width, 1673 in_6g_pwr_mode); 1674 1675 return is_cfi_supported; 1676 } 1677 1678 /** 1679 * reg_get_cfis_from_opclassmap_for_6g()- Get channels from the opclass map 1680 * for 6GHz 1681 * @pdev: Pointer to pdev 1682 * @cap: Pointer to regdmn_ap_cap_opclass_t 1683 * @op_class_tbl: Pointer to op_class_tbl 1684 * @in_opclass_conf: input opclass configuration 1685 * Supported or not-supported by current HW mode 1686 * @in_6g_pwr_mode: 6g power type which decides 6G channel list lookup. 1687 * 1688 * Populate channels from opclass map to regdmn_ap_cap_opclass_t as supported 1689 * and non-supported channels for 6Ghz. 1690 * 1691 * Return: void. 1692 */ 1693 static void reg_get_cfis_from_opclassmap_for_6g( 1694 struct wlan_objmgr_pdev *pdev, 1695 struct regdmn_ap_cap_opclass_t *cap, 1696 const struct reg_dmn_op_class_map_t *op_class_tbl, 1697 enum opclass_config in_opclass_conf, 1698 enum supported_6g_pwr_types in_6g_pwr_mode) 1699 { 1700 uint8_t n_sup_chans = 0, n_unsup_chans = 0, j; 1701 const struct c_freq_lst *p_cfi_lst = op_class_tbl->p_cfi_lst_obj; 1702 qdf_freq_t cfi_freq; 1703 qdf_freq_t start_freq = op_class_tbl->start_freq; 1704 uint16_t bw = op_class_tbl->chan_spacing; 1705 1706 for (j = 0; j < p_cfi_lst->num_cfis; j++) { 1707 uint8_t cfi = p_cfi_lst->p_cfis_arr[j]; 1708 bool is_cfi_supported; 1709 1710 cfi_freq = start_freq + FREQ_TO_CHAN_SCALE * cfi; 1711 is_cfi_supported = reg_is_cfi_supported(pdev, 1712 cfi_freq, 1713 bw, 1714 op_class_tbl->op_class, 1715 in_6g_pwr_mode); 1716 if (is_cfi_supported && 1717 (in_opclass_conf == OPCLASSES_SUPPORTED_BY_CUR_HWMODE || 1718 in_opclass_conf == OPCLASSES_SUPPORTED_BY_DOMAIN)) { 1719 cap->sup_chan_list[n_sup_chans++] = cfi; 1720 cap->num_supported_chan++; 1721 } else { 1722 cap->non_sup_chan_list[n_unsup_chans++] = cfi; 1723 cap->num_non_supported_chan++; 1724 } 1725 } 1726 } 1727 1728 static uint16_t reg_find_nearest_ieee_bw(uint16_t spacing) 1729 { 1730 #define SMALLEST_BW 20 1731 return (spacing / SMALLEST_BW) * SMALLEST_BW; 1732 } 1733 1734 /** 1735 * reg_get_cfis_from_opclassmap_for_non6g()- Get channels from the opclass map 1736 * for non-6GHz 1737 * @pdev: Pointer to pdev 1738 * @cap: Pointer to regdmn_ap_cap_opclass_t 1739 * @op_class_tbl: Pointer to op_class_tbl 1740 * @in_opclass_conf: input opclass configuration 1741 * Supported or not-supported by current HW mode 1742 * @in_6g_pwr_mode: 6g power type which decides 6G channel list lookup. 1743 * 1744 * Populate channels from opclass map to regdmn_ap_cap_opclass_t as supported 1745 * and non-supported channels for non-6Ghz. 1746 * 1747 * Return: void. 1748 */ 1749 static void reg_get_cfis_from_opclassmap_for_non6g( 1750 struct wlan_objmgr_pdev *pdev, 1751 struct regdmn_ap_cap_opclass_t *cap, 1752 const struct reg_dmn_op_class_map_t *op_class_tbl, 1753 enum opclass_config in_opclass_conf, 1754 enum supported_6g_pwr_types in_6g_pwr_mode) 1755 { 1756 qdf_freq_t start_freq = op_class_tbl->start_freq; 1757 uint8_t chan_idx = 0, n_sup_chans = 0, n_unsup_chans = 0; 1758 1759 while (op_class_tbl->channels[chan_idx]) { 1760 uint8_t op_cls_chan; 1761 qdf_freq_t pri_freq; 1762 enum phy_ch_width ch_width; 1763 bool is_supported; 1764 uint16_t opcls_bw; 1765 1766 op_cls_chan = reg_get_chan_or_chan_center(op_class_tbl, 1767 &chan_idx); 1768 pri_freq = start_freq + FREQ_TO_CHAN_SCALE * op_cls_chan; 1769 opcls_bw = reg_find_nearest_ieee_bw(op_class_tbl->chan_spacing); 1770 ch_width = reg_find_chwidth_from_bw(opcls_bw); 1771 pri_freq = reg_get_nearest_primary_freq(opcls_bw, 1772 pri_freq, 1773 op_class_tbl->op_class); 1774 is_supported = reg_is_chan_supported(pdev, 1775 pri_freq, 1776 0, 1777 ch_width, 1778 in_6g_pwr_mode); 1779 1780 if (is_supported && 1781 (in_opclass_conf == OPCLASSES_SUPPORTED_BY_CUR_HWMODE || 1782 in_opclass_conf == OPCLASSES_SUPPORTED_BY_DOMAIN)) { 1783 cap->sup_chan_list[n_sup_chans++] = op_cls_chan; 1784 cap->num_supported_chan++; 1785 } else { 1786 cap->non_sup_chan_list[n_unsup_chans++] = op_cls_chan; 1787 cap->num_non_supported_chan++; 1788 } 1789 } 1790 } 1791 1792 /** 1793 * reg_get_channels_from_opclassmap()- Get channels from the opclass map 1794 * @pdev: Pointer to pdev 1795 * @reg_ap_cap: Pointer to reg_ap_cap 1796 * @index: Pointer to index of reg_ap_cap 1797 * @op_class_tbl: Pointer to op_class_tbl 1798 * @is_opclass_operable: Set true if opclass is operable, else set false 1799 * @in_opclass_conf: input opclass configuration 1800 * Supported or not-supported by current HW mode 1801 * @in_6g_pwr_mode: 6g power type which decides 6G channel list lookup. 1802 * 1803 * Populate channels from opclass map to reg_ap_cap as supported and 1804 * non-supported channels. 1805 * 1806 * Return: void. 1807 */ 1808 static void 1809 reg_get_channels_from_opclassmap( 1810 struct wlan_objmgr_pdev *pdev, 1811 struct regdmn_ap_cap_opclass_t *reg_ap_cap, 1812 uint8_t index, 1813 const struct reg_dmn_op_class_map_t *op_class_tbl, 1814 bool *is_opclass_operable, 1815 enum opclass_config in_opclass_conf, 1816 enum supported_6g_pwr_types in_6g_pwr_mode) 1817 { 1818 struct regdmn_ap_cap_opclass_t *cap = ®_ap_cap[index]; 1819 1820 if (reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) { 1821 reg_get_cfis_from_opclassmap_for_6g(pdev, 1822 cap, 1823 op_class_tbl, 1824 in_opclass_conf, 1825 in_6g_pwr_mode); 1826 } else { 1827 reg_get_cfis_from_opclassmap_for_non6g(pdev, 1828 cap, 1829 op_class_tbl, 1830 in_opclass_conf, 1831 in_6g_pwr_mode); 1832 } 1833 1834 if (cap->num_supported_chan >= 1) 1835 *is_opclass_operable = true; 1836 } 1837 1838 QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev, 1839 struct regdmn_ap_cap_opclass_t *reg_ap_cap, 1840 uint8_t *n_opclasses, 1841 uint8_t max_supp_op_class, 1842 bool global_tbl_lookup, 1843 enum supported_6g_pwr_types in_6g_pwr_mode) 1844 { 1845 uint8_t max_reg_power = 0; 1846 const struct reg_dmn_op_class_map_t *op_class_tbl; 1847 uint8_t index = 0; 1848 enum opclass_config opclass_conf = OPCLASSES_SUPPORTED_BY_DOMAIN; 1849 1850 if (global_tbl_lookup) 1851 op_class_tbl = global_op_class; 1852 else 1853 reg_get_op_class_tbl_by_chan_map(&op_class_tbl); 1854 1855 max_reg_power = reg_get_max_tx_power(pdev); 1856 1857 while (op_class_tbl->op_class && (index < max_supp_op_class)) { 1858 bool is_opclass_operable = false; 1859 1860 qdf_mem_zero(reg_ap_cap[index].sup_chan_list, 1861 REG_MAX_CHANNELS_PER_OPERATING_CLASS); 1862 reg_ap_cap[index].num_supported_chan = 0; 1863 qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list, 1864 REG_MAX_CHANNELS_PER_OPERATING_CLASS); 1865 reg_ap_cap[index].num_non_supported_chan = 0; 1866 reg_get_channels_from_opclassmap(pdev, 1867 reg_ap_cap, 1868 index, 1869 op_class_tbl, 1870 &is_opclass_operable, 1871 opclass_conf, 1872 in_6g_pwr_mode); 1873 if (is_opclass_operable) { 1874 reg_ap_cap[index].op_class = op_class_tbl->op_class; 1875 reg_ap_cap[index].ch_width = 1876 op_class_tbl->chan_spacing; 1877 reg_ap_cap[index].start_freq = 1878 op_class_tbl->start_freq; 1879 reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power; 1880 reg_ap_cap[index].behav_limit = 1881 op_class_tbl->behav_limit; 1882 index++; 1883 } 1884 1885 op_class_tbl++; 1886 } 1887 1888 *n_opclasses = index; 1889 1890 return QDF_STATUS_SUCCESS; 1891 } 1892 1893 bool reg_is_6ghz_op_class(struct wlan_objmgr_pdev *pdev, uint8_t op_class) 1894 { 1895 return ((op_class >= MIN_6GHZ_OPER_CLASS) && 1896 (op_class <= MAX_6GHZ_OPER_CLASS)); 1897 } 1898 1899 /** 1900 * reg_is_opclass_band_found() - Check if the input opclass is 2G or 5G. 1901 * @country: Pointer to country. 1902 * @op_class: Operating class. 1903 * @bandmask: Bitmask for band. 1904 * 1905 * Return : Return true if the input opclass' band (2Ghz or 5Ghz) matches one 1906 * of bandmask's band. 1907 */ 1908 static bool reg_is_opclass_band_found(const uint8_t *country, 1909 uint8_t op_class, 1910 uint8_t bandmask) 1911 { 1912 const struct reg_dmn_op_class_map_t *op_class_tbl; 1913 1914 op_class_tbl = reg_get_class_from_country((uint8_t *)country); 1915 1916 while (op_class_tbl && op_class_tbl->op_class) { 1917 if (op_class_tbl->op_class == op_class) { 1918 qdf_freq_t freq = op_class_tbl->start_freq + 1919 (op_class_tbl->channels[0] * FREQ_TO_CHAN_SCALE); 1920 1921 if ((bandmask & BIT(REG_BAND_5G)) && 1922 REG_IS_5GHZ_FREQ(freq)) 1923 return true; 1924 1925 if ((bandmask & BIT(REG_BAND_2G)) && 1926 REG_IS_24GHZ_CH_FREQ(freq)) 1927 return true; 1928 1929 return false; 1930 } 1931 1932 op_class_tbl++; 1933 } 1934 1935 reg_err_rl("Opclass %d is not found", op_class); 1936 1937 return false; 1938 } 1939 1940 bool reg_is_5ghz_op_class(const uint8_t *country, uint8_t op_class) 1941 { 1942 return reg_is_opclass_band_found(country, op_class, BIT(REG_BAND_5G)); 1943 } 1944 1945 bool reg_is_2ghz_op_class(const uint8_t *country, uint8_t op_class) 1946 { 1947 return reg_is_opclass_band_found(country, op_class, BIT(REG_BAND_2G)); 1948 } 1949 1950 /** 1951 * reg_convert_chan_spacing_to_width() - Convert channel spacing to 1952 * channel width. 1953 * @chan_spacing: Channel spacing 1954 * @opclass_chwidth: Opclass channel width 1955 * 1956 * Return: None 1957 */ 1958 #ifdef WLAN_FEATURE_11BE 1959 static void reg_convert_chan_spacing_to_width(uint16_t chan_spacing, 1960 uint16_t *opclass_chwidth) 1961 { 1962 switch (chan_spacing) { 1963 case BW_20_MHZ: 1964 case BW_25_MHZ: 1965 *opclass_chwidth = BW_20_MHZ; 1966 break; 1967 case BW_40_MHZ: 1968 *opclass_chwidth = BW_40_MHZ; 1969 break; 1970 case BW_80_MHZ: 1971 *opclass_chwidth = BW_80_MHZ; 1972 break; 1973 case BW_160_MHZ: 1974 *opclass_chwidth = BW_160_MHZ; 1975 break; 1976 case BW_320_MHZ: 1977 *opclass_chwidth = BW_320_MHZ; 1978 break; 1979 default: 1980 *opclass_chwidth = 0; 1981 } 1982 } 1983 #else 1984 static void reg_convert_chan_spacing_to_width(uint16_t chan_spacing, 1985 uint16_t *opclass_chwidth) 1986 { 1987 switch (chan_spacing) { 1988 case BW_20_MHZ: 1989 case BW_25_MHZ: 1990 *opclass_chwidth = BW_20_MHZ; 1991 break; 1992 case BW_40_MHZ: 1993 *opclass_chwidth = BW_40_MHZ; 1994 break; 1995 case BW_80_MHZ: 1996 *opclass_chwidth = BW_80_MHZ; 1997 break; 1998 case BW_160_MHZ: 1999 *opclass_chwidth = BW_160_MHZ; 2000 break; 2001 default: 2002 *opclass_chwidth = 0; 2003 } 2004 } 2005 #endif 2006 2007 QDF_STATUS 2008 reg_get_opclass_for_cur_hwmode(struct wlan_objmgr_pdev *pdev, 2009 struct regdmn_ap_cap_opclass_t *reg_ap_cap, 2010 uint8_t *n_opclasses, 2011 uint8_t max_supp_op_class, 2012 bool global_tbl_lookup, 2013 enum phy_ch_width max_chwidth, 2014 bool is_80p80_supp, 2015 enum supported_6g_pwr_types in_6g_pwr_mode) 2016 { 2017 uint8_t max_reg_power = 0; 2018 const struct reg_dmn_op_class_map_t *op_class_tbl; 2019 uint8_t index = 0; 2020 uint16_t out_width; 2021 2022 if (global_tbl_lookup) 2023 op_class_tbl = global_op_class; 2024 else 2025 reg_get_op_class_tbl_by_chan_map(&op_class_tbl); 2026 2027 max_reg_power = reg_get_max_tx_power(pdev); 2028 2029 out_width = reg_get_bw_value(max_chwidth); 2030 2031 while (op_class_tbl->op_class && (index < max_supp_op_class)) { 2032 bool is_opclass_operable = false; 2033 enum opclass_config opclass_in_config = 2034 OPCLASSES_SUPPORTED_BY_CUR_HWMODE; 2035 uint16_t opclass_width; 2036 2037 qdf_mem_zero(reg_ap_cap[index].sup_chan_list, 2038 REG_MAX_CHANNELS_PER_OPERATING_CLASS); 2039 reg_ap_cap[index].num_supported_chan = 0; 2040 qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list, 2041 REG_MAX_CHANNELS_PER_OPERATING_CLASS); 2042 reg_ap_cap[index].num_non_supported_chan = 0; 2043 2044 reg_convert_chan_spacing_to_width(op_class_tbl->chan_spacing, 2045 &opclass_width); 2046 2047 if ((opclass_width > out_width) || 2048 ((op_class_tbl->behav_limit == BIT(BEHAV_BW80_PLUS)) && 2049 !is_80p80_supp)) 2050 opclass_in_config = 2051 OPCLASSES_NOT_SUPPORTED_BY_CUR_HWMODE; 2052 2053 reg_get_channels_from_opclassmap(pdev, 2054 reg_ap_cap, 2055 index, 2056 op_class_tbl, 2057 &is_opclass_operable, 2058 opclass_in_config, 2059 in_6g_pwr_mode); 2060 2061 if (is_opclass_operable && opclass_in_config == 2062 OPCLASSES_SUPPORTED_BY_CUR_HWMODE) { 2063 reg_ap_cap[index].op_class = op_class_tbl->op_class; 2064 reg_ap_cap[index].ch_width = 2065 op_class_tbl->chan_spacing; 2066 reg_ap_cap[index].start_freq = 2067 op_class_tbl->start_freq; 2068 reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power; 2069 reg_ap_cap[index].behav_limit = 2070 op_class_tbl->behav_limit; 2071 index++; 2072 } 2073 op_class_tbl++; 2074 } 2075 2076 *n_opclasses = index; 2077 2078 return QDF_STATUS_SUCCESS; 2079 } 2080 2081 #ifndef CONFIG_REG_CLIENT 2082 /** 2083 * reg_enable_disable_chan_in_mas_chan_list() - Mark the opclass flag of the 2084 * freq/channel as disabled in the master channel list. Then based on that 2085 * regulatory disable/enable the freq/channel in the current channel list 2086 * @pdev_priv_obj: Pointer to regulatory pdev private object 2087 * @chan_num: 2.4 GHz or 5 GHz channel number 2088 * @is_disable: Boolean to disable or enable 2089 * 2090 * Return: void 2091 */ 2092 static void 2093 reg_enable_disable_chan_in_mas_chan_list(struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj, 2094 uint8_t chan_num, 2095 bool is_disable) 2096 { 2097 enum channel_enum chan_enum; 2098 struct regulatory_channel *mas_chan_list; 2099 qdf_freq_t freq; 2100 2101 freq = reg_legacy_chan_to_freq(pdev_priv_obj->pdev_ptr, chan_num); 2102 2103 /* 2104 * freq = 0 represent a regulatory disabled channel in master channel 2105 * list. Do not apply opclass disable/enable on a channel disabled in 2106 * the master channel list. 2107 */ 2108 if (!freq) { 2109 reg_err("Frequency should not be zero"); 2110 return; 2111 } 2112 2113 chan_enum = reg_get_chan_enum_for_freq(freq); 2114 if (reg_is_chan_enum_invalid(chan_enum)) { 2115 reg_err("Invalid chan enum %d", chan_enum); 2116 return; 2117 } 2118 2119 mas_chan_list = pdev_priv_obj->mas_chan_list; 2120 2121 if (is_disable) { 2122 mas_chan_list[chan_enum].opclass_chan_disable = true; 2123 } else { 2124 /* A channel can be enabled only if its not in NOL */ 2125 if (!mas_chan_list[chan_enum].nol_chan) 2126 mas_chan_list[chan_enum].opclass_chan_disable = false; 2127 } 2128 } 2129 2130 /** 2131 * reg_enable_disable_chan_freq() - Disable or enable a channel in the master 2132 * channel list, that is present in the operating class table's channel set. 2133 * @pdev: Pointer to pdev. 2134 * @is_disable: Boolean to disable or enable 2135 * @ieee_chan_list: Pointer to ieee_chan_list 2136 * @chan_list_size: Size of ieee_chan_list 2137 * 2138 * Return: void. 2139 */ 2140 static void 2141 reg_enable_disable_chan_freq(struct wlan_objmgr_pdev *pdev, 2142 bool is_disable, 2143 uint8_t *ieee_chan_list, 2144 uint8_t chan_list_size) 2145 { 2146 uint8_t i; 2147 struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj; 2148 2149 pdev_priv_obj = reg_get_pdev_obj(pdev); 2150 if (!pdev_priv_obj) { 2151 reg_err("pdev priv obj is NULL"); 2152 return; 2153 } 2154 2155 for (i = 0; i < chan_list_size; i++) { 2156 reg_enable_disable_chan_in_mas_chan_list(pdev_priv_obj, 2157 ieee_chan_list[i], 2158 is_disable); 2159 } 2160 2161 reg_compute_pdev_current_chan_list(pdev_priv_obj); 2162 } 2163 2164 /** 2165 * reg_is_chan_in_opclass_chan_list() - Check if a channel is present in the 2166 * operating class table's channel set 2167 * @chan: IEEE channel number 2168 * @opclass_chan_list: Pointer to opclass_chan_list 2169 * 2170 * Return: bool. 2171 */ 2172 static bool 2173 reg_is_chan_in_opclass_chan_list(uint8_t chan, const uint8_t *opclass_chan_list) 2174 { 2175 uint8_t j; 2176 2177 for (j = 0; j < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 2178 opclass_chan_list[j]; j++) { 2179 if (chan == opclass_chan_list[j]) 2180 return true; 2181 } 2182 2183 return false; 2184 } 2185 2186 /** 2187 * reg_is_inlst_subset_of_opchanlst() - Check if a channel present 2188 * in the input ieee_chan_list, is absent in the operating class table 2189 * channel set. 2190 * @opclass_chan_list: Pointer to opclass_chan_list 2191 * @ieee_chan_list: Pointer to ieee_chan_list 2192 * @ieee_chan_list_size: Size of ieee_chan_list 2193 * 2194 * Return: True if channel is absent in operating class table channel set. 2195 */ 2196 static bool 2197 reg_is_inlst_subset_of_opchanlst(const uint8_t *opclass_chan_list, 2198 uint8_t *ieee_chan_list, 2199 uint8_t ieee_chan_list_size) 2200 { 2201 uint8_t i; 2202 2203 for (i = 0; i < ieee_chan_list_size; i++) { 2204 if (!reg_is_chan_in_opclass_chan_list(ieee_chan_list[i], 2205 opclass_chan_list)) 2206 return true; 2207 } 2208 2209 return false; 2210 } 2211 2212 static bool reg_is_chanspacing_20mhz(uint16_t ch_spacing) 2213 { 2214 return (ch_spacing >= BW_20_MHZ) && (ch_spacing <= BW_25_MHZ); 2215 } 2216 2217 QDF_STATUS reg_enable_disable_opclass_chans(struct wlan_objmgr_pdev *pdev, 2218 bool is_disable, uint8_t opclass, 2219 uint8_t *ieee_chan_list, 2220 uint8_t chan_list_size, 2221 bool global_tbl_lookup) 2222 { 2223 const struct reg_dmn_op_class_map_t *op_class_tbl; 2224 struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj; 2225 2226 if (!ieee_chan_list) { 2227 reg_err("IEEE channel list is empty"); 2228 return QDF_STATUS_E_INVAL; 2229 } 2230 2231 pdev_priv_obj = reg_get_pdev_obj(pdev); 2232 if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) { 2233 reg_err("pdev reg obj is NULL"); 2234 return QDF_STATUS_E_FAILURE; 2235 } 2236 2237 if (global_tbl_lookup) 2238 op_class_tbl = global_op_class; 2239 else 2240 reg_get_op_class_tbl_by_chan_map(&op_class_tbl); 2241 2242 if (reg_is_6ghz_op_class(pdev, opclass)) { 2243 reg_err("6GHz operating class is not supported"); 2244 return QDF_STATUS_E_INVAL; 2245 } 2246 2247 while (op_class_tbl->op_class) { 2248 if (opclass == op_class_tbl->op_class) { 2249 if (!reg_is_chanspacing_20mhz(op_class_tbl->chan_spacing)) { 2250 reg_err("Opclass should only be 20 MHz opclass"); 2251 return QDF_STATUS_E_INVAL; 2252 } 2253 2254 if (reg_is_inlst_subset_of_opchanlst(op_class_tbl->channels, 2255 ieee_chan_list, 2256 chan_list_size)) { 2257 reg_err("Invalid channel present in chan list"); 2258 return QDF_STATUS_E_INVAL; 2259 } 2260 2261 reg_enable_disable_chan_freq(pdev, is_disable, 2262 ieee_chan_list, 2263 chan_list_size); 2264 2265 return QDF_STATUS_SUCCESS; 2266 } 2267 2268 op_class_tbl++; 2269 } 2270 2271 reg_err("The opclass is not found %d", opclass); 2272 return QDF_STATUS_E_INVAL; 2273 } 2274 #endif /* #ifndef CONFIG_REG_CLIENT */ 2275 #endif 2276