1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) 2025 Arm Ltd. 3 /* This file is intended to be included into mpam_devices.c */ 4 5 #include <kunit/test.h> 6 7 /* 8 * This test catches fields that aren't being sanitised - but can't tell you 9 * which one... 10 */ 11 static void test__props_mismatch(struct kunit *test) 12 { 13 struct mpam_props parent = { 0 }; 14 struct mpam_props child; 15 16 memset(&child, 0xff, sizeof(child)); 17 __props_mismatch(&parent, &child, false); 18 19 memset(&child, 0, sizeof(child)); 20 KUNIT_EXPECT_EQ(test, memcmp(&parent, &child, sizeof(child)), 0); 21 22 memset(&child, 0xff, sizeof(child)); 23 __props_mismatch(&parent, &child, true); 24 25 KUNIT_EXPECT_EQ(test, memcmp(&parent, &child, sizeof(child)), 0); 26 } 27 28 static struct list_head fake_classes_list; 29 static struct mpam_class fake_class = { 0 }; 30 static struct mpam_component fake_comp1 = { 0 }; 31 static struct mpam_component fake_comp2 = { 0 }; 32 static struct mpam_vmsc fake_vmsc1 = { 0 }; 33 static struct mpam_vmsc fake_vmsc2 = { 0 }; 34 static struct mpam_msc fake_msc1 = { 0 }; 35 static struct mpam_msc fake_msc2 = { 0 }; 36 static struct mpam_msc_ris fake_ris1 = { 0 }; 37 static struct mpam_msc_ris fake_ris2 = { 0 }; 38 static struct platform_device fake_pdev = { 0 }; 39 40 static inline void reset_fake_hierarchy(void) 41 { 42 INIT_LIST_HEAD(&fake_classes_list); 43 44 memset(&fake_class, 0, sizeof(fake_class)); 45 fake_class.level = 3; 46 fake_class.type = MPAM_CLASS_CACHE; 47 INIT_LIST_HEAD_RCU(&fake_class.components); 48 INIT_LIST_HEAD(&fake_class.classes_list); 49 50 memset(&fake_comp1, 0, sizeof(fake_comp1)); 51 memset(&fake_comp2, 0, sizeof(fake_comp2)); 52 fake_comp1.comp_id = 1; 53 fake_comp2.comp_id = 2; 54 INIT_LIST_HEAD(&fake_comp1.vmsc); 55 INIT_LIST_HEAD(&fake_comp1.class_list); 56 INIT_LIST_HEAD(&fake_comp2.vmsc); 57 INIT_LIST_HEAD(&fake_comp2.class_list); 58 59 memset(&fake_vmsc1, 0, sizeof(fake_vmsc1)); 60 memset(&fake_vmsc2, 0, sizeof(fake_vmsc2)); 61 INIT_LIST_HEAD(&fake_vmsc1.ris); 62 INIT_LIST_HEAD(&fake_vmsc1.comp_list); 63 fake_vmsc1.msc = &fake_msc1; 64 INIT_LIST_HEAD(&fake_vmsc2.ris); 65 INIT_LIST_HEAD(&fake_vmsc2.comp_list); 66 fake_vmsc2.msc = &fake_msc2; 67 68 memset(&fake_ris1, 0, sizeof(fake_ris1)); 69 memset(&fake_ris2, 0, sizeof(fake_ris2)); 70 fake_ris1.ris_idx = 1; 71 INIT_LIST_HEAD(&fake_ris1.msc_list); 72 fake_ris2.ris_idx = 2; 73 INIT_LIST_HEAD(&fake_ris2.msc_list); 74 75 fake_msc1.pdev = &fake_pdev; 76 fake_msc2.pdev = &fake_pdev; 77 78 list_add(&fake_class.classes_list, &fake_classes_list); 79 } 80 81 static void test_mpam_enable_merge_features(struct kunit *test) 82 { 83 reset_fake_hierarchy(); 84 85 mutex_lock(&mpam_list_lock); 86 87 /* One Class+Comp, two RIS in one vMSC with common features */ 88 fake_comp1.class = &fake_class; 89 list_add(&fake_comp1.class_list, &fake_class.components); 90 fake_comp2.class = NULL; 91 fake_vmsc1.comp = &fake_comp1; 92 list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 93 fake_vmsc2.comp = NULL; 94 fake_ris1.vmsc = &fake_vmsc1; 95 list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 96 fake_ris2.vmsc = &fake_vmsc1; 97 list_add(&fake_ris2.vmsc_list, &fake_vmsc1.ris); 98 99 mpam_set_feature(mpam_feat_cpor_part, &fake_ris1.props); 100 mpam_set_feature(mpam_feat_cpor_part, &fake_ris2.props); 101 fake_ris1.props.cpbm_wd = 4; 102 fake_ris2.props.cpbm_wd = 4; 103 104 mpam_enable_merge_features(&fake_classes_list); 105 106 KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_cpor_part, &fake_class.props)); 107 KUNIT_EXPECT_EQ(test, fake_class.props.cpbm_wd, 4); 108 109 reset_fake_hierarchy(); 110 111 /* One Class+Comp, two RIS in one vMSC with non-overlapping features */ 112 fake_comp1.class = &fake_class; 113 list_add(&fake_comp1.class_list, &fake_class.components); 114 fake_comp2.class = NULL; 115 fake_vmsc1.comp = &fake_comp1; 116 list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 117 fake_vmsc2.comp = NULL; 118 fake_ris1.vmsc = &fake_vmsc1; 119 list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 120 fake_ris2.vmsc = &fake_vmsc1; 121 list_add(&fake_ris2.vmsc_list, &fake_vmsc1.ris); 122 123 mpam_set_feature(mpam_feat_cpor_part, &fake_ris1.props); 124 mpam_set_feature(mpam_feat_cmax_cmin, &fake_ris2.props); 125 fake_ris1.props.cpbm_wd = 4; 126 fake_ris2.props.cmax_wd = 4; 127 128 mpam_enable_merge_features(&fake_classes_list); 129 130 /* Multiple RIS within one MSC controlling the same resource can be mismatched */ 131 KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_cpor_part, &fake_class.props)); 132 KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_cmax_cmin, &fake_class.props)); 133 KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_cmax_cmin, &fake_vmsc1.props)); 134 KUNIT_EXPECT_EQ(test, fake_class.props.cpbm_wd, 4); 135 KUNIT_EXPECT_EQ(test, fake_vmsc1.props.cmax_wd, 4); 136 KUNIT_EXPECT_EQ(test, fake_class.props.cmax_wd, 4); 137 138 reset_fake_hierarchy(); 139 140 /* One Class+Comp, two MSC with overlapping features */ 141 fake_comp1.class = &fake_class; 142 list_add(&fake_comp1.class_list, &fake_class.components); 143 fake_comp2.class = NULL; 144 fake_vmsc1.comp = &fake_comp1; 145 list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 146 fake_vmsc2.comp = &fake_comp1; 147 list_add(&fake_vmsc2.comp_list, &fake_comp1.vmsc); 148 fake_ris1.vmsc = &fake_vmsc1; 149 list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 150 fake_ris2.vmsc = &fake_vmsc2; 151 list_add(&fake_ris2.vmsc_list, &fake_vmsc2.ris); 152 153 mpam_set_feature(mpam_feat_cpor_part, &fake_ris1.props); 154 mpam_set_feature(mpam_feat_cpor_part, &fake_ris2.props); 155 fake_ris1.props.cpbm_wd = 4; 156 fake_ris2.props.cpbm_wd = 4; 157 158 mpam_enable_merge_features(&fake_classes_list); 159 160 KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_cpor_part, &fake_class.props)); 161 KUNIT_EXPECT_EQ(test, fake_class.props.cpbm_wd, 4); 162 163 reset_fake_hierarchy(); 164 165 /* One Class+Comp, two MSC with non-overlapping features */ 166 fake_comp1.class = &fake_class; 167 list_add(&fake_comp1.class_list, &fake_class.components); 168 fake_comp2.class = NULL; 169 fake_vmsc1.comp = &fake_comp1; 170 list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 171 fake_vmsc2.comp = &fake_comp1; 172 list_add(&fake_vmsc2.comp_list, &fake_comp1.vmsc); 173 fake_ris1.vmsc = &fake_vmsc1; 174 list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 175 fake_ris2.vmsc = &fake_vmsc2; 176 list_add(&fake_ris2.vmsc_list, &fake_vmsc2.ris); 177 178 mpam_set_feature(mpam_feat_cpor_part, &fake_ris1.props); 179 mpam_set_feature(mpam_feat_cmax_cmin, &fake_ris2.props); 180 fake_ris1.props.cpbm_wd = 4; 181 fake_ris2.props.cmax_wd = 4; 182 183 mpam_enable_merge_features(&fake_classes_list); 184 185 /* 186 * Multiple RIS in different MSC can't control the same resource, 187 * mismatched features can not be supported. 188 */ 189 KUNIT_EXPECT_FALSE(test, mpam_has_feature(mpam_feat_cpor_part, &fake_class.props)); 190 KUNIT_EXPECT_FALSE(test, mpam_has_feature(mpam_feat_cmax_cmin, &fake_class.props)); 191 KUNIT_EXPECT_EQ(test, fake_class.props.cpbm_wd, 0); 192 KUNIT_EXPECT_EQ(test, fake_class.props.cmax_wd, 0); 193 194 reset_fake_hierarchy(); 195 196 /* One Class+Comp, two MSC with incompatible overlapping features */ 197 fake_comp1.class = &fake_class; 198 list_add(&fake_comp1.class_list, &fake_class.components); 199 fake_comp2.class = NULL; 200 fake_vmsc1.comp = &fake_comp1; 201 list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 202 fake_vmsc2.comp = &fake_comp1; 203 list_add(&fake_vmsc2.comp_list, &fake_comp1.vmsc); 204 fake_ris1.vmsc = &fake_vmsc1; 205 list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 206 fake_ris2.vmsc = &fake_vmsc2; 207 list_add(&fake_ris2.vmsc_list, &fake_vmsc2.ris); 208 209 mpam_set_feature(mpam_feat_cpor_part, &fake_ris1.props); 210 mpam_set_feature(mpam_feat_cpor_part, &fake_ris2.props); 211 mpam_set_feature(mpam_feat_mbw_part, &fake_ris1.props); 212 mpam_set_feature(mpam_feat_mbw_part, &fake_ris2.props); 213 fake_ris1.props.cpbm_wd = 5; 214 fake_ris2.props.cpbm_wd = 3; 215 fake_ris1.props.mbw_pbm_bits = 5; 216 fake_ris2.props.mbw_pbm_bits = 3; 217 218 mpam_enable_merge_features(&fake_classes_list); 219 220 /* 221 * Multiple RIS in different MSC can't control the same resource, 222 * mismatched features can not be supported. 223 */ 224 KUNIT_EXPECT_FALSE(test, mpam_has_feature(mpam_feat_cpor_part, &fake_class.props)); 225 KUNIT_EXPECT_FALSE(test, mpam_has_feature(mpam_feat_mbw_part, &fake_class.props)); 226 KUNIT_EXPECT_EQ(test, fake_class.props.cpbm_wd, 0); 227 KUNIT_EXPECT_EQ(test, fake_class.props.mbw_pbm_bits, 0); 228 229 reset_fake_hierarchy(); 230 231 /* One Class+Comp, two MSC with overlapping features that need tweaking */ 232 fake_comp1.class = &fake_class; 233 list_add(&fake_comp1.class_list, &fake_class.components); 234 fake_comp2.class = NULL; 235 fake_vmsc1.comp = &fake_comp1; 236 list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 237 fake_vmsc2.comp = &fake_comp1; 238 list_add(&fake_vmsc2.comp_list, &fake_comp1.vmsc); 239 fake_ris1.vmsc = &fake_vmsc1; 240 list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 241 fake_ris2.vmsc = &fake_vmsc2; 242 list_add(&fake_ris2.vmsc_list, &fake_vmsc2.ris); 243 244 mpam_set_feature(mpam_feat_mbw_min, &fake_ris1.props); 245 mpam_set_feature(mpam_feat_mbw_min, &fake_ris2.props); 246 mpam_set_feature(mpam_feat_cmax_cmax, &fake_ris1.props); 247 mpam_set_feature(mpam_feat_cmax_cmax, &fake_ris2.props); 248 fake_ris1.props.bwa_wd = 5; 249 fake_ris2.props.bwa_wd = 3; 250 fake_ris1.props.cmax_wd = 5; 251 fake_ris2.props.cmax_wd = 3; 252 253 mpam_enable_merge_features(&fake_classes_list); 254 255 /* 256 * RIS with different control properties need to be sanitised so the 257 * class has the common set of properties. 258 */ 259 KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_mbw_min, &fake_class.props)); 260 KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_cmax_cmax, &fake_class.props)); 261 KUNIT_EXPECT_EQ(test, fake_class.props.bwa_wd, 3); 262 KUNIT_EXPECT_EQ(test, fake_class.props.cmax_wd, 3); 263 264 reset_fake_hierarchy(); 265 266 /* One Class Two Comp with overlapping features */ 267 fake_comp1.class = &fake_class; 268 list_add(&fake_comp1.class_list, &fake_class.components); 269 fake_comp2.class = &fake_class; 270 list_add(&fake_comp2.class_list, &fake_class.components); 271 fake_vmsc1.comp = &fake_comp1; 272 list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 273 fake_vmsc2.comp = &fake_comp2; 274 list_add(&fake_vmsc2.comp_list, &fake_comp2.vmsc); 275 fake_ris1.vmsc = &fake_vmsc1; 276 list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 277 fake_ris2.vmsc = &fake_vmsc2; 278 list_add(&fake_ris2.vmsc_list, &fake_vmsc2.ris); 279 280 mpam_set_feature(mpam_feat_cpor_part, &fake_ris1.props); 281 mpam_set_feature(mpam_feat_cpor_part, &fake_ris2.props); 282 fake_ris1.props.cpbm_wd = 4; 283 fake_ris2.props.cpbm_wd = 4; 284 285 mpam_enable_merge_features(&fake_classes_list); 286 287 KUNIT_EXPECT_TRUE(test, mpam_has_feature(mpam_feat_cpor_part, &fake_class.props)); 288 KUNIT_EXPECT_EQ(test, fake_class.props.cpbm_wd, 4); 289 290 reset_fake_hierarchy(); 291 292 /* One Class Two Comp with non-overlapping features */ 293 fake_comp1.class = &fake_class; 294 list_add(&fake_comp1.class_list, &fake_class.components); 295 fake_comp2.class = &fake_class; 296 list_add(&fake_comp2.class_list, &fake_class.components); 297 fake_vmsc1.comp = &fake_comp1; 298 list_add(&fake_vmsc1.comp_list, &fake_comp1.vmsc); 299 fake_vmsc2.comp = &fake_comp2; 300 list_add(&fake_vmsc2.comp_list, &fake_comp2.vmsc); 301 fake_ris1.vmsc = &fake_vmsc1; 302 list_add(&fake_ris1.vmsc_list, &fake_vmsc1.ris); 303 fake_ris2.vmsc = &fake_vmsc2; 304 list_add(&fake_ris2.vmsc_list, &fake_vmsc2.ris); 305 306 mpam_set_feature(mpam_feat_cpor_part, &fake_ris1.props); 307 mpam_set_feature(mpam_feat_cmax_cmin, &fake_ris2.props); 308 fake_ris1.props.cpbm_wd = 4; 309 fake_ris2.props.cmax_wd = 4; 310 311 mpam_enable_merge_features(&fake_classes_list); 312 313 /* 314 * Multiple components can't control the same resource, mismatched features can 315 * not be supported. 316 */ 317 KUNIT_EXPECT_FALSE(test, mpam_has_feature(mpam_feat_cpor_part, &fake_class.props)); 318 KUNIT_EXPECT_FALSE(test, mpam_has_feature(mpam_feat_cmax_cmin, &fake_class.props)); 319 KUNIT_EXPECT_EQ(test, fake_class.props.cpbm_wd, 0); 320 KUNIT_EXPECT_EQ(test, fake_class.props.cmax_wd, 0); 321 322 mutex_unlock(&mpam_list_lock); 323 } 324 325 static void test_mpam_reset_msc_bitmap(struct kunit *test) 326 { 327 char __iomem *buf = kunit_kzalloc(test, SZ_16K, GFP_KERNEL); 328 struct mpam_msc fake_msc = {}; 329 u32 *test_result; 330 331 if (!buf) 332 return; 333 334 fake_msc.mapped_hwpage = buf; 335 fake_msc.mapped_hwpage_sz = SZ_16K; 336 cpumask_copy(&fake_msc.accessibility, cpu_possible_mask); 337 338 /* Satisfy lockdep checks */ 339 mutex_init(&fake_msc.part_sel_lock); 340 mutex_lock(&fake_msc.part_sel_lock); 341 342 test_result = (u32 *)(buf + MPAMCFG_CPBM); 343 344 mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 0); 345 KUNIT_EXPECT_EQ(test, test_result[0], 0); 346 KUNIT_EXPECT_EQ(test, test_result[1], 0); 347 test_result[0] = 0; 348 test_result[1] = 0; 349 350 mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 1); 351 KUNIT_EXPECT_EQ(test, test_result[0], 1); 352 KUNIT_EXPECT_EQ(test, test_result[1], 0); 353 test_result[0] = 0; 354 test_result[1] = 0; 355 356 mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 16); 357 KUNIT_EXPECT_EQ(test, test_result[0], 0xffff); 358 KUNIT_EXPECT_EQ(test, test_result[1], 0); 359 test_result[0] = 0; 360 test_result[1] = 0; 361 362 mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 32); 363 KUNIT_EXPECT_EQ(test, test_result[0], 0xffffffff); 364 KUNIT_EXPECT_EQ(test, test_result[1], 0); 365 test_result[0] = 0; 366 test_result[1] = 0; 367 368 mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 33); 369 KUNIT_EXPECT_EQ(test, test_result[0], 0xffffffff); 370 KUNIT_EXPECT_EQ(test, test_result[1], 1); 371 test_result[0] = 0; 372 test_result[1] = 0; 373 374 mutex_unlock(&fake_msc.part_sel_lock); 375 } 376 377 static struct kunit_case mpam_devices_test_cases[] = { 378 KUNIT_CASE(test_mpam_reset_msc_bitmap), 379 KUNIT_CASE(test_mpam_enable_merge_features), 380 KUNIT_CASE(test__props_mismatch), 381 {} 382 }; 383 384 static struct kunit_suite mpam_devices_test_suite = { 385 .name = "mpam_devices_test_suite", 386 .test_cases = mpam_devices_test_cases, 387 }; 388 389 kunit_test_suites(&mpam_devices_test_suite); 390