libxcoder 5.6.0
Loading...
Searching...
No Matches
ni_quadraprobe.c
Go to the documentation of this file.
1#include <stdio.h>
2#include <stdint.h>
3#include <stddef.h>
4#include <stdlib.h>
5#include <string.h>
6#include <sys/stat.h>
7#include <unistd.h>
8#include <fcntl.h>
9#include <errno.h>
10#include <limits.h>
11#include <dirent.h>
12#include <sys/mman.h>
13#include <stdbool.h>
14
15#define LOG_SIZE (1024 * 1024)
16#define NUM_CORES 5
17#define PCI_SYSFS_PATH "/sys/bus/pci/devices"
18#define QUADRA_VENDOR_ID 0x1d82
19#define QUADRA_DEVICE_ID 0x0401
20
21#if defined(__linux__)
22
23const char *const core_names[NUM_CORES] = {"np", "dp", "ep", "tp", "fp"};
24
25typedef struct {
26 char sysfs_path[256];
27 int domain;
28 int bus;
29 int slot;
30 int bar4_fd;
31 unsigned char *bar4_base;
32 off_t barsize;
33 uint32_t core_log_offsets[NUM_CORES];
34 int log_size;
35} QuadraDevice;
36
37int bdf_to_sysfs(const char* bdf, char* sysfs_path, size_t pathsz, int *domain, int *bus, int *slot)
38{
39 unsigned d=0, b=0, s=0, f=0;
40 if (sscanf(bdf, "%x:%x:%x.%x", &d, &b, &s, &f) != 4)
41 return -1;
42 if (snprintf(sysfs_path, pathsz, "/sys/bus/pci/devices/%04x:%02x:%02x.%x", d, b, s, f) < 0)
43 return -1;
44 if (domain) *domain = (int)d;
45 if (bus) *bus = (int)b;
46 if (slot) *slot = (int)s;
47 return 0;
48}
49
50static int safe_realloc_devices(QuadraDevice **p_devs, int new_cap)
51{
52 QuadraDevice *new_devs = realloc(*p_devs, new_cap * sizeof(**p_devs));
53 if (!new_devs)
54 {
55 free(*p_devs);
56 *p_devs = NULL;
57 return -1;
58 }
59 *p_devs = new_devs;
60 return 0;
61}
62
63int quadra_device_find(QuadraDevice **out_devs)
64{
65 DIR *dir = opendir(PCI_SYSFS_PATH);
66 if (!dir)
67 {
68 perror("opendir(sysfs)");
69 return -1;
70 }
71
72 struct dirent *entry;
73 QuadraDevice *devs = calloc(8, sizeof(*devs));
74 int dev_count = 0, capacity = 8;
75 if (!devs)
76 {
77 closedir(dir);
78 return -1;
79 }
80
81 char path[PATH_MAX];
82 while ((entry = readdir(dir)))
83 {
84 if (entry->d_name[0] == '.')
85 continue;
86
87 if (snprintf(path, sizeof(path), "%s/%s", PCI_SYSFS_PATH, entry->d_name) < 0)
88 continue;
89
90 struct stat st;
91 if (stat(path, &st) < 0 || !S_ISDIR(st.st_mode))
92 continue;
93
94 char ven_path[PATH_MAX], dev_path[PATH_MAX];
95 if (snprintf(ven_path, sizeof(ven_path), "%s/vendor", path) < 0)
96 continue;
97 if (snprintf(dev_path, sizeof(dev_path), "%s/device", path) < 0)
98 continue;
99
100 FILE *fv = fopen(ven_path, "r");
101 if (!fv)
102 continue;
103
104 char buf[32];
105 if (!fgets(buf, sizeof(buf), fv))
106 {
107 fclose(fv);
108 continue;
109 }
110 fclose(fv);
111
112 unsigned long ven = strtoul(buf, NULL, 0);
113 if (ven != QUADRA_VENDOR_ID)
114 continue;
115
116 /* Read device */
117 FILE *fd = fopen(dev_path, "r");
118 if (!fd)
119 continue;
120
121 if (!fgets(buf, sizeof(buf), fd))
122 {
123 fclose(fd);
124 continue;
125 }
126 fclose(fd);
127
128 unsigned long dev = strtoul(buf, NULL, 0);
129 if (dev != QUADRA_DEVICE_ID)
130 continue;
131
132 if (dev_count >= capacity)
133 {
134 capacity *= 2;
135 if (safe_realloc_devices(&devs, capacity) < 0)
136 {
137 closedir(dir);
138 return -1;
139 }
140 }
141
142 if (bdf_to_sysfs(entry->d_name,
143 devs[dev_count].sysfs_path, sizeof(devs[dev_count].sysfs_path),
144 &devs[dev_count].domain, &devs[dev_count].bus, &devs[dev_count].slot) == 0)
145 {
146 dev_count++;
147 }
148 }
149
150 closedir(dir);
151
152 if (dev_count == 0)
153 {
154 free(devs);
155 return 0;
156 }
157
158 *out_devs = devs;
159 return dev_count;
160}
161
162int quadra_init_mmap(QuadraDevice *qd)
163{
164 char bar4path[PATH_MAX];
165 struct stat bar4stat;
166 if (snprintf(bar4path, sizeof(bar4path), "%s/resource4", qd->sysfs_path) < 0)
167 return -1;
168 if (geteuid() != 0)
169 {
170 (void)fprintf(stderr, "Permission error: You must run as root (sudo)\n");
171 return -1;
172 }
173 qd->bar4_fd = open(bar4path, O_RDWR | O_SYNC);
174 if (qd->bar4_fd == -1)
175 {
176 perror("open(bar4)");
177 return -1;
178 }
179 if (fstat(qd->bar4_fd, &bar4stat) == 0)
180 {
181 qd->barsize = bar4stat.st_size;
182 }
183 qd->bar4_base = mmap(NULL, qd->barsize, PROT_READ | PROT_WRITE, MAP_SHARED, qd->bar4_fd, 0);
184 if (qd->bar4_base == MAP_FAILED)
185 {
186 if (errno == EACCES)
187 (void)fprintf(stderr, "Permission error: Cannot mmap %s. Run as root (sudo).\n", bar4path);
188 else if (errno == EINVAL)
189 (void)fprintf(stderr, "EINVAL: mmap() on BAR4 failed. Try kernel flag 'iomem=relaxed'.\n");
190 else
191 (void)fprintf(stderr, "Failed to mmap BAR4 at %s: %s\n", bar4path, strerror(errno));
192 close(qd->bar4_fd);
193 qd->bar4_fd = -1;
194 return -1;
195 }
196 return 0;
197}
198
199void fill_core_log_offsets(QuadraDevice *qd)
200{
201 uint8_t *base = qd->bar4_base;
202 off_t offset = 0xf8f5000;
203 for (int i = 0; i < NUM_CORES; ++i)
204 {
205 qd->core_log_offsets[i] = *(uint32_t *)(base + offset + 4 * (size_t)i) & 0x0FFFFFFF;
206 }
207 qd->log_size = 1024 * 1024;
208}
209
210void fill_core_reset_log_offsets(QuadraDevice *qd)
211{
212 uint8_t *base = qd->bar4_base;
213 off_t offset = 0xf8fd0c0;
214 for (int i = 0; i < NUM_CORES; ++i)
215 {
216 qd->core_log_offsets[i] = *(uint32_t *)(base + offset + 4 * (size_t)i) & 0x0FFFFFFF;
217 }
218 qd->log_size = 64 * 1024;
219}
220
221int dump_raw_logs(QuadraDevice *qd, const char *outdir, bool core_reset_log)
222{
223 if (core_reset_log)
224 {
225 fill_core_reset_log_offsets(qd);
226 }
227 else
228 {
229 fill_core_log_offsets(qd);
230 }
231 int rc = 0;
232 for (int core_idx = 0; core_idx < NUM_CORES; ++core_idx)
233 {
234 const char *core = core_names[core_idx];
235 uint32_t log_offset = qd->core_log_offsets[core_idx];
236 char fname[PATH_MAX];
237 if (snprintf(fname, sizeof(fname), "%s/raw_%s_slot_%02x_%04x.bin",
238 outdir, core, qd->bus, qd->domain) < 0) continue;
239 FILE *fp = fopen(fname, "wb");
240 if (!fp)
241 {
242 perror("fopen");
243 rc = -1;
244 continue;
245 }
246 if (fwrite(qd->bar4_base + log_offset, 1, (size_t)qd->log_size, fp) != (size_t)qd->log_size)
247 {
248 (void)fprintf(stderr, "Short write on %s\n", fname);
249 rc = -1;
250 }
251 (void)fclose(fp);
252 chmod(fname, 0664);
253 if (memcmp(qd->bar4_base + log_offset, "hashid", 6) == 0)
254 {
255 char hstr[17] = {0};
256 memcpy(hstr, qd->bar4_base + log_offset, 16);
257 (void)fprintf(stderr, "%s: %s\n", core, hstr);
258 }
259 (void)fprintf(stderr, "[INFO] Dumped log: %s\n", fname);
260 }
261 return rc;
262}
263
264int ni_rsrc_log_dump(const char *outdir, bool core_reset_log)
265{
266 QuadraDevice *devs = NULL;
267 int ndev = quadra_device_find(&devs);
268 if (ndev <= 0)
269 {
270 free(devs);
271 (void)fprintf(stderr, "[WARN] No Quadra devices found in sysfs (vendor 1d82).\n");
272 return 1;
273 }
274 int fail_count = 0;
275 for (int i = 0; i < ndev; ++i)
276 {
277 if (quadra_init_mmap(&devs[i]) == 0)
278 {
279 int rc = dump_raw_logs(&devs[i], outdir ? outdir : ".", core_reset_log);
280 fail_count += (rc != 0);
281 }
282 else
283 {
284 (void)fprintf(stderr, "[ERROR] Failed to mmap device %d\n", i);
285 fail_count++;
286 }
287 }
288 free(devs);
289 return (fail_count == 0) ? 0 : 2;
290}
291#endif
#define QUADRA_VENDOR_ID
#define NUM_CORES
#define QUADRA_DEVICE_ID
#define PCI_SYSFS_PATH