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 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 60 static 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 86 static 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 112 static 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 123 static 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 142 static 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 160 static 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 186 static 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 198 static 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 220 static 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 241 static 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 268 static struct kunit_case devinfo_test_cases[] = { 269 KUNIT_CASE(devinfo_table_order), 270 KUNIT_CASE(devinfo_discrete_match), 271 KUNIT_CASE(devinfo_names), 272 KUNIT_CASE(devinfo_no_cfg_dups), 273 KUNIT_CASE(devinfo_no_name_dups), 274 KUNIT_CASE(devinfo_check_subdev_match), 275 KUNIT_CASE(devinfo_check_killer_subdev), 276 KUNIT_CASE(devinfo_pci_ids), 277 KUNIT_CASE(devinfo_no_mac_cfg_dups), 278 KUNIT_CASE(devinfo_api_range), 279 {} 280 }; 281 282 static struct kunit_suite iwlwifi_devinfo = { 283 .name = "iwlwifi-devinfo", 284 .test_cases = devinfo_test_cases, 285 }; 286 287 kunit_test_suite(iwlwifi_devinfo); 288