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