xref: /linux/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c (revision 001821b0e79716c4e17c71d8e053a23599a7a508)
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