1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright © 2023 Intel Corporation
4 */
5
6 #include <linux/string.h>
7 #include <linux/xarray.h>
8
9 #include <drm/drm_drv.h>
10 #include <drm/drm_kunit_helpers.h>
11
12 #include <kunit/test.h>
13
14 #include "regs/xe_gt_regs.h"
15 #include "regs/xe_reg_defs.h"
16 #include "xe_device.h"
17 #include "xe_device_types.h"
18 #include "xe_pci_test.h"
19 #include "xe_reg_sr.h"
20 #include "xe_rtp.h"
21
22 #define REGULAR_REG1 XE_REG(1)
23 #define REGULAR_REG2 XE_REG(2)
24 #define REGULAR_REG3 XE_REG(3)
25 #define MCR_REG1 XE_REG_MCR(1)
26 #define MCR_REG2 XE_REG_MCR(2)
27 #define MCR_REG3 XE_REG_MCR(3)
28 #define MASKED_REG1 XE_REG(1, XE_REG_OPTION_MASKED)
29
30 #undef XE_REG_MCR
31 #define XE_REG_MCR(...) XE_REG(__VA_ARGS__, .mcr = 1)
32
33 struct rtp_test_case {
34 const char *name;
35 struct xe_reg expected_reg;
36 u32 expected_set_bits;
37 u32 expected_clr_bits;
38 unsigned long expected_count;
39 unsigned int expected_sr_errors;
40 const struct xe_rtp_entry_sr *entries;
41 };
42
match_yes(const struct xe_gt * gt,const struct xe_hw_engine * hwe)43 static bool match_yes(const struct xe_gt *gt, const struct xe_hw_engine *hwe)
44 {
45 return true;
46 }
47
match_no(const struct xe_gt * gt,const struct xe_hw_engine * hwe)48 static bool match_no(const struct xe_gt *gt, const struct xe_hw_engine *hwe)
49 {
50 return false;
51 }
52
53 static const struct rtp_test_case cases[] = {
54 {
55 .name = "coalesce-same-reg",
56 .expected_reg = REGULAR_REG1,
57 .expected_set_bits = REG_BIT(0) | REG_BIT(1),
58 .expected_clr_bits = REG_BIT(0) | REG_BIT(1),
59 .expected_count = 1,
60 /* Different bits on the same register: create a single entry */
61 .entries = (const struct xe_rtp_entry_sr[]) {
62 { XE_RTP_NAME("basic-1"),
63 XE_RTP_RULES(FUNC(match_yes)),
64 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
65 },
66 { XE_RTP_NAME("basic-2"),
67 XE_RTP_RULES(FUNC(match_yes)),
68 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
69 },
70 {}
71 },
72 },
73 {
74 .name = "no-match-no-add",
75 .expected_reg = REGULAR_REG1,
76 .expected_set_bits = REG_BIT(0),
77 .expected_clr_bits = REG_BIT(0),
78 .expected_count = 1,
79 /* Don't coalesce second entry since rules don't match */
80 .entries = (const struct xe_rtp_entry_sr[]) {
81 { XE_RTP_NAME("basic-1"),
82 XE_RTP_RULES(FUNC(match_yes)),
83 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
84 },
85 { XE_RTP_NAME("basic-2"),
86 XE_RTP_RULES(FUNC(match_no)),
87 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
88 },
89 {}
90 },
91 },
92 {
93 .name = "no-match-no-add-multiple-rules",
94 .expected_reg = REGULAR_REG1,
95 .expected_set_bits = REG_BIT(0),
96 .expected_clr_bits = REG_BIT(0),
97 .expected_count = 1,
98 /* Don't coalesce second entry due to one of the rules */
99 .entries = (const struct xe_rtp_entry_sr[]) {
100 { XE_RTP_NAME("basic-1"),
101 XE_RTP_RULES(FUNC(match_yes)),
102 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
103 },
104 { XE_RTP_NAME("basic-2"),
105 XE_RTP_RULES(FUNC(match_yes), FUNC(match_no)),
106 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
107 },
108 {}
109 },
110 },
111 {
112 .name = "two-regs-two-entries",
113 .expected_reg = REGULAR_REG1,
114 .expected_set_bits = REG_BIT(0),
115 .expected_clr_bits = REG_BIT(0),
116 .expected_count = 2,
117 /* Same bits on different registers are not coalesced */
118 .entries = (const struct xe_rtp_entry_sr[]) {
119 { XE_RTP_NAME("basic-1"),
120 XE_RTP_RULES(FUNC(match_yes)),
121 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
122 },
123 { XE_RTP_NAME("basic-2"),
124 XE_RTP_RULES(FUNC(match_yes)),
125 XE_RTP_ACTIONS(SET(REGULAR_REG2, REG_BIT(0)))
126 },
127 {}
128 },
129 },
130 {
131 .name = "clr-one-set-other",
132 .expected_reg = REGULAR_REG1,
133 .expected_set_bits = REG_BIT(0),
134 .expected_clr_bits = REG_BIT(1) | REG_BIT(0),
135 .expected_count = 1,
136 /* Check clr vs set actions on different bits */
137 .entries = (const struct xe_rtp_entry_sr[]) {
138 { XE_RTP_NAME("basic-1"),
139 XE_RTP_RULES(FUNC(match_yes)),
140 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
141 },
142 { XE_RTP_NAME("basic-2"),
143 XE_RTP_RULES(FUNC(match_yes)),
144 XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_BIT(1)))
145 },
146 {}
147 },
148 },
149 {
150 #define TEMP_MASK REG_GENMASK(10, 8)
151 #define TEMP_FIELD REG_FIELD_PREP(TEMP_MASK, 2)
152 .name = "set-field",
153 .expected_reg = REGULAR_REG1,
154 .expected_set_bits = TEMP_FIELD,
155 .expected_clr_bits = TEMP_MASK,
156 .expected_count = 1,
157 /* Check FIELD_SET works */
158 .entries = (const struct xe_rtp_entry_sr[]) {
159 { XE_RTP_NAME("basic-1"),
160 XE_RTP_RULES(FUNC(match_yes)),
161 XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1,
162 TEMP_MASK, TEMP_FIELD))
163 },
164 {}
165 },
166 #undef TEMP_MASK
167 #undef TEMP_FIELD
168 },
169 {
170 .name = "conflict-duplicate",
171 .expected_reg = REGULAR_REG1,
172 .expected_set_bits = REG_BIT(0),
173 .expected_clr_bits = REG_BIT(0),
174 .expected_count = 1,
175 .expected_sr_errors = 1,
176 .entries = (const struct xe_rtp_entry_sr[]) {
177 { XE_RTP_NAME("basic-1"),
178 XE_RTP_RULES(FUNC(match_yes)),
179 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
180 },
181 /* drop: setting same values twice */
182 { XE_RTP_NAME("basic-2"),
183 XE_RTP_RULES(FUNC(match_yes)),
184 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
185 },
186 {}
187 },
188 },
189 {
190 .name = "conflict-not-disjoint",
191 .expected_reg = REGULAR_REG1,
192 .expected_set_bits = REG_BIT(0),
193 .expected_clr_bits = REG_BIT(0),
194 .expected_count = 1,
195 .expected_sr_errors = 1,
196 .entries = (const struct xe_rtp_entry_sr[]) {
197 { XE_RTP_NAME("basic-1"),
198 XE_RTP_RULES(FUNC(match_yes)),
199 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
200 },
201 /* drop: bits are not disjoint with previous entries */
202 { XE_RTP_NAME("basic-2"),
203 XE_RTP_RULES(FUNC(match_yes)),
204 XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_GENMASK(1, 0)))
205 },
206 {}
207 },
208 },
209 {
210 .name = "conflict-reg-type",
211 .expected_reg = REGULAR_REG1,
212 .expected_set_bits = REG_BIT(0),
213 .expected_clr_bits = REG_BIT(0),
214 .expected_count = 1,
215 .expected_sr_errors = 2,
216 .entries = (const struct xe_rtp_entry_sr[]) {
217 { XE_RTP_NAME("basic-1"),
218 XE_RTP_RULES(FUNC(match_yes)),
219 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
220 },
221 /* drop: regular vs MCR */
222 { XE_RTP_NAME("basic-2"),
223 XE_RTP_RULES(FUNC(match_yes)),
224 XE_RTP_ACTIONS(SET(MCR_REG1, REG_BIT(1)))
225 },
226 /* drop: regular vs masked */
227 { XE_RTP_NAME("basic-3"),
228 XE_RTP_RULES(FUNC(match_yes)),
229 XE_RTP_ACTIONS(SET(MASKED_REG1, REG_BIT(0)))
230 },
231 {}
232 },
233 },
234 };
235
xe_rtp_process_tests(struct kunit * test)236 static void xe_rtp_process_tests(struct kunit *test)
237 {
238 const struct rtp_test_case *param = test->param_value;
239 struct xe_device *xe = test->priv;
240 struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt;
241 struct xe_reg_sr *reg_sr = >->reg_sr;
242 const struct xe_reg_sr_entry *sre, *sr_entry = NULL;
243 struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt);
244 unsigned long idx, count = 0;
245
246 xe_reg_sr_init(reg_sr, "xe_rtp_tests", xe);
247 xe_rtp_process_to_sr(&ctx, param->entries, reg_sr);
248
249 xa_for_each(®_sr->xa, idx, sre) {
250 if (idx == param->expected_reg.addr)
251 sr_entry = sre;
252
253 count++;
254 }
255
256 KUNIT_EXPECT_EQ(test, count, param->expected_count);
257 KUNIT_EXPECT_EQ(test, sr_entry->clr_bits, param->expected_clr_bits);
258 KUNIT_EXPECT_EQ(test, sr_entry->set_bits, param->expected_set_bits);
259 KUNIT_EXPECT_EQ(test, sr_entry->reg.raw, param->expected_reg.raw);
260 KUNIT_EXPECT_EQ(test, reg_sr->errors, param->expected_sr_errors);
261 }
262
rtp_desc(const struct rtp_test_case * t,char * desc)263 static void rtp_desc(const struct rtp_test_case *t, char *desc)
264 {
265 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
266 }
267
268 KUNIT_ARRAY_PARAM(rtp, cases, rtp_desc);
269
xe_rtp_test_init(struct kunit * test)270 static int xe_rtp_test_init(struct kunit *test)
271 {
272 struct xe_device *xe;
273 struct device *dev;
274 int ret;
275
276 dev = drm_kunit_helper_alloc_device(test);
277 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
278
279 xe = drm_kunit_helper_alloc_drm_device(test, dev,
280 struct xe_device,
281 drm, DRIVER_GEM);
282 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe);
283
284 /* Initialize an empty device */
285 test->priv = NULL;
286 ret = xe_pci_fake_device_init(xe);
287 KUNIT_ASSERT_EQ(test, ret, 0);
288
289 xe->drm.dev = dev;
290 test->priv = xe;
291
292 return 0;
293 }
294
xe_rtp_test_exit(struct kunit * test)295 static void xe_rtp_test_exit(struct kunit *test)
296 {
297 struct xe_device *xe = test->priv;
298
299 drm_kunit_helper_free_device(test, xe->drm.dev);
300 }
301
302 static struct kunit_case xe_rtp_tests[] = {
303 KUNIT_CASE_PARAM(xe_rtp_process_tests, rtp_gen_params),
304 {}
305 };
306
307 static struct kunit_suite xe_rtp_test_suite = {
308 .name = "xe_rtp",
309 .init = xe_rtp_test_init,
310 .exit = xe_rtp_test_exit,
311 .test_cases = xe_rtp_tests,
312 };
313
314 kunit_test_suite(xe_rtp_test_suite);
315
316 MODULE_AUTHOR("Intel Corporation");
317 MODULE_LICENSE("GPL");
318 MODULE_DESCRIPTION("xe_rtp kunit test");
319 MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);
320