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_step) 35 pos += scnprintf(buf + pos, sizeof(buf) - pos, 36 " rf_step=%c", 37 di->rf_step == SILICON_Z_STEP ? 'Z' : 38 'A' + di->rf_step); 39 else 40 pos += scnprintf(buf + pos, sizeof(buf) - pos, 41 " rf_step=*"); 42 43 if (di->match_rf_id) 44 pos += scnprintf(buf + pos, sizeof(buf) - pos, 45 " rf_id=0x%x", di->rf_id); 46 else 47 pos += scnprintf(buf + pos, sizeof(buf) - pos, 48 " rf_id=*"); 49 50 if (di->match_cdb) 51 pos += scnprintf(buf + pos, sizeof(buf) - pos, 52 " cdb=%d", di->cdb); 53 else 54 pos += scnprintf(buf + pos, sizeof(buf) - pos, 55 " cdb=*"); 56 57 58 printk(KERN_DEBUG "%sdev=%04x subdev=%04x/%04x%s\n", 59 pfx, di->device, di->subdevice, subdevice_mask, buf); 60 } 61 62 static void devinfo_table_order(struct kunit *test) 63 { 64 int idx; 65 66 for (idx = 0; idx < iwl_dev_info_table_size; idx++) { 67 const struct iwl_dev_info *di = &iwl_dev_info_table[idx]; 68 const struct iwl_dev_info *ret; 69 70 ret = iwl_pci_find_dev_info(di->device, di->subdevice, 71 di->rf_type, di->cdb, 72 di->rf_id, di->bw_limit, 73 di->rf_step); 74 if (!ret) { 75 iwl_pci_print_dev_info("No entry found for: ", di); 76 KUNIT_FAIL(test, 77 "No entry found for entry at index %d\n", idx); 78 } else if (ret != di) { 79 iwl_pci_print_dev_info("searched: ", di); 80 iwl_pci_print_dev_info("found: ", ret); 81 KUNIT_FAIL(test, 82 "unusable entry at index %d (found index %d instead)\n", 83 idx, (int)(ret - iwl_dev_info_table)); 84 } 85 } 86 } 87 88 static void devinfo_names(struct kunit *test) 89 { 90 int idx; 91 92 for (idx = 0; idx < iwl_dev_info_table_size; idx++) { 93 const struct iwl_dev_info *di = &iwl_dev_info_table[idx]; 94 95 KUNIT_ASSERT_TRUE(test, di->name); 96 } 97 } 98 99 static void devinfo_no_cfg_dups(struct kunit *test) 100 { 101 for (int i = 0; i < iwl_dev_info_table_size; i++) { 102 const struct iwl_rf_cfg *cfg_i = iwl_dev_info_table[i].cfg; 103 104 for (int j = 0; j < i; j++) { 105 const struct iwl_rf_cfg *cfg_j = iwl_dev_info_table[j].cfg; 106 107 if (cfg_i == cfg_j) 108 continue; 109 110 KUNIT_EXPECT_NE_MSG(test, memcmp(cfg_i, cfg_j, 111 sizeof(*cfg_i)), 0, 112 "identical configs: %ps and %ps\n", 113 cfg_i, cfg_j); 114 } 115 } 116 } 117 118 static void devinfo_no_name_dups(struct kunit *test) 119 { 120 for (int i = 0; i < iwl_dev_info_table_size; i++) { 121 for (int j = 0; j < i; j++) { 122 if (iwl_dev_info_table[i].name == iwl_dev_info_table[j].name) 123 continue; 124 125 KUNIT_EXPECT_NE_MSG(test, 126 strcmp(iwl_dev_info_table[i].name, 127 iwl_dev_info_table[j].name), 128 0, 129 "name dup: %ps/%ps", 130 iwl_dev_info_table[i].name, 131 iwl_dev_info_table[j].name); 132 } 133 } 134 } 135 136 static void devinfo_check_subdev_match(struct kunit *test) 137 { 138 for (int i = 0; i < iwl_dev_info_table_size; i++) { 139 const struct iwl_dev_info *di = &iwl_dev_info_table[i]; 140 u16 subdevice_mask = GENMASK(di->subdevice_m_h, 141 di->subdevice_m_l); 142 143 /* if BW limit bit is matched then must have a limit */ 144 if (di->match_bw_limit == 1 && di->bw_limit == 1) 145 KUNIT_EXPECT_NE(test, di->cfg->bw_limit, 0); 146 147 /* if subdevice is ANY we can have RF ID/BW limit */ 148 if (di->subdevice == (u16)IWL_CFG_ANY) 149 continue; 150 151 /* same if the subdevice mask doesn't overlap them */ 152 if (IWL_SUBDEVICE_RF_ID(subdevice_mask) == 0 && 153 IWL_SUBDEVICE_BW_LIM(subdevice_mask) == 0) 154 continue; 155 156 /* but otherwise they shouldn't be used */ 157 KUNIT_EXPECT_EQ(test, (int)di->match_rf_id, 0); 158 KUNIT_EXPECT_EQ(test, (int)di->match_bw_limit, 0); 159 } 160 } 161 162 static void devinfo_check_killer_subdev(struct kunit *test) 163 { 164 for (int i = 0; i < iwl_dev_info_table_size; i++) { 165 const struct iwl_dev_info *di = &iwl_dev_info_table[i]; 166 167 if (!strstr(di->name, "Killer")) 168 continue; 169 170 KUNIT_EXPECT_NE(test, di->subdevice, (u16)IWL_CFG_ANY); 171 } 172 } 173 174 static void devinfo_pci_ids(struct kunit *test) 175 { 176 struct pci_dev *dev; 177 178 dev = kunit_kmalloc(test, sizeof(*dev), GFP_KERNEL); 179 KUNIT_ASSERT_NOT_NULL(test, dev); 180 181 for (int i = 0; iwl_hw_card_ids[i].vendor; i++) { 182 const struct pci_device_id *s, *t; 183 184 s = &iwl_hw_card_ids[i]; 185 dev->vendor = s->vendor; 186 dev->device = s->device; 187 dev->subsystem_vendor = s->subvendor; 188 dev->subsystem_device = s->subdevice; 189 dev->class = s->class; 190 191 t = pci_match_id(iwl_hw_card_ids, dev); 192 KUNIT_EXPECT_PTR_EQ(test, t, s); 193 } 194 } 195 196 static void devinfo_no_mac_cfg_dups(struct kunit *test) 197 { 198 for (int i = 0; iwl_hw_card_ids[i].vendor; i++) { 199 const struct iwl_mac_cfg *cfg_i = 200 (void *)iwl_hw_card_ids[i].driver_data; 201 202 for (int j = 0; j < i; j++) { 203 const struct iwl_mac_cfg *cfg_j = 204 (void *)iwl_hw_card_ids[j].driver_data; 205 206 if (cfg_i == cfg_j) 207 continue; 208 209 KUNIT_EXPECT_NE_MSG(test, memcmp(cfg_j, cfg_i, 210 sizeof(*cfg_i)), 0, 211 "identical configs: %ps and %ps\n", 212 cfg_i, cfg_j); 213 } 214 } 215 } 216 217 static struct kunit_case devinfo_test_cases[] = { 218 KUNIT_CASE(devinfo_table_order), 219 KUNIT_CASE(devinfo_names), 220 KUNIT_CASE(devinfo_no_cfg_dups), 221 KUNIT_CASE(devinfo_no_name_dups), 222 KUNIT_CASE(devinfo_check_subdev_match), 223 KUNIT_CASE(devinfo_check_killer_subdev), 224 KUNIT_CASE(devinfo_pci_ids), 225 KUNIT_CASE(devinfo_no_mac_cfg_dups), 226 {} 227 }; 228 229 static struct kunit_suite iwlwifi_devinfo = { 230 .name = "iwlwifi-devinfo", 231 .test_cases = devinfo_test_cases, 232 }; 233 234 kunit_test_suite(iwlwifi_devinfo); 235