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