File Index
Files and directories
Sign in
FILE

devinfo.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c C
  1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
  2/*
  3 * KUnit tests for the iwlwifi device info table
  4 *
  5 * Copyright (C) 2023-2025 Intel Corporation
  6 */
  7#include <kunit/test.h>
  8#include <linux/pci.h>
  9#include "iwl-drv.h"
 10#include "iwl-config.h"
 11
 12MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
 13
 14static void iwl_pci_print_dev_info(const char *pfx, const struct iwl_dev_info *di)
 15{
 16	u16 subdevice_mask = GENMASK(di->subdevice_m_h, di->subdevice_m_l);
 17	char buf[100] = {};
 18	int pos = 0;
 19
 20	if (di->match_rf_type)
 21		pos += scnprintf(buf + pos, sizeof(buf) - pos,
 22				 " rf_type=%03x", di->rf_type);
 23	else
 24		pos += scnprintf(buf + pos, sizeof(buf) - pos,
 25				 " rf_type=*");
 26
 27	if (di->match_bw_limit)
 28		pos += scnprintf(buf + pos, sizeof(buf) - pos,
 29				 " bw_limit=%d", di->bw_limit);
 30	else
 31		pos += scnprintf(buf + pos, sizeof(buf) - pos,
 32				 " bw_limit=*");
 33
 34	if (di->match_rf_id)
 35		pos += scnprintf(buf + pos, sizeof(buf) - pos,
 36				 " rf_id=0x%x", di->rf_id);
 37	else
 38		pos += scnprintf(buf + pos, sizeof(buf) - pos,
 39				 " rf_id=*");
 40
 41	if (di->match_cdb)
 42		pos += scnprintf(buf + pos, sizeof(buf) - pos,
 43				 " cdb=%d", di->cdb);
 44	else
 45		pos += scnprintf(buf + pos, sizeof(buf) - pos,
 46				 " cdb=*");
 47
 48	if (di->match_discrete)
 49		pos += scnprintf(buf + pos, sizeof(buf) - pos,
 50				 " discrete=%d",
 51				 di->discrete);
 52	else
 53		pos += scnprintf(buf + pos, sizeof(buf) - pos,
 54				 " discrete=*");
 55
 56	printk(KERN_DEBUG "%sdev=%04x subdev=%04x/%04x%s\n",
 57	       pfx, di->device, di->subdevice, subdevice_mask, buf);
 58}
 59
 60static void devinfo_table_order(struct kunit *test)
 61{
 62	int idx;
 63
 64	for (idx = 0; idx < iwl_dev_info_table_size; idx++) {
 65		const struct iwl_dev_info *di = &iwl_dev_info_table[idx];
 66		const struct iwl_dev_info *ret;
 67
 68		ret = iwl_pci_find_dev_info(di->device, di->subdevice,
 69					    di->rf_type, di->cdb,
 70					    di->rf_id, di->bw_limit,
 71					    di->discrete);
 72		if (!ret) {
 73			iwl_pci_print_dev_info("No entry found for: ", di);
 74			KUNIT_FAIL(test,
 75				   "No entry found for entry at index %d\n", idx);
 76		} else if (ret != di) {
 77			iwl_pci_print_dev_info("searched: ", di);
 78			iwl_pci_print_dev_info("found:    ", ret);
 79			KUNIT_FAIL(test,
 80				   "unusable entry at index %d (found index %d instead)\n",
 81				   idx, (int)(ret - iwl_dev_info_table));
 82		}
 83	}
 84}
 85
 86static void devinfo_discrete_match(struct kunit *test)
 87{
 88	/*
 89	 * Validate that any entries with discrete/integrated match have
 90	 * the same config with the value inverted (if they match at all.)
 91	 */
 92
 93	for (int idx = 0; idx < iwl_dev_info_table_size; idx++) {
 94		const struct iwl_dev_info *di = &iwl_dev_info_table[idx];
 95		const struct iwl_dev_info *ret;
 96
 97		if (!di->match_discrete)
 98			continue;
 99
100		ret = iwl_pci_find_dev_info(di->device, di->subdevice,
101					    di->rf_type, di->cdb,
102					    di->rf_id, di->bw_limit,
103					    !di->discrete);
104		if (!ret)
105			continue;
106		KUNIT_EXPECT_PTR_EQ(test, di->cfg, ret->cfg);
107		/* and check the name is different, that'd be the point of it */
108		KUNIT_EXPECT_NE(test, strcmp(di->name, ret->name), 0);
109	}
110}
111
112static void devinfo_names(struct kunit *test)
113{
114	int idx;
115
116	for (idx = 0; idx < iwl_dev_info_table_size; idx++) {
117		const struct iwl_dev_info *di = &iwl_dev_info_table[idx];
118
119		KUNIT_ASSERT_TRUE(test, di->name);
120	}
121}
122
123static void devinfo_no_cfg_dups(struct kunit *test)
124{
125	for (int i = 0; i < iwl_dev_info_table_size; i++) {
126		const struct iwl_rf_cfg *cfg_i = iwl_dev_info_table[i].cfg;
127
128		for (int j = 0; j < i; j++) {
129			const struct iwl_rf_cfg *cfg_j = iwl_dev_info_table[j].cfg;
130
131			if (cfg_i == cfg_j)
132				continue;
133
134			KUNIT_EXPECT_NE_MSG(test, memcmp(cfg_i, cfg_j,
135							 sizeof(*cfg_i)), 0,
136					    "identical configs: %ps and %ps\n",
137					    cfg_i, cfg_j);
138		}
139	}
140}
141
142static void devinfo_no_name_dups(struct kunit *test)
143{
144	for (int i = 0; i < iwl_dev_info_table_size; i++) {
145		for (int j = 0; j < i; j++) {
146			if (iwl_dev_info_table[i].name == iwl_dev_info_table[j].name)
147				continue;
148
149			KUNIT_EXPECT_NE_MSG(test,
150					    strcmp(iwl_dev_info_table[i].name,
151						   iwl_dev_info_table[j].name),
152					    0,
153					    "name dup: %ps/%ps",
154					    iwl_dev_info_table[i].name,
155					    iwl_dev_info_table[j].name);
156		}
157	}
158}
159
160static void devinfo_check_subdev_match(struct kunit *test)
161{
162	for (int i = 0; i < iwl_dev_info_table_size; i++) {
163		const struct iwl_dev_info *di = &iwl_dev_info_table[i];
164		u16 subdevice_mask = GENMASK(di->subdevice_m_h,
165					     di->subdevice_m_l);
166
167		/* if BW limit bit is matched then must have a limit */
168		if (di->match_bw_limit == 1 && di->bw_limit == 1)
169			KUNIT_EXPECT_NE(test, di->cfg->bw_limit, 0);
170
171		/* if subdevice is ANY we can have RF ID/BW limit */
172		if (di->subdevice == (u16)IWL_CFG_ANY)
173			continue;
174
175		/* same if the subdevice mask doesn't overlap them */
176		if (IWL_SUBDEVICE_RF_ID(subdevice_mask) == 0 &&
177		    IWL_SUBDEVICE_BW_LIM(subdevice_mask) == 0)
178			continue;
179
180		/* but otherwise they shouldn't be used */
181		KUNIT_EXPECT_EQ(test, (int)di->match_rf_id, 0);
182		KUNIT_EXPECT_EQ(test, (int)di->match_bw_limit, 0);
183	}
184}
185
186static void devinfo_check_killer_subdev(struct kunit *test)
187{
188	for (int i = 0; i < iwl_dev_info_table_size; i++) {
189		const struct iwl_dev_info *di = &iwl_dev_info_table[i];
190
191		if (!strstr(di->name, "Killer"))
192			continue;
193
194		KUNIT_EXPECT_NE(test, di->subdevice, (u16)IWL_CFG_ANY);
195	}
196}
197
198static void devinfo_pci_ids(struct kunit *test)
199{
200	struct pci_dev *dev;
201
202	dev = kunit_kmalloc(test, sizeof(*dev), GFP_KERNEL);
203	KUNIT_ASSERT_NOT_NULL(test, dev);
204
205	for (int i = 0; iwl_hw_card_ids[i].vendor; i++) {
206		const struct pci_device_id *s, *t;
207
208		s = &iwl_hw_card_ids[i];
209		dev->vendor = s->vendor;
210		dev->device = s->device;
211		dev->subsystem_vendor = s->subvendor;
212		dev->subsystem_device = s->subdevice;
213		dev->class = s->class;
214
215		t = pci_match_id(iwl_hw_card_ids, dev);
216		KUNIT_EXPECT_PTR_EQ(test, t, s);
217	}
218}
219
220static void devinfo_no_mac_cfg_dups(struct kunit *test)
221{
222	for (int i = 0; iwl_hw_card_ids[i].vendor; i++) {
223		const struct iwl_mac_cfg *cfg_i =
224			(void *)iwl_hw_card_ids[i].driver_data;
225
226		for (int j = 0; j < i; j++) {
227			const struct iwl_mac_cfg *cfg_j =
228				(void *)iwl_hw_card_ids[j].driver_data;
229
230			if (cfg_i == cfg_j)
231				continue;
232
233			KUNIT_EXPECT_NE_MSG(test, memcmp(cfg_j, cfg_i,
234							 sizeof(*cfg_i)), 0,
235					    "identical configs: %ps and %ps\n",
236					    cfg_i, cfg_j);
237		}
238	}
239}
240
241static void devinfo_api_range(struct kunit *test)
242{
243	/* Check that all iwl_mac_cfg's have either both min and max set, or neither */
244	for (int i = 0; iwl_hw_card_ids[i].vendor; i++) {
245		const struct iwl_mac_cfg *mac_cfg =
246			(void *)iwl_hw_card_ids[i].driver_data;
247		const struct iwl_family_base_params *base = mac_cfg->base;
248
249		KUNIT_EXPECT_EQ_MSG(test, !!base->ucode_api_min,
250				    !!base->ucode_api_max,
251				    "%ps: ucode_api_min (%u) and ucode_api_min (%u) should be both set or neither.\n",
252				    base, base->ucode_api_min,
253				    base->ucode_api_max);
254	}
255
256	/* Check the same for the iwl_rf_cfg's */
257	for (int i = 0; i < iwl_dev_info_table_size; i++) {
258		const struct iwl_rf_cfg *rf_cfg = iwl_dev_info_table[i].cfg;
259
260		KUNIT_EXPECT_EQ_MSG(test, !!rf_cfg->ucode_api_min,
261				    !!rf_cfg->ucode_api_max,
262				    "%ps: ucode_api_min (%u) and ucode_api_min (%u) should be both set or neither.\n",
263				    rf_cfg, rf_cfg->ucode_api_min,
264				    rf_cfg->ucode_api_max);
265	}
266}
267
268static void devinfo_pci_ids_config(struct kunit *test)
269{
270	for (int i = 0; iwl_hw_card_ids[i].vendor; i++) {
271		const struct pci_device_id *s = &iwl_hw_card_ids[i];
272		const struct iwl_dev_info *di;
273
274		if (s->device == PCI_ANY_ID || s->subdevice == PCI_ANY_ID)
275			continue;
276
277#if IS_ENABLED(CONFIG_IWLMVM) || IS_ENABLED(CONFIG_IWLMLD)
278		/*
279		 * The check below only works for old (pre-CNVI) devices. Most
280		 * new have subdevice==ANY, so are already skipped, but for some
281		 * Bz platform(s) we list all the RF PCI IDs. Skip those too.
282		 */
283		if (s->driver_data == (kernel_ulong_t)&iwl_bz_mac_cfg)
284			continue;
285#endif
286
287		di = iwl_pci_find_dev_info(s->device, s->subdevice,
288					   0, 0, 0, 0, true);
289
290		KUNIT_EXPECT_PTR_NE_MSG(test, di, NULL,
291					"PCI ID %04x:%04x not found\n",
292					s->device, s->subdevice);
293	}
294}
295
296static struct kunit_case devinfo_test_cases[] = {
297	KUNIT_CASE(devinfo_table_order),
298	KUNIT_CASE(devinfo_discrete_match),
299	KUNIT_CASE(devinfo_names),
300	KUNIT_CASE(devinfo_no_cfg_dups),
301	KUNIT_CASE(devinfo_no_name_dups),
302	KUNIT_CASE(devinfo_check_subdev_match),
303	KUNIT_CASE(devinfo_check_killer_subdev),
304	KUNIT_CASE(devinfo_pci_ids),
305	KUNIT_CASE(devinfo_no_mac_cfg_dups),
306	KUNIT_CASE(devinfo_api_range),
307	KUNIT_CASE(devinfo_pci_ids_config),
308	{}
309};
310
311static struct kunit_suite iwlwifi_devinfo = {
312	.name = "iwlwifi-devinfo",
313	.test_cases = devinfo_test_cases,
314};
315
316kunit_test_suite(iwlwifi_devinfo);
~/ Read-only file preview.