xref: /illumos-gate/usr/src/test/os-tests/tests/zen_umc/zen_umc_test.c (revision a4955f4fa65e38d70c07d38e657a9aff43fa155f)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2022 Oxide Computer Company
14  */
15 
16 /*
17  * Test the memory decoding and normalization features at the heart of the
18  * zen_umc(4D) driver.
19  */
20 
21 #include <stdio.h>
22 #include <string.h>
23 #include <inttypes.h>
24 #include <err.h>
25 #include <stdlib.h>
26 #include <sys/sysmacros.h>
27 
28 #include "zen_umc_test.h"
29 
30 static const char *
31 zen_umc_test_strerror(zen_umc_decode_failure_t fail)
32 {
33 	switch (fail) {
34 	case ZEN_UMC_DECODE_F_NONE:
35 		return ("Actually succeeded");
36 	case ZEN_UMC_DECODE_F_OUTSIDE_DRAM:
37 		return ("Address outside of DRAM");
38 	case ZEN_UMC_DECODE_F_NO_DF_RULE:
39 		return ("Address didn't find a DF rule that matched");
40 	case ZEN_UMC_DECODE_F_ILEAVE_UNDERFLOW:
41 		return ("Interleave adjustments caused PA to underflow");
42 	case ZEN_UMC_DECODE_F_CHAN_ILEAVE_NOTSUP:
43 		return ("Unsupported channel interleave");
44 	case ZEN_UMC_DECODE_F_COD_BAD_ILEAVE:
45 		return ("Unsupported interleave settings for COD hash");
46 	case ZEN_UMC_DECODE_F_NPS_BAD_ILEAVE:
47 		return ("Unsupported interleave settings for NPS hash");
48 	case ZEN_UMC_DECODE_F_BAD_REMAP_SET:
49 		return ("Remap ruleset was invalid");
50 	case ZEN_UMC_DECODE_F_BAD_REMAP_ENTRY:
51 		return ("Remap entry was invalid");
52 	case ZEN_UMC_DECODE_F_REMAP_HAS_BAD_COMP:
53 		return ("Remap entry is not a valid component ID");
54 	case ZEN_UMC_DECODE_F_CANNOT_MAP_FABID:
55 		return ("Failed to find target fabric ID");
56 	case ZEN_UMC_DECODE_F_UMC_DOESNT_HAVE_PA:
57 		return ("Target UMC does not have a DRAM rule for PA");
58 	case ZEN_UMC_DECODE_F_CALC_NORM_UNDERFLOW:
59 		return ("Address normalization underflowed");
60 	case ZEN_UMC_DECODE_F_NO_CS_BASE_MATCH:
61 		return ("No chip-select matched normal address");
62 	default:
63 		return ("<unknown>");
64 	}
65 }
66 
67 static const char *
68 zen_umc_test_strenum(zen_umc_decode_failure_t fail)
69 {
70 	switch (fail) {
71 	case ZEN_UMC_DECODE_F_NONE:
72 		return ("ZEN_UMC_DECODE_F_NONE");
73 	case ZEN_UMC_DECODE_F_OUTSIDE_DRAM:
74 		return ("ZEN_UMC_DECODE_F_OUTSIDE_DRAM");
75 	case ZEN_UMC_DECODE_F_NO_DF_RULE:
76 		return ("ZEN_UMC_DECODE_F_NO_DF_RULE");
77 	case ZEN_UMC_DECODE_F_ILEAVE_UNDERFLOW:
78 		return ("ZEN_UMC_DECODE_F_ILEAVE_UNDERFLOW");
79 	case ZEN_UMC_DECODE_F_CHAN_ILEAVE_NOTSUP:
80 		return ("ZEN_UMC_DECODE_F_CHAN_ILEAVE_NOTSUP");
81 	case ZEN_UMC_DECODE_F_COD_BAD_ILEAVE:
82 		return ("ZEN_UMC_DECODE_F_COD_BAD_ILEAVE");
83 	case ZEN_UMC_DECODE_F_NPS_BAD_ILEAVE:
84 		return ("ZEN_UMC_DECODE_F_NPS_BAD_ILEAVE");
85 	case ZEN_UMC_DECODE_F_BAD_REMAP_SET:
86 		return ("ZEN_UMC_DECODE_F_BAD_REMAP_SET");
87 	case ZEN_UMC_DECODE_F_BAD_REMAP_ENTRY:
88 		return ("ZEN_UMC_DECODE_F_BAD_REMAP_ENTRY");
89 	case ZEN_UMC_DECODE_F_REMAP_HAS_BAD_COMP:
90 		return ("ZEN_UMC_DECODE_F_REMAP_HAS_BAD_COMP");
91 	case ZEN_UMC_DECODE_F_CANNOT_MAP_FABID:
92 		return ("ZEN_UMC_DECODE_F_CANNOT_MAP_FABID");
93 	case ZEN_UMC_DECODE_F_UMC_DOESNT_HAVE_PA:
94 		return ("ZEN_UMC_DECODE_F_UMC_DOESNT_HAVE_PA");
95 	case ZEN_UMC_DECODE_F_CALC_NORM_UNDERFLOW:
96 		return ("ZEN_UMC_DECODE_F_CALC_NORM_UNDERFLOW");
97 	case ZEN_UMC_DECODE_F_NO_CS_BASE_MATCH:
98 		return ("ZEN_UMC_DECODE_F_NO_CS_BASE_MATCH");
99 	default:
100 		return ("<unknown>");
101 	}
102 }
103 
104 static boolean_t
105 zen_umc_test_fabric_one(const umc_fabric_test_t *test)
106 {
107 	boolean_t ret = B_TRUE;
108 
109 	(void) printf("Running test: %s\n", test->uft_desc);
110 	if (test->uft_compose) {
111 		uint32_t fab, sock, die, comp;
112 		boolean_t rtt = B_TRUE;
113 		boolean_t valid;
114 
115 		valid = zen_fabric_id_valid_parts(test->uft_decomp,
116 		    test->uft_sock_id, test->uft_die_id, test->uft_comp_id);
117 		if (!valid) {
118 			if (test->uft_valid) {
119 				(void) printf("\tInvalid fabric ID parts "
120 				    "found\n");
121 				return (B_FALSE);
122 			}
123 
124 			(void) printf("\tTEST PASSED: Invalid Fabric parts "
125 			    "detected\n");
126 			return (B_TRUE);
127 		} else {
128 			if (!test->uft_valid) {
129 				(void) printf("\tFabric ID parts validated, "
130 				    "but expected failure\n");
131 				return (B_FALSE);
132 			}
133 		}
134 		zen_fabric_id_compose(test->uft_decomp, test->uft_sock_id,
135 		    test->uft_die_id, test->uft_comp_id, &fab);
136 		if (fab != test->uft_fabric_id) {
137 			(void) printf("\tFabric ID mismatch\n"
138 			    "\t\texpected 0x%x\n\t\tfound    0x%x\n",
139 			    test->uft_fabric_id, fab);
140 			ret = B_FALSE;
141 		} else {
142 			(void) printf("\tTEST PASSED: Fabric ID composition\n");
143 		}
144 
145 		zen_fabric_id_decompose(test->uft_decomp, fab, &sock, &die,
146 		    &comp);
147 		if (sock != test->uft_sock_id) {
148 			(void) printf("\tRound-trip socket mismatch\n"
149 			    "\t\texpected %u\n\t\tfound %u\n",
150 			    test->uft_sock_id, sock);
151 			ret = rtt = B_FALSE;
152 		}
153 
154 		if (die != test->uft_die_id) {
155 			(void) printf("\tRound-trip die mismatch\n"
156 			    "\t\texpected %u\n\t\tfound %u\n",
157 			    test->uft_die_id, die);
158 			ret = rtt = B_FALSE;
159 		}
160 
161 		if (comp != test->uft_comp_id) {
162 			(void) printf("\tRound-trip comp mismatch\n"
163 			    "\t\texpected %u\n\t\tfound %u\n",
164 			    test->uft_comp_id, comp);
165 			ret = rtt = B_FALSE;
166 		}
167 
168 		if (rtt) {
169 			(void) printf("\tTEST PASSED: Round-trip Fabric ID "
170 			    "decomposition\n");
171 		}
172 	} else {
173 		uint32_t fab, sock, die, comp;
174 		boolean_t valid;
175 
176 		valid = zen_fabric_id_valid_fabid(test->uft_decomp,
177 		    test->uft_fabric_id);
178 		if (!valid) {
179 			if (test->uft_valid) {
180 				(void) printf("\tInvalid fabric ID found\n");
181 				return (B_FALSE);
182 			}
183 
184 			(void) printf("\tTEST PASSED: Successfully found "
185 			    "invalid fabric ID\n");
186 			return (B_TRUE);
187 		} else {
188 			if (!test->uft_valid) {
189 				(void) printf("\tFabric ID validated, "
190 				    "but expected to find an invalid one\n");
191 				return (B_FALSE);
192 			}
193 		}
194 		zen_fabric_id_decompose(test->uft_decomp, test->uft_fabric_id,
195 		    &sock, &die, &comp);
196 		if (sock != test->uft_sock_id) {
197 			(void) printf("\tsocket mismatch\n"
198 			    "\t\texpected %u\n\t\tfound %u\n",
199 			    test->uft_sock_id, sock);
200 			ret = B_FALSE;
201 		}
202 
203 		if (die != test->uft_die_id) {
204 			(void) printf("\tdie mismatch\n"
205 			    "\t\texpected %u\n\t\tfound %u\n",
206 			    test->uft_die_id, die);
207 			ret = B_FALSE;
208 		}
209 
210 		if (comp != test->uft_comp_id) {
211 			(void) printf("\tcomp mismatch\n"
212 			    "\t\texpected %u\n\t\tfound %u\n",
213 			    test->uft_comp_id, comp);
214 			ret = B_FALSE;
215 		}
216 
217 		if (ret) {
218 			(void) printf("\tTEST PASSED: Fabric ID "
219 			    "Decomposition\n");
220 		}
221 
222 		zen_fabric_id_compose(test->uft_decomp, sock, die, comp, &fab);
223 		if (fab != test->uft_fabric_id) {
224 			(void) printf("\tFabric ID mismatch on round trip\n"
225 			    "\t\texpected 0x%x\n\t\tfound    0x%x\n",
226 			    test->uft_fabric_id, fab);
227 			ret = B_FALSE;
228 		} else {
229 			(void) printf("\tTEST PASSED: Round-trip Fabric ID "
230 			    "composition\n");
231 		}
232 	}
233 
234 	return (ret);
235 }
236 
237 static boolean_t
238 zen_umc_test_decode_one(const umc_decode_test_t *test)
239 {
240 	boolean_t pass;
241 	zen_umc_decoder_t dec;
242 
243 	(void) printf("Running test: %s\n", test->udt_desc);
244 	(void) printf("\tDecoding address: 0x%" PRIx64 "\n", test->udt_pa);
245 	memset(&dec, '\0', sizeof (dec));
246 
247 	pass = zen_umc_decode_pa(test->udt_umc, test->udt_pa, &dec);
248 	if (pass && !test->udt_pass) {
249 		uint32_t sock, die, comp;
250 
251 		zen_fabric_id_decompose(&test->udt_umc->umc_decomp,
252 		    dec.dec_targ_fabid, &sock, &die, &comp);
253 
254 		(void) printf("\tdecode unexpectedly succeeded\n");
255 		(void) printf("\texpected error '%s' (%s/0x%x)\n",
256 		    zen_umc_test_strerror(test->udt_fail),
257 		    zen_umc_test_strenum(test->udt_fail),
258 		    test->udt_fail);
259 		(void) printf("\t\tdecoded socket: 0x%x\n", sock);
260 		(void) printf("\t\tdecoded die: 0x%x\n", die);
261 		(void) printf("\t\tdecoded component: 0x%x\n", comp);
262 		(void) printf("\t\tnormal address: 0x%" PRIx64 "\n",
263 		    dec.dec_norm_addr);
264 		(void) printf("\t\tdecoded dimm: 0x%x\n", dec.dec_dimm_no);
265 		(void) printf("\t\tdecoded row: 0x%x\n", dec.dec_dimm_row);
266 		(void) printf("\t\tdecoded column: 0x%x\n", dec.dec_dimm_col);
267 		(void) printf("\t\tdecoded bank: 0x%x\n", dec.dec_dimm_bank);
268 		(void) printf("\t\tdecoded bank group: 0x%x\n",
269 		    dec.dec_dimm_bank_group);
270 		(void) printf("\t\tdecoded rm: 0x%x\n", dec.dec_dimm_rm);
271 		(void) printf("\t\tdecoded cs: 0x%x\n", dec.dec_dimm_csno);
272 		(void) printf("\ttest failed\n");
273 		return (B_FALSE);
274 	} else if (pass) {
275 		uint32_t sock, die, comp;
276 		boolean_t success = B_TRUE;
277 
278 		zen_fabric_id_decompose(&test->udt_umc->umc_decomp,
279 		    dec.dec_targ_fabid, &sock, &die, &comp);
280 		if (test->udt_sock != UINT8_MAX &&
281 		    test->udt_sock != sock) {
282 			(void) printf("\tsocket mismatch\n"
283 			    "\t\texpected 0x%x\n\t\tfound    0x%x\n",
284 			    test->udt_sock, sock);
285 			success = B_FALSE;
286 		}
287 
288 		if (test->udt_die != UINT8_MAX &&
289 		    test->udt_die != die) {
290 			(void) printf("\tdie mismatch\n"
291 			    "\t\texpected 0x%x\n\t\tfound    0x%x\n",
292 			    test->udt_die, die);
293 			success = B_FALSE;
294 		}
295 
296 		if (test->udt_comp != UINT8_MAX &&
297 		    test->udt_comp != comp) {
298 			(void) printf("\tcomp mismatch\n"
299 			    "\t\texpected 0x%x\n\t\tfound    0x%x\n",
300 			    test->udt_comp, comp);
301 			success = B_FALSE;
302 		}
303 
304 		if (test->udt_norm_addr != UINT64_MAX &&
305 		    test->udt_norm_addr != dec.dec_norm_addr) {
306 			(void) printf("\tnormalized address mismatch\n"
307 			    "\t\texpected 0x%" PRIx64 "\n"
308 			    "\t\tfound    0x%" PRIx64 "\n",
309 			    test->udt_norm_addr, dec.dec_norm_addr);
310 			success = B_FALSE;
311 		}
312 
313 		if (test->udt_dimm_no != UINT32_MAX &&
314 		    test->udt_dimm_no != dec.dec_dimm_no) {
315 			(void) printf("\tDIMM number mismatch\n"
316 			    "\t\texpected 0x%x\n\t\tfound    0x%x\n",
317 			    test->udt_dimm_no, dec.dec_dimm_no);
318 			success = B_FALSE;
319 		}
320 
321 		if (test->udt_dimm_col != UINT32_MAX &&
322 		    test->udt_dimm_col != dec.dec_dimm_col) {
323 			(void) printf("\tcolumn mismatch\n"
324 			    "\t\texpected 0x%x\n\t\tfound    0x%x\n",
325 			    test->udt_dimm_col, dec.dec_dimm_col);
326 			success = B_FALSE;
327 		}
328 
329 		if (test->udt_dimm_row != UINT32_MAX &&
330 		    test->udt_dimm_row != dec.dec_dimm_row) {
331 			(void) printf("\trow mismatch\n"
332 			    "\t\texpected 0x%x\n\t\tfound    0x%x\n",
333 			    test->udt_dimm_row, dec.dec_dimm_row);
334 			success = B_FALSE;
335 		}
336 
337 		if (test->udt_dimm_bank != UINT8_MAX &&
338 		    test->udt_dimm_bank != dec.dec_dimm_bank) {
339 			(void) printf("\tbank mismatch\n"
340 			    "\t\texpected 0x%x\n\t\tfound    0x%x\n",
341 			    test->udt_dimm_bank, dec.dec_dimm_bank);
342 			success = B_FALSE;
343 		}
344 
345 		if (test->udt_dimm_bank_group != UINT8_MAX &&
346 		    test->udt_dimm_bank_group != dec.dec_dimm_bank_group) {
347 			(void) printf("\tbank group mismatch\n"
348 			    "\t\texpected 0x%x\n\t\tfound    0x%x\n",
349 			    test->udt_dimm_bank_group, dec.dec_dimm_bank_group);
350 			success = B_FALSE;
351 		}
352 
353 		if (test->udt_dimm_subchan != UINT8_MAX &&
354 		    test->udt_dimm_subchan != dec.dec_dimm_subchan) {
355 			(void) printf("\tsub-channel mismatch\n"
356 			    "\t\texpected 0x%x\n\t\tfound    0x%x\n",
357 			    test->udt_dimm_subchan, dec.dec_dimm_subchan);
358 			success = B_FALSE;
359 		}
360 
361 		if (test->udt_dimm_rm != UINT8_MAX &&
362 		    test->udt_dimm_rm != dec.dec_dimm_rm) {
363 			(void) printf("\tRM mismatch\n"
364 			    "\t\texpected 0x%x\n\t\tfound    0x%x\n",
365 			    test->udt_dimm_rm, dec.dec_dimm_rm);
366 			success = B_FALSE;
367 		}
368 
369 		if (test->udt_dimm_cs != UINT8_MAX &&
370 		    test->udt_dimm_cs != dec.dec_dimm_csno) {
371 			(void) printf("\tCS mismatch\n"
372 			    "\t\texpected 0x%x\n\t\tfound    0x%x\n",
373 			    test->udt_dimm_cs, dec.dec_dimm_csno);
374 			success = B_FALSE;
375 		}
376 
377 		if (success) {
378 			(void) printf("\tTEST PASSED: Successfully decoded "
379 			    "PA\n");
380 		} else {
381 			(void) printf("\tTEST FAILED!\n");
382 		}
383 		return (success);
384 	} else if (!pass && !test->udt_pass) {
385 		if (dec.dec_fail != test->udt_fail) {
386 			(void) printf("\terror mismatch\n"
387 			    "\t\texpected '%s' (%s/0x%x)\n"
388 			    "\t\tfound '%s' (%s/0x%x)\n",
389 			    zen_umc_test_strerror(test->udt_fail),
390 			    zen_umc_test_strenum(test->udt_fail),
391 			    test->udt_fail,
392 			    zen_umc_test_strerror(dec.dec_fail),
393 			    zen_umc_test_strenum(dec.dec_fail),
394 			    dec.dec_fail);
395 			return (B_FALSE);
396 		}
397 
398 		(void) printf("\tTEST PASSED: Correct error generated\n");
399 		return (B_TRUE);
400 	} else {
401 		(void) printf("\tdecode failed with error '%s' (%s/0x%x)\n",
402 		    zen_umc_test_strerror(dec.dec_fail),
403 		    zen_umc_test_strenum(dec.dec_fail),
404 		    dec.dec_fail);
405 
406 		if (test->udt_norm_addr != UINT64_MAX) {
407 			(void) printf("\t\texpected normal address: "
408 			    "0x%" PRIx64 "\n", test->udt_norm_addr);
409 		}
410 
411 		if (test->udt_sock != UINT8_MAX) {
412 			(void) printf("\t\texpected socket: 0x%x\n",
413 			    test->udt_sock);
414 		}
415 
416 		if (test->udt_die != UINT8_MAX) {
417 			(void) printf("\t\texpected die: 0x%x\n",
418 			    test->udt_die);
419 		}
420 
421 		if (test->udt_comp != UINT8_MAX) {
422 			(void) printf("\t\texpected comp: 0x%x\n",
423 			    test->udt_comp);
424 		}
425 
426 		if (test->udt_dimm_no != UINT32_MAX) {
427 			(void) printf("\t\texpected DIMM number: 0x%x\n",
428 			    test->udt_dimm_no);
429 		}
430 
431 		if (test->udt_dimm_col != UINT32_MAX) {
432 			(void) printf("\t\texpected column: 0x%x\n",
433 			    test->udt_dimm_col);
434 		}
435 
436 		if (test->udt_dimm_row != UINT32_MAX) {
437 			(void) printf("\t\texpected row: 0x%x\n",
438 			    test->udt_dimm_row);
439 		}
440 
441 		if (test->udt_dimm_bank != UINT8_MAX) {
442 			(void) printf("\t\texpected bank: 0x%x\n",
443 			    test->udt_dimm_bank);
444 		}
445 
446 		if (test->udt_dimm_bank_group != UINT8_MAX) {
447 			(void) printf("\t\texpected bank group: 0x%x\n",
448 			    test->udt_dimm_bank_group);
449 		}
450 
451 		if (test->udt_dimm_subchan != UINT8_MAX) {
452 			(void) printf("\t\texpected sub-channel: 0x%x\n",
453 			    test->udt_dimm_subchan);
454 		}
455 
456 		if (test->udt_dimm_rm != UINT8_MAX) {
457 			(void) printf("\t\texpected RM: 0x%x\n",
458 			    test->udt_dimm_rm);
459 		}
460 
461 		if (test->udt_dimm_cs != UINT8_MAX) {
462 			(void) printf("\t\texpected CS: 0x%x\n",
463 			    test->udt_dimm_cs);
464 		}
465 
466 		return (B_FALSE);
467 	}
468 }
469 
470 static void
471 zen_umc_test_fabric(const umc_fabric_test_t *tests, uint_t *ntests,
472     uint_t *nfail)
473 {
474 	for (uint_t i = 0; tests[i].uft_desc != NULL; i++) {
475 		if (!zen_umc_test_fabric_one(&tests[i]))
476 			*nfail += 1;
477 		*ntests += 1;
478 	}
479 }
480 
481 static void
482 zen_umc_test_decode(const umc_decode_test_t *tests, uint_t *ntests,
483     uint_t *nfail)
484 {
485 	for (uint_t i = 0; tests[i].udt_desc != NULL; i++) {
486 		if (!zen_umc_test_decode_one(&tests[i]))
487 			*nfail += 1;
488 		*ntests += 1;
489 	}
490 }
491 
492 typedef struct zen_umc_test_set {
493 	const char *set_name;
494 	const umc_decode_test_t *set_test;
495 } zen_umc_test_set_t;
496 
497 static const zen_umc_test_set_t zen_umc_test_set[] = {
498 	{ "basic", zen_umc_test_basics },
499 	{ "channel", zen_umc_test_chans },
500 	{ "cod", zen_umc_test_cod },
501 	{ "errors", zen_umc_test_errors },
502 	{ "hole", zen_umc_test_hole },
503 	{ "ilv", zen_umc_test_ilv },
504 	{ "multi", zen_umc_test_multi },
505 	{ "nps", zen_umc_test_nps },
506 	{ "remap", zen_umc_test_remap },
507 };
508 
509 static void
510 zen_umc_test_selected(int argc, char *argv[], uint_t *ntests, uint_t *nfail)
511 {
512 	for (int i = 1; i < argc; i++) {
513 		boolean_t ran = B_FALSE;
514 
515 		if (strcmp(argv[i], "fabric_ids") == 0) {
516 			zen_umc_test_fabric(zen_umc_test_fabric_ids, ntests,
517 			    nfail);
518 			continue;
519 		}
520 
521 		for (uint_t t = 0; t < ARRAY_SIZE(zen_umc_test_set); t++) {
522 			const zen_umc_test_set_t *s = &zen_umc_test_set[t];
523 
524 			if (strcmp(s->set_name, argv[i]) == 0) {
525 				zen_umc_test_decode(s->set_test, ntests, nfail);
526 				ran = B_TRUE;
527 				break;
528 			}
529 		}
530 
531 		if (!ran) {
532 			errx(EXIT_FAILURE, "Unknown test suite: %s", argv[i]);
533 		}
534 	}
535 }
536 
537 int
538 main(int argc, char *argv[])
539 {
540 	uint_t ntests = 0, nfail = 0;
541 
542 	if (argc > 1) {
543 		zen_umc_test_selected(argc, argv, &ntests, &nfail);
544 	} else {
545 		zen_umc_test_fabric(zen_umc_test_fabric_ids, &ntests, &nfail);
546 		for (uint_t i = 0; i < ARRAY_SIZE(zen_umc_test_set); i++) {
547 			zen_umc_test_decode(zen_umc_test_set[i].set_test,
548 			    &ntests, &nfail);
549 		}
550 	}
551 	(void) printf("%u/%u tests passed\n", ntests - nfail, ntests);
552 	return (nfail > 0);
553 }
554