Switchtec Userspace PROJECT_NUMBER = 3.1
switchtec.c
Go to the documentation of this file.
1/*
2 * Microsemi Switchtec(tm) PCIe Management Library
3 * Copyright (c) 2017, Microsemi Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24
30#define SWITCHTEC_LIB_CORE
31
32#include "switchtec_priv.h"
33
34#include "switchtec/switchtec.h"
35#include "switchtec/mrpc.h"
36#include "switchtec/errors.h"
37#include "switchtec/log.h"
38#include "switchtec/endian.h"
39#include "switchtec/utils.h"
40
41#include <string.h>
42#include <unistd.h>
43#include <errno.h>
44#include <time.h>
45
64 char *mod_name;
65 char **entries;
67};
68
72struct log_defs {
75};
76
81 unsigned short device_id;
82 enum switchtec_gen gen;
83 enum switchtec_variant var;
84};
85
90 {0x8531, SWITCHTEC_GEN3, SWITCHTEC_PFX}, //PFX 24xG3
91 {0x8532, SWITCHTEC_GEN3, SWITCHTEC_PFX}, //PFX 32xG3
92 {0x8533, SWITCHTEC_GEN3, SWITCHTEC_PFX}, //PFX 48xG3
93 {0x8534, SWITCHTEC_GEN3, SWITCHTEC_PFX}, //PFX 64xG3
94 {0x8535, SWITCHTEC_GEN3, SWITCHTEC_PFX}, //PFX 80xG3
95 {0x8536, SWITCHTEC_GEN3, SWITCHTEC_PFX}, //PFX 96xG3
96 {0x8541, SWITCHTEC_GEN3, SWITCHTEC_PSX}, //PSX 24xG3
97 {0x8542, SWITCHTEC_GEN3, SWITCHTEC_PSX}, //PSX 32xG3
98 {0x8543, SWITCHTEC_GEN3, SWITCHTEC_PSX}, //PSX 48xG3
99 {0x8544, SWITCHTEC_GEN3, SWITCHTEC_PSX}, //PSX 64xG3
100 {0x8545, SWITCHTEC_GEN3, SWITCHTEC_PSX}, //PSX 80xG3
101 {0x8546, SWITCHTEC_GEN3, SWITCHTEC_PSX}, //PSX 96xG3
102 {0x8551, SWITCHTEC_GEN3, SWITCHTEC_PAX}, //PAX 24XG3
103 {0x8552, SWITCHTEC_GEN3, SWITCHTEC_PAX}, //PAX 32XG3
104 {0x8553, SWITCHTEC_GEN3, SWITCHTEC_PAX}, //PAX 48XG3
105 {0x8554, SWITCHTEC_GEN3, SWITCHTEC_PAX}, //PAX 64XG3
106 {0x8555, SWITCHTEC_GEN3, SWITCHTEC_PAX}, //PAX 80XG3
107 {0x8556, SWITCHTEC_GEN3, SWITCHTEC_PAX}, //PAX 96XG3
108 {0x8561, SWITCHTEC_GEN3, SWITCHTEC_PFXL}, //PFXL 24XG3
109 {0x8562, SWITCHTEC_GEN3, SWITCHTEC_PFXL}, //PFXL 32XG3
110 {0x8563, SWITCHTEC_GEN3, SWITCHTEC_PFXL}, //PFXL 48XG3
111 {0x8564, SWITCHTEC_GEN3, SWITCHTEC_PFXL}, //PFXL 64XG3
112 {0x8565, SWITCHTEC_GEN3, SWITCHTEC_PFXL}, //PFXL 80XG3
113 {0x8566, SWITCHTEC_GEN3, SWITCHTEC_PFXL}, //PFXL 96XG3
114 {0x8571, SWITCHTEC_GEN3, SWITCHTEC_PFXI}, //PFXI 24XG3
115 {0x8572, SWITCHTEC_GEN3, SWITCHTEC_PFXI}, //PFXI 32XG3
116 {0x8573, SWITCHTEC_GEN3, SWITCHTEC_PFXI}, //PFXI 48XG3
117 {0x8574, SWITCHTEC_GEN3, SWITCHTEC_PFXI}, //PFXI 64XG3
118 {0x8575, SWITCHTEC_GEN3, SWITCHTEC_PFXI}, //PFXI 80XG3
119 {0x8576, SWITCHTEC_GEN3, SWITCHTEC_PFXI}, //PFXI 96XG3
120 {0x4000, SWITCHTEC_GEN4, SWITCHTEC_PFX}, //PFX 100XG4
121 {0x4084, SWITCHTEC_GEN4, SWITCHTEC_PFX}, //PFX 84XG4
122 {0x4068, SWITCHTEC_GEN4, SWITCHTEC_PFX}, //PFX 68XG4
123 {0x4052, SWITCHTEC_GEN4, SWITCHTEC_PFX}, //PFX 52XG4
124 {0x4036, SWITCHTEC_GEN4, SWITCHTEC_PFX}, //PFX 36XG4
125 {0x4028, SWITCHTEC_GEN4, SWITCHTEC_PFX}, //PFX 28XG4
126 {0x4100, SWITCHTEC_GEN4, SWITCHTEC_PSX}, //PSX 100XG4
127 {0x4184, SWITCHTEC_GEN4, SWITCHTEC_PSX}, //PSX 84XG4
128 {0x4168, SWITCHTEC_GEN4, SWITCHTEC_PSX}, //PSX 68XG4
129 {0x4152, SWITCHTEC_GEN4, SWITCHTEC_PSX}, //PSX 52XG4
130 {0x4136, SWITCHTEC_GEN4, SWITCHTEC_PSX}, //PSX 36XG4
131 {0x4128, SWITCHTEC_GEN4, SWITCHTEC_PSX}, //PSX 28XG4
132 {0x4200, SWITCHTEC_GEN4, SWITCHTEC_PAX}, //PAX 100XG4
133 {0x4284, SWITCHTEC_GEN4, SWITCHTEC_PAX}, //PAX 84XG4
134 {0x4268, SWITCHTEC_GEN4, SWITCHTEC_PAX}, //PAX 68XG4
135 {0x4252, SWITCHTEC_GEN4, SWITCHTEC_PAX}, //PAX 52XG4
136 {0x4236, SWITCHTEC_GEN4, SWITCHTEC_PAX}, //PAX 36XG4
137 {0x4352, SWITCHTEC_GEN4, SWITCHTEC_PFXA}, //PFXA 52XG4
138 {0x4336, SWITCHTEC_GEN4, SWITCHTEC_PFXA}, //PFXA 36XG4
139 {0x4328, SWITCHTEC_GEN4, SWITCHTEC_PFXA}, //PFXA 28XG4
140 {0x4452, SWITCHTEC_GEN4, SWITCHTEC_PSXA}, //PSXA 52XG4
141 {0x4436, SWITCHTEC_GEN4, SWITCHTEC_PSXA}, //PSXA 36XG4
142 {0x4428, SWITCHTEC_GEN4, SWITCHTEC_PSXA}, //PSXA 28XG4
143 {0x4552, SWITCHTEC_GEN4, SWITCHTEC_PAXA}, //PAXA 52XG4
144 {0x4536, SWITCHTEC_GEN4, SWITCHTEC_PAXA}, //PAXA 36XG4
145 {0x4528, SWITCHTEC_GEN4, SWITCHTEC_PAXA}, //PAXA 28XG4
146 {0x4228, SWITCHTEC_GEN4, SWITCHTEC_PAX}, //PAX 28XG4
147 {0x5000, SWITCHTEC_GEN5, SWITCHTEC_PFX}, //PFX 100XG5
148 {0x5084, SWITCHTEC_GEN5, SWITCHTEC_PFX}, //PFX 84XG5
149 {0x5068, SWITCHTEC_GEN5, SWITCHTEC_PFX}, //PFX 68XG5
150 {0x5052, SWITCHTEC_GEN5, SWITCHTEC_PFX}, //PFX 52XG5
151 {0x5036, SWITCHTEC_GEN5, SWITCHTEC_PFX}, //PFX 36XG5
152 {0x5028, SWITCHTEC_GEN5, SWITCHTEC_PFX}, //PFX 28XG5
153 {0x5100, SWITCHTEC_GEN5, SWITCHTEC_PSX}, //PSX 100XG5
154 {0x5184, SWITCHTEC_GEN5, SWITCHTEC_PSX}, //PSX 84XG5
155 {0x5168, SWITCHTEC_GEN5, SWITCHTEC_PSX}, //PSX 68XG5
156 {0x5152, SWITCHTEC_GEN5, SWITCHTEC_PSX}, //PSX 52XG5
157 {0x5136, SWITCHTEC_GEN5, SWITCHTEC_PSX}, //PSX 36XG5
158 {0x5128, SWITCHTEC_GEN5, SWITCHTEC_PSX}, //PSX 28XG5
159 {0x5200, SWITCHTEC_GEN5, SWITCHTEC_PAX}, //PAX 100XG5
160 {0x5284, SWITCHTEC_GEN5, SWITCHTEC_PAX}, //PAX 84XG5
161 {0x5268, SWITCHTEC_GEN5, SWITCHTEC_PAX}, //PAX 68XG5
162 {0x5252, SWITCHTEC_GEN5, SWITCHTEC_PAX}, //PAX 52XG5
163 {0x5236, SWITCHTEC_GEN5, SWITCHTEC_PAX}, //PAX 36XG5
164 {0x5228, SWITCHTEC_GEN5, SWITCHTEC_PAX}, //PAX 28XG5
165 {0x5300, SWITCHTEC_GEN5, SWITCHTEC_PAXA}, //PAX-A 100XG5
166 {0x5384, SWITCHTEC_GEN5, SWITCHTEC_PAXA}, //PAX-A 84XG5
167 {0x5368, SWITCHTEC_GEN5, SWITCHTEC_PAXA}, //PAX-A 68XG5
168 {0x5352, SWITCHTEC_GEN5, SWITCHTEC_PAXA}, //PAX-A 52XG5
169 {0x5336, SWITCHTEC_GEN5, SWITCHTEC_PAXA}, //PAX-A 36XG5
170 {0x5328, SWITCHTEC_GEN5, SWITCHTEC_PAXA}, //PAX-A 28XG5
171 {0x5400, SWITCHTEC_GEN5, SWITCHTEC_PFXA}, //PFX-A 100XG5
172 {0x5484, SWITCHTEC_GEN5, SWITCHTEC_PFXA}, //PFX-A 84XG5
173 {0x5468, SWITCHTEC_GEN5, SWITCHTEC_PFXA}, //PFX-A 68XG5
174 {0x5452, SWITCHTEC_GEN5, SWITCHTEC_PFXA}, //PFX-A 52XG5
175 {0x5436, SWITCHTEC_GEN5, SWITCHTEC_PFXA}, //PFX-A 36XG5
176 {0x5428, SWITCHTEC_GEN5, SWITCHTEC_PFXA}, //PFX-A 28XG5
177 {0},
178};
179
180static int set_gen_variant(struct switchtec_dev * dev)
181{
183 int ret;
184
185 dev->boot_phase = SWITCHTEC_BOOT_PHASE_FW;
186 dev->gen = SWITCHTEC_GEN_UNKNOWN;
187 dev->var = SWITCHTEC_VAR_UNKNOWN;
188 dev->device_id = dev->ops->get_device_id(dev);
189
190 while (id->device_id) {
191 if (id->device_id == dev->device_id) {
192 dev->gen = id->gen;
193 dev->var = id->var;
194
195 return 0;
196 }
197
198 id++;
199 }
200
201 ret = switchtec_get_device_info(dev, &dev->boot_phase, &dev->gen, NULL);
202 if (ret)
203 return -1;
204
205 return 0;
206}
207
208static int set_local_pax_id(struct switchtec_dev *dev)
209{
210 unsigned char local_pax_id;
211 int ret;
212
213 dev->local_pax_id = -1;
214
215 if (!switchtec_is_pax_all(dev))
216 return 0;
217
218 ret = switchtec_cmd(dev, MRPC_GET_PAX_ID, NULL, 0,
219 &local_pax_id, sizeof(local_pax_id));
220 if (ret)
221 return -1;
222
223 dev->local_pax_id = local_pax_id;
224 return 0;
225}
226
232{
233 free(devlist);
234}
235
253struct switchtec_dev *switchtec_open(const char *device)
254{
255 int idx;
256 int domain = 0;
257 int bus, dev, func;
258 char path[PATH_MAX];
259 int inst;
260 char *endptr;
261 struct switchtec_dev *ret;
262
263 if (sscanf(device, "%i@%i", &bus, &dev) == 2) {
264 ret = switchtec_open_i2c_by_adapter(bus, dev);
265 goto found;
266 }
267
268 if (sscanf(device, "%2049[^@]@%i", path, &dev) == 2) {
269 ret = switchtec_open_i2c(path, dev);
270 goto found;
271 }
272
273 if (device[0] == '/' &&
274 sscanf(device, "%2049[^:]:%i", path, &dev) == 2) {
275 ret = switchtec_open_i2c(path, dev);
276 goto found;
277 }
278
279 if (strchr(device, '/') || strchr(device, '\\')) {
280 ret = switchtec_open_by_path(device);
281 goto found;
282 }
283
284 if (sscanf(device, "%x:%x.%x", &bus, &dev, &func) == 3) {
285 ret = switchtec_open_by_pci_addr(domain, bus, dev, func);
286 goto found;
287 }
288
289 if (sscanf(device, "%x:%x:%x.%x", &domain, &bus, &dev, &func) == 4) {
290 ret = switchtec_open_by_pci_addr(domain, bus, dev, func);
291 goto found;
292 }
293
294 if (sscanf(device, "%2049[^:]:%i", path, &inst) == 2) {
295 ret = switchtec_open_eth(path, inst);
296 goto found;
297 }
298
299 errno = 0;
300 idx = strtol(device, &endptr, 0);
301 if (!errno && endptr != device) {
302 ret = switchtec_open_by_index(idx);
303 goto found;
304 }
305
306 if (sscanf(device, "switchtec%d", &idx) == 1) {
307 ret = switchtec_open_by_index(idx);
308 goto found;
309 }
310
311 errno = ENODEV;
312 return NULL;
313
314found:
315 if (!ret) {
316 errno = ENODEV;
317 return NULL;
318 }
319
320 snprintf(ret->name, sizeof(ret->name), "%s", device);
321
322 if (set_gen_variant(ret))
323 return NULL;
324
325 if (set_local_pax_id(ret))
326 return NULL;
327
328 return ret;
329}
330
338_PURE int switchtec_device_id(struct switchtec_dev *dev)
339{
340 return dev->device_id;
341}
342
350_PURE enum switchtec_gen switchtec_gen(struct switchtec_dev *dev)
351{
352 return dev->gen;
353}
354
362_PURE enum switchtec_variant switchtec_variant(struct switchtec_dev *dev)
363{
364 return dev->var;
365}
366
374_PURE enum switchtec_boot_phase switchtec_boot_phase(struct switchtec_dev *dev)
375{
376 return dev->boot_phase;
377}
378
386_PURE const char *switchtec_name(struct switchtec_dev *dev)
387{
388 return dev->name;
389}
390
396_PURE int switchtec_partition(struct switchtec_dev *dev)
397{
398 return dev->partition;
399}
400
401int switchtec_set_pax_id(struct switchtec_dev *dev, int pax_id)
402{
403 if (!switchtec_is_pax_all(dev) && (pax_id != SWITCHTEC_PAX_ID_LOCAL))
404 return -1;
405
406 if (pax_id == SWITCHTEC_PAX_ID_LOCAL)
407 dev->pax_id = dev->local_pax_id;
408 else
409 dev->pax_id = pax_id;
410
411 return 0;
412}
413
414static int compare_port_id(const void *aa, const void *bb)
415{
416 const struct switchtec_port_id *a = aa, *b = bb;
417
418 if (a->partition != b->partition)
419 return a->partition - b->partition;
420 if (a->upstream != b->upstream)
421 return b->upstream - a->upstream;
422 return a->log_id - b->log_id;
423}
424
425static int compare_status(const void *aa, const void *bb)
426{
427 const struct switchtec_status *a = aa, *b = bb;
428
429 return compare_port_id(&a->port, &b->port);
430}
431
432static const char *lane_reversal_str(int link_up,
433 int lane_reversal)
434{
435 if (!link_up)
436 return "N/A";
437
438 switch(lane_reversal) {
439 case 0: return "Normal Lane Ordering";
440 case 1: return "x16 (Full) Lane Reversal";
441 case 2: return "x2 Lane Reversal";
442 case 4: return "x4 Lane Reversal";
443 case 8: return "x8 Lane Reversal";
444 default: return "Unknown Lane Ordering";
445 }
446}
447
448static void generate_lane_str(struct switchtec_status *s)
449{
450 int i, l;
451
452 for (i = 0; i < s->cfg_lnk_width; i++)
453 s->lanes[i] = 'x';
454
455 if (!s->link_up)
456 return;
457
458 l = s->first_act_lane;
459 if (!l && s->lane_reversal)
460 l += s->neg_lnk_width - 1;
461
462 for (i = 0; i < s->neg_lnk_width; i++) {
463 if (l < 0)
464 break;
465
466 if (i < 10)
467 s->lanes[l] = '0' + i;
468 else
469 s->lanes[l] = 'a' + i - 10;
470
471 l += s->lane_reversal ? -1 : 1;
472 }
473}
474
486int switchtec_status(struct switchtec_dev *dev,
487 struct switchtec_status **status)
488{
489 uint64_t port_bitmap = 0;
490 int ret;
491 int i, p;
492 int nr_ports = 0;
493 struct switchtec_status *s;
494 int max_ports;
495
496 if (!status) {
497 errno = EINVAL;
498 return -errno;
499 }
500
501 max_ports = switchtec_max_supported_ports(dev);
502
503 struct {
504 uint8_t phys_port_id;
505 uint8_t par_id;
506 uint8_t log_port_id;
507 uint8_t stk_id;
508 uint8_t cfg_lnk_width;
509 uint8_t neg_lnk_width;
510 uint8_t usp_flag;
511 uint8_t linkup_linkrate;
512 uint16_t LTSSM;
513 uint8_t lane_reversal;
514 uint8_t first_act_lane;
515 } ports[max_ports];
516
517 ret = switchtec_cmd(dev, MRPC_LNKSTAT, &port_bitmap, sizeof(port_bitmap),
518 ports, sizeof(ports));
519 if (ret)
520 return ret;
521
522
523 for (i = 0; i < max_ports; i++) {
524 if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS)
525 continue;
526 nr_ports++;
527 }
528
529 s = *status = calloc(nr_ports, sizeof(*s));
530 if (!s)
531 return -ENOMEM;
532
533 for (i = 0, p = 0; i < max_ports && p < nr_ports; i++) {
534 if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS)
535 continue;
536
537 s[p].port.partition = ports[i].par_id;
538 s[p].port.stack = ports[i].stk_id >> 4;
539 s[p].port.upstream = ports[i].usp_flag;
540 s[p].port.stk_id = ports[i].stk_id & 0xF;
541 s[p].port.phys_id = ports[i].phys_port_id;
542 s[p].port.log_id = ports[i].log_port_id;
543
544 s[p].cfg_lnk_width = ports[i].cfg_lnk_width;
545 s[p].neg_lnk_width = ports[i].neg_lnk_width;
546 s[p].link_up = ports[i].linkup_linkrate >> 7;
547 s[p].link_rate = ports[i].linkup_linkrate & 0x7F;
548 s[p].ltssm = le16toh(ports[i].LTSSM);
549 s[p].ltssm_str = switchtec_ltssm_str(s[p].ltssm, 1);
550 s[p].lane_reversal = ports[i].lane_reversal;
551 s[p].lane_reversal_str = lane_reversal_str(s[p].link_up,
552 s[p].lane_reversal);
553 s[p].first_act_lane = ports[i].first_act_lane & 0xF;
554 s[p].acs_ctrl = -1;
555 generate_lane_str(&s[p]);
556
557 p++;
558 }
559
560 qsort(s, nr_ports, sizeof(*s), compare_status);
561
562 return nr_ports;
563}
564
571void switchtec_status_free(struct switchtec_status *status, int ports)
572{
573 int i;
574
575 for (i = 0; i < ports; i++) {
576 if (status[i].pci_bdf)
577 free(status[i].pci_bdf);
578
579 if (status[i].pci_bdf_path)
580 free(status[i].pci_bdf_path);
581
582 if (status[i].pci_dev)
583 free(status[i].pci_dev);
584
585 if (status[i].class_devices)
586 free(status[i].class_devices);
587 }
588
589 free(status);
590}
591
599
610const char *switchtec_strerror(void)
611{
612 const char *msg = "Unknown MRPC error";
613 int err;
614
615 if ((errno & (SWITCHTEC_ERRNO_MRPC_FLAG_BIT |
616 SWITCHTEC_ERRNO_GENERAL_FLAG_BIT)) == 0) {
617 if (errno)
618 return strerror(errno);
619 else
620 return platform_strerror();
621 }
622
623 if (errno & SWITCHTEC_ERRNO_GENERAL_FLAG_BIT) {
624 switch (errno) {
625 case SWITCHTEC_ERR_LOG_DEF_READ_ERROR:
626 msg = "Error reading log definition file"; break;
627 case SWITCHTEC_ERR_BIN_LOG_READ_ERROR:
628 msg = "Error reading binary log file"; break;
629 case SWITCHTEC_ERR_PARSED_LOG_WRITE_ERROR:
630 msg = "Error writing parsed log file"; break;
631 case SWITCHTEC_ERR_LOG_DEF_DATA_INVAL:
632 msg = "Invalid log definition data"; break;
633 case SWITCHTEC_ERR_INVALID_PORT:
634 msg = "Invalid port specified"; break;
635 case SWITCHTEC_ERR_INVALID_LANE:
636 msg = "Invalid lane specified"; break;
637 default:
638 msg = "Unknown Switchtec error"; break;
639 }
640
641 return msg;
642 }
643
644 err = errno & ~SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
645
646 switch (err) {
647 case ERR_NO_AVAIL_MRPC_THREAD:
648 msg = "No available MRPC handler thread"; break;
649 case ERR_HANDLER_THREAD_NOT_IDLE:
650 msg = "The handler thread is not idle"; break;
651 case ERR_NO_BG_THREAD:
652 msg = "No background thread run for the command"; break;
653
654 case ERR_REFCLK_SUBCMD_INVALID:
655 case ERR_STACKBIF_SUBCMD_INVALID:
656 case ERR_SUBCMD_INVALID: msg = "Invalid subcommand"; break;
657 case ERR_CMD_INVALID: msg = "Invalid command"; break;
658 case ERR_PARAM_INVALID: msg = "Invalid parameter"; break;
659 case ERR_BAD_FW_STATE: msg = "Bad firmware state"; break;
660 case ERR_MRPC_DENIED: msg = "MRPC request denied"; break;
661 case ERR_MRPC_NO_PREV_DATA:
662 msg = "No previous adaptation object data";
663 break;
664 case ERR_REFCLK_STACK_ID_INVALID:
665 case ERR_STACKBIF_STACK_ID_INVALID:
666 case ERR_STACK_INVALID: msg = "Invalid Stack"; break;
667 case ERR_LOOPBACK_PORT_INVALID:
668 case ERR_PORT_INVALID: msg = "Invalid Port"; break;
669 case ERR_EVENT_INVALID: msg = "Invalid Event"; break;
670 case ERR_RST_RULE_FAILED: msg = "Reset rule search failed"; break;
671 case ERR_UART_NOT_SUPPORTED:
672 msg = "UART interface not supported for this command"; break;
673 case ERR_XML_VERSION_MISMATCH:
674 msg = "XML version mismatch between MAIN and CFG partition";
675 break;
676 case ERR_ACCESS_REFUSED: msg = "Access Refused"; break;
677
678 case ERR_STACKBIF_CODE_INVALID:
679 msg = "Stack bifurcation code invalid"; break;
680 break;
681 case ERR_STACKBIF_PORT_BOUND:
682 msg = "Port already bound"; break;
683 break;
684
685 default: break;
686 }
687
688 switch (mrpc_error_cmd) {
689 case MRPC_PORTPARTP2P:
690 switch (err) {
691 case ERR_PHYC_PORT_ARDY_BIND:
692 msg = "Physical port already bound"; break;
693 case ERR_LOGC_PORT_ARDY_BIND:
694 msg = "Logical bridge instance already bound"; break;
695 case ERR_BIND_PRTT_NOT_EXIST:
696 msg = "Partition does not exist"; break;
697 case ERR_PHYC_PORT_NOT_EXIST:
698 msg = "Physical port does not exist"; break;
699 case ERR_PHYC_PORT_DIS:
700 msg = "Physical port disabled"; break;
701 case ERR_NO_LOGC_PORT:
702 msg = "No logical bridge instance"; break;
703 case ERR_BIND_IN_PROGRESS:
704 msg = "Bind/unbind in progress"; break;
705 case ERR_BIND_TGT_IS_USP:
706 msg = "Bind/unbind target is USP"; break;
707 case ERR_BIND_SUBCMD_INVALID:
708 msg = "Sub-command does not exist"; break;
709 case ERR_PHYC_PORT_LINK_ACT:
710 msg = "Physical port link active"; break;
711 case ERR_LOGC_PORT_NOT_BIND_PHYC_PORT:
712 msg = "Logical bridge not bind to physical port"; break;
713 case ERR_UNBIND_OPT_INVALID:
714 msg = "Invalid unbind option"; break;
715 case ERR_BIND_CHECK_FAIL:
716 msg = "Port bind checking failed"; break;
717 default: break;
718 }
719 break;
720 default: break;
721 }
722
723 return msg;
724}
725
733void switchtec_perror(const char *str)
734{
735 const char *msg = switchtec_strerror();
736 int is_mrpc = errno & SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
737 int err = errno & ~SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
738
739 if (is_mrpc)
740 fprintf(stderr, "%s: %s (MRPC: 0x%x, error: 0x%x)\n",
741 str, msg, mrpc_error_cmd, err);
742 else
743 fprintf(stderr, "%s: %s\n", str, msg);
744}
745
764int switchtec_echo(struct switchtec_dev *dev, uint32_t input,
765 uint32_t *output)
766{
767 return switchtec_cmd(dev, MRPC_ECHO, &input, sizeof(input),
768 output, sizeof(*output));
769}
770
780int switchtec_hard_reset(struct switchtec_dev *dev)
781{
782 uint32_t subcmd = 0;
783
784 return switchtec_cmd(dev, MRPC_RESET, &subcmd, sizeof(subcmd),
785 NULL, 0);
786}
787
792static void free_log_defs(struct log_defs *defs)
793{
794 int i, j;
795
796 if (!defs->module_defs)
797 return;
798
799 for (i = 0; i < defs->num_alloc; i++) {
800 free(defs->module_defs[i].mod_name);
801
802 for (j = 0; j < defs->module_defs[i].num_entries; j++)
803 free(defs->module_defs[i].entries[j]);
804
805 free(defs->module_defs[i].entries);
806 }
807
808 free(defs->module_defs);
809}
810
817static int realloc_log_defs(struct log_defs *defs, int num_modules)
818{
819 int i;
820
821 defs->module_defs = realloc(defs->module_defs,
822 (num_modules *
823 sizeof(struct module_log_defs)));
824 if (!defs->module_defs) {
825 free_log_defs(defs);
826 return -1;
827 }
828
829 for (i = defs->num_alloc; i < num_modules; i++)
830 memset(&defs->module_defs[i], 0,
831 sizeof(struct module_log_defs));
832
833 defs->num_alloc = num_modules;
834
835 return 0;
836}
837
844static bool parse_int(char *str, int *val)
845{
846 char *endptr;
847
848 errno = 0;
849 *val = strtol(str, &endptr, 0);
850
851 if ((endptr == str) || (*endptr != '\0') || (errno != 0))
852 return false;
853
854 return true;
855}
856
863static int read_app_log_defs(FILE *log_def_file, struct log_defs *defs)
864{
865 int ret;
866 char line[512];
867 char *tok;
868 int mod_id;
869 struct module_log_defs *mod_defs;
870 int num_entries;
871 int i;
872
873 /* allocate some log definition entries */
874 ret = realloc_log_defs(defs, 200);
875 if (ret < 0)
876 return ret;
877
878 while (fgets(line, sizeof(line), log_def_file)) {
879
880 /* ignore comments */
881 if (line[0] == '#')
882 continue;
883
884 /* strip any newline characters */
885 line[strcspn(line, "\r\n")] = '\0';
886
887 /*
888 * Tokenize and parse the line. Module headings are of the form:
889 * mod_name mod_id num_entries
890 */
891 tok = strtok(line, " \t");
892 if (!tok)
893 continue;
894
895 tok = strtok(NULL, " \t");
896 if (!tok)
897 continue;
898
899 if (!parse_int(tok, &mod_id)) {
900 errno = SWITCHTEC_ERR_LOG_DEF_DATA_INVAL;
901 goto err_free_log_defs;
902 }
903
904 /* reallocate more log definition entries if needed */
905 if (mod_id > defs->num_alloc) {
906 ret = realloc_log_defs(defs, mod_id * 2);
907 if (ret < 0)
908 return ret;
909 }
910
911 mod_defs = &defs->module_defs[mod_id];
912
913 tok = strtok(NULL, " \t");
914 if (!tok)
915 continue;
916
917 if (!parse_int(tok, &num_entries)) {
918 errno = SWITCHTEC_ERR_LOG_DEF_DATA_INVAL;
919 goto err_free_log_defs;
920 }
921
922 /*
923 * Skip this module if it has already been done. This can happen
924 * if the module is duplicated in the log definition file.
925 */
926 if (mod_defs->mod_name != NULL) {
927 for (i = 0; i < num_entries; i++) {
928 if (!fgets(line, sizeof(line),
929 log_def_file))
930 break;
931 }
932 continue;
933 }
934
935 mod_defs->mod_name = strdup(line);
936 mod_defs->num_entries = num_entries;
937 mod_defs->entries = calloc(mod_defs->num_entries,
938 sizeof(*mod_defs->entries));
939 if (!mod_defs->entries)
940 goto err_free_log_defs;
941
942 for (i = 0; i < mod_defs->num_entries; i++) {
943 if (fgets(line, sizeof(line), log_def_file) == NULL) {
944 errno = SWITCHTEC_ERR_LOG_DEF_READ_ERROR;
945 goto err_free_log_defs;
946 }
947
948 mod_defs->entries[i] = strdup(line);
949 if (!mod_defs->entries[i])
950 goto err_free_log_defs;
951 }
952 }
953
954 if (ferror(log_def_file)) {
955 errno = SWITCHTEC_ERR_LOG_DEF_READ_ERROR;
956 goto err_free_log_defs;
957 }
958
959 return 0;
960
961err_free_log_defs:
962 free_log_defs(defs);
963 return -1;
964}
965
972static int read_mailbox_log_defs(FILE *log_def_file, struct log_defs *defs)
973{
974 int ret;
975 char line[512];
976 struct module_log_defs *mod_defs;
977 int num_entries_alloc;
978
979 /*
980 * The mailbox log definitions don't keep track of modules. Allocate a
981 * single log definition entry for all definitions.
982 */
983 ret = realloc_log_defs(defs, 1);
984 if (ret < 0)
985 return ret;
986
987 mod_defs = &defs->module_defs[0];
988 mod_defs->num_entries = 0;
989
990 /* allocate some entries */
991 num_entries_alloc = 100;
992 mod_defs->entries = calloc(num_entries_alloc,
993 sizeof(*mod_defs->entries));
994 if (!mod_defs->entries)
995 goto err_free_log_defs;
996
997 while (fgets(line, sizeof(line), log_def_file)) {
998 /* ignore comments */
999 if (line[0] == '#')
1000 continue;
1001
1002 if (mod_defs->num_entries >= num_entries_alloc) {
1003 /* allocate more entries */
1004 num_entries_alloc *= 2;
1005 mod_defs->entries = realloc(mod_defs->entries,
1006 (num_entries_alloc *
1007 sizeof(*mod_defs->entries)));
1008 if (!mod_defs->entries)
1009 goto err_free_log_defs;
1010 }
1011
1012 mod_defs->entries[mod_defs->num_entries] = strdup(line);
1013 if (!mod_defs->entries[mod_defs->num_entries])
1014 goto err_free_log_defs;
1015
1016 mod_defs->num_entries++;
1017 }
1018
1019 if (ferror(log_def_file)) {
1020 errno = SWITCHTEC_ERR_LOG_DEF_READ_ERROR;
1021 goto err_free_log_defs;
1022 }
1023
1024 return 0;
1025
1026err_free_log_defs:
1027 free_log_defs(defs);
1028 return -1;
1029}
1030
1042static int write_parsed_log(struct log_a_data log_data[],
1043 size_t count, int init_entry_idx,
1044 struct log_defs *defs,
1045 enum switchtec_log_parse_type log_type,
1046 FILE *log_file, int ts_factor)
1047{
1048 int i;
1049 int ret;
1050 int entry_idx = init_entry_idx;
1051 unsigned long long time;
1052 unsigned int nanos, micros, millis, secs, mins, hours, days;
1053 unsigned int entry_num;
1054 unsigned int mod_id;
1055 unsigned int log_sev = 0;
1056 const char *log_sev_strs[] = {"DISABLED", "HIGHEST", "HIGH", "MEDIUM",
1057 "LOW", "LOWEST"};
1058 bool is_bl1;
1059 struct module_log_defs *mod_defs;
1060
1061 if (entry_idx == 0) {
1062 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP)
1063 fputs(" #|Timestamp |Module |Severity |Event ID |Event\n",
1064 log_file);
1065 else
1066 fputs(" #|Timestamp |Source |Event ID |Event\n",
1067 log_file);
1068 }
1069
1070 for (i = 0; i < count; i ++) {
1071 /* timestamp is in the first 2 DWords */
1072 time = (((unsigned long long)log_data[i].data[0] << 32) |
1073 log_data[i].data[1]) * ts_factor/100;
1074 nanos = time % 1000;
1075 time /= 1000;
1076 micros = time % 1000;
1077 time /= 1000;
1078 millis = time % 1000;
1079 time /= 1000;
1080 secs = time % 60;
1081 time /= 60;
1082 mins = time % 60;
1083 time /= 60;
1084 hours = time % 24;
1085 days = time / 24;
1086
1087 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP) {
1088 /*
1089 * app log: module ID and log severity are in the 3rd
1090 * DWord
1091 */
1092 mod_id = (log_data[i].data[2] >> 16) & 0xFFF;
1093 log_sev = (log_data[i].data[2] >> 28) & 0xF;
1094
1095 if ((mod_id > defs->num_alloc) ||
1096 (defs->module_defs[mod_id].mod_name == NULL) ||
1097 (strlen(defs->module_defs[mod_id].mod_name) == 0)) {
1098 if (fprintf(log_file, "(Invalid module ID: 0x%x)\n",
1099 mod_id) < 0)
1100 goto ret_print_error;
1101 continue;
1102 }
1103
1104 if (log_sev >= ARRAY_SIZE(log_sev_strs)) {
1105 if (fprintf(log_file, "(Invalid log severity: %d)\n",
1106 log_sev) < 0)
1107 goto ret_print_error;
1108 continue;
1109 }
1110 } else {
1111 /*
1112 * mailbox log: BL1/BL2 indication is in the 3rd
1113 * DWord
1114 */
1115 is_bl1 = (((log_data[i].data[2] >> 27) & 1) == 0);
1116
1117 /* mailbox log definitions are all in the first entry */
1118 mod_id = 0;
1119 }
1120
1121 mod_defs = &defs->module_defs[mod_id];
1122
1123 /* entry number is in the 3rd DWord */
1124 entry_num = log_data[i].data[2] & 0x0000FFFF;
1125
1126 if (entry_num >= mod_defs->num_entries) {
1127 if (fprintf(log_file,
1128 "(Invalid log entry number: %d (module 0x%x))\n",
1129 entry_num, mod_id) < 0)
1130 goto ret_print_error;
1131 continue;
1132 }
1133
1134 /* print the entry index and timestamp */
1135 if (ts_factor == 0)
1136 ret = fprintf(log_file,
1137 "%04d|xxxd xx:xx:xx.xxx,xxx,xxx|",
1138 entry_idx);
1139 else
1140 ret = fprintf(log_file,
1141 "%04d|%03dd %02d:%02d:%02d.%03d,%03d,%03d|",
1142 entry_idx, days, hours, mins, secs,
1143 millis, micros, nanos);
1144
1145 if (ret < 0)
1146 goto ret_print_error;
1147
1148 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP) {
1149 /* print the module name and log severity */
1150 if (fprintf(log_file, "%-12s |%-8s |0x%04x |",
1151 mod_defs->mod_name, log_sev_strs[log_sev],
1152 entry_num) < 0)
1153 goto ret_print_error;
1154 } else {
1155 /* print the log source (BL1/BL2) */
1156 if (fprintf(log_file, "%-6s |0x%04x |",
1157 (is_bl1 ? "BL1" : "BL2"), entry_num) < 0)
1158 goto ret_print_error;
1159 }
1160
1161 /* print the log entry */
1162 if (fprintf(log_file, mod_defs->entries[entry_num],
1163 log_data[i].data[3], log_data[i].data[4],
1164 log_data[i].data[5], log_data[i].data[6],
1165 log_data[i].data[7]) < 0)
1166 goto ret_print_error;
1167
1168 entry_idx++;
1169 }
1170
1171 if (fflush(log_file) != 0)
1172 return -1;
1173
1174 return 0;
1175
1176ret_print_error:
1177 errno = SWITCHTEC_ERR_PARSED_LOG_WRITE_ERROR;
1178 return -1;
1179}
1180
1181static int parse_def_header(FILE *log_def_file, uint32_t *fw_version,
1182 uint32_t *sdk_version)
1183{
1184 char line[512];
1185 int i;
1186
1187 *fw_version = 0;
1188 *sdk_version = 0;
1189 while (fgets(line, sizeof(line), log_def_file)) {
1190 if (line[0] != '#')
1191 continue;
1192
1193 i = 0;
1194 while (line[i] == ' ' || line[i] == '#') i++;
1195
1196 if (strncasecmp(line + i, "SDK Version:", 12) == 0) {
1197 i += 12;
1198 while (line[i] == ' ') i++;
1199 sscanf(line + i, "%i", (int*)sdk_version);
1200 }
1201 else if (strncasecmp(line + i, "FW Version:", 11) == 0) {
1202 i += 11;
1203 while (line[i] == ' ') i++;
1204 sscanf(line + i, "%i", (int*)fw_version);
1205 }
1206 }
1207
1208 rewind(log_def_file);
1209 return 0;
1210}
1211
1212static int append_log_header(int fd, uint32_t sdk_version,
1213 uint32_t fw_version, int binary)
1214{
1215 int ret;
1216 struct log_header {
1217 uint8_t magic[8];
1218 uint32_t fw_version;
1219 uint32_t sdk_version;
1220 uint32_t flags;
1221 uint32_t rsvd[3];
1222 } header = {
1223 .magic = {'S', 'W', 'M', 'C', 'L', 'O', 'G', 'F'},
1224 .fw_version = fw_version,
1225 .sdk_version = sdk_version
1226 };
1227 char hdr_str_fmt[] = "#########################\n"
1228 "## FW version %08x\n"
1229 "## SDK version %08x\n"
1230 "#########################\n\n";
1231 char hdr_str[512];
1232
1233 if (binary) {
1234 ret = write(fd, &header, sizeof(header));
1235 } else {
1236 snprintf(hdr_str, 512, hdr_str_fmt, fw_version, sdk_version);
1237 ret = write(fd, hdr_str, strlen(hdr_str));
1238 }
1239
1240 return ret;
1241}
1242
1243static int get_ts_factor(enum switchtec_gen gen)
1244{
1245 if (gen == SWITCHTEC_GEN_UNKNOWN)
1246 return 0;
1247 else if (gen == SWITCHTEC_GEN3)
1248 return 1000;
1249 else
1250 return 833;
1251}
1252
1253static int log_a_to_file(struct switchtec_dev *dev, int sub_cmd_id,
1254 int fd, FILE *log_def_file,
1255 struct switchtec_log_file_info *info)
1256{
1257 int ret = -1;
1258 int read = 0;
1259 struct log_a_retr_result res;
1260 struct log_a_retr cmd = {
1261 .sub_cmd_id = sub_cmd_id,
1262 .start = -1,
1263 };
1264 struct log_defs defs = {
1265 .module_defs = NULL,
1266 .num_alloc = 0};
1267 FILE *log_file;
1268 int entry_idx = 0;
1269 uint32_t fw_version = 0;
1270 uint32_t sdk_version = 0;
1271
1272 if (log_def_file != NULL) {
1273 ret = parse_def_header(log_def_file, &fw_version,
1274 &sdk_version);
1275 if (ret)
1276 return ret;
1277 /* read the log definition file into defs */
1278 ret = read_app_log_defs(log_def_file, &defs);
1279 if (ret < 0)
1280 return ret;
1281 }
1282
1283 res.hdr.remain = 1;
1284
1285 while (res.hdr.remain) {
1286 ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
1287 &res, sizeof(res));
1288 if (ret)
1289 goto ret_free_log_defs;
1290 if (res.hdr.overflow && info)
1291 info->overflow = 1;
1292 if (read == 0) {
1293 if (dev->gen < SWITCHTEC_GEN5) {
1294 res.hdr.sdk_version = 0;
1295 res.hdr.fw_version = 0;
1296 }
1297
1298 if (info) {
1299 info->def_fw_version = fw_version;
1300 info->def_sdk_version = sdk_version;
1301 info->log_fw_version = res.hdr.fw_version;
1302 info->log_sdk_version = res.hdr.sdk_version;
1303 }
1304
1305 if (res.hdr.sdk_version != sdk_version ||
1306 res.hdr.fw_version != fw_version) {
1307 if (info && log_def_file)
1308 info->version_mismatch = true;
1309
1310 }
1311
1312 append_log_header(fd, res.hdr.sdk_version,
1313 res.hdr.fw_version,
1314 log_def_file == NULL? 1 : 0);
1315 }
1316
1317 if (log_def_file == NULL) {
1318 /* write the binary log data to a file */
1319 ret = write(fd, res.data,
1320 sizeof(*res.data) * res.hdr.count);
1321 if (ret < 0)
1322 return ret;
1323 } else {
1324 log_file = fdopen(fd, "w");
1325 if (!log_file)
1326 goto ret_free_log_defs;
1327
1328 /* parse the log data and write it to a file */
1329 ret = write_parsed_log(res.data, res.hdr.count,
1330 entry_idx, &defs,
1331 SWITCHTEC_LOG_PARSE_TYPE_APP,
1332 log_file,
1333 get_ts_factor(dev->gen));
1334 if (ret < 0)
1335 goto ret_free_log_defs;
1336
1337 entry_idx += res.hdr.count;
1338 }
1339
1340 read += le32toh(res.hdr.count);
1341 cmd.start = res.hdr.next_start;
1342 }
1343
1344 ret = 0;
1345
1346ret_free_log_defs:
1347 free_log_defs(&defs);
1348 return ret;
1349}
1350
1351static int log_b_to_file(struct switchtec_dev *dev, int sub_cmd_id, int fd)
1352{
1353 int ret;
1354 int read = 0;
1355 struct log_b_retr_result res;
1356 struct log_b_retr cmd = {
1357 .sub_cmd_id = sub_cmd_id,
1358 .offset = 0,
1359 .length = htole32(sizeof(res.data)),
1360 };
1361
1362 res.hdr.remain = sizeof(res.data);
1363
1364 while (res.hdr.remain) {
1365 ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
1366 &res, sizeof(res));
1367 if (ret)
1368 return -1;
1369
1370 ret = write(fd, res.data, res.hdr.length);
1371 if (ret < 0)
1372 return ret;
1373
1374 read += le32toh(res.hdr.length);
1375 cmd.offset = htole32(read);
1376 }
1377
1378 return 0;
1379}
1380
1381static int log_c_to_file(struct switchtec_dev *dev, int sub_cmd_id, int fd)
1382{
1383 int ret;
1384 struct log_cmd {
1385 uint8_t subcmd;
1386 uint8_t rsvd[3];
1387 } cmd = {};
1388
1389 struct log_reply {
1390 uint8_t reason;
1391 uint8_t rsvd[3];
1392 uint32_t nvlog_version;
1393 uint32_t thread_handle;
1394 uint32_t fw_version;
1395 uint32_t timestamp1;
1396 uint32_t timestamp2;
1397 } reply;
1398
1399 cmd.subcmd = sub_cmd_id;
1400
1401 ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
1402 &reply, sizeof(reply));
1403 if (ret)
1404 return -1;
1405
1406 ret = write(fd, &reply, sizeof(reply));
1407 if (ret < 0)
1408 return ret;
1409
1410 return 0;
1411}
1412
1413static int log_ram_flash_to_file(struct switchtec_dev *dev,
1414 int gen5_cmd, int gen4_cmd, int gen4_cmd_lgcy,
1415 int fd, FILE *log_def_file,
1416 struct switchtec_log_file_info *info)
1417{
1418 int ret;
1419
1420 if (switchtec_is_gen5(dev)) {
1421 return log_a_to_file(dev, gen5_cmd, fd, log_def_file,
1422 info);
1423 } else {
1424 ret = log_a_to_file(dev, gen4_cmd, fd, log_def_file,
1425 info);
1426
1427 /* somehow hardware returns ERR_LOGC_PORT_ARDY_BIND
1428 * instead of ERR_SUBCMD_INVALID if this subcommand
1429 * is not supported, so we fall back to legacy
1430 * subcommand on ERR_LOGC_PORT_ARDY_BIND error as well
1431 */
1432 if (ret > 0 &&
1433 (ERRNO_MRPC(errno) == ERR_LOGC_PORT_ARDY_BIND ||
1434 ERRNO_MRPC(errno) == ERR_SUBCMD_INVALID))
1435 ret = log_a_to_file(dev, gen4_cmd_lgcy, fd,
1436 log_def_file, info);
1437
1438 return ret;
1439 }
1440}
1441
1451int switchtec_log_to_file(struct switchtec_dev *dev,
1452 enum switchtec_log_type type, int fd, FILE *log_def_file,
1453 struct switchtec_log_file_info *info)
1454{
1455 if (info)
1456 memset(info, 0, sizeof(*info));
1457
1458 switch (type) {
1459 case SWITCHTEC_LOG_RAM:
1460 return log_ram_flash_to_file(dev,
1461 MRPC_FWLOGRD_RAM_GEN5,
1462 MRPC_FWLOGRD_RAM_WITH_FLAG,
1463 MRPC_FWLOGRD_RAM,
1464 fd, log_def_file, info);
1465 case SWITCHTEC_LOG_FLASH:
1466 return log_ram_flash_to_file(dev,
1467 MRPC_FWLOGRD_FLASH_GEN5,
1468 MRPC_FWLOGRD_FLASH_WITH_FLAG,
1469 MRPC_FWLOGRD_FLASH,
1470 fd, log_def_file, info);
1471 case SWITCHTEC_LOG_MEMLOG:
1472 return log_b_to_file(dev, MRPC_FWLOGRD_MEMLOG, fd);
1473 case SWITCHTEC_LOG_REGS:
1474 return log_b_to_file(dev, MRPC_FWLOGRD_REGS, fd);
1475 case SWITCHTEC_LOG_THRD_STACK:
1476 return log_b_to_file(dev, MRPC_FWLOGRD_THRD_STACK, fd);
1477 case SWITCHTEC_LOG_SYS_STACK:
1478 return log_b_to_file(dev, MRPC_FWLOGRD_SYS_STACK, fd);
1479 case SWITCHTEC_LOG_THRD:
1480 return log_b_to_file(dev, MRPC_FWLOGRD_THRD, fd);
1481 case SWITCHTEC_LOG_NVHDR:
1482 return log_c_to_file(dev, MRPC_FWLOGRD_NVHDR, fd);
1483 };
1484
1485 errno = EINVAL;
1486 return -errno;
1487}
1488
1489static int parse_log_header(FILE *bin_log_file, uint32_t *fw_version,
1490 uint32_t *sdk_version)
1491{
1492 struct log_header {
1493 uint8_t magic[8];
1494 uint32_t fw_version;
1495 uint32_t sdk_version;
1496 uint32_t flags;
1497 uint32_t rsvd[3];
1498 } header;
1499
1500 char sig[8] = {'S', 'W', 'M', 'C', 'L', 'O', 'G', 'F'};
1501 int ret;
1502
1503 ret = fread(&header, sizeof(header), 1, bin_log_file);
1504 if (ret <= 0) {
1505 errno = EBADF;
1506 return -EBADF;
1507 }
1508
1509 if (memcmp(sig, header.magic, 8)) {
1510 rewind(bin_log_file);
1511 *fw_version = 0;
1512 *sdk_version = 0;
1513 return 0;
1514 }
1515
1516 *fw_version = header.fw_version;
1517 *sdk_version = header.sdk_version;
1518
1519 return 0;
1520}
1521
1532int switchtec_parse_log(FILE *bin_log_file, FILE *log_def_file,
1533 FILE *parsed_log_file,
1534 enum switchtec_log_parse_type log_type,
1535 enum switchtec_gen gen,
1536 struct switchtec_log_file_info *info)
1537{
1538 int ret;
1539 struct log_a_data log_data;
1540 struct log_defs defs = {
1541 .module_defs = NULL,
1542 .num_alloc = 0};
1543 int entry_idx = 0;
1544 uint32_t fw_version_log;
1545 uint32_t sdk_version_log;
1546 uint32_t fw_version_def;
1547 uint32_t sdk_version_def;
1548 enum switchtec_gen gen_file;
1549
1550 if (info)
1551 memset(info, 0, sizeof(*info));
1552
1553 if ((log_type != SWITCHTEC_LOG_PARSE_TYPE_APP) &&
1554 (log_type != SWITCHTEC_LOG_PARSE_TYPE_MAILBOX)) {
1555 errno = EINVAL;
1556 return -errno;
1557 }
1558
1559 ret = parse_log_header(bin_log_file, &fw_version_log,
1560 &sdk_version_log);
1561 if (ret)
1562 return ret;
1563 ret = parse_def_header(log_def_file, &fw_version_def,
1564 &sdk_version_def);
1565 if (ret)
1566 return ret;
1567
1568 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_MAILBOX) {
1569 fw_version_log = fw_version_def;
1570 sdk_version_log = sdk_version_def;
1571 }
1572
1573 if (info) {
1574 info->def_fw_version = fw_version_def;
1575 info->def_sdk_version = sdk_version_def;
1576
1577 info->log_fw_version = fw_version_log;
1578 info->log_sdk_version = sdk_version_log;
1579 }
1580 /* read the log definition file into defs */
1581 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP)
1582 ret = read_app_log_defs(log_def_file, &defs);
1583 else
1584 ret = read_mailbox_log_defs(log_def_file, &defs);
1585
1586 ret = append_log_header(fileno(parsed_log_file), sdk_version_log,
1587 fw_version_log, 0);
1588 if (ret < 0)
1589 return ret;
1590
1591 /* parse each log entry */
1592 while (fread(&log_data, sizeof(struct log_a_data), 1,
1593 bin_log_file) == 1) {
1594 if(fw_version_log)
1595 gen_file = switchtec_fw_version_to_gen(fw_version_log);
1596 else
1597 gen_file = switchtec_fw_version_to_gen(fw_version_def);
1598
1599 if (gen_file != SWITCHTEC_GEN_UNKNOWN &&
1600 gen != SWITCHTEC_GEN_UNKNOWN) {
1601 if (info)
1602 info->gen_ignored = true;
1603 } else if (gen_file == SWITCHTEC_GEN_UNKNOWN &&
1604 gen == SWITCHTEC_GEN_UNKNOWN) {
1605 if (info)
1606 info->gen_unknown = true;
1607 } else if (gen != SWITCHTEC_GEN_UNKNOWN) {
1608 gen_file = gen;
1609 }
1610
1611 ret = write_parsed_log(&log_data, 1, entry_idx, &defs,
1612 log_type, parsed_log_file,
1613 get_ts_factor(gen_file));
1614 if (ret < 0)
1615 goto ret_free_log_defs;
1616
1617 entry_idx++;
1618 }
1619
1620 if (ferror(bin_log_file)) {
1621 errno = SWITCHTEC_ERR_BIN_LOG_READ_ERROR;
1622 ret = -1;
1623 }
1624
1625 if (fw_version_def != fw_version_log ||
1626 sdk_version_def != sdk_version_log) {
1627 if (info)
1628 info->version_mismatch = true;
1629 ret = ENOEXEC;
1630 }
1631
1632ret_free_log_defs:
1633 free_log_defs(&defs);
1634 return ret;
1635}
1636
1644int switchtec_log_def_to_file(struct switchtec_dev *dev,
1645 enum switchtec_log_def_type type,
1646 FILE* file)
1647{
1648 int ret;
1649 struct log_cmd {
1650 uint8_t subcmd;
1651 uint8_t rsvd[3];
1652 uint16_t idx;
1653 uint16_t mod_id;
1654 } cmd = {};
1655
1656 struct log_reply {
1657 uint16_t end_of_data;
1658 uint16_t data_len;
1659 uint16_t next_idx;
1660 uint16_t next_mod_id;
1661 uint8_t data[MRPC_MAX_DATA_LEN - 16];
1662 } reply = {};
1663
1664 switch (type) {
1665 case SWITCHTEC_LOG_DEF_TYPE_APP:
1666 cmd.subcmd = MRPC_LOG_DEF_APP;
1667 break;
1668
1669 case SWITCHTEC_LOG_DEF_TYPE_MAILBOX:
1670 cmd.subcmd = MRPC_LOG_DEF_MAILBOX;
1671 break;
1672
1673 default:
1674 errno = EINVAL;
1675 return -errno;
1676 }
1677
1678 do {
1679 ret = switchtec_cmd(dev, MRPC_LOG_DEF_GET, &cmd, sizeof(cmd),
1680 &reply, sizeof(reply));
1681 if (ret)
1682 return -1;
1683
1684 ret = fwrite(reply.data, reply.data_len, 1, file);
1685 if (ret < 0)
1686 return ret;
1687
1688 cmd.idx = reply.next_idx;
1689 cmd.mod_id = reply.next_mod_id;
1690 } while (!reply.end_of_data);
1691
1692 return 0;
1693}
1694
1695static enum switchtec_gen map_to_gen(uint32_t gen)
1696{
1697 enum switchtec_gen ret = SWITCHTEC_GEN_UNKNOWN;
1698
1699 switch (gen) {
1700 case 0:
1701 ret = SWITCHTEC_GEN4;
1702 break;
1703 case 1:
1704 ret = SWITCHTEC_GEN5;
1705 break;
1706 default:
1707 ret = SWITCHTEC_GEN_UNKNOWN;
1708 break;
1709 }
1710
1711 return ret;
1712}
1713
1722int switchtec_get_device_info(struct switchtec_dev *dev,
1723 enum switchtec_boot_phase *phase,
1724 enum switchtec_gen *gen,
1725 enum switchtec_rev *rev)
1726{
1727 int ret;
1728 uint32_t ping_dw = 0;
1729 uint32_t dev_info;
1730 struct get_dev_info_reply {
1731 uint32_t dev_info;
1732 uint32_t ping_reply;
1733 } reply;
1734
1735 ping_dw = time(NULL);
1736
1737 /*
1738 * The I2C TWI Ping command also dumps information about the
1739 * revision and image phase.
1740 */
1741 ret = switchtec_cmd(dev, MRPC_I2C_TWI_PING, &ping_dw,
1742 sizeof(ping_dw),
1743 &reply, sizeof(reply));
1744 if (ret == 0) {
1745 if (ping_dw != ~reply.ping_reply)
1746 return -1;
1747
1748 dev_info = le32toh(reply.dev_info);
1749 if (phase)
1750 *phase = dev_info & 0xff;
1751 if (rev)
1752 *rev = (dev_info >> 8) & 0x0f;
1753 if (gen)
1754 *gen = map_to_gen((dev_info >> 12) & 0x0f);
1755 } else if (ERRNO_MRPC(errno) == ERR_CMD_INVALID) {
1756 if (phase)
1757 *phase = SWITCHTEC_BOOT_PHASE_FW;
1758 if (gen)
1759 *gen = SWITCHTEC_GEN3;
1760 if (rev)
1761 *rev = SWITCHTEC_REV_UNKNOWN;
1762
1763 errno = 0;
1764 } else {
1765 return -1;
1766 }
1767
1768 return 0;
1769}
1770
1777float switchtec_die_temp(struct switchtec_dev *dev)
1778{
1779 int ret;
1780 uint32_t sub_cmd_id;
1781 uint32_t temp;
1782
1783 if (switchtec_is_gen3(dev)) {
1784 sub_cmd_id = MRPC_DIETEMP_SET_MEAS;
1785 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1786 sizeof(sub_cmd_id), NULL, 0);
1787 if (ret)
1788 return -100.0;
1789
1790 sub_cmd_id = MRPC_DIETEMP_GET;
1791 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1792 sizeof(sub_cmd_id), &temp, sizeof(temp));
1793 if (ret)
1794 return -100.0;
1795 } else {
1796 sub_cmd_id = MRPC_DIETEMP_GET_GEN4;
1797 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1798 sizeof(sub_cmd_id), &temp, sizeof(temp));
1799 if (ret)
1800 return -100.0;
1801 }
1802
1803 return le32toh(temp) / 100.;
1804}
1805
1806int switchtec_bind_info(struct switchtec_dev *dev,
1807 struct switchtec_bind_status_out *status, int phy_port)
1808{
1809 struct switchtec_bind_status_in sub_cmd_id = {
1810 .sub_cmd = MRPC_PORT_INFO,
1811 .phys_port_id = phy_port
1812 };
1813
1814 return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
1815 sizeof(sub_cmd_id), status, sizeof(*status));
1816}
1817
1818int switchtec_bind(struct switchtec_dev *dev, int par_id, int log_port,
1819 int phy_port)
1820{
1821 uint32_t output;
1822
1823 struct switchtec_bind_in sub_cmd_id = {
1824 .sub_cmd = MRPC_PORT_BIND,
1825 .par_id = par_id,
1826 .log_port_id = log_port,
1827 .phys_port_id = phy_port
1828 };
1829
1830 return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
1831 sizeof(sub_cmd_id), &output, sizeof(output));
1832}
1833
1834int switchtec_unbind(struct switchtec_dev *dev, int par_id, int log_port)
1835{
1836 uint32_t output;
1837
1838 struct switchtec_unbind_in sub_cmd_id = {
1839 .sub_cmd = MRPC_PORT_UNBIND,
1840 .par_id = par_id,
1841 .log_port_id = log_port,
1842 .opt = 2
1843 };
1844
1845 return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
1846 sizeof(sub_cmd_id), &output, sizeof(output));
1847}
1848
1849static int __switchtec_calc_lane_id(struct switchtec_status *port, int lane_id)
1850{
1851 int lane;
1852
1853 if (lane_id >= port->neg_lnk_width) {
1854 errno = SWITCHTEC_ERR_INVALID_LANE;
1855 return -1;
1856 }
1857
1858 lane = port->port.phys_id * 2;
1859 if (!port->lane_reversal)
1860 lane += lane_id;
1861 else
1862 lane += port->cfg_lnk_width - 1 - lane_id;
1863
1864 switch (port->port.phys_id) {
1865 /* Trident (Gen4) - Ports 48 to 51 maps to 96 to 99 */
1866 case 48: return 96;
1867 case 49: return 97;
1868 case 50: return 98;
1869 case 51: return 99;
1870 /* Hrapoon (Gen5) - Ports 56 to 59 maps to 96 to 99 */
1871 case 56: return 96;
1872 case 57: return 97;
1873 case 58: return 98;
1874 case 59: return 99;
1875 default: return lane;
1876 }
1877}
1878
1887int switchtec_calc_lane_id(struct switchtec_dev *dev, int phys_port_id,
1888 int lane_id, struct switchtec_status *port)
1889{
1890 struct switchtec_status *status;
1891 int ports, i;
1892 int rc = 0;
1893
1894 ports = switchtec_status(dev, &status);
1895 if (ports < 0)
1896 return ports;
1897
1898 for (i = 0; i < ports; i++)
1899 if (status[i].port.phys_id == phys_port_id)
1900 break;
1901
1902 if (i == ports) {
1903 errno = SWITCHTEC_ERR_INVALID_PORT;
1904 rc = -1;
1905 goto out;
1906 }
1907
1908 if (port)
1909 *port = status[i];
1910
1911 rc = __switchtec_calc_lane_id(&status[i], lane_id);
1912
1913out:
1914 switchtec_status_free(status, ports);
1915 return rc;
1916}
1917
1927int switchtec_calc_port_lane(struct switchtec_dev *dev, int lane_id,
1928 int *phys_port_id, int *port_lane_id,
1929 struct switchtec_status *port)
1930{
1931 struct switchtec_status *status;
1932 int ports, i, p, lane;
1933 int rc = 0;
1934
1935 ports = switchtec_status(dev, &status);
1936 if (ports < 0)
1937 return ports;
1938
1939 if (lane_id >= 96) {
1940 if (dev->gen < SWITCHTEC_GEN5)
1941 p = lane_id - 96 + 48;
1942 else
1943 p = lane_id - 96 + 56;
1944
1945 for (i = 0; i < ports; i++)
1946 if (status[i].port.phys_id == p)
1947 break;
1948 } else {
1949 for (i = 0; i < ports; i++) {
1950 p = status[i].port.phys_id * 2;
1951 if (lane_id >= p && lane_id < p + status[i].cfg_lnk_width)
1952 break;
1953 }
1954 }
1955
1956 if (i == ports) {
1957 errno = SWITCHTEC_ERR_INVALID_PORT;
1958 rc = -1;
1959 goto out;
1960 }
1961
1962 if (port)
1963 *port = status[i];
1964
1965 if (phys_port_id)
1966 *phys_port_id = status[i].port.phys_id;
1967
1968 lane = lane_id - status[i].port.phys_id * 2;
1969 if (port->lane_reversal)
1970 lane = status[i].cfg_lnk_width - 1 - lane;
1971
1972 if (port_lane_id)
1973 *port_lane_id = lane;
1974
1975out:
1976 switchtec_status_free(status, ports);
1977 return rc;
1978}
1979
1991int switchtec_calc_lane_mask(struct switchtec_dev *dev, int phys_port_id,
1992 int lane_id, int num_lanes, int *lane_mask,
1993 struct switchtec_status *port)
1994{
1995 struct switchtec_status *status;
1996 int ports, i, l, lane;
1997 int rc = 0;
1998
1999 ports = switchtec_status(dev, &status);
2000 if (ports < 0)
2001 return ports;
2002
2003 for (i = 0; i < ports; i++)
2004 if (status[i].port.phys_id == phys_port_id)
2005 break;
2006
2007 if (i == ports) {
2008 errno = SWITCHTEC_ERR_INVALID_PORT;
2009 rc = -1;
2010 goto out;
2011 }
2012
2013 if (port)
2014 *port = status[i];
2015
2016 for (l = lane_id; l < lane_id + num_lanes; l++) {
2017 lane = __switchtec_calc_lane_id(&status[i], l);
2018 if (lane < 0) {
2019 rc = -1;
2020 goto out;
2021 }
2022
2023 lane_mask[lane >> 5] |= 1 << (lane & 0x1F);
2024 }
2025
2026out:
2027 switchtec_status_free(status, ports);
2028 return rc;
2029}
2030
2038bool switchtec_stack_bif_port_valid(struct switchtec_dev *dev, int stack_id,
2039 int port_id)
2040{
2041 if (dev->gen == SWITCHTEC_GEN4)
2042 return stack_id * 8 + port_id < 52;
2043
2044 return true;
2045}
2046
2054int switchtec_stack_bif_width(struct switchtec_dev *dev, int stack_id,
2055 int port_bif)
2056{
2057 if (!port_bif)
2058 return 1;
2059
2060 if (port_bif != 1 && port_bif != 2 && port_bif != 4 && port_bif != 8 &&
2061 port_bif != 16) {
2062 errno = -EINVAL;
2063 return -1;
2064 }
2065
2066 if (dev->gen == SWITCHTEC_GEN4 && stack_id == 6)
2067 return port_bif;
2068 else
2069 return (port_bif + 1) / 2;
2070}
2071
2079int switchtec_get_stack_bif(struct switchtec_dev *dev, int stack_id,
2080 int port_bif[SWITCHTEC_PORTS_PER_STACK])
2081{
2082 struct switchtec_stackbif out, in = {
2083 .sub_cmd = MRPC_STACKBIF_GET,
2084 .stack_id = stack_id,
2085 };
2086 int ret, i;
2087
2088 ret = switchtec_cmd(dev, MRPC_STACKBIF, &in, sizeof(in), &out,
2089 sizeof(out));
2090 if (ret)
2091 return ret;
2092
2093 for (i = 0; i < SWITCHTEC_PORTS_PER_STACK; i++) {
2094 if (!switchtec_stack_bif_port_valid(dev, stack_id, i)) {
2095 port_bif[i] = -1;
2096 continue;
2097 }
2098
2099 switch (out.code & 0xF) {
2100 case 0x0: port_bif[i] = 0; break;
2101 case 0x1: port_bif[i] = 2; break;
2102 case 0x2: port_bif[i] = 4; break;
2103 case 0x4: port_bif[i] = 8; break;
2104 case 0x8: port_bif[i] = 16; break;
2105 case 0xf: port_bif[i] = 1; break;
2106 default:
2107 errno = -EPROTO;
2108 return -1;
2109 }
2110 out.code >>= 4;
2111 }
2112
2113 return 0;
2114}
2115
2123int switchtec_set_stack_bif(struct switchtec_dev *dev, int stack_id,
2124 int port_bif[SWITCHTEC_PORTS_PER_STACK])
2125{
2126 struct switchtec_stackbif out, in = {
2127 .sub_cmd = MRPC_STACKBIF_SET,
2128 .stack_id = stack_id,
2129 };
2130 int i;
2131
2132 for (i = 0; i < SWITCHTEC_PORTS_PER_STACK; i++) {
2133 switch (port_bif[i]) {
2134 case 0: in.code |= 0x0 << (i * 4); break;
2135 case 1: in.code |= 0xf << (i * 4); break;
2136 case 2: in.code |= 0x1 << (i * 4); break;
2137 case 4: in.code |= 0x2 << (i * 4); break;
2138 case 8: in.code |= 0x4 << (i * 4); break;
2139 case 16: in.code |= 0x8 << (i * 4); break;
2140 default:
2141 errno = -EINVAL;
2142 return -1;
2143 }
2144 }
2145
2146 return switchtec_cmd(dev, MRPC_STACKBIF, &in, sizeof(in), &out,
2147 sizeof(out));
2148}
2149
struct switchtec_dev * switchtec_open(const char *device)
Open a Switchtec device by string.
Definition: switchtec.c:253
void switchtec_list_free(struct switchtec_device_info *devlist)
Free a list of device info structures allocated by switchtec_list()
Definition: switchtec.c:231
struct switchtec_dev * switchtec_open_by_index(int index)
Open a switchtec device by index.
int switchtec_cmd(struct switchtec_dev *dev, uint32_t cmd, const void *payload, size_t payload_len, void *resp, size_t resp_len)
Execute an MRPC command.
Definition: platform.c:164
void switchtec_perror(const char *str)
Print an error string to stdout.
Definition: switchtec.c:733
int mrpc_error_cmd
The MRPC command ID when errno is set.
Definition: switchtec.c:598
struct switchtec_dev * switchtec_open_i2c(const char *path, int i2c_addr)
Open a switchtec device behind an I2C device.
void switchtec_status_free(struct switchtec_status *status, int ports)
Free a list of status structures allocated by switchtec_status()
Definition: switchtec.c:571
int switchtec_status(struct switchtec_dev *dev, struct switchtec_status **status)
Get the status of all the ports on a switchtec device.
Definition: switchtec.c:486
struct switchtec_dev * switchtec_open_by_path(const char *path)
Open a switchtec device by path.
_PURE const char * switchtec_name(struct switchtec_dev *dev)
Get the string that was used to open the deviec.
Definition: switchtec.c:386
const char * switchtec_strerror(void)
Return a message coresponding to the last error.
Definition: switchtec.c:610
static const struct switchtec_device_id switchtec_device_id_tbl[]
Supported Switchtec device id table.
Definition: switchtec.c:89
_PURE int switchtec_device_id(struct switchtec_dev *dev)
Get the device id of the device.
Definition: switchtec.c:338
_PURE enum switchtec_boot_phase switchtec_boot_phase(struct switchtec_dev *dev)
Get boot phase of the device.
Definition: switchtec.c:374
struct switchtec_dev * switchtec_open_eth(const char *ip, const int inst)
Open a switchtec device over ethernet.
_PURE enum switchtec_gen switchtec_gen(struct switchtec_dev *dev)
Get the generation of the device.
Definition: switchtec.c:350
_PURE enum switchtec_variant switchtec_variant(struct switchtec_dev *dev)
Get the variant type of the device.
Definition: switchtec.c:362
_PURE int switchtec_partition(struct switchtec_dev *dev)
Get the partiton number of the device that was opened.
Definition: switchtec.c:396
struct switchtec_dev * switchtec_open_by_pci_addr(int domain, int bus, int device, int func)
Open a switchtec device by PCI address (BDF)
enum switchtec_gen switchtec_fw_version_to_gen(unsigned int version)
Extract generation information from FW version number.
Definition: fw.c:397
int switchtec_stack_bif_width(struct switchtec_dev *dev, int stack_id, int port_bif)
Return the number of stack ports used for a given bifurcation.
Definition: switchtec.c:2054
int switchtec_calc_lane_mask(struct switchtec_dev *dev, int phys_port_id, int lane_id, int num_lanes, int *lane_mask, struct switchtec_status *port)
Calculate the lane mask for lanes within a physical port.
Definition: switchtec.c:1991
int switchtec_log_to_file(struct switchtec_dev *dev, enum switchtec_log_type type, int fd, FILE *log_def_file, struct switchtec_log_file_info *info)
Dump the Switchtec log data to a file.
Definition: switchtec.c:1451
static int read_mailbox_log_defs(FILE *log_def_file, struct log_defs *defs)
Read a mailbox log definition file and store the definitions.
Definition: switchtec.c:972
int switchtec_parse_log(FILE *bin_log_file, FILE *log_def_file, FILE *parsed_log_file, enum switchtec_log_parse_type log_type, enum switchtec_gen gen, struct switchtec_log_file_info *info)
Parse a binary app log or mailbox log to a text file.
Definition: switchtec.c:1532
float switchtec_die_temp(struct switchtec_dev *dev)
Get the die temperature of the switchtec device.
Definition: switchtec.c:1777
int switchtec_get_stack_bif(struct switchtec_dev *dev, int stack_id, int port_bif[SWITCHTEC_PORTS_PER_STACK])
Get the bifurcation of ports in a stack.
Definition: switchtec.c:2079
static void free_log_defs(struct log_defs *defs)
Free log definition data.
Definition: switchtec.c:792
bool switchtec_stack_bif_port_valid(struct switchtec_dev *dev, int stack_id, int port_id)
Return true if a port within a stack is valid.
Definition: switchtec.c:2038
int switchtec_hard_reset(struct switchtec_dev *dev)
Perform an MRPC hard reset command.
Definition: switchtec.c:780
int switchtec_log_def_to_file(struct switchtec_dev *dev, enum switchtec_log_def_type type, FILE *file)
Dump the Switchtec log definition data to a file.
Definition: switchtec.c:1644
int switchtec_get_device_info(struct switchtec_dev *dev, enum switchtec_boot_phase *phase, enum switchtec_gen *gen, enum switchtec_rev *rev)
Get device generation, revision, and boot phase info.
Definition: switchtec.c:1722
static int read_app_log_defs(FILE *log_def_file, struct log_defs *defs)
Read an app log definition file and store the definitions.
Definition: switchtec.c:863
static int realloc_log_defs(struct log_defs *defs, int num_modules)
Allocate / reallocate log definition data.
Definition: switchtec.c:817
int switchtec_echo(struct switchtec_dev *dev, uint32_t input, uint32_t *output)
Perform an MRPC echo command.
Definition: switchtec.c:764
static bool parse_int(char *str, int *val)
Parse an integer from a string.
Definition: switchtec.c:844
int switchtec_set_stack_bif(struct switchtec_dev *dev, int stack_id, int port_bif[SWITCHTEC_PORTS_PER_STACK])
Set the bifurcation of ports in a stack.
Definition: switchtec.c:2123
int switchtec_calc_lane_id(struct switchtec_dev *dev, int phys_port_id, int lane_id, struct switchtec_status *port)
Calculate the global lane ID for a lane within a physical port.
Definition: switchtec.c:1887
int switchtec_calc_port_lane(struct switchtec_dev *dev, int lane_id, int *phys_port_id, int *port_lane_id, struct switchtec_status *port)
Calculate the port and lane within the port from a global lane ID.
Definition: switchtec.c:1927
static int write_parsed_log(struct log_a_data log_data[], size_t count, int init_entry_idx, struct log_defs *defs, enum switchtec_log_parse_type log_type, FILE *log_file, int ts_factor)
Parse an app log or mailbox log and write the results to a file.
Definition: switchtec.c:1042
Definition: log.h:41
Definition: log.h:32
Definition: log.h:67
Log definitions for all modules.
Definition: switchtec.c:72
struct module_log_defs * module_defs
per-module log definitions
Definition: switchtec.c:73
int num_alloc
number of modules allocated
Definition: switchtec.c:74
Module-specific log definitions.
Definition: switchtec.c:63
char * mod_name
module name
Definition: switchtec.c:64
int num_entries
number of log entries
Definition: switchtec.c:66
char ** entries
log entry array
Definition: switchtec.c:65
Switchtec device id to generation/variant mapping.
Definition: switchtec.c:80
Represents a Switchtec device in the switchtec_list() function.
Definition: switchtec.h:131
Information about log file and log definition file.
Definition: switchtec.h:217
Port identification.
Definition: switchtec.h:144
unsigned char upstream
1 if this is an upstream port
Definition: switchtec.h:148
unsigned char partition
Partition the port is in.
Definition: switchtec.h:145
unsigned char stk_id
Port number within the stack.
Definition: switchtec.h:149
unsigned char log_id
Logical port number.
Definition: switchtec.h:151
unsigned char phys_id
Physical port number.
Definition: switchtec.h:150
unsigned char stack
Stack number.
Definition: switchtec.h:147
Port status structure.
Definition: switchtec.h:160
struct switchtec_port_id port
Port ID.
Definition: switchtec.h:161
unsigned char link_up
1 if the link is up
Definition: switchtec.h:164
unsigned char lane_reversal
Lane reversal.
Definition: switchtec.h:168
unsigned int acs_ctrl
ACS Setting of the Port.
Definition: switchtec.h:180
const char * lane_reversal_str
Lane reversal as a string.
Definition: switchtec.h:169
unsigned char cfg_lnk_width
Configured link width.
Definition: switchtec.h:162
unsigned char link_rate
Link rate/gen.
Definition: switchtec.h:165
unsigned char first_act_lane
First active lane.
Definition: switchtec.h:170
unsigned char neg_lnk_width
Negotiated link width.
Definition: switchtec.h:163
uint16_t ltssm
Link state.
Definition: switchtec.h:166
const char * ltssm_str
Link state as a string.
Definition: switchtec.h:167
Main Switchtec header.
switchtec_log_parse_type
Log types to parse.
Definition: switchtec.h:209
switchtec_rev
Device hardware revision.
Definition: switchtec.h:96
switchtec_gen
The PCIe generations.
Definition: switchtec.h:86
switchtec_log_def_type
Log definition data types.
Definition: switchtec.h:231
switchtec_variant
The variant types of Switchtec device.
Definition: switchtec.h:116
switchtec_log_type
Describe the type of logs too dump.
Definition: switchtec.h:195
switchtec_boot_phase
Device boot phase.
Definition: switchtec.h:106
static int switchtec_max_supported_ports(struct switchtec_dev *dev)
Return the max number of ports of a Switchtec device.
Definition: switchtec.h:447
static int switchtec_is_gen5(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 5 device.
Definition: switchtec.h:439
static int switchtec_is_pax_all(struct switchtec_dev *dev)
Return whether a Switchtec device is PAX(A).
Definition: switchtec.h:548
static int switchtec_is_gen3(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 3 device.
Definition: switchtec.h:423