diff options
Diffstat (limited to 'sys/contrib/dev/iwlwifi/mld/tests/link-selection.c')
| -rw-r--r-- | sys/contrib/dev/iwlwifi/mld/tests/link-selection.c | 339 | 
1 files changed, 339 insertions, 0 deletions
| diff --git a/sys/contrib/dev/iwlwifi/mld/tests/link-selection.c b/sys/contrib/dev/iwlwifi/mld/tests/link-selection.c new file mode 100644 index 000000000000..766c24db3613 --- /dev/null +++ b/sys/contrib/dev/iwlwifi/mld/tests/link-selection.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * KUnit tests for link selection functions + * + * Copyright (C) 2025 Intel Corporation + */ +#include <kunit/static_stub.h> + +#include "utils.h" +#include "mld.h" +#include "link.h" +#include "iface.h" +#include "phy.h" +#include "mlo.h" + +static const struct link_grading_test_case { +	const char *desc; +	struct { +		struct { +			u8 link_id; +			const struct cfg80211_chan_def *chandef; +			bool active; +			s32 signal; +			bool has_chan_util_elem; +			u8 chan_util; /* 0-255 , used only if has_chan_util_elem is true */ +			u8 chan_load_by_us; /* 0-100, used only if active is true */; +		} link; +	} input; +	unsigned int expected_grade; +} link_grading_cases[] = { +	{ +		.desc = "channel util of 128 (50%)", +		.input.link = { +			.link_id = 0, +			.chandef = &chandef_2ghz_20mhz, +			.active = false, +			.has_chan_util_elem = true, +			.chan_util = 128, +		}, +		.expected_grade = 86, +	}, +	{ +		.desc = "channel util of 180 (70%)", +		.input.link = { +			.link_id = 0, +			.chandef = &chandef_2ghz_20mhz, +			.active = false, +			.has_chan_util_elem = true, +			.chan_util = 180, +		}, +		.expected_grade = 51, +	}, +	{ +		.desc = "channel util of 180 (70%), channel load by us of 10%", +		.input.link = { +			.link_id = 0, +			.chandef = &chandef_2ghz_20mhz, +			.has_chan_util_elem = true, +			.chan_util = 180, +			.active = true, +			.chan_load_by_us = 10, +		}, +		.expected_grade = 67, +	}, +		{ +		.desc = "no channel util element", +		.input.link = { +			.link_id = 0, +			.chandef = &chandef_2ghz_20mhz, +			.active = true, +		}, +		.expected_grade = 120, +	}, +}; + +KUNIT_ARRAY_PARAM_DESC(link_grading, link_grading_cases, desc); + +static void setup_link(struct ieee80211_bss_conf *link) +{ +	struct kunit *test = kunit_get_current_test(); +	struct iwl_mld *mld = test->priv; +	const struct link_grading_test_case *test_param = +		(const void *)(test->param_value); + +	KUNIT_ALLOC_AND_ASSERT(test, link->bss); + +	link->bss->signal = DBM_TO_MBM(test_param->input.link.signal); + +	link->chanreq.oper = *test_param->input.link.chandef; + +	if (test_param->input.link.has_chan_util_elem) { +		struct cfg80211_bss_ies *ies; +		struct ieee80211_bss_load_elem bss_load = { +			.channel_util = test_param->input.link.chan_util, +		}; +		struct element *elem = +			iwlmld_kunit_gen_element(WLAN_EID_QBSS_LOAD, +						 &bss_load, +						 sizeof(bss_load)); +		unsigned int elem_len = sizeof(*elem) + sizeof(bss_load); + +		KUNIT_ALLOC_AND_ASSERT_SIZE(test, ies, sizeof(*ies) + elem_len); +		memcpy(ies->data, elem, elem_len); +		ies->len = elem_len; +		rcu_assign_pointer(link->bss->beacon_ies, ies); +		rcu_assign_pointer(link->bss->ies, ies); +	} + +	if (test_param->input.link.active) { +		struct ieee80211_chanctx_conf *chan_ctx = +			wiphy_dereference(mld->wiphy, link->chanctx_conf); +		struct iwl_mld_phy *phy; + +		KUNIT_ASSERT_NOT_NULL(test, chan_ctx); + +		phy = iwl_mld_phy_from_mac80211(chan_ctx); + +		phy->channel_load_by_us = test_param->input.link.chan_load_by_us; +	} +} + +static void test_link_grading(struct kunit *test) +{ +	struct iwl_mld *mld = test->priv; +	const struct link_grading_test_case *test_param = +		(const void *)(test->param_value); +	struct ieee80211_vif *vif; +	struct ieee80211_bss_conf *link; +	unsigned int actual_grade; +	/* Extract test case parameters */ +	u8 link_id = test_param->input.link.link_id; +	bool active = test_param->input.link.active; +	u16 valid_links; +	struct iwl_mld_kunit_link assoc_link = { +		.chandef = test_param->input.link.chandef, +	}; + +	/* If the link is not active, use a different link as the assoc link */ +	if (active) { +		assoc_link.id = link_id; +		valid_links = BIT(link_id); +	} else { +		assoc_link.id = BIT(ffz(BIT(link_id))); +		valid_links = BIT(assoc_link.id) | BIT(link_id); +	} + +	vif = iwlmld_kunit_setup_mlo_assoc(valid_links, &assoc_link); + +	wiphy_lock(mld->wiphy); +	link = wiphy_dereference(mld->wiphy, vif->link_conf[link_id]); +	KUNIT_ASSERT_NOT_NULL(test, link); + +	setup_link(link); + +	actual_grade = iwl_mld_get_link_grade(mld, link); +	wiphy_unlock(mld->wiphy); + +	/* Assert that the returned grade matches the expected grade */ +	KUNIT_EXPECT_EQ(test, actual_grade, test_param->expected_grade); +} + +static struct kunit_case link_selection_cases[] = { +	KUNIT_CASE_PARAM(test_link_grading, link_grading_gen_params), +	{}, +}; + +static struct kunit_suite link_selection = { +	.name = "iwlmld-link-selection-tests", +	.test_cases = link_selection_cases, +	.init = iwlmld_kunit_test_init, +}; + +kunit_test_suite(link_selection); + +static const struct link_pair_case { +	const char *desc; +	const struct cfg80211_chan_def *chandef_a, *chandef_b; +	bool low_latency_vif; +	u32 chan_load_not_by_us; +	bool primary_link_active; +	u32 expected_result; +} link_pair_cases[] = { +	{ +		.desc = "Unequal bandwidth, primary link inactive, EMLSR not allowed", +		.low_latency_vif = false, +		.primary_link_active = false, +		.chandef_a = &chandef_5ghz_40mhz, +		.chandef_b = &chandef_6ghz_20mhz, +		.expected_result = IWL_MLD_EMLSR_EXIT_CHAN_LOAD, +	}, +	{ +		.desc = "Equal bandwidths, sufficient channel load, EMLSR allowed", +		.low_latency_vif = false, +		.primary_link_active = true, +		.chan_load_not_by_us = 11, +		.chandef_a = &chandef_5ghz_40mhz, +		.chandef_b = &chandef_6ghz_40mhz, +		.expected_result = 0, +	}, +	{ +		.desc = "Equal bandwidths, insufficient channel load, EMLSR not allowed", +		.low_latency_vif = false, +		.primary_link_active = true, +		.chan_load_not_by_us = 6, +		.chandef_a = &chandef_5ghz_80mhz, +		.chandef_b = &chandef_6ghz_80mhz, +		.expected_result = IWL_MLD_EMLSR_EXIT_CHAN_LOAD, +	}, +	{ +		.desc = "Low latency VIF, sufficient channel load, EMLSR allowed", +		.low_latency_vif = true, +		.primary_link_active = true, +		.chan_load_not_by_us = 6, +		.chandef_a = &chandef_5ghz_160mhz, +		.chandef_b = &chandef_6ghz_160mhz, +		.expected_result = 0, +	}, +	{ +		.desc = "Different bandwidths (2x ratio), primary link load permits EMLSR", +		.low_latency_vif = false, +		.primary_link_active = true, +		.chan_load_not_by_us = 30, +		.chandef_a = &chandef_5ghz_40mhz, +		.chandef_b = &chandef_6ghz_20mhz, +		.expected_result = 0, +	}, +	{ +		.desc = "Different bandwidths (4x ratio), primary link load permits EMLSR", +		.low_latency_vif = false, +		.primary_link_active = true, +		.chan_load_not_by_us = 45, +		.chandef_a = &chandef_5ghz_80mhz, +		.chandef_b = &chandef_6ghz_20mhz, +		.expected_result = 0, +	}, +	{ +		.desc = "Different bandwidths (16x ratio), primary link load insufficient", +		.low_latency_vif = false, +		.primary_link_active = true, +		.chan_load_not_by_us = 45, +		.chandef_a = &chandef_6ghz_320mhz, +		.chandef_b = &chandef_5ghz_20mhz, +		.expected_result = IWL_MLD_EMLSR_EXIT_CHAN_LOAD, +	}, +	{ +		.desc = "Same band not allowed (2.4 GHz)", +		.low_latency_vif = false, +		.primary_link_active = true, +		.chan_load_not_by_us = 30, +		.chandef_a = &chandef_2ghz_20mhz, +		.chandef_b = &chandef_2ghz_11_20mhz, +		.expected_result = IWL_MLD_EMLSR_EXIT_EQUAL_BAND, +	}, +	{ +		.desc = "Same band not allowed (5 GHz)", +		.low_latency_vif = false, +		.primary_link_active = true, +		.chan_load_not_by_us = 30, +		.chandef_a = &chandef_5ghz_40mhz, +		.chandef_b = &chandef_5ghz_40mhz, +		.expected_result = IWL_MLD_EMLSR_EXIT_EQUAL_BAND, +	}, +	{ +		.desc = "Same band allowed (5 GHz separated)", +		.low_latency_vif = false, +		.primary_link_active = true, +		.chan_load_not_by_us = 30, +		.chandef_a = &chandef_5ghz_40mhz, +		.chandef_b = &chandef_5ghz_120_40mhz, +		.expected_result = 0, +	}, +	{ +		.desc = "Same band not allowed (6 GHz)", +		.low_latency_vif = false, +		.primary_link_active = true, +		.chan_load_not_by_us = 30, +		.chandef_a = &chandef_6ghz_160mhz, +		.chandef_b = &chandef_6ghz_221_160mhz, +		.expected_result = IWL_MLD_EMLSR_EXIT_EQUAL_BAND, +	}, +}; + +KUNIT_ARRAY_PARAM_DESC(link_pair, link_pair_cases, desc); + +static void test_iwl_mld_link_pair_allows_emlsr(struct kunit *test) +{ +	const struct link_pair_case *params = test->param_value; +	struct iwl_mld *mld = test->priv; +	struct ieee80211_vif *vif; +	/* link A is the primary and link B is the secondary */ +	struct iwl_mld_link_sel_data a = { +		.chandef = params->chandef_a, +		.link_id = 4, +	}; +	struct iwl_mld_link_sel_data b = { +		.chandef = params->chandef_b, +		.link_id = 5, +	}; +	struct iwl_mld_kunit_link assoc_link = { +		.chandef = params->primary_link_active ? a.chandef : b.chandef, +		.id = params->primary_link_active ? a.link_id : b.link_id, +	}; +	u32 result; + +	vif = iwlmld_kunit_setup_mlo_assoc(BIT(a.link_id) | BIT(b.link_id), +					   &assoc_link); + +	if (params->low_latency_vif) +		iwl_mld_vif_from_mac80211(vif)->low_latency_causes = 1; + +	wiphy_lock(mld->wiphy); + +	/* Simulate channel load */ +	if (params->primary_link_active) { +		struct iwl_mld_phy *phy = +			iwlmld_kunit_get_phy_of_link(vif, a.link_id); + +		phy->avg_channel_load_not_by_us = params->chan_load_not_by_us; +	} + +	result = iwl_mld_emlsr_pair_state(vif, &a, &b); + +	wiphy_unlock(mld->wiphy); + +	KUNIT_EXPECT_EQ(test, result, params->expected_result); +} + +static struct kunit_case link_pair_criteria_test_cases[] = { +	KUNIT_CASE_PARAM(test_iwl_mld_link_pair_allows_emlsr, link_pair_gen_params), +	{} +}; + +static struct kunit_suite link_pair_criteria_tests = { +	.name = "iwlmld_link_pair_allows_emlsr", +	.test_cases = link_pair_criteria_test_cases, +	.init = iwlmld_kunit_test_init, +}; + +kunit_test_suite(link_pair_criteria_tests); | 
