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 2025 Oxide Computer Company
14 */
15
16 /*
17 * Facilitate access to the AMD Zen data fabric
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <err.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <strings.h>
29 #include <zen_udf.h>
30
31 static void
udf_readone(int fd,uint8_t inst,uint8_t func,uint16_t reg,zen_udf_flags_t flags)32 udf_readone(int fd, uint8_t inst, uint8_t func, uint16_t reg,
33 zen_udf_flags_t flags)
34 {
35 int ret;
36 zen_udf_io_t zui;
37
38 bzero(&zui, sizeof (zui));
39 zui.zui_flags = flags;
40 zui.zui_inst = inst;
41 zui.zui_func = func;
42 zui.zui_reg = reg;
43
44 ret = ioctl(fd, ZEN_UDF_READ, &zui);
45 if (ret != 0) {
46 err(EXIT_FAILURE, "failed to issue read ioctl");
47 }
48
49 if ((flags & ZEN_UDF_F_BCAST) == 0) {
50 (void) printf("ifr %x/%x/%x: 0x%" PRIx64 "\n",
51 inst, func, reg, zui.zui_data);
52 } else {
53 (void) printf("ifr bcast/%x/%x: 0x%" PRIx64 "\n",
54 func, reg, zui.zui_data);
55 }
56 }
57
58 int
main(int argc,char * argv[])59 main(int argc, char *argv[])
60 {
61 int c, fd;
62 const char *device = NULL;
63 const char *funcstr = NULL;
64 const char *inststr = NULL;
65 const char *regstr = NULL;
66 zen_udf_flags_t flags = 0;
67 uint8_t func, inst = UINT8_MAX;
68 uint16_t reg;
69 unsigned long lval;
70 char *eptr;
71
72 while ((c = getopt(argc, argv, "d:f:bi:r:l")) != -1) {
73 switch (c) {
74 case 'd':
75 device = optarg;
76 break;
77 case 'f':
78 funcstr = optarg;
79 break;
80 case 'b':
81 flags |= ZEN_UDF_F_BCAST;
82 break;
83 case 'i':
84 inststr = optarg;
85 break;
86 case 'l':
87 flags |= ZEN_UDF_F_64;
88 break;
89 case 'r':
90 regstr = optarg;
91 break;
92 }
93 }
94
95 if (device == NULL || funcstr == NULL || regstr == NULL ||
96 (inststr == NULL && (flags & ZEN_UDF_F_BCAST) == 0)) {
97 warnx("missing required arguments");
98 (void) fprintf(stderr, "Usage: "
99 "\tudf \t[-l] -d device -f func -b -r reg\n"
100 "\t\t[-l] -d device -f func -i inst -r reg\n");
101 exit(2);
102 }
103
104 errno = 0;
105 lval = strtoul(funcstr, &eptr, 0);
106 if (errno != 0 || lval > UINT8_MAX || *eptr != '\0') {
107 errx(EXIT_FAILURE, "failed to parse -f: %s", funcstr);
108 }
109 func = (uint8_t)lval;
110
111 if ((flags & ZEN_UDF_F_BCAST) == 0) {
112 lval = strtoul(inststr, &eptr, 0);
113 if (errno != 0 || lval > UINT8_MAX || *eptr != '\0') {
114 errx(EXIT_FAILURE, "failed to parse -i: %s", inststr);
115 }
116 inst = (uint8_t)lval;
117 } else if (inststr != NULL) {
118 errx(EXIT_FAILURE, "pass just one of -b or -i inst");
119 }
120
121 lval = strtoul(regstr, &eptr, 0);
122 if (errno != 0 || lval > UINT16_MAX || *eptr != '\0') {
123 errx(EXIT_FAILURE, "failed to parse -r: %s", regstr);
124 }
125 reg = (uint16_t)lval;
126
127 if ((fd = open(device, O_RDONLY)) < 0) {
128 err(EXIT_FAILURE, "failed to open %s", device);
129 }
130
131 udf_readone(fd, inst, func, reg, flags);
132 (void) close(fd);
133 return (0);
134 }
135