xref: /linux/drivers/resctrl/test_mpam_devices.c (revision 44fc84337b6eae580a51cf6f7ca6a22ef1349556)
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