1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * KUnit tests for channel helper functions 4 * 5 * Copyright (C) 2024 Intel Corporation 6 */ 7 #include <net/mac80211.h> 8 #include "../mvm.h" 9 #include <kunit/test.h> 10 11 MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING); 12 13 static struct wiphy wiphy = { 14 .mtx = __MUTEX_INITIALIZER(wiphy.mtx), 15 }; 16 17 static struct ieee80211_hw hw = { 18 .wiphy = &wiphy, 19 }; 20 21 static struct ieee80211_channel chan_5ghz = { 22 .band = NL80211_BAND_5GHZ, 23 }; 24 25 static struct ieee80211_channel chan_6ghz = { 26 .band = NL80211_BAND_6GHZ, 27 }; 28 29 static struct ieee80211_channel chan_2ghz = { 30 .band = NL80211_BAND_2GHZ, 31 }; 32 33 static struct cfg80211_chan_def chandef_a = {}; 34 35 static struct cfg80211_chan_def chandef_b = {}; 36 37 static struct iwl_mvm_phy_ctxt ctx = {}; 38 39 static struct iwl_mvm_vif_link_info mvm_link = { 40 .phy_ctxt = &ctx, 41 .active = true 42 }; 43 44 static struct cfg80211_bss bss = {}; 45 46 static struct ieee80211_bss_conf link_conf = {.bss = &bss}; 47 48 static const struct iwl_fw_cmd_version entry = { 49 .group = LEGACY_GROUP, 50 .cmd = BT_PROFILE_NOTIFICATION, 51 .notif_ver = 4 52 }; 53 54 static struct iwl_fw fw = { 55 .ucode_capa = { 56 .n_cmd_versions = 1, 57 .cmd_versions = &entry, 58 }, 59 }; 60 61 static struct iwl_mvm mvm = { 62 .hw = &hw, 63 .fw = &fw, 64 }; 65 66 static const struct link_grading_case { 67 const char *desc; 68 const struct cfg80211_chan_def chandef; 69 s32 signal; 70 s16 channel_util; 71 int chan_load_by_us; 72 unsigned int grade; 73 } link_grading_cases[] = { 74 { 75 .desc = "UHB, RSSI below range, no factors", 76 .chandef = { 77 .chan = &chan_6ghz, 78 .width = NL80211_CHAN_WIDTH_20, 79 }, 80 .signal = -100, 81 .grade = 177, 82 }, 83 { 84 .desc = "LB, RSSI in range, no factors", 85 .chandef = { 86 .chan = &chan_2ghz, 87 .width = NL80211_CHAN_WIDTH_20, 88 }, 89 .signal = -84, 90 .grade = 344, 91 }, 92 { 93 .desc = "HB, RSSI above range, no factors", 94 .chandef = { 95 .chan = &chan_5ghz, 96 .width = NL80211_CHAN_WIDTH_20, 97 }, 98 .signal = -50, 99 .grade = 3442, 100 }, 101 { 102 .desc = "HB, BSS Load IE (20 percent), inactive link, no puncturing factor", 103 .chandef = { 104 .chan = &chan_5ghz, 105 .width = NL80211_CHAN_WIDTH_20, 106 }, 107 .signal = -66, 108 .channel_util = 51, 109 .grade = 1836, 110 }, 111 { 112 .desc = "LB, BSS Load IE (20 percent), active link, chan_load_by_us=10 percent. No puncturing factor", 113 .chandef = { 114 .chan = &chan_2ghz, 115 .width = NL80211_CHAN_WIDTH_20, 116 }, 117 .signal = -61, 118 .channel_util = 51, 119 .chan_load_by_us = 10, 120 .grade = 2061, 121 }, 122 { 123 .desc = "UHB, BSS Load IE (40 percent), active link, chan_load_by_us=50 (invalid) percent. No puncturing factor", 124 .chandef = { 125 .chan = &chan_6ghz, 126 .width = NL80211_CHAN_WIDTH_20, 127 }, 128 .signal = -66, 129 .channel_util = 102, 130 .chan_load_by_us = 50, 131 .grade = 1552, 132 }, 133 { .desc = "HB, 80 MHz, no channel load factor, punctured percentage 0", 134 .chandef = { 135 .chan = &chan_5ghz, 136 .width = NL80211_CHAN_WIDTH_80, 137 .punctured = 0x0000 138 }, 139 .signal = -72, 140 .grade = 1750, 141 }, 142 { .desc = "HB, 160 MHz, no channel load factor, punctured percentage 25", 143 .chandef = { 144 .chan = &chan_5ghz, 145 .width = NL80211_CHAN_WIDTH_160, 146 .punctured = 0x3 147 }, 148 .signal = -72, 149 .grade = 1312, 150 }, 151 { .desc = "UHB, 320 MHz, no channel load factor, punctured percentage 12.5 (2/16)", 152 .chandef = { 153 .chan = &chan_6ghz, 154 .width = NL80211_CHAN_WIDTH_320, 155 .punctured = 0x3 156 }, 157 .signal = -72, 158 .grade = 1806, 159 }, 160 { .desc = "HB, 160 MHz, channel load 20, channel load by us 10, punctured percentage 25", 161 .chandef = { 162 .chan = &chan_5ghz, 163 .width = NL80211_CHAN_WIDTH_160, 164 .punctured = 0x3 165 }, 166 .channel_util = 51, 167 .chan_load_by_us = 10, 168 .signal = -72, 169 .grade = 1179, 170 }, 171 }; 172 173 KUNIT_ARRAY_PARAM_DESC(link_grading, link_grading_cases, desc) 174 175 static void setup_link_conf(struct kunit *test) 176 { 177 const struct link_grading_case *params = test->param_value; 178 size_t vif_size = sizeof(struct ieee80211_vif) + 179 sizeof(struct iwl_mvm_vif); 180 struct ieee80211_vif *vif = kunit_kzalloc(test, vif_size, GFP_KERNEL); 181 struct ieee80211_bss_load_elem *bss_load; 182 struct element *element; 183 size_t ies_size = sizeof(struct cfg80211_bss_ies) + sizeof(*bss_load) + sizeof(element); 184 struct cfg80211_bss_ies *ies; 185 struct iwl_mvm_vif *mvmvif; 186 187 KUNIT_ASSERT_NOT_NULL(test, vif); 188 189 mvmvif = iwl_mvm_vif_from_mac80211(vif); 190 if (params->chan_load_by_us > 0) { 191 ctx.channel_load_by_us = params->chan_load_by_us; 192 mvmvif->link[0] = &mvm_link; 193 } 194 195 link_conf.vif = vif; 196 link_conf.chanreq.oper = params->chandef; 197 bss.signal = DBM_TO_MBM(params->signal); 198 199 ies = kunit_kzalloc(test, ies_size, GFP_KERNEL); 200 KUNIT_ASSERT_NOT_NULL(test, ies); 201 ies->len = sizeof(*bss_load) + sizeof(struct element); 202 203 element = (void *)ies->data; 204 element->datalen = sizeof(*bss_load); 205 element->id = 11; 206 207 bss_load = (void *)element->data; 208 bss_load->channel_util = params->channel_util; 209 210 rcu_assign_pointer(bss.ies, ies); 211 } 212 213 static void test_link_grading(struct kunit *test) 214 { 215 const struct link_grading_case *params = test->param_value; 216 unsigned int ret; 217 218 setup_link_conf(test); 219 220 rcu_read_lock(); 221 ret = iwl_mvm_get_link_grade(&link_conf); 222 rcu_read_unlock(); 223 224 KUNIT_EXPECT_EQ(test, ret, params->grade); 225 226 kunit_kfree(test, link_conf.vif); 227 RCU_INIT_POINTER(bss.ies, NULL); 228 } 229 230 static struct kunit_case link_grading_test_cases[] = { 231 KUNIT_CASE_PARAM(test_link_grading, link_grading_gen_params), 232 {} 233 }; 234 235 static struct kunit_suite link_grading = { 236 .name = "iwlmvm-link-grading", 237 .test_cases = link_grading_test_cases, 238 }; 239 240 kunit_test_suite(link_grading); 241 242 static const struct valid_link_pair_case { 243 const char *desc; 244 bool bt; 245 struct ieee80211_channel *chan_a; 246 struct ieee80211_channel *chan_b; 247 enum nl80211_chan_width cw_a; 248 enum nl80211_chan_width cw_b; 249 s32 sig_a; 250 s32 sig_b; 251 bool csa_a; 252 bool valid; 253 } valid_link_pair_cases[] = { 254 { 255 .desc = "HB + UHB, valid.", 256 .chan_a = &chan_6ghz, 257 .chan_b = &chan_5ghz, 258 .valid = true, 259 }, 260 { 261 .desc = "LB + HB, no BT.", 262 .chan_a = &chan_2ghz, 263 .chan_b = &chan_5ghz, 264 .valid = false, 265 }, 266 { 267 .desc = "LB + HB, with BT.", 268 .bt = true, 269 .chan_a = &chan_2ghz, 270 .chan_b = &chan_5ghz, 271 .valid = false, 272 }, 273 { 274 .desc = "Same band", 275 .chan_a = &chan_2ghz, 276 .chan_b = &chan_2ghz, 277 .valid = false, 278 }, 279 { 280 .desc = "RSSI: LB, 20 MHz, low", 281 .chan_a = &chan_2ghz, 282 .cw_a = NL80211_CHAN_WIDTH_20, 283 .sig_a = -68, 284 .chan_b = &chan_5ghz, 285 .valid = false, 286 }, 287 { 288 .desc = "RSSI: UHB, 20 MHz, high", 289 .chan_a = &chan_6ghz, 290 .cw_a = NL80211_CHAN_WIDTH_20, 291 .sig_a = -66, 292 .chan_b = &chan_5ghz, 293 .cw_b = NL80211_CHAN_WIDTH_20, 294 .valid = true, 295 }, 296 { 297 .desc = "RSSI: UHB, 40 MHz, low", 298 .chan_a = &chan_6ghz, 299 .cw_a = NL80211_CHAN_WIDTH_40, 300 .sig_a = -65, 301 .chan_b = &chan_5ghz, 302 .cw_b = NL80211_CHAN_WIDTH_40, 303 .valid = false, 304 }, 305 { 306 .desc = "RSSI: UHB, 40 MHz, high", 307 .chan_a = &chan_6ghz, 308 .cw_a = NL80211_CHAN_WIDTH_40, 309 .sig_a = -63, 310 .chan_b = &chan_5ghz, 311 .cw_b = NL80211_CHAN_WIDTH_40, 312 .valid = true, 313 }, 314 { 315 .desc = "RSSI: UHB, 80 MHz, low", 316 .chan_a = &chan_6ghz, 317 .cw_a = NL80211_CHAN_WIDTH_80, 318 .sig_a = -62, 319 .chan_b = &chan_5ghz, 320 .cw_b = NL80211_CHAN_WIDTH_80, 321 .valid = false, 322 }, 323 { 324 .desc = "RSSI: UHB, 80 MHz, high", 325 .chan_a = &chan_6ghz, 326 .cw_a = NL80211_CHAN_WIDTH_80, 327 .sig_a = -60, 328 .chan_b = &chan_5ghz, 329 .cw_b = NL80211_CHAN_WIDTH_80, 330 .valid = true, 331 }, 332 { 333 .desc = "RSSI: UHB, 160 MHz, low", 334 .chan_a = &chan_6ghz, 335 .cw_a = NL80211_CHAN_WIDTH_160, 336 .sig_a = -59, 337 .chan_b = &chan_5ghz, 338 .cw_b = NL80211_CHAN_WIDTH_160, 339 .valid = false, 340 }, 341 { 342 .desc = "RSSI: HB, 160 MHz, high", 343 .chan_a = &chan_6ghz, 344 .cw_a = NL80211_CHAN_WIDTH_160, 345 .sig_a = -5, 346 .chan_b = &chan_5ghz, 347 .cw_b = NL80211_CHAN_WIDTH_160, 348 .valid = true, 349 }, 350 { 351 .desc = "CSA active", 352 .chan_a = &chan_6ghz, 353 .cw_a = NL80211_CHAN_WIDTH_160, 354 .sig_a = -5, 355 .chan_b = &chan_5ghz, 356 .cw_b = NL80211_CHAN_WIDTH_160, 357 .valid = false, 358 /* same as previous entry with valid=true except for CSA */ 359 .csa_a = true, 360 }, 361 }; 362 363 KUNIT_ARRAY_PARAM_DESC(valid_link_pair, valid_link_pair_cases, desc) 364 365 static void test_valid_link_pair(struct kunit *test) 366 { 367 const struct valid_link_pair_case *params = test->param_value; 368 size_t vif_size = sizeof(struct ieee80211_vif) + 369 sizeof(struct iwl_mvm_vif); 370 struct ieee80211_vif *vif = kunit_kzalloc(test, vif_size, GFP_KERNEL); 371 struct iwl_trans *trans = kunit_kzalloc(test, sizeof(struct iwl_trans), 372 GFP_KERNEL); 373 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 374 struct iwl_mvm_link_sel_data link_a = { 375 .chandef = &chandef_a, 376 .link_id = 1, 377 .signal = params->sig_a, 378 }; 379 struct iwl_mvm_link_sel_data link_b = { 380 .chandef = &chandef_b, 381 .link_id = 5, 382 .signal = params->sig_b, 383 }; 384 struct ieee80211_bss_conf *conf; 385 bool result; 386 387 KUNIT_ASSERT_NOT_NULL(test, vif); 388 KUNIT_ASSERT_NOT_NULL(test, trans); 389 390 chandef_a.chan = params->chan_a; 391 chandef_b.chan = params->chan_b; 392 393 chandef_a.width = params->cw_a ?: NL80211_CHAN_WIDTH_20; 394 chandef_b.width = params->cw_b ?: NL80211_CHAN_WIDTH_20; 395 396 #ifdef CONFIG_IWLWIFI_SUPPORT_DEBUG_OVERRIDES 397 trans->dbg_cfg = default_dbg_config; 398 #endif 399 mvm.trans = trans; 400 401 mvm.last_bt_notif.wifi_loss_low_rssi = params->bt; 402 mvmvif->mvm = &mvm; 403 404 conf = kunit_kzalloc(test, sizeof(*vif->link_conf[0]), GFP_KERNEL); 405 KUNIT_ASSERT_NOT_NULL(test, conf); 406 conf->chanreq.oper = chandef_a; 407 conf->csa_active = params->csa_a; 408 vif->link_conf[link_a.link_id] = (void __rcu *)conf; 409 410 conf = kunit_kzalloc(test, sizeof(*vif->link_conf[0]), GFP_KERNEL); 411 KUNIT_ASSERT_NOT_NULL(test, conf); 412 conf->chanreq.oper = chandef_b; 413 vif->link_conf[link_b.link_id] = (void __rcu *)conf; 414 415 wiphy_lock(&wiphy); 416 result = iwl_mvm_mld_valid_link_pair(vif, &link_a, &link_b); 417 wiphy_unlock(&wiphy); 418 419 KUNIT_EXPECT_EQ(test, result, params->valid); 420 421 kunit_kfree(test, vif); 422 kunit_kfree(test, trans); 423 } 424 425 static struct kunit_case valid_link_pair_test_cases[] = { 426 KUNIT_CASE_PARAM(test_valid_link_pair, valid_link_pair_gen_params), 427 {}, 428 }; 429 430 static struct kunit_suite valid_link_pair = { 431 .name = "iwlmvm-valid-link-pair", 432 .test_cases = valid_link_pair_test_cases, 433 }; 434 435 kunit_test_suite(valid_link_pair); 436