Switchtec Userspace PROJECT_NUMBER = 4.0
Loading...
Searching...
No Matches
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 if (!dev->device_id)
190 switchtec_get_device_id_bl2(dev,
191 (unsigned short *)&dev->device_id);
192
193 while (id->device_id) {
194 if (id->device_id == dev->device_id) {
195 dev->gen = id->gen;
196 dev->var = id->var;
197
198 break;
199 }
200
201 id++;
202 }
203
204 ret = switchtec_get_device_info(dev, &dev->boot_phase, &dev->gen, NULL);
205 if (ret)
206 return -1;
207
208 return 0;
209}
210
211static int set_local_pax_id(struct switchtec_dev *dev)
212{
213 unsigned char local_pax_id;
214 int ret;
215
216 dev->local_pax_id = -1;
217
218 if (!switchtec_is_pax_all(dev))
219 return 0;
220
221 ret = switchtec_cmd(dev, MRPC_GET_PAX_ID, NULL, 0,
222 &local_pax_id, sizeof(local_pax_id));
223 if (ret)
224 return -1;
225
226 dev->local_pax_id = local_pax_id;
227 return 0;
228}
229
235{
236 free(devlist);
237}
238
256struct switchtec_dev *switchtec_open(const char *device)
257{
258 int idx;
259 int domain = 0;
260 int bus, dev, func;
261 char path[PATH_MAX];
262 int inst;
263 char *endptr;
264 struct switchtec_dev *ret;
265
266 if (sscanf(device, "%i@%i", &bus, &dev) == 2) {
267 ret = switchtec_open_i2c_by_adapter(bus, dev);
268 goto found;
269 }
270
271 if (sscanf(device, "%2049[^@]@%i", path, &dev) == 2) {
272 ret = switchtec_open_i2c(path, dev);
273 goto found;
274 }
275
276 if (device[0] == '/' &&
277 sscanf(device, "%2049[^:]:%i", path, &dev) == 2) {
278 ret = switchtec_open_i2c(path, dev);
279 goto found;
280 }
281
282 if (strchr(device, '/') || strchr(device, '\\')) {
283 ret = switchtec_open_by_path(device);
284 goto found;
285 }
286
287 if (sscanf(device, "%x:%x.%x", &bus, &dev, &func) == 3) {
288 ret = switchtec_open_by_pci_addr(domain, bus, dev, func);
289 goto found;
290 }
291
292 if (sscanf(device, "%x:%x:%x.%x", &domain, &bus, &dev, &func) == 4) {
293 ret = switchtec_open_by_pci_addr(domain, bus, dev, func);
294 goto found;
295 }
296
297 if (sscanf(device, "%2049[^:]:%i", path, &inst) == 2) {
298 ret = switchtec_open_eth(path, inst);
299 goto found;
300 }
301
302 errno = 0;
303 idx = strtol(device, &endptr, 0);
304 if (!errno && endptr != device) {
305 ret = switchtec_open_by_index(idx);
306 goto found;
307 }
308
309 if (sscanf(device, "switchtec%d", &idx) == 1) {
310 ret = switchtec_open_by_index(idx);
311 goto found;
312 }
313
314 errno = ENODEV;
315 return NULL;
316
317found:
318 if (!ret) {
319 errno = ENODEV;
320 return NULL;
321 }
322
323 snprintf(ret->name, sizeof(ret->name), "%s", device);
324
325 if (set_gen_variant(ret))
326 return NULL;
327
328 if (set_local_pax_id(ret))
329 return NULL;
330
331 return ret;
332}
333
341_PURE int switchtec_device_id(struct switchtec_dev *dev)
342{
343 return dev->device_id;
344}
345
353_PURE enum switchtec_gen switchtec_gen(struct switchtec_dev *dev)
354{
355 return dev->gen;
356}
357
365_PURE enum switchtec_variant switchtec_variant(struct switchtec_dev *dev)
366{
367 return dev->var;
368}
369
377_PURE enum switchtec_boot_phase switchtec_boot_phase(struct switchtec_dev *dev)
378{
379 return dev->boot_phase;
380}
381
389_PURE const char *switchtec_name(struct switchtec_dev *dev)
390{
391 return dev->name;
392}
393
399_PURE int switchtec_partition(struct switchtec_dev *dev)
400{
401 return dev->partition;
402}
403
404int switchtec_set_pax_id(struct switchtec_dev *dev, int pax_id)
405{
406 if (!switchtec_is_pax_all(dev) && (pax_id != SWITCHTEC_PAX_ID_LOCAL))
407 return -1;
408
409 if (pax_id == SWITCHTEC_PAX_ID_LOCAL)
410 dev->pax_id = dev->local_pax_id;
411 else
412 dev->pax_id = pax_id;
413
414 return 0;
415}
416
417static int compare_port_id(const void *aa, const void *bb)
418{
419 const struct switchtec_port_id *a = aa, *b = bb;
420
421 if (a->partition != b->partition)
422 return a->partition - b->partition;
423 if (a->upstream != b->upstream)
424 return b->upstream - a->upstream;
425 return a->log_id - b->log_id;
426}
427
428static int compare_status(const void *aa, const void *bb)
429{
430 const struct switchtec_status *a = aa, *b = bb;
431
432 return compare_port_id(&a->port, &b->port);
433}
434
435static const char *lane_reversal_str(int link_up,
436 int lane_reversal)
437{
438 if (!link_up)
439 return "N/A";
440
441 switch(lane_reversal) {
442 case 0: return "Normal Lane Ordering";
443 case 1: return "x16 (Full) Lane Reversal";
444 case 2: return "x2 Lane Reversal";
445 case 4: return "x4 Lane Reversal";
446 case 8: return "x8 Lane Reversal";
447 default: return "Unknown Lane Ordering";
448 }
449}
450
451static void generate_lane_str(struct switchtec_status *s)
452{
453 int i, l;
454
455 for (i = 0; i < s->cfg_lnk_width; i++)
456 s->lanes[i] = 'x';
457
458 if (!s->link_up)
459 return;
460
461 l = s->first_act_lane;
462 if (!l && s->lane_reversal)
463 l += s->neg_lnk_width - 1;
464
465 for (i = 0; i < s->neg_lnk_width; i++) {
466 if (l < 0)
467 break;
468
469 if (i < 10)
470 s->lanes[l] = '0' + i;
471 else
472 s->lanes[l] = 'a' + i - 10;
473
474 l += s->lane_reversal ? -1 : 1;
475 }
476}
477
489int switchtec_status(struct switchtec_dev *dev,
490 struct switchtec_status **status)
491{
492 uint64_t port_bitmap = 0;
493 int ret;
494 int i, p;
495 int nr_ports = 0;
496 struct switchtec_status *s;
497 int max_ports;
498
499 if (!status) {
500 errno = EINVAL;
501 return -errno;
502 }
503
504 max_ports = switchtec_max_supported_ports(dev);
505
506 struct {
507 uint8_t phys_port_id;
508 uint8_t par_id;
509 uint8_t log_port_id;
510 uint8_t stk_id;
511 uint8_t cfg_lnk_width;
512 uint8_t neg_lnk_width;
513 uint8_t usp_flag;
514 uint8_t linkup_linkrate;
515 uint16_t LTSSM;
516 uint8_t lane_reversal;
517 uint8_t first_act_lane;
518 } ports[max_ports];
519
520 ret = switchtec_cmd(dev, MRPC_LNKSTAT, &port_bitmap, sizeof(port_bitmap),
521 ports, sizeof(ports));
522 if (ret)
523 return ret;
524
525
526 for (i = 0; i < max_ports; i++) {
527 if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS)
528 continue;
529 nr_ports++;
530 }
531
532 s = *status = calloc(nr_ports, sizeof(*s));
533 if (!s)
534 return -ENOMEM;
535
536 for (i = 0, p = 0; i < max_ports && p < nr_ports; i++) {
537 if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS)
538 continue;
539
540 s[p].port.partition = ports[i].par_id;
541 s[p].port.stack = ports[i].stk_id >> 4;
542 s[p].port.upstream = ports[i].usp_flag;
543 s[p].port.stk_id = ports[i].stk_id & 0xF;
544 s[p].port.phys_id = ports[i].phys_port_id;
545 s[p].port.log_id = ports[i].log_port_id;
546
547 s[p].cfg_lnk_width = ports[i].cfg_lnk_width;
548 s[p].neg_lnk_width = ports[i].neg_lnk_width;
549 s[p].link_up = ports[i].linkup_linkrate >> 7;
550 s[p].link_rate = ports[i].linkup_linkrate & 0x7F;
551 s[p].ltssm = le16toh(ports[i].LTSSM);
552 s[p].ltssm_str = switchtec_ltssm_str(s[p].ltssm, 1);
553 s[p].lane_reversal = ports[i].lane_reversal;
554 s[p].lane_reversal_str = lane_reversal_str(s[p].link_up,
555 s[p].lane_reversal);
556 s[p].first_act_lane = ports[i].first_act_lane & 0xF;
557 s[p].acs_ctrl = -1;
558 generate_lane_str(&s[p]);
559
560 p++;
561 }
562
563 qsort(s, nr_ports, sizeof(*s), compare_status);
564
565 return nr_ports;
566}
567
574void switchtec_status_free(struct switchtec_status *status, int ports)
575{
576 int i;
577
578 for (i = 0; i < ports; i++) {
579 if (status[i].pci_bdf)
580 free(status[i].pci_bdf);
581
582 if (status[i].pci_bdf_path)
583 free(status[i].pci_bdf_path);
584
585 if (status[i].pci_dev)
586 free(status[i].pci_dev);
587
588 if (status[i].class_devices)
589 free(status[i].class_devices);
590 }
591
592 free(status);
593}
594
602
613const char *switchtec_strerror(void)
614{
615 const char *msg = "Unknown MRPC error";
616 int err;
617
618 if ((errno & (SWITCHTEC_ERRNO_MRPC_FLAG_BIT |
619 SWITCHTEC_ERRNO_GENERAL_FLAG_BIT)) == 0) {
620 if (errno)
621 return strerror(errno);
622 else
623 return platform_strerror();
624 }
625
626 if (errno & SWITCHTEC_ERRNO_GENERAL_FLAG_BIT) {
627 switch (errno) {
628 case SWITCHTEC_ERR_LOG_DEF_READ_ERROR:
629 msg = "Error reading log definition file"; break;
630 case SWITCHTEC_ERR_BIN_LOG_READ_ERROR:
631 msg = "Error reading binary log file"; break;
632 case SWITCHTEC_ERR_PARSED_LOG_WRITE_ERROR:
633 msg = "Error writing parsed log file"; break;
634 case SWITCHTEC_ERR_LOG_DEF_DATA_INVAL:
635 msg = "Invalid log definition data"; break;
636 case SWITCHTEC_ERR_INVALID_PORT:
637 msg = "Invalid port specified"; break;
638 case SWITCHTEC_ERR_INVALID_LANE:
639 msg = "Invalid lane specified"; break;
640 default:
641 msg = "Unknown Switchtec error"; break;
642 }
643
644 return msg;
645 }
646
647 err = errno & ~SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
648
649 switch (err) {
650 case ERR_NO_AVAIL_MRPC_THREAD:
651 msg = "No available MRPC handler thread"; break;
652 case ERR_HANDLER_THREAD_NOT_IDLE:
653 msg = "The handler thread is not idle"; break;
654 case ERR_NO_BG_THREAD:
655 msg = "No background thread run for the command"; break;
656
657 case ERR_REFCLK_SUBCMD_INVALID:
658 case ERR_STACKBIF_SUBCMD_INVALID:
659 case ERR_SUBCMD_INVALID: msg = "Invalid subcommand"; break;
660 case ERR_CMD_INVALID: msg = "Invalid command"; break;
661 case ERR_PARAM_INVALID: msg = "Invalid parameter"; break;
662 case ERR_BAD_FW_STATE: msg = "Bad firmware state"; break;
663 case ERR_MRPC_DENIED: msg = "MRPC request denied"; break;
664 case ERR_MRPC_NO_PREV_DATA:
665 msg = "No previous adaptation object data";
666 break;
667 case ERR_REFCLK_STACK_ID_INVALID:
668 case ERR_STACKBIF_STACK_ID_INVALID:
669 case ERR_STACK_INVALID: msg = "Invalid Stack"; break;
670 case ERR_LOOPBACK_PORT_INVALID:
671 case ERR_PORT_INVALID: msg = "Invalid Port"; break;
672 case ERR_EVENT_INVALID: msg = "Invalid Event"; break;
673 case ERR_RST_RULE_FAILED: msg = "Reset rule search failed"; break;
674 case ERR_UART_NOT_SUPPORTED:
675 msg = "UART interface not supported for this command"; break;
676 case ERR_XML_VERSION_MISMATCH:
677 msg = "XML version mismatch between MAIN and CFG partition";
678 break;
679 case ERR_ACCESS_REFUSED: msg = "Access Refused"; break;
680
681 case ERR_STACKBIF_CODE_INVALID:
682 msg = "Stack bifurcation code invalid"; break;
683 break;
684 case ERR_STACKBIF_PORT_BOUND:
685 msg = "Port already bound"; break;
686 break;
687
688 default: break;
689 }
690
691 switch (mrpc_error_cmd) {
692 case MRPC_PORTPARTP2P:
693 switch (err) {
694 case ERR_PHYC_PORT_ARDY_BIND:
695 msg = "Physical port already bound"; break;
696 case ERR_LOGC_PORT_ARDY_BIND:
697 msg = "Logical bridge instance already bound"; break;
698 case ERR_BIND_PRTT_NOT_EXIST:
699 msg = "Partition does not exist"; break;
700 case ERR_PHYC_PORT_NOT_EXIST:
701 msg = "Physical port does not exist"; break;
702 case ERR_PHYC_PORT_DIS:
703 msg = "Physical port disabled"; break;
704 case ERR_NO_LOGC_PORT:
705 msg = "No logical bridge instance"; break;
706 case ERR_BIND_IN_PROGRESS:
707 msg = "Bind/unbind in progress"; break;
708 case ERR_BIND_TGT_IS_USP:
709 msg = "Bind/unbind target is USP"; break;
710 case ERR_BIND_SUBCMD_INVALID:
711 msg = "Sub-command does not exist"; break;
712 case ERR_PHYC_PORT_LINK_ACT:
713 msg = "Physical port link active"; break;
714 case ERR_LOGC_PORT_NOT_BIND_PHYC_PORT:
715 msg = "Logical bridge not bind to physical port"; break;
716 case ERR_UNBIND_OPT_INVALID:
717 msg = "Invalid unbind option"; break;
718 case ERR_BIND_CHECK_FAIL:
719 msg = "Port bind checking failed"; break;
720 default: break;
721 }
722 break;
723 default: break;
724 }
725
726 return msg;
727}
728
736void switchtec_perror(const char *str)
737{
738 const char *msg = switchtec_strerror();
739 int is_mrpc = errno & SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
740 int err = errno & ~SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
741
742 if (is_mrpc)
743 fprintf(stderr, "%s: %s (MRPC: 0x%x, error: 0x%x)\n",
744 str, msg, mrpc_error_cmd, err);
745 else
746 fprintf(stderr, "%s: %s\n", str, msg);
747}
748
767int switchtec_echo(struct switchtec_dev *dev, uint32_t input,
768 uint32_t *output)
769{
770 return switchtec_cmd(dev, MRPC_ECHO, &input, sizeof(input),
771 output, sizeof(*output));
772}
773
783int switchtec_hard_reset(struct switchtec_dev *dev)
784{
785 uint32_t subcmd = 0;
786
787 return switchtec_cmd(dev, MRPC_RESET, &subcmd, sizeof(subcmd),
788 NULL, 0);
789}
790
795static void free_log_defs(struct log_defs *defs)
796{
797 int i, j;
798
799 if (!defs->module_defs)
800 return;
801
802 for (i = 0; i < defs->num_alloc; i++) {
803 free(defs->module_defs[i].mod_name);
804
805 for (j = 0; j < defs->module_defs[i].num_entries; j++)
806 free(defs->module_defs[i].entries[j]);
807
808 free(defs->module_defs[i].entries);
809 }
810
811 free(defs->module_defs);
812}
813
820static int realloc_log_defs(struct log_defs *defs, int num_modules)
821{
822 int i;
823
824 defs->module_defs = realloc(defs->module_defs,
825 (num_modules *
826 sizeof(struct module_log_defs)));
827 if (!defs->module_defs) {
828 free_log_defs(defs);
829 return -1;
830 }
831
832 for (i = defs->num_alloc; i < num_modules; i++)
833 memset(&defs->module_defs[i], 0,
834 sizeof(struct module_log_defs));
835
836 defs->num_alloc = num_modules;
837
838 return 0;
839}
840
847static bool parse_int(char *str, int *val)
848{
849 char *endptr;
850
851 errno = 0;
852 *val = strtol(str, &endptr, 0);
853
854 if ((endptr == str) || (*endptr != '\0') || (errno != 0))
855 return false;
856
857 return true;
858}
859
866static int read_app_log_defs(FILE *log_def_file, struct log_defs *defs)
867{
868 int ret;
869 char line[512];
870 char *tok;
871 int mod_id;
872 struct module_log_defs *mod_defs;
873 int num_entries;
874 int i;
875
876 /* allocate some log definition entries */
877 ret = realloc_log_defs(defs, 200);
878 if (ret < 0)
879 return ret;
880
881 while (fgets(line, sizeof(line), log_def_file)) {
882
883 /* ignore comments */
884 if (line[0] == '#')
885 continue;
886
887 /* strip any newline characters */
888 line[strcspn(line, "\r\n")] = '\0';
889
890 /*
891 * Tokenize and parse the line. Module headings are of the form:
892 * mod_name mod_id num_entries
893 */
894 tok = strtok(line, " \t");
895 if (!tok)
896 continue;
897
898 tok = strtok(NULL, " \t");
899 if (!tok)
900 continue;
901
902 if (!parse_int(tok, &mod_id)) {
903 errno = SWITCHTEC_ERR_LOG_DEF_DATA_INVAL;
904 goto err_free_log_defs;
905 }
906
907 /* reallocate more log definition entries if needed */
908 if (mod_id > defs->num_alloc) {
909 ret = realloc_log_defs(defs, mod_id * 2);
910 if (ret < 0)
911 return ret;
912 }
913
914 mod_defs = &defs->module_defs[mod_id];
915
916 tok = strtok(NULL, " \t");
917 if (!tok)
918 continue;
919
920 if (!parse_int(tok, &num_entries)) {
921 errno = SWITCHTEC_ERR_LOG_DEF_DATA_INVAL;
922 goto err_free_log_defs;
923 }
924
925 /*
926 * Skip this module if it has already been done. This can happen
927 * if the module is duplicated in the log definition file.
928 */
929 if (mod_defs->mod_name != NULL) {
930 for (i = 0; i < num_entries; i++) {
931 if (!fgets(line, sizeof(line),
932 log_def_file))
933 break;
934 }
935 continue;
936 }
937
938 mod_defs->mod_name = strdup(line);
939 mod_defs->num_entries = num_entries;
940 mod_defs->entries = calloc(mod_defs->num_entries,
941 sizeof(*mod_defs->entries));
942 if (!mod_defs->entries)
943 goto err_free_log_defs;
944
945 for (i = 0; i < mod_defs->num_entries; i++) {
946 if (fgets(line, sizeof(line), log_def_file) == NULL) {
947 errno = SWITCHTEC_ERR_LOG_DEF_READ_ERROR;
948 goto err_free_log_defs;
949 }
950
951 mod_defs->entries[i] = strdup(line);
952 if (!mod_defs->entries[i])
953 goto err_free_log_defs;
954 }
955 }
956
957 if (ferror(log_def_file)) {
958 errno = SWITCHTEC_ERR_LOG_DEF_READ_ERROR;
959 goto err_free_log_defs;
960 }
961
962 return 0;
963
964err_free_log_defs:
965 free_log_defs(defs);
966 return -1;
967}
968
975static int read_mailbox_log_defs(FILE *log_def_file, struct log_defs *defs)
976{
977 int ret;
978 char line[512];
979 struct module_log_defs *mod_defs;
980 int num_entries_alloc;
981
982 /*
983 * The mailbox log definitions don't keep track of modules. Allocate a
984 * single log definition entry for all definitions.
985 */
986 ret = realloc_log_defs(defs, 1);
987 if (ret < 0)
988 return ret;
989
990 mod_defs = &defs->module_defs[0];
991 mod_defs->num_entries = 0;
992
993 /* allocate some entries */
994 num_entries_alloc = 100;
995 mod_defs->entries = calloc(num_entries_alloc,
996 sizeof(*mod_defs->entries));
997 if (!mod_defs->entries)
998 goto err_free_log_defs;
999
1000 while (fgets(line, sizeof(line), log_def_file)) {
1001 /* ignore comments */
1002 if (line[0] == '#')
1003 continue;
1004
1005 if (mod_defs->num_entries >= num_entries_alloc) {
1006 /* allocate more entries */
1007 num_entries_alloc *= 2;
1008 mod_defs->entries = realloc(mod_defs->entries,
1009 (num_entries_alloc *
1010 sizeof(*mod_defs->entries)));
1011 if (!mod_defs->entries)
1012 goto err_free_log_defs;
1013 }
1014
1015 mod_defs->entries[mod_defs->num_entries] = strdup(line);
1016 if (!mod_defs->entries[mod_defs->num_entries])
1017 goto err_free_log_defs;
1018
1019 mod_defs->num_entries++;
1020 }
1021
1022 if (ferror(log_def_file)) {
1023 errno = SWITCHTEC_ERR_LOG_DEF_READ_ERROR;
1024 goto err_free_log_defs;
1025 }
1026
1027 return 0;
1028
1029err_free_log_defs:
1030 free_log_defs(defs);
1031 return -1;
1032}
1033
1045static int write_parsed_log(struct log_a_data log_data[],
1046 size_t count, int init_entry_idx,
1047 struct log_defs *defs,
1048 enum switchtec_log_parse_type log_type,
1049 FILE *log_file, int ts_factor)
1050{
1051 int i;
1052 int ret;
1053 int entry_idx = init_entry_idx;
1054 unsigned long long time;
1055 unsigned int nanos, micros, millis, secs, mins, hours, days;
1056 unsigned int entry_num;
1057 unsigned int mod_id;
1058 unsigned int log_sev = 0;
1059 const char *log_sev_strs[] = {"DISABLED", "HIGHEST", "HIGH", "MEDIUM",
1060 "LOW", "LOWEST"};
1061 bool is_bl1;
1062 struct module_log_defs *mod_defs;
1063
1064 if (entry_idx == 0) {
1065 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP)
1066 fputs(" #|Timestamp |Module |Severity |Event ID |Event\n",
1067 log_file);
1068 else
1069 fputs(" #|Timestamp |Source |Event ID |Event\n",
1070 log_file);
1071 }
1072
1073 for (i = 0; i < count; i ++) {
1074 /* timestamp is in the first 2 DWords */
1075 time = (((unsigned long long)log_data[i].data[0] << 32) |
1076 log_data[i].data[1]) * ts_factor/100;
1077 nanos = time % 1000;
1078 time /= 1000;
1079 micros = time % 1000;
1080 time /= 1000;
1081 millis = time % 1000;
1082 time /= 1000;
1083 secs = time % 60;
1084 time /= 60;
1085 mins = time % 60;
1086 time /= 60;
1087 hours = time % 24;
1088 days = time / 24;
1089
1090 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP) {
1091 /*
1092 * app log: module ID and log severity are in the 3rd
1093 * DWord
1094 */
1095 mod_id = (log_data[i].data[2] >> 16) & 0xFFF;
1096 log_sev = (log_data[i].data[2] >> 28) & 0xF;
1097
1098 if ((mod_id > defs->num_alloc) ||
1099 (defs->module_defs[mod_id].mod_name == NULL) ||
1100 (strlen(defs->module_defs[mod_id].mod_name) == 0)) {
1101 if (fprintf(log_file, "(Invalid module ID: 0x%x)\n",
1102 mod_id) < 0)
1103 goto ret_print_error;
1104 continue;
1105 }
1106
1107 if (log_sev >= ARRAY_SIZE(log_sev_strs)) {
1108 if (fprintf(log_file, "(Invalid log severity: %d)\n",
1109 log_sev) < 0)
1110 goto ret_print_error;
1111 continue;
1112 }
1113 } else {
1114 /*
1115 * mailbox log: BL1/BL2 indication is in the 3rd
1116 * DWord
1117 */
1118 is_bl1 = (((log_data[i].data[2] >> 27) & 1) == 0);
1119
1120 /* mailbox log definitions are all in the first entry */
1121 mod_id = 0;
1122 }
1123
1124 mod_defs = &defs->module_defs[mod_id];
1125
1126 /* entry number is in the 3rd DWord */
1127 entry_num = log_data[i].data[2] & 0x0000FFFF;
1128
1129 if (entry_num >= mod_defs->num_entries) {
1130 if (fprintf(log_file,
1131 "(Invalid log entry number: %d (module 0x%x))\n",
1132 entry_num, mod_id) < 0)
1133 goto ret_print_error;
1134 continue;
1135 }
1136
1137 /* print the entry index and timestamp */
1138 if (ts_factor == 0)
1139 ret = fprintf(log_file,
1140 "%04d|xxxd xx:xx:xx.xxx,xxx,xxx|",
1141 entry_idx);
1142 else
1143 ret = fprintf(log_file,
1144 "%04d|%03dd %02d:%02d:%02d.%03d,%03d,%03d|",
1145 entry_idx, days, hours, mins, secs,
1146 millis, micros, nanos);
1147
1148 if (ret < 0)
1149 goto ret_print_error;
1150
1151 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP) {
1152 /* print the module name and log severity */
1153 if (fprintf(log_file, "%-12s |%-8s |0x%04x |",
1154 mod_defs->mod_name, log_sev_strs[log_sev],
1155 entry_num) < 0)
1156 goto ret_print_error;
1157 } else {
1158 /* print the log source (BL1/BL2) */
1159 if (fprintf(log_file, "%-6s |0x%04x |",
1160 (is_bl1 ? "BL1" : "BL2"), entry_num) < 0)
1161 goto ret_print_error;
1162 }
1163
1164 /* print the log entry */
1165 if (fprintf(log_file, mod_defs->entries[entry_num],
1166 log_data[i].data[3], log_data[i].data[4],
1167 log_data[i].data[5], log_data[i].data[6],
1168 log_data[i].data[7]) < 0)
1169 goto ret_print_error;
1170
1171 entry_idx++;
1172 }
1173
1174 if (fflush(log_file) != 0)
1175 return -1;
1176
1177 return 0;
1178
1179ret_print_error:
1180 errno = SWITCHTEC_ERR_PARSED_LOG_WRITE_ERROR;
1181 return -1;
1182}
1183
1184static int parse_def_header(FILE *log_def_file, uint32_t *fw_version,
1185 uint32_t *sdk_version)
1186{
1187 char line[512];
1188 int i;
1189
1190 *fw_version = 0;
1191 *sdk_version = 0;
1192 while (fgets(line, sizeof(line), log_def_file)) {
1193 if (line[0] != '#')
1194 continue;
1195
1196 i = 0;
1197 while (line[i] == ' ' || line[i] == '#') i++;
1198
1199 if (strncasecmp(line + i, "SDK Version:", 12) == 0) {
1200 i += 12;
1201 while (line[i] == ' ') i++;
1202 sscanf(line + i, "%i", (int*)sdk_version);
1203 }
1204 else if (strncasecmp(line + i, "FW Version:", 11) == 0) {
1205 i += 11;
1206 while (line[i] == ' ') i++;
1207 sscanf(line + i, "%i", (int*)fw_version);
1208 }
1209 }
1210
1211 rewind(log_def_file);
1212 return 0;
1213}
1214
1215static int append_log_header(int fd, uint32_t sdk_version,
1216 uint32_t fw_version, int binary)
1217{
1218 int ret;
1219 struct log_header {
1220 uint8_t magic[8];
1221 uint32_t fw_version;
1222 uint32_t sdk_version;
1223 uint32_t flags;
1224 uint32_t rsvd[3];
1225 } header = {
1226 .magic = {'S', 'W', 'M', 'C', 'L', 'O', 'G', 'F'},
1227 .fw_version = fw_version,
1228 .sdk_version = sdk_version
1229 };
1230 char hdr_str_fmt[] = "#########################\n"
1231 "## FW version %08x\n"
1232 "## SDK version %08x\n"
1233 "#########################\n\n";
1234 char hdr_str[512];
1235
1236 if (binary) {
1237 ret = write(fd, &header, sizeof(header));
1238 } else {
1239 snprintf(hdr_str, 512, hdr_str_fmt, fw_version, sdk_version);
1240 ret = write(fd, hdr_str, strlen(hdr_str));
1241 }
1242
1243 return ret;
1244}
1245
1246static int get_ts_factor(enum switchtec_gen gen)
1247{
1248 if (gen == SWITCHTEC_GEN_UNKNOWN)
1249 return 0;
1250 else if (gen == SWITCHTEC_GEN3)
1251 return 1000;
1252 else
1253 return 833;
1254}
1255
1256static int log_a_to_file(struct switchtec_dev *dev, int sub_cmd_id,
1257 int fd, FILE *log_def_file,
1258 struct switchtec_log_file_info *info)
1259{
1260 int ret = -1;
1261 int read = 0;
1262 struct log_a_retr_result res;
1263 struct log_a_retr cmd = {
1264 .sub_cmd_id = sub_cmd_id,
1265 .start = -1,
1266 };
1267 struct log_defs defs = {
1268 .module_defs = NULL,
1269 .num_alloc = 0};
1270 FILE *log_file;
1271 int entry_idx = 0;
1272 uint32_t fw_version = 0;
1273 uint32_t sdk_version = 0;
1274
1275 if (log_def_file != NULL) {
1276 ret = parse_def_header(log_def_file, &fw_version,
1277 &sdk_version);
1278 if (ret)
1279 return ret;
1280 /* read the log definition file into defs */
1281 ret = read_app_log_defs(log_def_file, &defs);
1282 if (ret < 0)
1283 return ret;
1284 }
1285
1286 res.hdr.remain = 1;
1287
1288 while (res.hdr.remain) {
1289 ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
1290 &res, sizeof(res));
1291 if (ret)
1292 goto ret_free_log_defs;
1293 if (res.hdr.overflow && info)
1294 info->overflow = 1;
1295 if (read == 0) {
1296 if (dev->gen < SWITCHTEC_GEN5) {
1297 res.hdr.sdk_version = 0;
1298 res.hdr.fw_version = 0;
1299 }
1300
1301 if (info) {
1302 info->def_fw_version = fw_version;
1303 info->def_sdk_version = sdk_version;
1304 info->log_fw_version = res.hdr.fw_version;
1305 info->log_sdk_version = res.hdr.sdk_version;
1306 }
1307
1308 if (res.hdr.sdk_version != sdk_version ||
1309 res.hdr.fw_version != fw_version) {
1310 if (info && log_def_file)
1311 info->version_mismatch = true;
1312
1313 }
1314
1315 append_log_header(fd, res.hdr.sdk_version,
1316 res.hdr.fw_version,
1317 log_def_file == NULL? 1 : 0);
1318 }
1319
1320 if (log_def_file == NULL) {
1321 /* write the binary log data to a file */
1322 ret = write(fd, res.data,
1323 sizeof(*res.data) * res.hdr.count);
1324 if (ret < 0)
1325 return ret;
1326 } else {
1327 log_file = fdopen(fd, "w");
1328 if (!log_file)
1329 goto ret_free_log_defs;
1330
1331 /* parse the log data and write it to a file */
1332 ret = write_parsed_log(res.data, res.hdr.count,
1333 entry_idx, &defs,
1334 SWITCHTEC_LOG_PARSE_TYPE_APP,
1335 log_file,
1336 get_ts_factor(dev->gen));
1337 if (ret < 0)
1338 goto ret_free_log_defs;
1339
1340 entry_idx += res.hdr.count;
1341 }
1342
1343 read += le32toh(res.hdr.count);
1344 cmd.start = res.hdr.next_start;
1345 }
1346
1347 ret = 0;
1348
1349ret_free_log_defs:
1350 free_log_defs(&defs);
1351 return ret;
1352}
1353
1354static int log_b_to_file(struct switchtec_dev *dev, int sub_cmd_id, int fd)
1355{
1356 int ret;
1357 int read = 0;
1358 struct log_b_retr_result res;
1359 struct log_b_retr cmd = {
1360 .sub_cmd_id = sub_cmd_id,
1361 .offset = 0,
1362 .length = htole32(sizeof(res.data)),
1363 };
1364
1365 res.hdr.remain = sizeof(res.data);
1366
1367 while (res.hdr.remain) {
1368 ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
1369 &res, sizeof(res));
1370 if (ret)
1371 return -1;
1372
1373 ret = write(fd, res.data, res.hdr.length);
1374 if (ret < 0)
1375 return ret;
1376
1377 read += le32toh(res.hdr.length);
1378 cmd.offset = htole32(read);
1379 }
1380
1381 return 0;
1382}
1383
1384static int log_c_to_file(struct switchtec_dev *dev, int sub_cmd_id, int fd)
1385{
1386 int ret;
1387 struct log_cmd {
1388 uint8_t subcmd;
1389 uint8_t rsvd[3];
1390 } cmd = {};
1391
1392 struct log_reply {
1393 uint8_t reason;
1394 uint8_t rsvd[3];
1395 uint32_t nvlog_version;
1396 uint32_t thread_handle;
1397 uint32_t fw_version;
1398 uint32_t timestamp1;
1399 uint32_t timestamp2;
1400 } reply;
1401
1402 cmd.subcmd = sub_cmd_id;
1403
1404 ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
1405 &reply, sizeof(reply));
1406 if (ret)
1407 return -1;
1408
1409 ret = write(fd, &reply, sizeof(reply));
1410 if (ret < 0)
1411 return ret;
1412
1413 return 0;
1414}
1415
1416static int log_ram_flash_to_file(struct switchtec_dev *dev,
1417 int gen5_cmd, int gen4_cmd, int gen4_cmd_lgcy,
1418 int fd, FILE *log_def_file,
1419 struct switchtec_log_file_info *info)
1420{
1421 int ret;
1422
1423 if (switchtec_is_gen5(dev)) {
1424 return log_a_to_file(dev, gen5_cmd, fd, log_def_file,
1425 info);
1426 } else {
1427 ret = log_a_to_file(dev, gen4_cmd, fd, log_def_file,
1428 info);
1429
1430 /* somehow hardware returns ERR_LOGC_PORT_ARDY_BIND
1431 * instead of ERR_SUBCMD_INVALID if this subcommand
1432 * is not supported, so we fall back to legacy
1433 * subcommand on ERR_LOGC_PORT_ARDY_BIND error as well
1434 */
1435 if (ret > 0 &&
1436 (ERRNO_MRPC(errno) == ERR_LOGC_PORT_ARDY_BIND ||
1437 ERRNO_MRPC(errno) == ERR_SUBCMD_INVALID))
1438 ret = log_a_to_file(dev, gen4_cmd_lgcy, fd,
1439 log_def_file, info);
1440
1441 return ret;
1442 }
1443}
1444
1454int switchtec_log_to_file(struct switchtec_dev *dev,
1455 enum switchtec_log_type type, int fd, FILE *log_def_file,
1456 struct switchtec_log_file_info *info)
1457{
1458 if (info)
1459 memset(info, 0, sizeof(*info));
1460
1461 switch (type) {
1462 case SWITCHTEC_LOG_RAM:
1463 return log_ram_flash_to_file(dev,
1464 MRPC_FWLOGRD_RAM_GEN5,
1465 MRPC_FWLOGRD_RAM_WITH_FLAG,
1466 MRPC_FWLOGRD_RAM,
1467 fd, log_def_file, info);
1468 case SWITCHTEC_LOG_FLASH:
1469 return log_ram_flash_to_file(dev,
1470 MRPC_FWLOGRD_FLASH_GEN5,
1471 MRPC_FWLOGRD_FLASH_WITH_FLAG,
1472 MRPC_FWLOGRD_FLASH,
1473 fd, log_def_file, info);
1474 case SWITCHTEC_LOG_MEMLOG:
1475 return log_b_to_file(dev, MRPC_FWLOGRD_MEMLOG, fd);
1476 case SWITCHTEC_LOG_REGS:
1477 return log_b_to_file(dev, MRPC_FWLOGRD_REGS, fd);
1478 case SWITCHTEC_LOG_THRD_STACK:
1479 return log_b_to_file(dev, MRPC_FWLOGRD_THRD_STACK, fd);
1480 case SWITCHTEC_LOG_SYS_STACK:
1481 return log_b_to_file(dev, MRPC_FWLOGRD_SYS_STACK, fd);
1482 case SWITCHTEC_LOG_THRD:
1483 return log_b_to_file(dev, MRPC_FWLOGRD_THRD, fd);
1484 case SWITCHTEC_LOG_NVHDR:
1485 return log_c_to_file(dev, MRPC_FWLOGRD_NVHDR, fd);
1486 };
1487
1488 errno = EINVAL;
1489 return -errno;
1490}
1491
1492static int parse_log_header(FILE *bin_log_file, uint32_t *fw_version,
1493 uint32_t *sdk_version)
1494{
1495 struct log_header {
1496 uint8_t magic[8];
1497 uint32_t fw_version;
1498 uint32_t sdk_version;
1499 uint32_t flags;
1500 uint32_t rsvd[3];
1501 } header;
1502
1503 char sig[8] = {'S', 'W', 'M', 'C', 'L', 'O', 'G', 'F'};
1504 int ret;
1505
1506 ret = fread(&header, sizeof(header), 1, bin_log_file);
1507 if (ret <= 0) {
1508 errno = EBADF;
1509 return -EBADF;
1510 }
1511
1512 if (memcmp(sig, header.magic, 8)) {
1513 rewind(bin_log_file);
1514 *fw_version = 0;
1515 *sdk_version = 0;
1516 return 0;
1517 }
1518
1519 *fw_version = header.fw_version;
1520 *sdk_version = header.sdk_version;
1521
1522 return 0;
1523}
1524
1535int switchtec_parse_log(FILE *bin_log_file, FILE *log_def_file,
1536 FILE *parsed_log_file,
1537 enum switchtec_log_parse_type log_type,
1538 enum switchtec_gen gen,
1539 struct switchtec_log_file_info *info)
1540{
1541 int ret;
1542 struct log_a_data log_data;
1543 struct log_defs defs = {
1544 .module_defs = NULL,
1545 .num_alloc = 0};
1546 int entry_idx = 0;
1547 uint32_t fw_version_log;
1548 uint32_t sdk_version_log;
1549 uint32_t fw_version_def;
1550 uint32_t sdk_version_def;
1551 enum switchtec_gen gen_file;
1552
1553 if (info)
1554 memset(info, 0, sizeof(*info));
1555
1556 if ((log_type != SWITCHTEC_LOG_PARSE_TYPE_APP) &&
1557 (log_type != SWITCHTEC_LOG_PARSE_TYPE_MAILBOX)) {
1558 errno = EINVAL;
1559 return -errno;
1560 }
1561
1562 ret = parse_log_header(bin_log_file, &fw_version_log,
1563 &sdk_version_log);
1564 if (ret)
1565 return ret;
1566 ret = parse_def_header(log_def_file, &fw_version_def,
1567 &sdk_version_def);
1568 if (ret)
1569 return ret;
1570
1571 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_MAILBOX) {
1572 fw_version_log = fw_version_def;
1573 sdk_version_log = sdk_version_def;
1574 }
1575
1576 if (info) {
1577 info->def_fw_version = fw_version_def;
1578 info->def_sdk_version = sdk_version_def;
1579
1580 info->log_fw_version = fw_version_log;
1581 info->log_sdk_version = sdk_version_log;
1582 }
1583 /* read the log definition file into defs */
1584 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP)
1585 ret = read_app_log_defs(log_def_file, &defs);
1586 else
1587 ret = read_mailbox_log_defs(log_def_file, &defs);
1588
1589 ret = append_log_header(fileno(parsed_log_file), sdk_version_log,
1590 fw_version_log, 0);
1591 if (ret < 0)
1592 return ret;
1593
1594 /* parse each log entry */
1595 while (fread(&log_data, sizeof(struct log_a_data), 1,
1596 bin_log_file) == 1) {
1597 if(fw_version_log)
1598 gen_file = switchtec_fw_version_to_gen(fw_version_log);
1599 else
1600 gen_file = switchtec_fw_version_to_gen(fw_version_def);
1601
1602 if (gen_file != SWITCHTEC_GEN_UNKNOWN &&
1603 gen != SWITCHTEC_GEN_UNKNOWN) {
1604 if (info)
1605 info->gen_ignored = true;
1606 } else if (gen_file == SWITCHTEC_GEN_UNKNOWN &&
1607 gen == SWITCHTEC_GEN_UNKNOWN) {
1608 if (info)
1609 info->gen_unknown = true;
1610 } else if (gen != SWITCHTEC_GEN_UNKNOWN) {
1611 gen_file = gen;
1612 }
1613
1614 ret = write_parsed_log(&log_data, 1, entry_idx, &defs,
1615 log_type, parsed_log_file,
1616 get_ts_factor(gen_file));
1617 if (ret < 0)
1618 goto ret_free_log_defs;
1619
1620 entry_idx++;
1621 }
1622
1623 if (ferror(bin_log_file)) {
1624 errno = SWITCHTEC_ERR_BIN_LOG_READ_ERROR;
1625 ret = -1;
1626 }
1627
1628 if (fw_version_def != fw_version_log ||
1629 sdk_version_def != sdk_version_log) {
1630 if (info)
1631 info->version_mismatch = true;
1632 ret = ENOEXEC;
1633 }
1634
1635ret_free_log_defs:
1636 free_log_defs(&defs);
1637 return ret;
1638}
1639
1647int switchtec_log_def_to_file(struct switchtec_dev *dev,
1648 enum switchtec_log_def_type type,
1649 FILE* file)
1650{
1651 int ret;
1652 struct log_cmd {
1653 uint8_t subcmd;
1654 uint8_t rsvd[3];
1655 uint16_t idx;
1656 uint16_t mod_id;
1657 } cmd = {};
1658
1659 struct log_reply {
1660 uint16_t end_of_data;
1661 uint16_t data_len;
1662 uint16_t next_idx;
1663 uint16_t next_mod_id;
1664 uint8_t data[MRPC_MAX_DATA_LEN - 16];
1665 } reply = {};
1666
1667 switch (type) {
1668 case SWITCHTEC_LOG_DEF_TYPE_APP:
1669 cmd.subcmd = MRPC_LOG_DEF_APP;
1670 break;
1671
1672 case SWITCHTEC_LOG_DEF_TYPE_MAILBOX:
1673 cmd.subcmd = MRPC_LOG_DEF_MAILBOX;
1674 break;
1675
1676 default:
1677 errno = EINVAL;
1678 return -errno;
1679 }
1680
1681 do {
1682 ret = switchtec_cmd(dev, MRPC_LOG_DEF_GET, &cmd, sizeof(cmd),
1683 &reply, sizeof(reply));
1684 if (ret)
1685 return -1;
1686
1687 ret = fwrite(reply.data, reply.data_len, 1, file);
1688 if (ret < 0)
1689 return ret;
1690
1691 cmd.idx = reply.next_idx;
1692 cmd.mod_id = reply.next_mod_id;
1693 } while (!reply.end_of_data);
1694
1695 return 0;
1696}
1697
1698static enum switchtec_gen map_to_gen(uint32_t gen)
1699{
1700 enum switchtec_gen ret = SWITCHTEC_GEN_UNKNOWN;
1701
1702 switch (gen) {
1703 case 0:
1704 ret = SWITCHTEC_GEN4;
1705 break;
1706 case 1:
1707 ret = SWITCHTEC_GEN5;
1708 break;
1709 default:
1710 ret = SWITCHTEC_GEN_UNKNOWN;
1711 break;
1712 }
1713
1714 return ret;
1715}
1716
1725int switchtec_get_device_info(struct switchtec_dev *dev,
1726 enum switchtec_boot_phase *phase,
1727 enum switchtec_gen *gen,
1728 enum switchtec_rev *rev)
1729{
1730 int ret;
1731 uint32_t ping_dw = 0;
1732 uint32_t dev_info;
1733 struct get_dev_info_reply {
1734 uint32_t dev_info;
1735 uint32_t ping_reply;
1736 } reply;
1737
1738 ping_dw = time(NULL);
1739
1740 /*
1741 * The I2C TWI Ping command also dumps information about the
1742 * revision and image phase.
1743 */
1744 ret = switchtec_cmd(dev, MRPC_I2C_TWI_PING, &ping_dw,
1745 sizeof(ping_dw),
1746 &reply, sizeof(reply));
1747 if (ret == 0) {
1748 if (ping_dw != ~reply.ping_reply)
1749 return -1;
1750
1751 dev_info = le32toh(reply.dev_info);
1752 if (phase)
1753 *phase = dev_info & 0xff;
1754 if (rev)
1755 *rev = (dev_info >> 8) & 0x0f;
1756 if (gen)
1757 *gen = map_to_gen((dev_info >> 12) & 0x0f);
1758 } else if (errno == EBADMSG || ERRNO_MRPC(errno) == ERR_CMD_INVALID) {
1759 if (phase)
1760 *phase = SWITCHTEC_BOOT_PHASE_FW;
1761 if (gen)
1762 *gen = SWITCHTEC_GEN3;
1763 if (rev)
1764 *rev = SWITCHTEC_REV_UNKNOWN;
1765
1766 errno = 0;
1767 } else {
1768 return -1;
1769 }
1770
1771 return 0;
1772}
1773
1780float switchtec_die_temp(struct switchtec_dev *dev)
1781{
1782 int ret;
1783 uint32_t sub_cmd_id;
1784 uint32_t temp;
1785
1786 if (switchtec_is_gen3(dev)) {
1787 sub_cmd_id = MRPC_DIETEMP_SET_MEAS;
1788 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1789 sizeof(sub_cmd_id), NULL, 0);
1790 if (ret)
1791 return -100.0;
1792
1793 sub_cmd_id = MRPC_DIETEMP_GET;
1794 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1795 sizeof(sub_cmd_id), &temp, sizeof(temp));
1796 if (ret)
1797 return -100.0;
1798 } else {
1799 sub_cmd_id = MRPC_DIETEMP_GET_GEN4;
1800 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1801 sizeof(sub_cmd_id), &temp, sizeof(temp));
1802 if (ret)
1803 return -100.0;
1804 }
1805
1806 return le32toh(temp) / 100.;
1807}
1808
1809int switchtec_bind_info(struct switchtec_dev *dev,
1810 struct switchtec_bind_status_out *status, int phy_port)
1811{
1812 struct switchtec_bind_status_in sub_cmd_id = {
1813 .sub_cmd = MRPC_PORT_INFO,
1814 .phys_port_id = phy_port
1815 };
1816
1817 return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
1818 sizeof(sub_cmd_id), status, sizeof(*status));
1819}
1820
1821int switchtec_bind(struct switchtec_dev *dev, int par_id, int log_port,
1822 int phy_port)
1823{
1824 uint32_t output;
1825
1826 struct switchtec_bind_in sub_cmd_id = {
1827 .sub_cmd = MRPC_PORT_BIND,
1828 .par_id = par_id,
1829 .log_port_id = log_port,
1830 .phys_port_id = phy_port
1831 };
1832
1833 return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
1834 sizeof(sub_cmd_id), &output, sizeof(output));
1835}
1836
1837int switchtec_unbind(struct switchtec_dev *dev, int par_id, int log_port)
1838{
1839 uint32_t output;
1840
1841 struct switchtec_unbind_in sub_cmd_id = {
1842 .sub_cmd = MRPC_PORT_UNBIND,
1843 .par_id = par_id,
1844 .log_port_id = log_port,
1845 .opt = 2
1846 };
1847
1848 return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
1849 sizeof(sub_cmd_id), &output, sizeof(output));
1850}
1851
1852static int __switchtec_calc_lane_id(struct switchtec_status *port, int lane_id)
1853{
1854 int lane;
1855
1856 if (lane_id >= port->neg_lnk_width) {
1857 errno = SWITCHTEC_ERR_INVALID_LANE;
1858 return -1;
1859 }
1860
1861 lane = port->port.phys_id * 2;
1862 if (!port->lane_reversal)
1863 lane += lane_id;
1864 else
1865 lane += port->cfg_lnk_width - 1 - lane_id;
1866
1867 switch (port->port.phys_id) {
1868 /* Trident (Gen4) - Ports 48 to 51 maps to 96 to 99 */
1869 case 48: return 96;
1870 case 49: return 97;
1871 case 50: return 98;
1872 case 51: return 99;
1873 /* Hrapoon (Gen5) - Ports 56 to 59 maps to 96 to 99 */
1874 case 56: return 96;
1875 case 57: return 97;
1876 case 58: return 98;
1877 case 59: return 99;
1878 default: return lane;
1879 }
1880}
1881
1890int switchtec_calc_lane_id(struct switchtec_dev *dev, int phys_port_id,
1891 int lane_id, struct switchtec_status *port)
1892{
1893 struct switchtec_status *status;
1894 int ports, i;
1895 int rc = 0;
1896
1897 ports = switchtec_status(dev, &status);
1898 if (ports < 0)
1899 return ports;
1900
1901 for (i = 0; i < ports; i++)
1902 if (status[i].port.phys_id == phys_port_id)
1903 break;
1904
1905 if (i == ports) {
1906 errno = SWITCHTEC_ERR_INVALID_PORT;
1907 rc = -1;
1908 goto out;
1909 }
1910
1911 if (port)
1912 *port = status[i];
1913
1914 rc = __switchtec_calc_lane_id(&status[i], lane_id);
1915
1916out:
1917 switchtec_status_free(status, ports);
1918 return rc;
1919}
1920
1930int switchtec_calc_port_lane(struct switchtec_dev *dev, int lane_id,
1931 int *phys_port_id, int *port_lane_id,
1932 struct switchtec_status *port)
1933{
1934 struct switchtec_status *status;
1935 int ports, i, p, lane;
1936 int rc = 0;
1937
1938 ports = switchtec_status(dev, &status);
1939 if (ports < 0)
1940 return ports;
1941
1942 if (lane_id >= 96) {
1943 if (dev->gen < SWITCHTEC_GEN5)
1944 p = lane_id - 96 + 48;
1945 else
1946 p = lane_id - 96 + 56;
1947
1948 for (i = 0; i < ports; i++)
1949 if (status[i].port.phys_id == p)
1950 break;
1951 } else {
1952 for (i = 0; i < ports; i++) {
1953 p = status[i].port.phys_id * 2;
1954 if (lane_id >= p && lane_id < p + status[i].cfg_lnk_width)
1955 break;
1956 }
1957 }
1958
1959 if (i == ports) {
1960 errno = SWITCHTEC_ERR_INVALID_PORT;
1961 rc = -1;
1962 goto out;
1963 }
1964
1965 if (port)
1966 *port = status[i];
1967
1968 if (phys_port_id)
1969 *phys_port_id = status[i].port.phys_id;
1970
1971 lane = lane_id - status[i].port.phys_id * 2;
1972 if (port->lane_reversal)
1973 lane = status[i].cfg_lnk_width - 1 - lane;
1974
1975 if (port_lane_id)
1976 *port_lane_id = lane;
1977
1978out:
1979 switchtec_status_free(status, ports);
1980 return rc;
1981}
1982
1994int switchtec_calc_lane_mask(struct switchtec_dev *dev, int phys_port_id,
1995 int lane_id, int num_lanes, int *lane_mask,
1996 struct switchtec_status *port)
1997{
1998 struct switchtec_status *status;
1999 int ports, i, l, lane;
2000 int rc = 0;
2001
2002 ports = switchtec_status(dev, &status);
2003 if (ports < 0)
2004 return ports;
2005
2006 for (i = 0; i < ports; i++)
2007 if (status[i].port.phys_id == phys_port_id)
2008 break;
2009
2010 if (i == ports) {
2011 errno = SWITCHTEC_ERR_INVALID_PORT;
2012 rc = -1;
2013 goto out;
2014 }
2015
2016 if (port)
2017 *port = status[i];
2018
2019 for (l = lane_id; l < lane_id + num_lanes; l++) {
2020 lane = __switchtec_calc_lane_id(&status[i], l);
2021 if (lane < 0) {
2022 rc = -1;
2023 goto out;
2024 }
2025
2026 lane_mask[lane >> 5] |= 1 << (lane & 0x1F);
2027 }
2028
2029out:
2030 switchtec_status_free(status, ports);
2031 return rc;
2032}
2033
2041bool switchtec_stack_bif_port_valid(struct switchtec_dev *dev, int stack_id,
2042 int port_id)
2043{
2044 if (dev->gen == SWITCHTEC_GEN4)
2045 return stack_id * 8 + port_id < 52;
2046
2047 return true;
2048}
2049
2057int switchtec_stack_bif_width(struct switchtec_dev *dev, int stack_id,
2058 int port_bif)
2059{
2060 if (!port_bif)
2061 return 1;
2062
2063 if (port_bif != 1 && port_bif != 2 && port_bif != 4 && port_bif != 8 &&
2064 port_bif != 16) {
2065 errno = -EINVAL;
2066 return -1;
2067 }
2068
2069 if (dev->gen == SWITCHTEC_GEN4 && stack_id == 6)
2070 return port_bif;
2071 else
2072 return (port_bif + 1) / 2;
2073}
2074
2082int switchtec_get_stack_bif(struct switchtec_dev *dev, int stack_id,
2083 int port_bif[SWITCHTEC_PORTS_PER_STACK])
2084{
2085 struct switchtec_stackbif out, in = {
2086 .sub_cmd = MRPC_STACKBIF_GET,
2087 .stack_id = stack_id,
2088 };
2089 int ret, i;
2090
2091 ret = switchtec_cmd(dev, MRPC_STACKBIF, &in, sizeof(in), &out,
2092 sizeof(out));
2093 if (ret)
2094 return ret;
2095
2096 for (i = 0; i < SWITCHTEC_PORTS_PER_STACK; i++) {
2097 if (!switchtec_stack_bif_port_valid(dev, stack_id, i)) {
2098 port_bif[i] = -1;
2099 continue;
2100 }
2101
2102 switch (out.code & 0xF) {
2103 case 0x0: port_bif[i] = 0; break;
2104 case 0x1: port_bif[i] = 2; break;
2105 case 0x2: port_bif[i] = 4; break;
2106 case 0x4: port_bif[i] = 8; break;
2107 case 0x8: port_bif[i] = 16; break;
2108 case 0xf: port_bif[i] = 1; break;
2109 default:
2110 errno = -EPROTO;
2111 return -1;
2112 }
2113 out.code >>= 4;
2114 }
2115
2116 return 0;
2117}
2118
2126int switchtec_set_stack_bif(struct switchtec_dev *dev, int stack_id,
2127 int port_bif[SWITCHTEC_PORTS_PER_STACK])
2128{
2129 struct switchtec_stackbif out, in = {
2130 .sub_cmd = MRPC_STACKBIF_SET,
2131 .stack_id = stack_id,
2132 };
2133 int i;
2134
2135 for (i = 0; i < SWITCHTEC_PORTS_PER_STACK; i++) {
2136 switch (port_bif[i]) {
2137 case 0: in.code |= 0x0 << (i * 4); break;
2138 case 1: in.code |= 0xf << (i * 4); break;
2139 case 2: in.code |= 0x1 << (i * 4); break;
2140 case 4: in.code |= 0x2 << (i * 4); break;
2141 case 8: in.code |= 0x4 << (i * 4); break;
2142 case 16: in.code |= 0x8 << (i * 4); break;
2143 default:
2144 errno = -EINVAL;
2145 return -1;
2146 }
2147 }
2148
2149 return switchtec_cmd(dev, MRPC_STACKBIF, &in, sizeof(in), &out,
2150 sizeof(out));
2151}
2152
struct switchtec_dev * switchtec_open(const char *device)
Open a Switchtec device by string.
Definition: switchtec.c:256
void switchtec_list_free(struct switchtec_device_info *devlist)
Free a list of device info structures allocated by switchtec_list()
Definition: switchtec.c:234
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:736
int mrpc_error_cmd
The MRPC command ID when errno is set.
Definition: switchtec.c:601
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:574
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:389
const char * switchtec_strerror(void)
Return a message coresponding to the last error.
Definition: switchtec.c:613
static const struct switchtec_device_id switchtec_device_id_tbl[]
Supported Switchtec device id table.
Definition: switchtec.c:89
struct switchtec_dev * switchtec_open_eth(const char *ip, const int inst)
Open a switchtec device over ethernet.
_PURE int switchtec_partition(struct switchtec_dev *dev)
Get the partiton number of the device that was opened.
Definition: switchtec.c:399
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:393
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:2057
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:1994
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:1454
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:975
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:1535
float switchtec_die_temp(struct switchtec_dev *dev)
Get the die temperature of the switchtec device.
Definition: switchtec.c:1780
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:2082
static void free_log_defs(struct log_defs *defs)
Free log definition data.
Definition: switchtec.c:795
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:2041
int switchtec_hard_reset(struct switchtec_dev *dev)
Perform an MRPC hard reset command.
Definition: switchtec.c:783
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:1647
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:1725
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:866
static int realloc_log_defs(struct log_defs *defs, int num_modules)
Allocate / reallocate log definition data.
Definition: switchtec.c:820
int switchtec_echo(struct switchtec_dev *dev, uint32_t input, uint32_t *output)
Perform an MRPC echo command.
Definition: switchtec.c:767
static bool parse_int(char *str, int *val)
Parse an integer from a string.
Definition: switchtec.c:847
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:2126
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:1890
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:1930
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:1045
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