1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * KUnit tests for link selection functions 4 * 5 * Copyright (C) 2025 Intel Corporation 6 */ 7 #include <kunit/static_stub.h> 8 9 #include "utils.h" 10 #include "mld.h" 11 #include "link.h" 12 #include "iface.h" 13 #include "phy.h" 14 #include "mlo.h" 15 16 static const struct link_grading_test_case { 17 const char *desc; 18 struct { 19 struct { 20 u8 link_id; 21 const struct cfg80211_chan_def *chandef; 22 bool active; 23 s32 signal; 24 bool has_chan_util_elem; 25 u8 chan_util; /* 0-255 , used only if has_chan_util_elem is true */ 26 u8 chan_load_by_us; /* 0-100, used only if active is true */; 27 } link; 28 } input; 29 unsigned int expected_grade; 30 } link_grading_cases[] = { 31 { 32 .desc = "channel util of 128 (50%)", 33 .input.link = { 34 .link_id = 0, 35 .chandef = &chandef_2ghz_20mhz, 36 .active = false, 37 .has_chan_util_elem = true, 38 .chan_util = 128, 39 }, 40 .expected_grade = 86, 41 }, 42 { 43 .desc = "channel util of 180 (70%)", 44 .input.link = { 45 .link_id = 0, 46 .chandef = &chandef_2ghz_20mhz, 47 .active = false, 48 .has_chan_util_elem = true, 49 .chan_util = 180, 50 }, 51 .expected_grade = 51, 52 }, 53 { 54 .desc = "channel util of 180 (70%), channel load by us of 10%", 55 .input.link = { 56 .link_id = 0, 57 .chandef = &chandef_2ghz_20mhz, 58 .has_chan_util_elem = true, 59 .chan_util = 180, 60 .active = true, 61 .chan_load_by_us = 10, 62 }, 63 .expected_grade = 67, 64 }, 65 { 66 .desc = "no channel util element", 67 .input.link = { 68 .link_id = 0, 69 .chandef = &chandef_2ghz_20mhz, 70 .active = true, 71 }, 72 .expected_grade = 120, 73 }, 74 }; 75 76 KUNIT_ARRAY_PARAM_DESC(link_grading, link_grading_cases, desc); 77 78 static void setup_link(struct ieee80211_bss_conf *link) 79 { 80 struct kunit *test = kunit_get_current_test(); 81 struct iwl_mld *mld = test->priv; 82 const struct link_grading_test_case *test_param = 83 (const void *)(test->param_value); 84 85 KUNIT_ALLOC_AND_ASSERT(test, link->bss); 86 87 link->bss->signal = DBM_TO_MBM(test_param->input.link.signal); 88 89 link->chanreq.oper = *test_param->input.link.chandef; 90 91 if (test_param->input.link.has_chan_util_elem) { 92 struct cfg80211_bss_ies *ies; 93 struct ieee80211_bss_load_elem bss_load = { 94 .channel_util = test_param->input.link.chan_util, 95 }; 96 struct element *elem = 97 iwlmld_kunit_gen_element(WLAN_EID_QBSS_LOAD, 98 &bss_load, 99 sizeof(bss_load)); 100 unsigned int elem_len = sizeof(*elem) + sizeof(bss_load); 101 102 KUNIT_ALLOC_AND_ASSERT_SIZE(test, ies, sizeof(*ies) + elem_len); 103 memcpy(ies->data, elem, elem_len); 104 ies->len = elem_len; 105 rcu_assign_pointer(link->bss->beacon_ies, ies); 106 rcu_assign_pointer(link->bss->ies, ies); 107 } 108 109 if (test_param->input.link.active) { 110 struct ieee80211_chanctx_conf *chan_ctx = 111 wiphy_dereference(mld->wiphy, link->chanctx_conf); 112 struct iwl_mld_phy *phy; 113 114 KUNIT_ASSERT_NOT_NULL(test, chan_ctx); 115 116 phy = iwl_mld_phy_from_mac80211(chan_ctx); 117 118 phy->channel_load_by_us = test_param->input.link.chan_load_by_us; 119 } 120 } 121 122 static void test_link_grading(struct kunit *test) 123 { 124 struct iwl_mld *mld = test->priv; 125 const struct link_grading_test_case *test_param = 126 (const void *)(test->param_value); 127 struct ieee80211_vif *vif; 128 struct ieee80211_bss_conf *link; 129 unsigned int actual_grade; 130 /* Extract test case parameters */ 131 u8 link_id = test_param->input.link.link_id; 132 bool active = test_param->input.link.active; 133 u16 valid_links; 134 struct iwl_mld_kunit_link assoc_link = { 135 .chandef = test_param->input.link.chandef, 136 }; 137 138 /* If the link is not active, use a different link as the assoc link */ 139 if (active) { 140 assoc_link.id = link_id; 141 valid_links = BIT(link_id); 142 } else { 143 assoc_link.id = BIT(ffz(BIT(link_id))); 144 valid_links = BIT(assoc_link.id) | BIT(link_id); 145 } 146 147 vif = iwlmld_kunit_setup_mlo_assoc(valid_links, &assoc_link); 148 149 wiphy_lock(mld->wiphy); 150 link = wiphy_dereference(mld->wiphy, vif->link_conf[link_id]); 151 KUNIT_ASSERT_NOT_NULL(test, link); 152 153 setup_link(link); 154 155 actual_grade = iwl_mld_get_link_grade(mld, link); 156 wiphy_unlock(mld->wiphy); 157 158 /* Assert that the returned grade matches the expected grade */ 159 KUNIT_EXPECT_EQ(test, actual_grade, test_param->expected_grade); 160 } 161 162 static struct kunit_case link_selection_cases[] = { 163 KUNIT_CASE_PARAM(test_link_grading, link_grading_gen_params), 164 {}, 165 }; 166 167 static struct kunit_suite link_selection = { 168 .name = "iwlmld-link-selection-tests", 169 .test_cases = link_selection_cases, 170 .init = iwlmld_kunit_test_init, 171 }; 172 173 kunit_test_suite(link_selection); 174 175 static const struct link_pair_case { 176 const char *desc; 177 const struct cfg80211_chan_def *chandef_a, *chandef_b; 178 bool low_latency_vif; 179 u32 chan_load_not_by_us; 180 bool primary_link_active; 181 u32 expected_result; 182 } link_pair_cases[] = { 183 { 184 .desc = "Unequal bandwidth, primary link inactive, EMLSR not allowed", 185 .low_latency_vif = false, 186 .primary_link_active = false, 187 .chandef_a = &chandef_5ghz_40mhz, 188 .chandef_b = &chandef_6ghz_20mhz, 189 .expected_result = IWL_MLD_EMLSR_EXIT_CHAN_LOAD, 190 }, 191 { 192 .desc = "Equal bandwidths, sufficient channel load, EMLSR allowed", 193 .low_latency_vif = false, 194 .primary_link_active = true, 195 .chan_load_not_by_us = 11, 196 .chandef_a = &chandef_5ghz_40mhz, 197 .chandef_b = &chandef_6ghz_40mhz, 198 .expected_result = 0, 199 }, 200 { 201 .desc = "Equal bandwidths, insufficient channel load, EMLSR not allowed", 202 .low_latency_vif = false, 203 .primary_link_active = true, 204 .chan_load_not_by_us = 6, 205 .chandef_a = &chandef_5ghz_80mhz, 206 .chandef_b = &chandef_6ghz_80mhz, 207 .expected_result = IWL_MLD_EMLSR_EXIT_CHAN_LOAD, 208 }, 209 { 210 .desc = "Low latency VIF, sufficient channel load, EMLSR allowed", 211 .low_latency_vif = true, 212 .primary_link_active = true, 213 .chan_load_not_by_us = 6, 214 .chandef_a = &chandef_5ghz_160mhz, 215 .chandef_b = &chandef_6ghz_160mhz, 216 .expected_result = 0, 217 }, 218 { 219 .desc = "Different bandwidths (2x ratio), primary link load permits EMLSR", 220 .low_latency_vif = false, 221 .primary_link_active = true, 222 .chan_load_not_by_us = 30, 223 .chandef_a = &chandef_5ghz_40mhz, 224 .chandef_b = &chandef_6ghz_20mhz, 225 .expected_result = 0, 226 }, 227 { 228 .desc = "Different bandwidths (4x ratio), primary link load permits EMLSR", 229 .low_latency_vif = false, 230 .primary_link_active = true, 231 .chan_load_not_by_us = 45, 232 .chandef_a = &chandef_5ghz_80mhz, 233 .chandef_b = &chandef_6ghz_20mhz, 234 .expected_result = 0, 235 }, 236 { 237 .desc = "Different bandwidths (16x ratio), primary link load insufficient", 238 .low_latency_vif = false, 239 .primary_link_active = true, 240 .chan_load_not_by_us = 45, 241 .chandef_a = &chandef_6ghz_320mhz, 242 .chandef_b = &chandef_5ghz_20mhz, 243 .expected_result = IWL_MLD_EMLSR_EXIT_CHAN_LOAD, 244 }, 245 { 246 .desc = "Same band not allowed (2.4 GHz)", 247 .low_latency_vif = false, 248 .primary_link_active = true, 249 .chan_load_not_by_us = 30, 250 .chandef_a = &chandef_2ghz_20mhz, 251 .chandef_b = &chandef_2ghz_11_20mhz, 252 .expected_result = IWL_MLD_EMLSR_EXIT_EQUAL_BAND, 253 }, 254 { 255 .desc = "Same band not allowed (5 GHz)", 256 .low_latency_vif = false, 257 .primary_link_active = true, 258 .chan_load_not_by_us = 30, 259 .chandef_a = &chandef_5ghz_40mhz, 260 .chandef_b = &chandef_5ghz_40mhz, 261 .expected_result = IWL_MLD_EMLSR_EXIT_EQUAL_BAND, 262 }, 263 { 264 .desc = "Same band allowed (5 GHz separated)", 265 .low_latency_vif = false, 266 .primary_link_active = true, 267 .chan_load_not_by_us = 30, 268 .chandef_a = &chandef_5ghz_40mhz, 269 .chandef_b = &chandef_5ghz_120_40mhz, 270 .expected_result = 0, 271 }, 272 { 273 .desc = "Same band not allowed (6 GHz)", 274 .low_latency_vif = false, 275 .primary_link_active = true, 276 .chan_load_not_by_us = 30, 277 .chandef_a = &chandef_6ghz_160mhz, 278 .chandef_b = &chandef_6ghz_221_160mhz, 279 .expected_result = IWL_MLD_EMLSR_EXIT_EQUAL_BAND, 280 }, 281 }; 282 283 KUNIT_ARRAY_PARAM_DESC(link_pair, link_pair_cases, desc); 284 285 static void test_iwl_mld_link_pair_allows_emlsr(struct kunit *test) 286 { 287 const struct link_pair_case *params = test->param_value; 288 struct iwl_mld *mld = test->priv; 289 struct ieee80211_vif *vif; 290 struct ieee80211_bss_conf *link; 291 /* link A is the primary and link B is the secondary */ 292 struct iwl_mld_link_sel_data a = { 293 .chandef = params->chandef_a, 294 .link_id = 4, 295 }; 296 struct iwl_mld_link_sel_data b = { 297 .chandef = params->chandef_b, 298 .link_id = 5, 299 }; 300 struct iwl_mld_kunit_link assoc_link = { 301 .chandef = params->primary_link_active ? a.chandef : b.chandef, 302 .id = params->primary_link_active ? a.link_id : b.link_id, 303 }; 304 u32 result; 305 306 vif = iwlmld_kunit_setup_mlo_assoc(BIT(a.link_id) | BIT(b.link_id), 307 &assoc_link); 308 309 if (params->low_latency_vif) 310 iwl_mld_vif_from_mac80211(vif)->low_latency_causes = 1; 311 312 wiphy_lock(mld->wiphy); 313 314 link = wiphy_dereference(mld->wiphy, vif->link_conf[a.link_id]); 315 KUNIT_ALLOC_AND_ASSERT(test, link->bss); 316 link = wiphy_dereference(mld->wiphy, vif->link_conf[b.link_id]); 317 KUNIT_ALLOC_AND_ASSERT(test, link->bss); 318 319 /* Simulate channel load */ 320 if (params->primary_link_active) { 321 struct iwl_mld_phy *phy = 322 iwlmld_kunit_get_phy_of_link(vif, a.link_id); 323 324 phy->avg_channel_load_not_by_us = params->chan_load_not_by_us; 325 } 326 327 result = iwl_mld_emlsr_pair_state(vif, &a, &b); 328 329 wiphy_unlock(mld->wiphy); 330 331 KUNIT_EXPECT_EQ(test, result, params->expected_result); 332 } 333 334 static struct kunit_case link_pair_criteria_test_cases[] = { 335 KUNIT_CASE_PARAM(test_iwl_mld_link_pair_allows_emlsr, link_pair_gen_params), 336 {} 337 }; 338 339 static struct kunit_suite link_pair_criteria_tests = { 340 .name = "iwlmld_link_pair_allows_emlsr", 341 .test_cases = link_pair_criteria_test_cases, 342 .init = iwlmld_kunit_test_init, 343 }; 344 345 kunit_test_suite(link_pair_criteria_tests); 346