jtag: drivers: xlnx-pcie-xvc: fix build on Linux pre v4.10
[openocd.git] / src / jtag / drivers / xlnx-pcie-xvc.c
1 /* SPDX-License-Identifier: GPL-2.0
2 *
3 * Copyright (c) 2019 Google, LLC.
4 * Author: Moritz Fischer <moritzf@google.com>
5 */
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include <stdint.h>
12 #include <stdlib.h>
13 #include <math.h>
14 #include <unistd.h>
15 #include <linux/pci.h>
16
17 #include <jtag/interface.h>
18 #include <jtag/swd.h>
19 #include <jtag/commands.h>
20 #include <helper/replacements.h>
21 #include <helper/bits.h>
22
23 /* Available only from kernel v4.10 */
24 #ifndef PCI_CFG_SPACE_EXP_SIZE
25 #define PCI_CFG_SPACE_EXP_SIZE 4096
26 #endif
27
28 #define PCIE_EXT_CAP_LST 0x100
29
30 #define XLNX_XVC_EXT_CAP 0x00
31 #define XLNX_XVC_VSEC_HDR 0x04
32 #define XLNX_XVC_LEN_REG 0x0C
33 #define XLNX_XVC_TMS_REG 0x10
34 #define XLNX_XVC_TDx_REG 0x14
35
36 #define XLNX_XVC_CAP_SIZE 0x20
37 #define XLNX_XVC_VSEC_ID 0x8
38 #define XLNX_XVC_MAX_BITS 0x20
39
40 struct xlnx_pcie_xvc {
41 int fd;
42 unsigned offset;
43 char *device;
44 };
45
46 static struct xlnx_pcie_xvc xlnx_pcie_xvc_state;
47 static struct xlnx_pcie_xvc *xlnx_pcie_xvc = &xlnx_pcie_xvc_state;
48
49 static int xlnx_pcie_xvc_read_reg(const int offset, uint32_t *val)
50 {
51 uint32_t res;
52 int err;
53
54 /* Note: This should be ok endianess-wise because by going
55 * through sysfs the kernel does the conversion in the config
56 * space accessor functions
57 */
58 err = pread(xlnx_pcie_xvc->fd, &res, sizeof(res),
59 xlnx_pcie_xvc->offset + offset);
60 if (err != sizeof(res)) {
61 LOG_ERROR("Failed to read offset %x", offset);
62 return ERROR_JTAG_DEVICE_ERROR;
63 }
64
65 if (val)
66 *val = res;
67
68 return ERROR_OK;
69 }
70
71 static int xlnx_pcie_xvc_write_reg(const int offset, const uint32_t val)
72 {
73 int err;
74
75 /* Note: This should be ok endianess-wise because by going
76 * through sysfs the kernel does the conversion in the config
77 * space accessor functions
78 */
79 err = pwrite(xlnx_pcie_xvc->fd, &val, sizeof(val),
80 xlnx_pcie_xvc->offset + offset);
81 if (err != sizeof(val)) {
82 LOG_ERROR("Failed to write offset: %x with value: %x",
83 offset, val);
84 return ERROR_JTAG_DEVICE_ERROR;
85 }
86
87 return ERROR_OK;
88 }
89
90 static int xlnx_pcie_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi,
91 uint32_t *tdo)
92 {
93 int err;
94
95 err = xlnx_pcie_xvc_write_reg(XLNX_XVC_LEN_REG, num_bits);
96 if (err != ERROR_OK)
97 return err;
98
99 err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TMS_REG, tms);
100 if (err != ERROR_OK)
101 return err;
102
103 err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TDx_REG, tdi);
104 if (err != ERROR_OK)
105 return err;
106
107 err = xlnx_pcie_xvc_read_reg(XLNX_XVC_TDx_REG, tdo);
108 if (err != ERROR_OK)
109 return err;
110
111 if (tdo)
112 LOG_DEBUG_IO("Transact num_bits: %zu, tms: %x, tdi: %x, tdo: %x",
113 num_bits, tms, tdi, *tdo);
114 else
115 LOG_DEBUG_IO("Transact num_bits: %zu, tms: %x, tdi: %x, tdo: <null>",
116 num_bits, tms, tdi);
117 return ERROR_OK;
118 }
119
120 int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd)
121 {
122 int tms = tap_get_state() == TAP_RESET ? 1 : 0;
123 size_t left = cmd->cmd.stableclocks->num_cycles;
124 size_t write;
125 int err;
126
127 LOG_DEBUG("stableclocks %i cycles", cmd->cmd.runtest->num_cycles);
128
129 while (left) {
130 write = MIN(XLNX_XVC_MAX_BITS, left);
131 err = xlnx_pcie_xvc_transact(write, tms, 0, NULL);
132 if (err != ERROR_OK)
133 return err;
134 left -= write;
135 };
136
137 return ERROR_OK;
138 }
139
140 static int xlnx_pcie_xvc_execute_statemove(size_t skip)
141 {
142 uint8_t tms_scan = tap_get_tms_path(tap_get_state(),
143 tap_get_end_state());
144 int tms_count = tap_get_tms_path_len(tap_get_state(),
145 tap_get_end_state());
146 int err;
147
148 LOG_DEBUG("statemove starting at (skip: %zu) %s end in %s", skip,
149 tap_state_name(tap_get_state()),
150 tap_state_name(tap_get_end_state()));
151
152
153 err = xlnx_pcie_xvc_transact(tms_count - skip, tms_scan >> skip, 0, NULL);
154 if (err != ERROR_OK)
155 return err;
156
157 tap_set_state(tap_get_end_state());
158
159 return ERROR_OK;
160 }
161
162 static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd)
163 {
164 int err = ERROR_OK;
165
166 LOG_DEBUG("runtest %i cycles, end in %i",
167 cmd->cmd.runtest->num_cycles,
168 cmd->cmd.runtest->end_state);
169
170 tap_state_t tmp_state = tap_get_end_state();
171
172 if (tap_get_state() != TAP_IDLE) {
173 tap_set_end_state(TAP_IDLE);
174 err = xlnx_pcie_xvc_execute_statemove(0);
175 if (err != ERROR_OK)
176 return err;
177 };
178
179 size_t left = cmd->cmd.runtest->num_cycles;
180 size_t write;
181
182 while (left) {
183 write = MIN(XLNX_XVC_MAX_BITS, left);
184 err = xlnx_pcie_xvc_transact(write, 0, 0, NULL);
185 if (err != ERROR_OK)
186 return err;
187 left -= write;
188 };
189
190 tap_set_end_state(tmp_state);
191 if (tap_get_state() != tap_get_end_state())
192 err = xlnx_pcie_xvc_execute_statemove(0);
193
194 return err;
195 }
196
197 static int xlnx_pcie_xvc_execute_pathmove(struct jtag_command *cmd)
198 {
199 size_t num_states = cmd->cmd.pathmove->num_states;
200 tap_state_t *path = cmd->cmd.pathmove->path;
201 int err = ERROR_OK;
202 size_t i;
203
204 LOG_DEBUG("pathmove: %i states, end in %i",
205 cmd->cmd.pathmove->num_states,
206 cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
207
208 for (i = 0; i < num_states; i++) {
209 if (path[i] == tap_state_transition(tap_get_state(), false)) {
210 err = xlnx_pcie_xvc_transact(1, 1, 0, NULL);
211 } else if (path[i] == tap_state_transition(tap_get_state(), true)) {
212 err = xlnx_pcie_xvc_transact(1, 0, 0, NULL);
213 } else {
214 LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.",
215 tap_state_name(tap_get_state()),
216 tap_state_name(path[i]));
217 err = ERROR_JTAG_QUEUE_FAILED;
218 }
219 if (err != ERROR_OK)
220 return err;
221 tap_set_state(path[i]);
222 }
223
224 tap_set_end_state(tap_get_state());
225
226 return ERROR_OK;
227 }
228
229 static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd)
230 {
231 enum scan_type type = jtag_scan_type(cmd->cmd.scan);
232 tap_state_t saved_end_state = cmd->cmd.scan->end_state;
233 bool ir_scan = cmd->cmd.scan->ir_scan;
234 uint32_t tdi, tms, tdo;
235 uint8_t *buf, *rd_ptr;
236 int err, scan_size;
237 size_t write;
238 size_t left;
239
240 scan_size = jtag_build_buffer(cmd->cmd.scan, &buf);
241 rd_ptr = buf;
242 LOG_DEBUG("%s scan type %d %d bits; starts in %s end in %s",
243 (cmd->cmd.scan->ir_scan) ? "IR" : "DR", type, scan_size,
244 tap_state_name(tap_get_state()),
245 tap_state_name(cmd->cmd.scan->end_state));
246
247 /* If we're in TAP_DR_SHIFT state but need to do a IR_SCAN or
248 * vice-versa, do a statemove to corresponding other state, then restore
249 * end state
250 */
251 if (ir_scan && tap_get_state() != TAP_IRSHIFT) {
252 tap_set_end_state(TAP_IRSHIFT);
253 err = xlnx_pcie_xvc_execute_statemove(0);
254 if (err != ERROR_OK)
255 goto out_err;
256 tap_set_end_state(saved_end_state);
257 } else if (!ir_scan && (tap_get_state() != TAP_DRSHIFT)) {
258 tap_set_end_state(TAP_DRSHIFT);
259 err = xlnx_pcie_xvc_execute_statemove(0);
260 if (err != ERROR_OK)
261 goto out_err;
262 tap_set_end_state(saved_end_state);
263 }
264
265 left = scan_size;
266 while (left) {
267 write = MIN(XLNX_XVC_MAX_BITS, left);
268 /* the last TMS should be a 1, to leave the state */
269 tms = left <= XLNX_XVC_MAX_BITS ? BIT(write - 1) : 0;
270 tdi = (type != SCAN_IN) ? buf_get_u32(rd_ptr, 0, write) : 0;
271 err = xlnx_pcie_xvc_transact(write, tms, tdi, type != SCAN_OUT ?
272 &tdo : NULL);
273 if (err != ERROR_OK)
274 goto out_err;
275 left -= write;
276 if (type != SCAN_OUT)
277 buf_set_u32(rd_ptr, 0, write, tdo);
278 rd_ptr += sizeof(uint32_t);
279 };
280
281 err = jtag_read_buffer(buf, cmd->cmd.scan);
282 if (buf)
283 free(buf);
284
285 if (tap_get_state() != tap_get_end_state())
286 err = xlnx_pcie_xvc_execute_statemove(1);
287
288 return err;
289
290 out_err:
291 if (buf)
292 free(buf);
293 return err;
294 }
295
296 static void xlnx_pcie_xvc_execute_reset(struct jtag_command *cmd)
297 {
298 LOG_DEBUG("reset trst: %i srst: %i", cmd->cmd.reset->trst,
299 cmd->cmd.reset->srst);
300 }
301
302 static void xlnx_pcie_xvc_execute_sleep(struct jtag_command *cmd)
303 {
304 LOG_DEBUG("sleep %" PRIi32 "", cmd->cmd.sleep->us);
305 usleep(cmd->cmd.sleep->us);
306 }
307
308 static int xlnx_pcie_xvc_execute_tms(struct jtag_command *cmd)
309 {
310 const size_t num_bits = cmd->cmd.tms->num_bits;
311 const uint8_t *bits = cmd->cmd.tms->bits;
312 size_t left, write;
313 uint32_t tms;
314 int err;
315
316 LOG_DEBUG("execute tms %zu", num_bits);
317
318 left = num_bits;
319 while (left) {
320 write = MIN(XLNX_XVC_MAX_BITS, left);
321 tms = buf_get_u32(bits, 0, write);
322 err = xlnx_pcie_xvc_transact(write, tms, 0, NULL);
323 if (err != ERROR_OK)
324 return err;
325 left -= write;
326 bits += 4;
327 };
328
329 return ERROR_OK;
330 }
331
332 static int xlnx_pcie_xvc_execute_command(struct jtag_command *cmd)
333 {
334 LOG_DEBUG("%s: cmd->type: %u", __func__, cmd->type);
335 switch (cmd->type) {
336 case JTAG_STABLECLOCKS:
337 return xlnx_pcie_xvc_execute_stableclocks(cmd);
338 case JTAG_RUNTEST:
339 return xlnx_pcie_xvc_execute_runtest(cmd);
340 case JTAG_TLR_RESET:
341 tap_set_end_state(cmd->cmd.statemove->end_state);
342 return xlnx_pcie_xvc_execute_statemove(0);
343 case JTAG_PATHMOVE:
344 return xlnx_pcie_xvc_execute_pathmove(cmd);
345 case JTAG_SCAN:
346 return xlnx_pcie_xvc_execute_scan(cmd);
347 case JTAG_RESET:
348 xlnx_pcie_xvc_execute_reset(cmd);
349 break;
350 case JTAG_SLEEP:
351 xlnx_pcie_xvc_execute_sleep(cmd);
352 break;
353 case JTAG_TMS:
354 return xlnx_pcie_xvc_execute_tms(cmd);
355 default:
356 LOG_ERROR("BUG: Unknown JTAG command type encountered.");
357 return ERROR_JTAG_QUEUE_FAILED;
358 }
359
360 return ERROR_OK;
361 }
362
363 static int xlnx_pcie_xvc_execute_queue(void)
364 {
365 struct jtag_command *cmd = jtag_command_queue;
366 int ret;
367
368 while (cmd) {
369 ret = xlnx_pcie_xvc_execute_command(cmd);
370
371 if (ret != ERROR_OK)
372 return ret;
373
374 cmd = cmd->next;
375 }
376
377 return ERROR_OK;
378 }
379
380
381 static int xlnx_pcie_xvc_init(void)
382 {
383 char filename[PATH_MAX];
384 uint32_t cap, vh;
385 int err;
386
387 snprintf(filename, PATH_MAX, "/sys/bus/pci/devices/%s/config",
388 xlnx_pcie_xvc->device);
389 xlnx_pcie_xvc->fd = open(filename, O_RDWR | O_SYNC);
390 if (xlnx_pcie_xvc->fd < 0) {
391 LOG_ERROR("Failed to open device: %s", filename);
392 return ERROR_JTAG_INIT_FAILED;
393 }
394
395 LOG_INFO("Scanning PCIe device %s's for Xilinx XVC/PCIe ...",
396 xlnx_pcie_xvc->device);
397 /* Parse the PCIe extended capability list and try to find
398 * vendor specific header */
399 xlnx_pcie_xvc->offset = PCIE_EXT_CAP_LST;
400 while (xlnx_pcie_xvc->offset <= PCI_CFG_SPACE_EXP_SIZE - sizeof(cap) &&
401 xlnx_pcie_xvc->offset >= PCIE_EXT_CAP_LST) {
402 err = xlnx_pcie_xvc_read_reg(XLNX_XVC_EXT_CAP, &cap);
403 if (err != ERROR_OK)
404 return err;
405 LOG_DEBUG("Checking capability at 0x%x; id=0x%04x version=0x%x next=0x%x",
406 xlnx_pcie_xvc->offset,
407 PCI_EXT_CAP_ID(cap),
408 PCI_EXT_CAP_VER(cap),
409 PCI_EXT_CAP_NEXT(cap));
410 if (PCI_EXT_CAP_ID(cap) == PCI_EXT_CAP_ID_VNDR) {
411 err = xlnx_pcie_xvc_read_reg(XLNX_XVC_VSEC_HDR, &vh);
412 if (err != ERROR_OK)
413 return err;
414 LOG_DEBUG("Checking possible match at 0x%x; id: 0x%x; rev: 0x%x; length: 0x%x",
415 xlnx_pcie_xvc->offset,
416 PCI_VNDR_HEADER_ID(vh),
417 PCI_VNDR_HEADER_REV(vh),
418 PCI_VNDR_HEADER_LEN(vh));
419 if ((PCI_VNDR_HEADER_ID(vh) == XLNX_XVC_VSEC_ID) &&
420 (PCI_VNDR_HEADER_LEN(vh) == XLNX_XVC_CAP_SIZE))
421 break;
422 }
423 xlnx_pcie_xvc->offset = PCI_EXT_CAP_NEXT(cap);
424 }
425 if ((xlnx_pcie_xvc->offset > PCI_CFG_SPACE_EXP_SIZE - XLNX_XVC_CAP_SIZE) ||
426 xlnx_pcie_xvc->offset < PCIE_EXT_CAP_LST) {
427 close(xlnx_pcie_xvc->fd);
428 return ERROR_JTAG_INIT_FAILED;
429 }
430
431 LOG_INFO("Found Xilinx XVC/PCIe capability at offset: 0x%x", xlnx_pcie_xvc->offset);
432
433 return ERROR_OK;
434 }
435
436 static int xlnx_pcie_xvc_quit(void)
437 {
438 int err;
439
440 err = close(xlnx_pcie_xvc->fd);
441 if (err)
442 return err;
443
444 return ERROR_OK;
445 }
446
447 COMMAND_HANDLER(xlnx_pcie_xvc_handle_config_command)
448 {
449 if (CMD_ARGC < 1)
450 return ERROR_COMMAND_SYNTAX_ERROR;
451
452 /* we can't really free this in a safe manner, so at least
453 * limit the memory we're leaking by freeing the old one first
454 * before allocating a new one ...
455 */
456 if (xlnx_pcie_xvc->device)
457 free(xlnx_pcie_xvc->device);
458
459 xlnx_pcie_xvc->device = strdup(CMD_ARGV[0]);
460 return ERROR_OK;
461 }
462
463 static const struct command_registration xlnx_pcie_xvc_command_handlers[] = {
464 {
465 .name = "xlnx_pcie_xvc_config",
466 .handler = xlnx_pcie_xvc_handle_config_command,
467 .mode = COMMAND_CONFIG,
468 .help = "Configure XVC/PCIe JTAG adapter",
469 .usage = "device",
470 },
471 COMMAND_REGISTRATION_DONE
472 };
473
474 static struct jtag_interface xlnx_pcie_xvc_interface = {
475 .execute_queue = &xlnx_pcie_xvc_execute_queue,
476 };
477
478 struct adapter_driver xlnx_pcie_xvc_adapter_driver = {
479 .name = "xlnx_pcie_xvc",
480 .transports = jtag_only,
481 .commands = xlnx_pcie_xvc_command_handlers,
482
483 .init = &xlnx_pcie_xvc_init,
484 .quit = &xlnx_pcie_xvc_quit,
485
486 .jtag_ops = &xlnx_pcie_xvc_interface,
487 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)