Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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 */
11static 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
28static struct list_head fake_classes_list;
29static struct mpam_class fake_class = { 0 };
30static struct mpam_component fake_comp1 = { 0 };
31static struct mpam_component fake_comp2 = { 0 };
32static struct mpam_vmsc fake_vmsc1 = { 0 };
33static struct mpam_vmsc fake_vmsc2 = { 0 };
34static struct mpam_msc fake_msc1 = { 0 };
35static struct mpam_msc fake_msc2 = { 0 };
36static struct mpam_msc_ris fake_ris1 = { 0 };
37static struct mpam_msc_ris fake_ris2 = { 0 };
38static struct platform_device fake_pdev = { 0 };
39
40static 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
81static 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
325static 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
377static 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
384static struct kunit_suite mpam_devices_test_suite = {
385 .name = "mpam_devices_test_suite",
386 .test_cases = mpam_devices_test_cases,
387};
388
389kunit_test_suites(&mpam_devices_test_suite);