wifi: iwlwifi: mld: add KUnit tests for link grading

Add tests for the link grading algorithm covering per-bandwidth
grading tables, channel load calculation, 6 GHz RSSI adjustments
including duplicated beacon and PSD/EIRP compensation, and
puncturing penalty.

Signed-off-by: Avinash Bhatt <avinash.bhatt@intel.com>
Link: https://patch.msgid.link/20260531135036.a4251e5665a0.I811b35680115e7de0ffd75b6b7a1c91ad361c97c@changeid
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
This commit is contained in:
Avinash Bhatt 2026-05-31 13:53:08 +03:00 committed by Miri Korenblit
parent 7d390ff7f2
commit a153825987
2 changed files with 255 additions and 35 deletions

View File

@ -3,6 +3,8 @@
* Copyright (C) 2024-2026 Intel Corporation
*/
#include <kunit/static_stub.h>
#include "constants.h"
#include "link.h"
#include "iface.h"
@ -1032,6 +1034,9 @@ iwl_mld_get_dup_beacon_rssi_adjust(struct iwl_mld *mld,
const struct cfg80211_bss_ies *beacon_ies;
const struct element *elem;
KUNIT_STATIC_STUB_REDIRECT(iwl_mld_get_dup_beacon_rssi_adjust,
mld, link_conf);
/* Duplicated beacon feature is only specific to 6 GHz */
if (WARN_ONCE(link_conf->chanreq.oper.chan->band != NL80211_BAND_6GHZ,
"Unexpected band %d\n",
@ -1109,6 +1114,9 @@ iwl_mld_get_psd_eirp_rssi_adjust(struct ieee80211_bss_conf *link_conf)
int bw_mhz, num_subchans;
u8 bw_index;
KUNIT_STATIC_STUB_REDIRECT(iwl_mld_get_psd_eirp_rssi_adjust,
link_conf);
/* PSD/EIRP adjustment is only specific to 6 GHz */
if (WARN_ONCE(link_conf->chanreq.oper.chan->band != NL80211_BAND_6GHZ,
"PSD/EIRP adjustment called for non-6 GHz band %d\n",

View File

@ -13,24 +13,39 @@
#include "phy.h"
#include "mlo.h"
struct link_grading_input {
u8 link_id;
const struct cfg80211_chan_def *chandef;
bool active;
s32 signal;
bool has_chan_util_elem;
u8 chan_util;
u8 chan_load_by_us;
s8 dup_beacon_adj;
s8 psd_eirp_adj;
u16 punctured;
};
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;
struct link_grading_input link;
unsigned int expected_grade;
} link_grading_cases[] = {
/* Per-bandwidth grading table tests */
{
.desc = "channel util of 128 (50%)",
.input.link = {
.desc = "20 MHz grading table: -75 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_2ghz_20mhz,
.active = false,
.signal = -75,
},
/* 137 * 0.7 (default 2.4GHz channel load 30%) */
.expected_grade = 96,
},
{
.desc = "20 MHz with channel util 128 (50%): -70 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_2ghz_20mhz,
.active = false,
@ -41,8 +56,8 @@ static const struct link_grading_test_case {
.expected_grade = 86,
},
{
.desc = "channel util of 180 (70%)",
.input.link = {
.desc = "20 MHz with channel util 180 (70%): -70 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_2ghz_20mhz,
.active = false,
@ -53,32 +68,222 @@ static const struct link_grading_test_case {
.expected_grade = 51,
},
{
.desc = "channel util of 180 (70%), channel load by us of 10%",
.input.link = {
.desc = "20 MHz active link with chan load by us 10%: -70 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_2ghz_20mhz,
.active = true,
.signal = -70,
.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 = {
{
.desc = "40 MHz grading table: -80 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_2ghz_20mhz,
.signal = -70,
.active = true,
.chandef = &chandef_5ghz_40mhz,
.active = false,
.signal = -80,
},
.expected_grade = 120,
/* 206 * 0.85 (default 5GHz channel load 15%) */
.expected_grade = 175,
},
{
.desc = "80 MHz grading table: -70 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_5ghz_80mhz,
.active = false,
.signal = -70,
},
/* 548 * 0.85 (default 5GHz channel load 15%) */
.expected_grade = 466,
},
{
.desc = "160 MHz grading table: -65 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_5ghz_160mhz,
.active = false,
.signal = -65,
},
/* 1240 * 0.85 (default 5GHz channel load 15%) */
.expected_grade = 1055,
},
{
.desc = "320 MHz grading table: -60 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_320mhz,
.active = false,
.signal = -60,
},
/* 3680 at -56 dBm (-60 + 4 dBm 6 GHz) */
.expected_grade = 3680,
},
/* 6 GHz RSSI adjustment integration tests */
{
.desc = "6 GHz 160 MHz with fixed +4 dBm adjustment",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_160mhz,
.active = false,
.signal = -69,
},
/* -69 + 4 dBm = -65, grade 1240 */
.expected_grade = 1240,
},
{
.desc = "6 GHz 80 MHz with fixed +4 dBm adjustment",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_80mhz,
.active = false,
.signal = -74,
},
/* -74 + 4 dBm = -70, grade 548 */
.expected_grade = 548,
},
{
.desc = "6 GHz 40 MHz with fixed +4 dBm adjustment",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_40mhz,
.active = false,
.signal = -84,
},
/* -84 + 4 dBm = -80, grade 206 */
.expected_grade = 206,
},
{
.desc = "6 GHz 20 MHz with fixed +4 dBm adjustment",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_20mhz,
.active = false,
.signal = -79,
},
.expected_grade = 137,
},
/* Duplicated beacon RSSI adjustment tests */
{
.desc = "6 GHz 40 MHz dup beacon: -81 dBm + 3 dBm = -78 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_40mhz,
.active = false,
.signal = -81,
.dup_beacon_adj = 3,
},
.expected_grade = 206,
},
{
.desc = "6 GHz 80 MHz dup beacon: -73 dBm + 6 dBm = -67 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_80mhz,
.active = false,
.signal = -73,
.dup_beacon_adj = 6,
},
.expected_grade = 620,
},
{
.desc = "6 GHz 160 MHz dup beacon: -74 dBm + 9 dBm = -65 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_160mhz,
.active = false,
.signal = -74,
.dup_beacon_adj = 9,
},
.expected_grade = 1240,
},
{
.desc = "6 GHz 320 MHz dup beacon: -72 dBm + 12 dBm = -60 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_320mhz,
.active = false,
.signal = -72,
.dup_beacon_adj = 12,
},
.expected_grade = 3296,
},
/* PSD/EIRP RSSI adjustment tests */
{
.desc = "6 GHz 80 MHz PSD/EIRP: -77 dBm + 3 dBm = -74 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_80mhz,
.active = false,
.signal = -77,
.psd_eirp_adj = 3,
},
/* -77 + 3 dBm = -74, grade 412; fallback +4: -73 -> 548 */
.expected_grade = 412,
},
{
.desc = "6 GHz 160 MHz PSD/EIRP: -70 dBm + 3 dBm = -67 dBm",
.link = {
.link_id = 0,
.chandef = &chandef_6ghz_160mhz,
.active = false,
.signal = -70,
.psd_eirp_adj = 3,
},
/* -70 + 3 dBm = -67, grade 1096; fallback +4: -66 -> 1240 */
.expected_grade = 1096,
},
/* Puncturing penalty tests */
{
.desc = "80 MHz with 20 MHz punctured: 3 active subchannels",
.link = {
.link_id = 0,
.chandef = &chandef_5ghz_80mhz,
.active = false,
.signal = -70,
.punctured = 0x2,
},
/* 548 * 0.85 (5GHz load) * 3/4 (puncturing) */
.expected_grade = 349,
},
{
.desc = "160 MHz with 40 MHz punctured: 6 active subchannels",
.link = {
.link_id = 0,
.chandef = &chandef_5ghz_160mhz,
.active = false,
.signal = -65,
.punctured = 0xC,
},
/* 1240 * 0.85 (5GHz load) * 6/8 (puncturing) */
.expected_grade = 791,
},
};
KUNIT_ARRAY_PARAM_DESC(link_grading, link_grading_cases, desc);
static s8 fake_dup_beacon_rssi_adjust(struct iwl_mld *mld,
struct ieee80211_bss_conf *link_conf)
{
const struct link_grading_test_case *params =
kunit_get_current_test()->param_value;
return params->link.dup_beacon_adj;
}
static s8 fake_psd_eirp_rssi_adjust(struct ieee80211_bss_conf *link_conf)
{
const struct link_grading_test_case *params =
kunit_get_current_test()->param_value;
return params->link.psd_eirp_adj;
}
static void setup_link(struct ieee80211_bss_conf *link)
{
struct kunit *test = kunit_get_current_test();
@ -88,14 +293,14 @@ static void setup_link(struct ieee80211_bss_conf *link)
KUNIT_ALLOC_AND_ASSERT(test, link->bss);
link->bss->signal = DBM_TO_MBM(test_param->input.link.signal);
link->bss->signal = DBM_TO_MBM(test_param->link.signal);
link->chanreq.oper = *test_param->input.link.chandef;
link->chanreq.oper = *test_param->link.chandef;
if (test_param->input.link.has_chan_util_elem) {
if (test_param->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,
.channel_util = test_param->link.chan_util,
};
struct element *elem =
iwlmld_kunit_gen_element(WLAN_EID_QBSS_LOAD,
@ -110,7 +315,10 @@ static void setup_link(struct ieee80211_bss_conf *link)
rcu_assign_pointer(link->bss->ies, ies);
}
if (test_param->input.link.active) {
if (test_param->link.punctured)
link->chanreq.oper.punctured = test_param->link.punctured;
if (test_param->link.active) {
struct ieee80211_chanctx_conf *chan_ctx =
wiphy_dereference(mld->wiphy, link->chanctx_conf);
struct iwl_mld_phy *phy;
@ -119,7 +327,7 @@ static void setup_link(struct ieee80211_bss_conf *link)
phy = iwl_mld_phy_from_mac80211(chan_ctx);
phy->channel_load_by_us = test_param->input.link.chan_load_by_us;
phy->channel_load_by_us = test_param->link.chan_load_by_us;
}
}
@ -131,12 +339,11 @@ static void test_link_grading(struct kunit *test)
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;
u8 link_id = test_param->link.link_id;
bool active = test_param->link.active;
u16 valid_links;
struct iwl_mld_kunit_link assoc_link = {
.chandef = test_param->input.link.chandef,
.chandef = test_param->link.chandef,
};
/* If the link is not active, use a different link as the assoc link */
@ -150,6 +357,11 @@ static void test_link_grading(struct kunit *test)
vif = iwlmld_kunit_setup_mlo_assoc(valid_links, &assoc_link);
kunit_activate_static_stub(test, iwl_mld_get_dup_beacon_rssi_adjust,
fake_dup_beacon_rssi_adjust);
kunit_activate_static_stub(test, iwl_mld_get_psd_eirp_rssi_adjust,
fake_psd_eirp_rssi_adjust);
wiphy_lock(mld->wiphy);
link = wiphy_dereference(mld->wiphy, vif->link_conf[link_id]);
KUNIT_ASSERT_NOT_NULL(test, link);