xref: /linux/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c (revision 08e77d5edf7063e206096474ead1ed210eae0338)
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 
12 MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
13 
14 static void iwl_pci_print_dev_info(const char *pfx, const struct iwl_dev_info *di)
15 {
16 	printk(KERN_DEBUG "%sdev=%.4x,subdev=%.4x,mac_type=%.4x,mac_step=%.4x,rf_type=%.4x,cdb=%d,jacket=%d,rf_id=%.2x,bw_limit=%d,cores=%.2x\n",
17 	       pfx, di->device, di->subdevice, di->mac_type, di->mac_step,
18 	       di->rf_type, di->cdb, di->jacket, di->rf_id, di->bw_limit,
19 	       di->cores);
20 }
21 
22 static void devinfo_table_order(struct kunit *test)
23 {
24 	int idx;
25 
26 	for (idx = 0; idx < iwl_dev_info_table_size; idx++) {
27 		const struct iwl_dev_info *di = &iwl_dev_info_table[idx];
28 		const struct iwl_dev_info *ret;
29 
30 		ret = iwl_pci_find_dev_info(di->device, di->subdevice,
31 					    di->mac_type, di->mac_step,
32 					    di->rf_type, di->cdb,
33 					    di->jacket, di->rf_id,
34 					    di->bw_limit,
35 					    di->cores, di->rf_step);
36 		if (!ret) {
37 			iwl_pci_print_dev_info("No entry found for: ", di);
38 			KUNIT_FAIL(test,
39 				   "No entry found for entry at index %d\n", idx);
40 		} else if (ret != di) {
41 			iwl_pci_print_dev_info("searched: ", di);
42 			iwl_pci_print_dev_info("found:    ", ret);
43 			KUNIT_FAIL(test,
44 				   "unusable entry at index %d (found index %d instead)\n",
45 				   idx, (int)(ret - iwl_dev_info_table));
46 		}
47 	}
48 }
49 
50 static void devinfo_names(struct kunit *test)
51 {
52 	int idx;
53 
54 	for (idx = 0; idx < iwl_dev_info_table_size; idx++) {
55 		const struct iwl_dev_info *di = &iwl_dev_info_table[idx];
56 
57 		KUNIT_ASSERT_TRUE(test, di->name);
58 	}
59 }
60 
61 static void devinfo_no_cfg_dups(struct kunit *test)
62 {
63 	/* allocate iwl_dev_info_table_size as upper bound */
64 	const struct iwl_cfg **cfgs = kunit_kcalloc(test,
65 						    iwl_dev_info_table_size,
66 						    sizeof(*cfgs), GFP_KERNEL);
67 	int p = 0;
68 
69 	KUNIT_ASSERT_NOT_NULL(test, cfgs);
70 
71 	/* build a list of unique (by pointer) configs first */
72 	for (int i = 0; i < iwl_dev_info_table_size; i++) {
73 		bool found = false;
74 
75 		for (int j = 0; j < p; j++) {
76 			if (cfgs[j] == iwl_dev_info_table[i].cfg) {
77 				found = true;
78 				break;
79 			}
80 		}
81 		if (!found) {
82 			cfgs[p] = iwl_dev_info_table[i].cfg;
83 			p++;
84 		}
85 	}
86 
87 	/* check that they're really all different */
88 	for (int i = 0; i < p; i++) {
89 		struct iwl_cfg cfg_i = *cfgs[i];
90 
91 		for (int j = 0; j < i; j++) {
92 			struct iwl_cfg cfg_j = *cfgs[j];
93 
94 			KUNIT_EXPECT_NE_MSG(test, memcmp(&cfg_i, &cfg_j,
95 							 sizeof(cfg_i)), 0,
96 					    "identical configs: %ps and %ps\n",
97 					    cfgs[i], cfgs[j]);
98 		}
99 	}
100 }
101 
102 static void devinfo_no_name_dups(struct kunit *test)
103 {
104 	for (int i = 0; i < iwl_dev_info_table_size; i++) {
105 		for (int j = 0; j < i; j++) {
106 			if (iwl_dev_info_table[i].name == iwl_dev_info_table[j].name)
107 				continue;
108 
109 			KUNIT_EXPECT_NE_MSG(test,
110 					    strcmp(iwl_dev_info_table[i].name,
111 						   iwl_dev_info_table[j].name),
112 					    0,
113 					    "name dup: %ps/%ps",
114 					    iwl_dev_info_table[i].name,
115 					    iwl_dev_info_table[j].name);
116 		}
117 	}
118 }
119 
120 static void devinfo_check_subdev_match(struct kunit *test)
121 {
122 	for (int i = 0; i < iwl_dev_info_table_size; i++) {
123 		const struct iwl_dev_info *di = &iwl_dev_info_table[i];
124 
125 		/* if BW limit bit is matched then must have a limit */
126 		if (di->bw_limit == 1)
127 			KUNIT_EXPECT_NE(test, di->cfg->bw_limit, 0);
128 
129 		if (di->subdevice == (u16)IWL_CFG_ANY)
130 			continue;
131 
132 		KUNIT_EXPECT_EQ(test, di->rf_id, (u8)IWL_CFG_ANY);
133 		KUNIT_EXPECT_EQ(test, di->bw_limit, (u8)IWL_CFG_ANY);
134 		KUNIT_EXPECT_EQ(test, di->cores, (u8)IWL_CFG_ANY);
135 	}
136 }
137 
138 static void devinfo_check_killer_subdev(struct kunit *test)
139 {
140 	for (int i = 0; i < iwl_dev_info_table_size; i++) {
141 		const struct iwl_dev_info *di = &iwl_dev_info_table[i];
142 
143 		if (!strstr(di->name, "Killer"))
144 			continue;
145 
146 		KUNIT_EXPECT_NE(test, di->subdevice, (u16)IWL_CFG_ANY);
147 	}
148 }
149 
150 static void devinfo_pci_ids(struct kunit *test)
151 {
152 	struct pci_dev *dev;
153 
154 	dev = kunit_kmalloc(test, sizeof(*dev), GFP_KERNEL);
155 	KUNIT_ASSERT_NOT_NULL(test, dev);
156 
157 	for (int i = 0; iwl_hw_card_ids[i].vendor; i++) {
158 		const struct pci_device_id *s, *t;
159 
160 		s = &iwl_hw_card_ids[i];
161 		dev->vendor = s->vendor;
162 		dev->device = s->device;
163 		dev->subsystem_vendor = s->subvendor;
164 		dev->subsystem_device = s->subdevice;
165 		dev->class = s->class;
166 
167 		t = pci_match_id(iwl_hw_card_ids, dev);
168 		KUNIT_EXPECT_PTR_EQ(test, t, s);
169 	}
170 }
171 
172 static void devinfo_no_trans_cfg_dups(struct kunit *test)
173 {
174 	/* allocate iwl_dev_info_table_size as upper bound */
175 	const struct iwl_cfg_trans_params **cfgs;
176 	int count = 0;
177 	int p = 0;
178 
179 	for (int i = 0; iwl_hw_card_ids[i].vendor; i++)
180 		count++;
181 
182 	cfgs = kunit_kcalloc(test, count, sizeof(*cfgs), GFP_KERNEL);
183 	KUNIT_ASSERT_NOT_NULL(test, cfgs);
184 
185 	/* build a list of unique (by pointer) configs first */
186 	for (int i = 0; iwl_hw_card_ids[i].vendor; i++) {
187 		struct iwl_cfg_trans_params *cfg;
188 		bool found = false;
189 
190 		cfg = (void *)iwl_hw_card_ids[i].driver_data;
191 
192 		for (int j = 0; j < p; j++) {
193 			if (cfgs[j] == cfg) {
194 				found = true;
195 				break;
196 			}
197 		}
198 		if (!found) {
199 			cfgs[p] = cfg;
200 			p++;
201 		}
202 	}
203 
204 	/* check that they're really all different */
205 	for (int i = 0; i < p; i++) {
206 		for (int j = 0; j < i; j++) {
207 			KUNIT_EXPECT_NE_MSG(test, memcmp(cfgs[i], cfgs[j],
208 							 sizeof(*cfgs[i])), 0,
209 					    "identical configs: %ps and %ps\n",
210 					    cfgs[i], cfgs[j]);
211 		}
212 	}
213 }
214 
215 static struct kunit_case devinfo_test_cases[] = {
216 	KUNIT_CASE(devinfo_table_order),
217 	KUNIT_CASE(devinfo_names),
218 	KUNIT_CASE(devinfo_no_cfg_dups),
219 	KUNIT_CASE(devinfo_no_name_dups),
220 	KUNIT_CASE(devinfo_check_subdev_match),
221 	KUNIT_CASE(devinfo_check_killer_subdev),
222 	KUNIT_CASE(devinfo_pci_ids),
223 	KUNIT_CASE(devinfo_no_trans_cfg_dups),
224 	{}
225 };
226 
227 static struct kunit_suite iwlwifi_devinfo = {
228 	.name = "iwlwifi-devinfo",
229 	.test_cases = devinfo_test_cases,
230 };
231 
232 kunit_test_suite(iwlwifi_devinfo);
233