File Index
Files and directories
Sign in
FILE

link-selection.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/intel/iwlwifi/mld/tests/link-selection.c C
  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
 16static 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
 76KUNIT_ARRAY_PARAM_DESC(link_grading, link_grading_cases, desc);
 77
 78static 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
122static 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
162static struct kunit_case link_selection_cases[] = {
163	KUNIT_CASE_PARAM(test_link_grading, link_grading_gen_params),
164	{},
165};
166
167static 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
173kunit_test_suite(link_selection);
174
175static 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
283KUNIT_ARRAY_PARAM_DESC(link_pair, link_pair_cases, desc);
284
285static 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	/* link A is the primary and link B is the secondary */
291	struct iwl_mld_link_sel_data a = {
292		.chandef = params->chandef_a,
293		.link_id = 4,
294	};
295	struct iwl_mld_link_sel_data b = {
296		.chandef = params->chandef_b,
297		.link_id = 5,
298	};
299	struct iwl_mld_kunit_link assoc_link = {
300		.chandef = params->primary_link_active ? a.chandef : b.chandef,
301		.id = params->primary_link_active ? a.link_id : b.link_id,
302	};
303	u32 result;
304
305	vif = iwlmld_kunit_setup_mlo_assoc(BIT(a.link_id) | BIT(b.link_id),
306					   &assoc_link);
307
308	if (params->low_latency_vif)
309		iwl_mld_vif_from_mac80211(vif)->low_latency_causes = 1;
310
311	wiphy_lock(mld->wiphy);
312
313	/* Simulate channel load */
314	if (params->primary_link_active) {
315		struct iwl_mld_phy *phy =
316			iwlmld_kunit_get_phy_of_link(vif, a.link_id);
317
318		phy->avg_channel_load_not_by_us = params->chan_load_not_by_us;
319	}
320
321	result = iwl_mld_emlsr_pair_state(vif, &a, &b);
322
323	wiphy_unlock(mld->wiphy);
324
325	KUNIT_EXPECT_EQ(test, result, params->expected_result);
326}
327
328static struct kunit_case link_pair_criteria_test_cases[] = {
329	KUNIT_CASE_PARAM(test_iwl_mld_link_pair_allows_emlsr, link_pair_gen_params),
330	{}
331};
332
333static struct kunit_suite link_pair_criteria_tests = {
334	.name = "iwlmld_link_pair_allows_emlsr",
335	.test_cases = link_pair_criteria_test_cases,
336	.init = iwlmld_kunit_test_init,
337};
338
339kunit_test_suite(link_pair_criteria_tests);
~/ Read-only file preview.