Switchtec Userspace PROJECT_NUMBER = 4.2
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
29
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
59
64 char *mod_name;
65 char **entries;
67};
68
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_PFXA}, //PFX-A 100XG5
166 {0x5384, SWITCHTEC_GEN5, SWITCHTEC_PFXA}, //PFX-A 84XG5
167 {0x5368, SWITCHTEC_GEN5, SWITCHTEC_PFXA}, //PFX-A 68XG5
168 {0x5352, SWITCHTEC_GEN5, SWITCHTEC_PFXA}, //PFX-A 52XG5
169 {0x5336, SWITCHTEC_GEN5, SWITCHTEC_PFXA}, //PFX-A 36XG5
170 {0x5328, SWITCHTEC_GEN5, SWITCHTEC_PFXA}, //PFX-A 28XG5
171 {0x5400, SWITCHTEC_GEN5, SWITCHTEC_PSXA}, //PSX-A 100XG5
172 {0x5484, SWITCHTEC_GEN5, SWITCHTEC_PSXA}, //PSX-A 84XG5
173 {0x5468, SWITCHTEC_GEN5, SWITCHTEC_PSXA}, //PSX-A 68XG5
174 {0x5452, SWITCHTEC_GEN5, SWITCHTEC_PSXA}, //PSX-A 52XG5
175 {0x5436, SWITCHTEC_GEN5, SWITCHTEC_PSXA}, //PSX-A 36XG5
176 {0x5428, SWITCHTEC_GEN5, SWITCHTEC_PSXA}, //PSX-A 28XG5
177 {0x5500, SWITCHTEC_GEN5, SWITCHTEC_PAXA}, //PAX-A 100XG5
178 {0x5584, SWITCHTEC_GEN5, SWITCHTEC_PAXA}, //PAX-A 84XG5
179 {0x5568, SWITCHTEC_GEN5, SWITCHTEC_PAXA}, //PAX-A 68XG5
180 {0x5552, SWITCHTEC_GEN5, SWITCHTEC_PAXA}, //PAX-A 52XG5
181 {0x5536, SWITCHTEC_GEN5, SWITCHTEC_PAXA}, //PAX-A 36XG5
182 {0x5528, SWITCHTEC_GEN5, SWITCHTEC_PAXA}, //PAX-A 28XG5
183 {0},
184};
185
186static int set_gen_variant(struct switchtec_dev * dev)
187{
189 int ret;
190
191 dev->boot_phase = SWITCHTEC_BOOT_PHASE_FW;
192 dev->gen = SWITCHTEC_GEN_UNKNOWN;
193 dev->var = SWITCHTEC_VAR_UNKNOWN;
194 dev->device_id = dev->ops->get_device_id(dev);
195 if (!dev->device_id)
196 switchtec_get_device_id_bl2(dev,
197 (unsigned short *)&dev->device_id);
198
199 while (id->device_id) {
200 if (id->device_id == dev->device_id) {
201 dev->gen = id->gen;
202 dev->var = id->var;
203
204 break;
205 }
206
207 id++;
208 }
209
210 dev->pax_id = SWITCHTEC_PAX_ID_LOCAL;
211 ret = switchtec_get_device_info(dev, &dev->boot_phase, &dev->gen, NULL);
212 if (ret)
213 return -1;
214
215 return 0;
216}
217
218static int set_local_pax_id(struct switchtec_dev *dev)
219{
220 unsigned char local_pax_id;
221 int ret;
222
223 dev->local_pax_id = -1;
224
225 if (!switchtec_is_pax_all(dev))
226 return 0;
227
228 ret = switchtec_cmd(dev, MRPC_GET_PAX_ID, NULL, 0,
229 &local_pax_id, sizeof(local_pax_id));
230 if (ret)
231 return -1;
232
233 dev->local_pax_id = local_pax_id;
234 return 0;
235}
236
242{
243 free(devlist);
244}
245
263struct switchtec_dev *switchtec_open(const char *device)
264{
265 int idx;
266 int domain = 0;
267 int bus, dev, func;
268 char path[PATH_MAX];
269 int inst;
270 char *endptr;
271 struct switchtec_dev *ret;
272
273 if (sscanf(device, "%i@%i", &bus, &dev) == 2) {
274 ret = switchtec_open_i2c_by_adapter(bus, dev);
275 goto found;
276 }
277
278 if (sscanf(device, "%2049[^@]@%i", path, &dev) == 2) {
279 ret = switchtec_open_i2c(path, dev);
280 goto found;
281 }
282
283 if (device[0] == '/' &&
284 sscanf(device, "%2049[^:]:%i", path, &dev) == 2) {
285 ret = switchtec_open_i2c(path, dev);
286 goto found;
287 }
288
289 if (strchr(device, '/') || strchr(device, '\\')) {
290 ret = switchtec_open_by_path(device);
291 goto found;
292 }
293
294 if (sscanf(device, "%x:%x.%x", &bus, &dev, &func) == 3) {
295 ret = switchtec_open_by_pci_addr(domain, bus, dev, func);
296 goto found;
297 }
298
299 if (sscanf(device, "%x:%x:%x.%x", &domain, &bus, &dev, &func) == 4) {
300 ret = switchtec_open_by_pci_addr(domain, bus, dev, func);
301 goto found;
302 }
303
304 if (sscanf(device, "%2049[^:]:%i", path, &inst) == 2) {
305 ret = switchtec_open_eth(path, inst);
306 goto found;
307 }
308
309 errno = 0;
310 idx = strtol(device, &endptr, 0);
311 if (!errno && endptr != device) {
312 ret = switchtec_open_by_index(idx);
313 goto found;
314 }
315
316 if (sscanf(device, "switchtec%d", &idx) == 1) {
317 ret = switchtec_open_by_index(idx);
318 goto found;
319 }
320
321 errno = ENODEV;
322 return NULL;
323
324found:
325 if (!ret) {
326 errno = ENODEV;
327 return NULL;
328 }
329
330 snprintf(ret->name, sizeof(ret->name), "%s", device);
331
332 if (set_gen_variant(ret))
333 return NULL;
334
335 if (set_local_pax_id(ret))
336 return NULL;
337
338 return ret;
339}
340
348_PURE int switchtec_device_id(struct switchtec_dev *dev)
349{
350 return dev->device_id;
351}
352
360_PURE enum switchtec_gen switchtec_gen(struct switchtec_dev *dev)
361{
362 return dev->gen;
363}
364
372_PURE enum switchtec_variant switchtec_variant(struct switchtec_dev *dev)
373{
374 return dev->var;
375}
376
384_PURE enum switchtec_boot_phase switchtec_boot_phase(struct switchtec_dev *dev)
385{
386 return dev->boot_phase;
387}
388
396_PURE const char *switchtec_name(struct switchtec_dev *dev)
397{
398 return dev->name;
399}
400
406_PURE int switchtec_partition(struct switchtec_dev *dev)
407{
408 return dev->partition;
409}
410
411int switchtec_set_pax_id(struct switchtec_dev *dev, int pax_id)
412{
413 if (!switchtec_is_pax_all(dev) && (pax_id != SWITCHTEC_PAX_ID_LOCAL))
414 return -1;
415
416 if (pax_id == SWITCHTEC_PAX_ID_LOCAL)
417 dev->pax_id = dev->local_pax_id;
418 else
419 dev->pax_id = pax_id;
420
421 return 0;
422}
423
424static int compare_port_id(const void *aa, const void *bb)
425{
426 const struct switchtec_port_id *a = aa, *b = bb;
427
428 if (a->partition != b->partition)
429 return a->partition - b->partition;
430 if (a->upstream != b->upstream)
431 return b->upstream - a->upstream;
432 return a->log_id - b->log_id;
433}
434
435static int compare_status(const void *aa, const void *bb)
436{
437 const struct switchtec_status *a = aa, *b = bb;
438
439 return compare_port_id(&a->port, &b->port);
440}
441
442static const char *lane_reversal_str(int link_up,
443 int lane_reversal)
444{
445 if (!link_up)
446 return "N/A";
447
448 switch(lane_reversal) {
449 case 0: return "Normal Lane Ordering";
450 case 1: return "x16 (Full) Lane Reversal";
451 case 2: return "x2 Lane Reversal";
452 case 4: return "x4 Lane Reversal";
453 case 8: return "x8 Lane Reversal";
454 default: return "Unknown Lane Ordering";
455 }
456}
457
458static void generate_lane_str(struct switchtec_status *s)
459{
460 int i, l;
461
462 for (i = 0; i < s->cfg_lnk_width; i++)
463 s->lanes[i] = 'x';
464
465 if (!s->link_up)
466 return;
467
468 l = s->first_act_lane;
469 if (!l && s->lane_reversal)
470 l += s->neg_lnk_width - 1;
471
472 for (i = 0; i < s->neg_lnk_width; i++) {
473 if (l < 0)
474 break;
475
476 if (i < 10)
477 s->lanes[l] = '0' + i;
478 else
479 s->lanes[l] = 'a' + i - 10;
480
481 l += s->lane_reversal ? -1 : 1;
482 }
483}
484
496int switchtec_status(struct switchtec_dev *dev,
497 struct switchtec_status **status)
498{
499 uint64_t port_bitmap = 0;
500 int ret;
501 int i, p;
502 int nr_ports = 0;
503 struct switchtec_status *s;
504 int max_ports;
505
506 if (!status) {
507 errno = EINVAL;
508 return -errno;
509 }
510
511 max_ports = switchtec_max_supported_ports(dev);
512
513 struct {
514 uint8_t phys_port_id;
515 uint8_t par_id;
516 uint8_t log_port_id;
517 uint8_t stk_id;
518 uint8_t cfg_lnk_width;
519 uint8_t neg_lnk_width;
520 uint8_t usp_flag;
521 uint8_t linkup_linkrate;
522 uint16_t LTSSM;
523 uint8_t lane_reversal;
524 uint8_t first_act_lane;
525 } ports[max_ports];
526
527 ret = switchtec_cmd(dev, MRPC_LNKSTAT, &port_bitmap, sizeof(port_bitmap),
528 ports, sizeof(ports));
529 if (ret)
530 return -1;
531
532
533 for (i = 0; i < max_ports; i++) {
534 if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS)
535 continue;
536 nr_ports++;
537 }
538
539 s = *status = calloc(nr_ports, sizeof(*s));
540 if (!s)
541 return -ENOMEM;
542
543 for (i = 0, p = 0; i < max_ports && p < nr_ports; i++) {
544 if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS)
545 continue;
546
547 s[p].port.partition = ports[i].par_id;
548 s[p].port.stack = ports[i].stk_id >> 4;
549 s[p].port.upstream = ports[i].usp_flag;
550 s[p].port.stk_id = ports[i].stk_id & 0xF;
551 s[p].port.phys_id = ports[i].phys_port_id;
552 s[p].port.log_id = ports[i].log_port_id;
553
554 s[p].cfg_lnk_width = ports[i].cfg_lnk_width;
555 s[p].neg_lnk_width = ports[i].neg_lnk_width;
556 s[p].link_up = ports[i].linkup_linkrate >> 7;
557 s[p].link_rate = ports[i].linkup_linkrate & 0x7F;
558 s[p].ltssm = le16toh(ports[i].LTSSM);
559 s[p].ltssm_str = switchtec_ltssm_str(s[p].ltssm, 1, dev);
560 s[p].lane_reversal = ports[i].lane_reversal;
561 s[p].lane_reversal_str = lane_reversal_str(s[p].link_up,
562 s[p].lane_reversal);
563 s[p].first_act_lane = ports[i].first_act_lane & 0xF;
564 s[p].acs_ctrl = -1;
565 generate_lane_str(&s[p]);
566
567 p++;
568 }
569
570 qsort(s, nr_ports, sizeof(*s), compare_status);
571
572 return nr_ports;
573}
574
581void switchtec_status_free(struct switchtec_status *status, int ports)
582{
583 int i;
584
585 for (i = 0; i < ports; i++) {
586 if (status[i].pci_bdf)
587 free(status[i].pci_bdf);
588
589 if (status[i].pci_bdf_path)
590 free(status[i].pci_bdf_path);
591
592 if (status[i].pci_dev)
593 free(status[i].pci_dev);
594
595 if (status[i].class_devices)
596 free(status[i].class_devices);
597 }
598
599 free(status);
600}
601
609
620const char *switchtec_strerror(void)
621{
622 const char *msg = "Unknown MRPC error";
623 int err;
624
625 if ((errno & (SWITCHTEC_ERRNO_MRPC_FLAG_BIT |
626 SWITCHTEC_ERRNO_GENERAL_FLAG_BIT)) == 0) {
627 if (errno)
628 return strerror(errno);
629 else
630 return platform_strerror();
631 }
632
633 if (errno & SWITCHTEC_ERRNO_GENERAL_FLAG_BIT) {
634 switch (errno) {
635 case SWITCHTEC_ERR_LOG_DEF_READ_ERROR:
636 msg = "Error reading log definition file"; break;
637 case SWITCHTEC_ERR_BIN_LOG_READ_ERROR:
638 msg = "Error reading binary log file"; break;
639 case SWITCHTEC_ERR_PARSED_LOG_WRITE_ERROR:
640 msg = "Error writing parsed log file"; break;
641 case SWITCHTEC_ERR_LOG_DEF_DATA_INVAL:
642 msg = "Invalid log definition data"; break;
643 case SWITCHTEC_ERR_INVALID_PORT:
644 msg = "Invalid port specified"; break;
645 case SWITCHTEC_ERR_INVALID_LANE:
646 msg = "Invalid lane specified"; break;
647 default:
648 msg = "Unknown Switchtec error"; break;
649 }
650
651 return msg;
652 }
653
654 err = errno & ~SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
655
656 switch (err) {
657 case ERR_NO_AVAIL_MRPC_THREAD:
658 msg = "No available MRPC handler thread"; break;
659 case ERR_HANDLER_THREAD_NOT_IDLE:
660 msg = "The handler thread is not idle"; break;
661 case ERR_NO_BG_THREAD:
662 msg = "No background thread run for the command"; break;
663
664 case ERR_REFCLK_SUBCMD_INVALID:
665 case ERR_STACKBIF_SUBCMD_INVALID:
666 case ERR_SUBCMD_INVALID: msg = "Invalid subcommand"; break;
667 case ERR_CMD_INVALID: msg = "Invalid command"; break;
668 case ERR_PARAM_INVALID: msg = "Invalid parameter"; break;
669 case ERR_BAD_FW_STATE: msg = "Bad firmware state"; break;
670 case ERR_MRPC_DENIED: msg = "MRPC request denied"; break;
671 case ERR_MRPC_NO_PREV_DATA:
672 msg = "No previous adaptation object data";
673 break;
674 case ERR_REFCLK_STACK_ID_INVALID:
675 case ERR_STACKBIF_STACK_ID_INVALID:
676 case ERR_STACK_INVALID: msg = "Invalid Stack"; break;
677 case ERR_LOOPBACK_PORT_INVALID:
678 case ERR_PORT_INVALID: msg = "Invalid Port"; break;
679 case ERR_EVENT_INVALID: msg = "Invalid Event"; break;
680 case ERR_RST_RULE_FAILED: msg = "Reset rule search failed"; break;
681 case ERR_UART_NOT_SUPPORTED:
682 msg = "UART interface not supported for this command"; break;
683 case ERR_XML_VERSION_MISMATCH:
684 msg = "XML version mismatch between MAIN and CFG partition";
685 break;
686 case ERR_ACCESS_REFUSED: msg = "Access Refused"; break;
687
688 case ERR_STACKBIF_CODE_INVALID:
689 msg = "Stack bifurcation code invalid"; break;
690 break;
691 case ERR_STACKBIF_PORT_BOUND:
692 msg = "Port already bound"; break;
693 break;
694
695 default: break;
696 }
697
698 switch (mrpc_error_cmd) {
699 case MRPC_PORTPARTP2P:
700 switch (err) {
701 case ERR_PHYC_PORT_ARDY_BIND:
702 msg = "Physical port already bound"; break;
703 case ERR_LOGC_PORT_ARDY_BIND:
704 msg = "Logical bridge instance already bound"; break;
705 case ERR_BIND_PRTT_NOT_EXIST:
706 msg = "Partition does not exist"; break;
707 case ERR_PHYC_PORT_NOT_EXIST:
708 msg = "Physical port does not exist"; break;
709 case ERR_PHYC_PORT_DIS:
710 msg = "Physical port disabled"; break;
711 case ERR_NO_LOGC_PORT:
712 msg = "No logical bridge instance"; break;
713 case ERR_BIND_IN_PROGRESS:
714 msg = "Bind/unbind in progress"; break;
715 case ERR_BIND_TGT_IS_USP:
716 msg = "Bind/unbind target is USP"; break;
717 case ERR_BIND_SUBCMD_INVALID:
718 msg = "Sub-command does not exist"; break;
719 case ERR_PHYC_PORT_LINK_ACT:
720 msg = "Physical port link active"; break;
721 case ERR_LOGC_PORT_NOT_BIND_PHYC_PORT:
722 msg = "Logical bridge not bind to physical port"; break;
723 case ERR_UNBIND_OPT_INVALID:
724 msg = "Invalid unbind option"; break;
725 case ERR_BIND_CHECK_FAIL:
726 msg = "Port bind checking failed"; break;
727 default: break;
728 }
729 break;
730 default: break;
731 }
732
733 return msg;
734}
735
743void switchtec_perror(const char *str)
744{
745 const char *msg = switchtec_strerror();
746 int is_mrpc = errno & SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
747 int err = errno & ~SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
748
749 if (is_mrpc)
750 fprintf(stderr, "%s: %s (MRPC: 0x%x, error: 0x%x)\n",
751 str, msg, mrpc_error_cmd, err);
752 else
753 fprintf(stderr, "%s: %s\n", str, msg);
754}
755
757
763
774int switchtec_echo(struct switchtec_dev *dev, uint32_t input,
775 uint32_t *output)
776{
777 return switchtec_cmd(dev, MRPC_ECHO, &input, sizeof(input),
778 output, sizeof(*output));
779}
780
790int switchtec_hard_reset(struct switchtec_dev *dev)
791{
792 uint32_t subcmd = 0;
793
794 return switchtec_cmd(dev, MRPC_RESET, &subcmd, sizeof(subcmd),
795 NULL, 0);
796}
797
802static void free_log_defs(struct log_defs *defs)
803{
804 int i, j;
805
806 if (!defs->module_defs)
807 return;
808
809 for (i = 0; i < defs->num_alloc; i++) {
810 free(defs->module_defs[i].mod_name);
811
812 for (j = 0; j < defs->module_defs[i].num_entries; j++)
813 free(defs->module_defs[i].entries[j]);
814
815 free(defs->module_defs[i].entries);
816 }
817
818 free(defs->module_defs);
819}
820
827static int realloc_log_defs(struct log_defs *defs, int num_modules)
828{
829 int i;
830
831 defs->module_defs = realloc(defs->module_defs,
832 (num_modules *
833 sizeof(struct module_log_defs)));
834 if (!defs->module_defs) {
835 free_log_defs(defs);
836 return -1;
837 }
838
839 for (i = defs->num_alloc; i < num_modules; i++)
840 memset(&defs->module_defs[i], 0,
841 sizeof(struct module_log_defs));
842
843 defs->num_alloc = num_modules;
844
845 return 0;
846}
847
854static bool parse_int(char *str, int *val)
855{
856 char *endptr;
857
858 errno = 0;
859 *val = strtol(str, &endptr, 0);
860
861 if ((endptr == str) || (*endptr != '\0') || (errno != 0))
862 return false;
863
864 return true;
865}
866
873static int read_app_log_defs(FILE *log_def_file, struct log_defs *defs)
874{
875 int ret;
876 char line[512];
877 char *tok;
878 int mod_id;
879 struct module_log_defs *mod_defs;
880 int num_entries;
881 int i;
882
883 /* allocate some log definition entries */
884 ret = realloc_log_defs(defs, 200);
885 if (ret < 0)
886 return ret;
887
888 while (fgets(line, sizeof(line), log_def_file)) {
889
890 /* ignore comments */
891 if (line[0] == '#')
892 continue;
893
894 /* strip any newline characters */
895 line[strcspn(line, "\r\n")] = '\0';
896
897 /*
898 * Tokenize and parse the line. Module headings are of the form:
899 * mod_name mod_id num_entries
900 */
901 tok = strtok(line, " \t");
902 if (!tok)
903 continue;
904
905 tok = strtok(NULL, " \t");
906 if (!tok)
907 continue;
908
909 if (!parse_int(tok, &mod_id)) {
910 errno = SWITCHTEC_ERR_LOG_DEF_DATA_INVAL;
911 goto err_free_log_defs;
912 }
913
914 /* reallocate more log definition entries if needed */
915 if (mod_id > defs->num_alloc) {
916 ret = realloc_log_defs(defs, mod_id * 2);
917 if (ret < 0)
918 return ret;
919 }
920
921 mod_defs = &defs->module_defs[mod_id];
922
923 tok = strtok(NULL, " \t");
924 if (!tok)
925 continue;
926
927 if (!parse_int(tok, &num_entries)) {
928 errno = SWITCHTEC_ERR_LOG_DEF_DATA_INVAL;
929 goto err_free_log_defs;
930 }
931
932 /*
933 * Skip this module if it has already been done. This can happen
934 * if the module is duplicated in the log definition file.
935 */
936 if (mod_defs->mod_name != NULL) {
937 for (i = 0; i < num_entries; i++) {
938 if (!fgets(line, sizeof(line),
939 log_def_file))
940 break;
941 }
942 continue;
943 }
944
945 mod_defs->mod_name = strdup(line);
946 mod_defs->num_entries = num_entries;
947 mod_defs->entries = calloc(mod_defs->num_entries,
948 sizeof(*mod_defs->entries));
949 if (!mod_defs->entries)
950 goto err_free_log_defs;
951
952 for (i = 0; i < mod_defs->num_entries; i++) {
953 if (fgets(line, sizeof(line), log_def_file) == NULL) {
954 errno = SWITCHTEC_ERR_LOG_DEF_READ_ERROR;
955 goto err_free_log_defs;
956 }
957
958 mod_defs->entries[i] = strdup(line);
959 if (!mod_defs->entries[i])
960 goto err_free_log_defs;
961 }
962 }
963
964 if (ferror(log_def_file)) {
965 errno = SWITCHTEC_ERR_LOG_DEF_READ_ERROR;
966 goto err_free_log_defs;
967 }
968
969 return 0;
970
971err_free_log_defs:
972 free_log_defs(defs);
973 return -1;
974}
975
982static int read_mailbox_log_defs(FILE *log_def_file, struct log_defs *defs)
983{
984 int ret;
985 char line[512];
986 struct module_log_defs *mod_defs;
987 int num_entries_alloc;
988
989 /*
990 * The mailbox log definitions don't keep track of modules. Allocate a
991 * single log definition entry for all definitions.
992 */
993 ret = realloc_log_defs(defs, 1);
994 if (ret < 0)
995 return ret;
996
997 mod_defs = &defs->module_defs[0];
998 mod_defs->num_entries = 0;
999
1000 /* allocate some entries */
1001 num_entries_alloc = 100;
1002 mod_defs->entries = calloc(num_entries_alloc,
1003 sizeof(*mod_defs->entries));
1004 if (!mod_defs->entries)
1005 goto err_free_log_defs;
1006
1007 while (fgets(line, sizeof(line), log_def_file)) {
1008 /* ignore comments */
1009 if (line[0] == '#')
1010 continue;
1011
1012 if (mod_defs->num_entries >= num_entries_alloc) {
1013 /* allocate more entries */
1014 num_entries_alloc *= 2;
1015 mod_defs->entries = realloc(mod_defs->entries,
1016 (num_entries_alloc *
1017 sizeof(*mod_defs->entries)));
1018 if (!mod_defs->entries)
1019 goto err_free_log_defs;
1020 }
1021
1022 mod_defs->entries[mod_defs->num_entries] = strdup(line);
1023 if (!mod_defs->entries[mod_defs->num_entries])
1024 goto err_free_log_defs;
1025
1026 mod_defs->num_entries++;
1027 }
1028
1029 if (ferror(log_def_file)) {
1030 errno = SWITCHTEC_ERR_LOG_DEF_READ_ERROR;
1031 goto err_free_log_defs;
1032 }
1033
1034 return 0;
1035
1036err_free_log_defs:
1037 free_log_defs(defs);
1038 return -1;
1039}
1040
1052static int write_parsed_log(struct log_a_data log_data[],
1053 size_t count, int init_entry_idx,
1054 struct log_defs *defs,
1055 enum switchtec_log_parse_type log_type,
1056 FILE *log_file, int ts_factor)
1057{
1058 int i;
1059 int ret;
1060 int entry_idx = init_entry_idx;
1061 unsigned long long time;
1062 unsigned int nanos, micros, millis, secs, mins, hours, days;
1063 unsigned int entry_num;
1064 unsigned int mod_id;
1065 unsigned int log_sev = 0;
1066 const char *log_sev_strs[] = {"DISABLED", "HIGHEST", "HIGH", "MEDIUM",
1067 "LOW", "LOWEST"};
1068 bool is_bl1;
1069 struct module_log_defs *mod_defs;
1070
1071 if (entry_idx == 0) {
1072 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP || log_type == SWITCHTEC_LOG_PARSE_TYPE_FTDC)
1073 fputs(" #|Timestamp |Module |Severity |Event ID |Event\n",
1074 log_file);
1075 else
1076 fputs(" #|Timestamp |Source |Event ID |Event\n",
1077 log_file);
1078 }
1079
1080 for (i = 0; i < count; i ++) {
1081 /* timestamp is in the first 2 DWords */
1082 time = (((unsigned long long)log_data[i].data[0] << 32) |
1083 log_data[i].data[1]) * ts_factor/100;
1084 nanos = time % 1000;
1085 time /= 1000;
1086 micros = time % 1000;
1087 time /= 1000;
1088 millis = time % 1000;
1089 time /= 1000;
1090 secs = time % 60;
1091 time /= 60;
1092 mins = time % 60;
1093 time /= 60;
1094 hours = time % 24;
1095 days = time / 24;
1096
1097 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP || log_type == SWITCHTEC_LOG_PARSE_TYPE_FTDC) {
1098 /*
1099 * app log: module ID and log severity are in the 3rd
1100 * DWord
1101 */
1102 mod_id = (log_data[i].data[2] >> 16) & 0xFFF;
1103 log_sev = (log_data[i].data[2] >> 28) & 0xF;
1104
1105 if ((mod_id > defs->num_alloc) ||
1106 (defs->module_defs[mod_id].mod_name == NULL) ||
1107 (strlen(defs->module_defs[mod_id].mod_name) == 0)) {
1108 if (fprintf(log_file, "(Invalid module ID: 0x%x)\n",
1109 mod_id) < 0)
1110 goto ret_print_error;
1111 continue;
1112 }
1113
1114 if (log_sev >= ARRAY_SIZE(log_sev_strs)) {
1115 if (fprintf(log_file, "(Invalid log severity: %d)\n",
1116 log_sev) < 0)
1117 goto ret_print_error;
1118 continue;
1119 }
1120 } else {
1121 /*
1122 * mailbox log: BL1/BL2 indication is in the 3rd
1123 * DWord
1124 */
1125 is_bl1 = (((log_data[i].data[2] >> 27) & 1) == 0);
1126
1127 /* mailbox log definitions are all in the first entry */
1128 mod_id = 0;
1129 }
1130
1131 mod_defs = &defs->module_defs[mod_id];
1132
1133 /* entry number is in the 3rd DWord */
1134 entry_num = log_data[i].data[2] & 0x0000FFFF;
1135
1136 if (entry_num >= mod_defs->num_entries) {
1137 if (fprintf(log_file,
1138 "(Invalid log entry number: %d (module 0x%x))\n",
1139 entry_num, mod_id) < 0)
1140 goto ret_print_error;
1141 continue;
1142 }
1143
1144 /* print the entry index and timestamp */
1145 if (ts_factor == 0)
1146 ret = fprintf(log_file,
1147 "%04d|xxxd xx:xx:xx.xxx,xxx,xxx|",
1148 entry_idx);
1149 else
1150 ret = fprintf(log_file,
1151 "%04d|%03dd %02d:%02d:%02d.%03d,%03d,%03d|",
1152 entry_idx, days, hours, mins, secs,
1153 millis, micros, nanos);
1154
1155 if (ret < 0)
1156 goto ret_print_error;
1157
1158 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP || log_type == SWITCHTEC_LOG_PARSE_TYPE_FTDC) {
1159 /* print the module name and log severity */
1160 if (fprintf(log_file, "%-12s |%-8s |0x%04x |",
1161 mod_defs->mod_name, log_sev_strs[log_sev],
1162 entry_num) < 0)
1163 goto ret_print_error;
1164 } else {
1165 /* print the log source (BL1/BL2) */
1166 if (fprintf(log_file, "%-6s |0x%04x |",
1167 (is_bl1 ? "BL1" : "BL2"), entry_num) < 0)
1168 goto ret_print_error;
1169 }
1170
1171 /* print the log entry */
1172 if (fprintf(log_file, mod_defs->entries[entry_num],
1173 log_data[i].data[3], log_data[i].data[4],
1174 log_data[i].data[5], log_data[i].data[6],
1175 log_data[i].data[7]) < 0)
1176 goto ret_print_error;
1177
1178 entry_idx++;
1179 }
1180
1181 if (fflush(log_file) != 0)
1182 return -1;
1183
1184 return 0;
1185
1186ret_print_error:
1187 errno = SWITCHTEC_ERR_PARSED_LOG_WRITE_ERROR;
1188 return -1;
1189}
1190
1191static int parse_def_header(FILE *log_def_file, uint32_t *fw_version,
1192 uint32_t *sdk_version)
1193{
1194 char line[512];
1195 int i;
1196
1197 *fw_version = 0;
1198 *sdk_version = 0;
1199 while (fgets(line, sizeof(line), log_def_file)) {
1200 if (line[0] != '#')
1201 continue;
1202
1203 i = 0;
1204 while (line[i] == ' ' || line[i] == '#') i++;
1205
1206 if (strncasecmp(line + i, "SDK Version:", 12) == 0) {
1207 i += 12;
1208 while (line[i] == ' ') i++;
1209 sscanf(line + i, "%i", (int*)sdk_version);
1210 }
1211 else if (strncasecmp(line + i, "FW Version:", 11) == 0) {
1212 i += 11;
1213 while (line[i] == ' ') i++;
1214 sscanf(line + i, "%i", (int*)fw_version);
1215 }
1216 }
1217
1218 rewind(log_def_file);
1219 return 0;
1220}
1221
1222static int append_ftdc_log_header(int fd, uint32_t sdk_def_version,
1223 uint32_t fw_def_version)
1224{
1225 int ret;
1226 char hdr_str_fmt[] = "##########################################\n"
1227 "## Parsed with FTDC log file from definition:\n"
1228 "## FW def version %08x\n"
1229 "## SDK def version %08x\n"
1230 "##########################################\n\n";
1231 char hdr_str[512];
1232
1233 snprintf(hdr_str, 512, hdr_str_fmt, fw_def_version, sdk_def_version);
1234 ret = write(fd, hdr_str, strlen(hdr_str));
1235
1236 return ret;
1237}
1238
1239static int append_log_header(int fd, uint32_t sdk_version,
1240 uint32_t fw_version, int binary)
1241{
1242 int ret;
1243 struct log_header {
1244 uint8_t magic[8];
1245 uint32_t fw_version;
1246 uint32_t sdk_version;
1247 uint32_t flags;
1248 uint32_t rsvd[3];
1249 } header = {
1250 .magic = {'S', 'W', 'M', 'C', 'L', 'O', 'G', 'F'},
1251 .fw_version = fw_version,
1252 .sdk_version = sdk_version
1253 };
1254 char hdr_str_fmt[] = "####################################\n"
1255 "## Parsed with definition file for\n"
1256 "## FW version %08x\n"
1257 "## SDK version %08x\n"
1258 "####################################\n\n";
1259 char hdr_str[512];
1260
1261 if (binary) {
1262 ret = write(fd, &header, sizeof(header));
1263 } else {
1264 snprintf(hdr_str, 512, hdr_str_fmt, fw_version, sdk_version);
1265 ret = write(fd, hdr_str, strlen(hdr_str));
1266 }
1267
1268 return ret;
1269}
1270
1271static int get_ts_factor(enum switchtec_gen gen)
1272{
1273 if (gen == SWITCHTEC_GEN_UNKNOWN)
1274 return 0;
1275 else if (gen == SWITCHTEC_GEN3)
1276 return 1000;
1277 else
1278 return 833;
1279}
1280
1281static int log_a_to_file(struct switchtec_dev *dev, int sub_cmd_id,
1282 int fd, FILE *log_def_file,
1283 struct switchtec_log_file_info *info)
1284{
1285 int ret = -1;
1286 int read = 0;
1287 struct log_a_retr_result res;
1288 struct log_a_retr cmd = {
1289 .sub_cmd_id = sub_cmd_id,
1290 .start = -1,
1291 };
1292 struct log_defs defs = {
1293 .module_defs = NULL,
1294 .num_alloc = 0};
1295 FILE *log_file;
1296 int entry_idx = 0;
1297 uint32_t fw_version = 0;
1298 uint32_t sdk_version = 0;
1299
1300 if (log_def_file != NULL) {
1301 ret = parse_def_header(log_def_file, &fw_version,
1302 &sdk_version);
1303 if (ret)
1304 return ret;
1305 /* read the log definition file into defs */
1306 ret = read_app_log_defs(log_def_file, &defs);
1307 if (ret < 0)
1308 return ret;
1309 }
1310
1311 res.hdr.remain = 1;
1312
1313 while (res.hdr.remain) {
1314 ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
1315 &res, sizeof(res));
1316 if (ret)
1317 goto ret_free_log_defs;
1318 if (res.hdr.overflow && info)
1319 info->overflow = 1;
1320 if (read == 0) {
1321 if (dev->gen < SWITCHTEC_GEN5) {
1322 res.hdr.sdk_version = 0;
1323 res.hdr.fw_version = 0;
1324 }
1325
1326 if (info) {
1327 info->def_fw_version = fw_version;
1328 info->def_sdk_version = sdk_version;
1329 info->log_fw_version = res.hdr.fw_version;
1330 info->log_sdk_version = res.hdr.sdk_version;
1331 }
1332
1333 if (res.hdr.sdk_version != sdk_version ||
1334 res.hdr.fw_version != fw_version) {
1335 if (info && log_def_file)
1336 info->version_mismatch = true;
1337
1338 }
1339
1340 append_log_header(fd, res.hdr.sdk_version,
1341 res.hdr.fw_version,
1342 log_def_file == NULL? 1 : 0);
1343 }
1344
1345 if (log_def_file == NULL) {
1346 /* write the binary log data to a file */
1347 ret = write(fd, res.data,
1348 sizeof(*res.data) * res.hdr.count);
1349 if (ret < 0)
1350 return ret;
1351 } else {
1352 log_file = fdopen(fd, "w");
1353 if (!log_file)
1354 goto ret_free_log_defs;
1355
1356 /* parse the log data and write it to a file */
1357 ret = write_parsed_log(res.data, res.hdr.count,
1358 entry_idx, &defs,
1359 SWITCHTEC_LOG_PARSE_TYPE_APP,
1360 log_file,
1361 get_ts_factor(dev->gen));
1362 if (ret < 0)
1363 goto ret_free_log_defs;
1364
1365 entry_idx += res.hdr.count;
1366 }
1367
1368 read += le32toh(res.hdr.count);
1369 cmd.start = res.hdr.next_start;
1370 }
1371
1372 ret = 0;
1373
1374ret_free_log_defs:
1375 free_log_defs(&defs);
1376 return ret;
1377}
1378
1379static int log_b_to_file(struct switchtec_dev *dev, int sub_cmd_id, int fd)
1380{
1381 int ret;
1382 int read = 0;
1383 struct log_b_retr_result res;
1384 struct log_b_retr cmd = {
1385 .sub_cmd_id = sub_cmd_id,
1386 .offset = 0,
1387 .length = htole32(sizeof(res.data)),
1388 };
1389
1390 res.hdr.remain = sizeof(res.data);
1391
1392 while (res.hdr.remain) {
1393 ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
1394 &res, sizeof(res));
1395 if (ret)
1396 return -1;
1397
1398 ret = write(fd, res.data, res.hdr.length);
1399 if (ret < 0)
1400 return ret;
1401
1402 read += le32toh(res.hdr.length);
1403 cmd.offset = htole32(read);
1404 }
1405
1406 return 0;
1407}
1408
1409static int log_c_to_file(struct switchtec_dev *dev, int sub_cmd_id, int fd)
1410{
1411 int ret;
1412 struct log_cmd {
1413 uint8_t subcmd;
1414 uint8_t rsvd[3];
1415 } cmd = {};
1416
1417 struct log_reply {
1418 uint8_t reason;
1419 uint8_t rsvd[3];
1420 uint32_t nvlog_version;
1421 uint32_t thread_handle;
1422 uint32_t fw_version;
1423 uint32_t timestamp1;
1424 uint32_t timestamp2;
1425 } reply;
1426
1427 cmd.subcmd = sub_cmd_id;
1428
1429 ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
1430 &reply, sizeof(reply));
1431 if (ret)
1432 return -1;
1433
1434 ret = write(fd, &reply, sizeof(reply));
1435 if (ret < 0)
1436 return ret;
1437
1438 return 0;
1439}
1440
1441static int log_d_to_file(struct switchtec_dev *dev, int sub_cmd_id, int fd)
1442{
1443 int ret;
1444 int read = 0;
1445
1446 struct log_ftdc_retr_result res;
1447 struct log_ftdc_retr cmd = {
1448 .sub_cmd_id = sub_cmd_id,
1449 .reserved = 0,
1450 .req_seq = 0,
1451 };
1452 uint32_t length = sizeof(res.data);
1453
1454 cmd.req_seq = 0;
1455 res.data[1] = 0;
1456
1457 while ( !(res.data[1]) ) {
1458 ret = switchtec_cmd(dev, MRPC_FTDC_LOG_DUMP, &cmd, sizeof(cmd),
1459 &res, sizeof(res));
1460 if (ret)
1461 return -1;
1462
1463 ret = write(fd, res.data, (res.data[0]+1)*4);
1464 if (ret < 0)
1465 return ret;
1466
1467 read += length;
1468 cmd.req_seq++;
1469
1470 }
1471
1472 return 0;
1473}
1474
1475static int log_ram_flash_to_file(struct switchtec_dev *dev,
1476 int gen5_cmd, int gen4_cmd, int gen4_cmd_lgcy,
1477 int fd, FILE *log_def_file,
1478 struct switchtec_log_file_info *info)
1479{
1480 int ret;
1481
1482 if (switchtec_is_gen5(dev)) {
1483 return log_a_to_file(dev, gen5_cmd, fd, log_def_file,
1484 info);
1485 } else {
1486 ret = log_a_to_file(dev, gen4_cmd, fd, log_def_file,
1487 info);
1488
1489 /* somehow hardware returns ERR_LOGC_PORT_ARDY_BIND
1490 * instead of ERR_SUBCMD_INVALID if this subcommand
1491 * is not supported, so we fall back to legacy
1492 * subcommand on ERR_LOGC_PORT_ARDY_BIND error as well
1493 */
1494 if (ret > 0 &&
1495 (ERRNO_MRPC(errno) == ERR_LOGC_PORT_ARDY_BIND ||
1496 ERRNO_MRPC(errno) == ERR_SUBCMD_INVALID))
1497 ret = log_a_to_file(dev, gen4_cmd_lgcy, fd,
1498 log_def_file, info);
1499
1500 return ret;
1501 }
1502}
1503
1513int switchtec_log_to_file(struct switchtec_dev *dev,
1514 enum switchtec_log_type type, int fd, FILE *log_def_file,
1515 struct switchtec_log_file_info *info)
1516{
1517 if (info)
1518 memset(info, 0, sizeof(*info));
1519
1520 switch (type) {
1521 case SWITCHTEC_LOG_RAM:
1522 return log_ram_flash_to_file(dev,
1523 MRPC_FWLOGRD_RAM_GEN5,
1524 MRPC_FWLOGRD_RAM_WITH_FLAG,
1525 MRPC_FWLOGRD_RAM,
1526 fd, log_def_file, info);
1527 case SWITCHTEC_LOG_FLASH:
1528 return log_ram_flash_to_file(dev,
1529 MRPC_FWLOGRD_FLASH_GEN5,
1530 MRPC_FWLOGRD_FLASH_WITH_FLAG,
1531 MRPC_FWLOGRD_FLASH,
1532 fd, log_def_file, info);
1533 case SWITCHTEC_LOG_FTDC:
1534 return log_d_to_file(dev, MRPC_FWLOGRD_RAM, fd);
1535 case SWITCHTEC_LOG_MEMLOG:
1536 return log_b_to_file(dev, MRPC_FWLOGRD_MEMLOG, fd);
1537 case SWITCHTEC_LOG_REGS:
1538 return log_b_to_file(dev, MRPC_FWLOGRD_REGS, fd);
1539 case SWITCHTEC_LOG_THRD_STACK:
1540 return log_b_to_file(dev, MRPC_FWLOGRD_THRD_STACK, fd);
1541 case SWITCHTEC_LOG_SYS_STACK:
1542 return log_b_to_file(dev, MRPC_FWLOGRD_SYS_STACK, fd);
1543 case SWITCHTEC_LOG_THRD:
1544 return log_b_to_file(dev, MRPC_FWLOGRD_THRD, fd);
1545 case SWITCHTEC_LOG_NVHDR:
1546 return log_c_to_file(dev, MRPC_FWLOGRD_NVHDR, fd);
1547 };
1548
1549 errno = EINVAL;
1550 return -errno;
1551}
1552
1553static int parse_log_header(FILE *bin_log_file, uint32_t *fw_version,
1554 uint32_t *sdk_version)
1555{
1556 struct log_header {
1557 uint8_t magic[8];
1558 uint32_t fw_version;
1559 uint32_t sdk_version;
1560 uint32_t flags;
1561 uint32_t rsvd[3];
1562 } header;
1563
1564 char sig[8] = {'S', 'W', 'M', 'C', 'L', 'O', 'G', 'F'};
1565 int ret;
1566
1567 ret = fread(&header, sizeof(header), 1, bin_log_file);
1568 if (ret <= 0) {
1569 errno = EBADF;
1570 return -EBADF;
1571 }
1572
1573 if (memcmp(sig, header.magic, 8)) {
1574 rewind(bin_log_file);
1575 *fw_version = 0;
1576 *sdk_version = 0;
1577 return 0;
1578 }
1579
1580 *fw_version = header.fw_version;
1581 *sdk_version = header.sdk_version;
1582
1583 return 0;
1584}
1585
1596int switchtec_parse_log(FILE *bin_log_file, FILE *log_def_file,
1597 FILE *parsed_log_file,
1598 enum switchtec_log_parse_type log_type,
1599 enum switchtec_gen gen,
1600 struct switchtec_log_file_info *info)
1601{
1602 int ret;
1603 struct log_a_data log_data;
1604 struct log_defs defs = {
1605 .module_defs = NULL,
1606 .num_alloc = 0};
1607 int entry_idx = 0;
1608 uint32_t fw_version_log = 0;
1609 uint32_t sdk_version_log = 0;
1610 uint32_t fw_version_def;
1611 uint32_t sdk_version_def;
1612 enum switchtec_gen gen_file;
1613
1614 if (info)
1615 memset(info, 0, sizeof(*info));
1616
1617 if ((log_type != SWITCHTEC_LOG_PARSE_TYPE_APP) &&
1618 (log_type != SWITCHTEC_LOG_PARSE_TYPE_MAILBOX) &&
1619 (log_type != SWITCHTEC_LOG_PARSE_TYPE_FTDC)) {
1620 errno = EINVAL;
1621 return -errno;
1622 }
1623
1624 if (log_type != SWITCHTEC_LOG_PARSE_TYPE_FTDC)
1625 {
1626 ret = parse_log_header(bin_log_file, &fw_version_log,
1627 &sdk_version_log);
1628 if (ret)
1629 return ret;
1630 }
1631
1632 ret = parse_def_header(log_def_file, &fw_version_def,
1633 &sdk_version_def);
1634 if (ret)
1635 return ret;
1636
1637 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_MAILBOX) {
1638 fw_version_log = fw_version_def;
1639 sdk_version_log = sdk_version_def;
1640 }
1641
1642 if (info) {
1643 info->def_fw_version = fw_version_def;
1644 info->def_sdk_version = sdk_version_def;
1645
1646 info->log_fw_version = fw_version_log;
1647 info->log_sdk_version = sdk_version_log;
1648 }
1649 /* read the log definition file into defs */
1650 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP || log_type == SWITCHTEC_LOG_PARSE_TYPE_FTDC)
1651 ret = read_app_log_defs(log_def_file, &defs);
1652 else
1653 ret = read_mailbox_log_defs(log_def_file, &defs);
1654
1655 if (ret < 0)
1656 return ret;
1657
1658 if (log_type != SWITCHTEC_LOG_PARSE_TYPE_FTDC)
1659 ret = append_log_header(fileno(parsed_log_file), sdk_version_log,
1660 fw_version_log, 0);
1661 else
1662 ret = append_ftdc_log_header(fileno(parsed_log_file), sdk_version_def,
1663 fw_version_def);
1664
1665 if (ret < 0)
1666 return ret;
1667
1668 /* parse each log entry */
1669 while (fread(&log_data, sizeof(struct log_a_data), 1,
1670 bin_log_file) == 1) {
1671 if(fw_version_log)
1672 gen_file = switchtec_fw_version_to_gen(fw_version_log);
1673 else
1674 gen_file = switchtec_fw_version_to_gen(fw_version_def);
1675
1676 if (gen_file != SWITCHTEC_GEN_UNKNOWN &&
1677 gen != SWITCHTEC_GEN_UNKNOWN) {
1678 if (info)
1679 info->gen_ignored = true;
1680 } else if (gen_file == SWITCHTEC_GEN_UNKNOWN &&
1681 gen == SWITCHTEC_GEN_UNKNOWN) {
1682 if (info)
1683 info->gen_unknown = true;
1684 } else if (gen != SWITCHTEC_GEN_UNKNOWN) {
1685 gen_file = gen;
1686 }
1687
1688 ret = write_parsed_log(&log_data, 1, entry_idx, &defs,
1689 log_type, parsed_log_file,
1690 get_ts_factor(gen_file));
1691 if (ret < 0)
1692 goto ret_free_log_defs;
1693
1694 entry_idx++;
1695 }
1696
1697 if (ferror(bin_log_file)) {
1698 errno = SWITCHTEC_ERR_BIN_LOG_READ_ERROR;
1699 ret = -1;
1700 }
1701
1702 if (fw_version_def != fw_version_log ||
1703 sdk_version_def != sdk_version_log) {
1704 if (info)
1705 info->version_mismatch = true;
1706 ret = ENOEXEC;
1707 }
1708
1709ret_free_log_defs:
1710 free_log_defs(&defs);
1711 return ret;
1712}
1713
1721int switchtec_log_def_to_file(struct switchtec_dev *dev,
1722 enum switchtec_log_def_type type,
1723 FILE* file)
1724{
1725 int ret;
1726 struct log_cmd {
1727 uint8_t subcmd;
1728 uint8_t rsvd[3];
1729 uint16_t idx;
1730 uint16_t mod_id;
1731 } cmd = {};
1732
1733 struct log_reply {
1734 uint16_t end_of_data;
1735 uint16_t data_len;
1736 uint16_t next_idx;
1737 uint16_t next_mod_id;
1738 uint8_t data[MRPC_MAX_DATA_LEN - 16];
1739 } reply = {};
1740
1741 switch (type) {
1742 case SWITCHTEC_LOG_DEF_TYPE_APP:
1743 cmd.subcmd = MRPC_LOG_DEF_APP;
1744 break;
1745
1746 case SWITCHTEC_LOG_DEF_TYPE_MAILBOX:
1747 cmd.subcmd = MRPC_LOG_DEF_MAILBOX;
1748 break;
1749
1750 default:
1751 errno = EINVAL;
1752 return -errno;
1753 }
1754
1755 do {
1756 ret = switchtec_cmd(dev, MRPC_LOG_DEF_GET, &cmd, sizeof(cmd),
1757 &reply, sizeof(reply));
1758 if (ret)
1759 return -1;
1760
1761 ret = fwrite(reply.data, reply.data_len, 1, file);
1762 if (ret < 0)
1763 return ret;
1764
1765 cmd.idx = reply.next_idx;
1766 cmd.mod_id = reply.next_mod_id;
1767 } while (!reply.end_of_data);
1768
1769 return 0;
1770}
1771
1772static enum switchtec_gen map_to_gen(uint32_t gen)
1773{
1774 enum switchtec_gen ret = SWITCHTEC_GEN_UNKNOWN;
1775
1776 switch (gen) {
1777 case 0:
1778 ret = SWITCHTEC_GEN4;
1779 break;
1780 case 1:
1781 ret = SWITCHTEC_GEN5;
1782 break;
1783 default:
1784 ret = SWITCHTEC_GEN_UNKNOWN;
1785 break;
1786 }
1787
1788 return ret;
1789}
1790
1799int switchtec_get_device_info(struct switchtec_dev *dev,
1800 enum switchtec_boot_phase *phase,
1801 enum switchtec_gen *gen,
1802 enum switchtec_rev *rev)
1803{
1804 int ret;
1805 uint32_t ping_dw = 0;
1806 uint32_t dev_info;
1807 struct get_dev_info_reply {
1808 uint32_t dev_info;
1809 uint32_t ping_reply;
1810 } reply;
1811
1812 ping_dw = time(NULL);
1813
1814 /*
1815 * The I2C TWI Ping command also dumps information about the
1816 * revision and image phase.
1817 */
1818 ret = switchtec_cmd(dev, MRPC_I2C_TWI_PING, &ping_dw,
1819 sizeof(ping_dw),
1820 &reply, sizeof(reply));
1821 if (ret == 0) {
1822 if (ping_dw != ~reply.ping_reply)
1823 return -1;
1824
1825 dev_info = le32toh(reply.dev_info);
1826 if (phase)
1827 *phase = dev_info & 0xff;
1828 if (rev)
1829 *rev = (dev_info >> 8) & 0x0f;
1830 if (gen)
1831 *gen = map_to_gen((dev_info >> 12) & 0x0f);
1832 } else if (errno == EBADMSG || ERRNO_MRPC(errno) == ERR_CMD_INVALID) {
1833 if (phase)
1834 *phase = SWITCHTEC_BOOT_PHASE_FW;
1835 if (gen)
1836 *gen = SWITCHTEC_GEN3;
1837 if (rev)
1838 *rev = SWITCHTEC_REV_UNKNOWN;
1839
1840 errno = 0;
1841 } else {
1842 return -1;
1843 }
1844
1845 return 0;
1846}
1847
1854float switchtec_die_temp(struct switchtec_dev *dev)
1855{
1856 int ret;
1857 uint32_t sub_cmd_id;
1858 uint32_t temp;
1859
1860 if (switchtec_is_gen3(dev)) {
1861 sub_cmd_id = MRPC_DIETEMP_SET_MEAS;
1862 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1863 sizeof(sub_cmd_id), NULL, 0);
1864 if (ret)
1865 return -100.0;
1866
1867 sub_cmd_id = MRPC_DIETEMP_GET;
1868 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1869 sizeof(sub_cmd_id), &temp, sizeof(temp));
1870 if (ret)
1871 return -100.0;
1872 } else if (switchtec_is_gen4(dev)) {
1873 sub_cmd_id = MRPC_DIETEMP_GET_GEN4;
1874 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1875 sizeof(sub_cmd_id), &temp, sizeof(temp));
1876 if (ret)
1877 return -100.0;
1878 } else {
1879 sub_cmd_id = MRPC_DIETEMP_GET_GEN5;
1880 uint32_t temps[4];
1881 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1882 sizeof(sub_cmd_id), temps, sizeof(temps));
1883 if (ret)
1884 return -100.0;
1885 temp = (temps[0] + temps[1] + temps[2] + temps[3]) / 4;
1886 }
1887
1888 return le32toh(temp) / 100.;
1889}
1890
1898int switchtec_die_temps(struct switchtec_dev *dev, int nr_sensor,
1899 float *sensor_readings)
1900{
1901 int ret;
1902 uint32_t sub_cmd_id;
1903 uint32_t temp;
1904
1905 if (nr_sensor <= 0 || !sensor_readings)
1906 return 0;
1907
1908 if (switchtec_is_gen3(dev)) {
1909 sub_cmd_id = MRPC_DIETEMP_SET_MEAS;
1910 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1911 sizeof(sub_cmd_id), NULL, 0);
1912 if (ret)
1913 return -100.0;
1914
1915 sub_cmd_id = MRPC_DIETEMP_GET;
1916 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1917 sizeof(sub_cmd_id), &temp, sizeof(temp));
1918 if (ret)
1919 return -100.0;
1920
1921 sensor_readings[0] = le32toh(temp) / 100.;
1922 return 1;
1923 } else if (switchtec_is_gen4(dev)) {
1924 sub_cmd_id = MRPC_DIETEMP_GET_GEN4;
1925 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1926 sizeof(sub_cmd_id), &temp, sizeof(temp));
1927 if (ret)
1928 return -100.0;
1929
1930 sensor_readings[0] = le32toh(temp) / 100.;
1931 return 1;
1932 } else {
1933 sub_cmd_id = MRPC_DIETEMP_GET_GEN5;
1934 uint32_t temps[4];
1935 int i;
1936
1937 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1938 sizeof(sub_cmd_id), temps, sizeof(temps));
1939 if (ret)
1940 return -100.0;
1941
1942 for (i = 0; i < nr_sensor && i < 4; i++)
1943 sensor_readings[i] = le32toh(temps[i]) / 100.;
1944
1945 return i;
1946 }
1947}
1948
1949int switchtec_bind_info(struct switchtec_dev *dev,
1950 struct switchtec_bind_status_out *status, int phy_port)
1951{
1952 struct switchtec_bind_status_in sub_cmd_id = {
1953 .sub_cmd = MRPC_PORT_INFO,
1954 .phys_port_id = phy_port
1955 };
1956
1957 return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
1958 sizeof(sub_cmd_id), status, sizeof(*status));
1959}
1960
1961int switchtec_bind(struct switchtec_dev *dev, int par_id, int log_port,
1962 int phy_port)
1963{
1964 uint32_t output;
1965
1966 struct switchtec_bind_in sub_cmd_id = {
1967 .sub_cmd = MRPC_PORT_BIND,
1968 .par_id = par_id,
1969 .log_port_id = log_port,
1970 .phys_port_id = phy_port
1971 };
1972
1973 return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
1974 sizeof(sub_cmd_id), &output, sizeof(output));
1975}
1976
1977int switchtec_unbind(struct switchtec_dev *dev, int par_id, int log_port)
1978{
1979 uint32_t output;
1980
1981 struct switchtec_unbind_in sub_cmd_id = {
1982 .sub_cmd = MRPC_PORT_UNBIND,
1983 .par_id = par_id,
1984 .log_port_id = log_port,
1985 .opt = 2
1986 };
1987
1988 return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
1989 sizeof(sub_cmd_id), &output, sizeof(output));
1990}
1991
1992static int __switchtec_calc_lane_id(struct switchtec_status *port, int lane_id)
1993{
1994 int lane;
1995
1996 if (lane_id >= port->neg_lnk_width) {
1997 errno = SWITCHTEC_ERR_INVALID_LANE;
1998 return -1;
1999 }
2000
2001 lane = port->port.phys_id * 2;
2002 if (!port->lane_reversal)
2003 lane += lane_id;
2004 else
2005 lane += port->cfg_lnk_width - 1 - lane_id;
2006
2007 switch (port->port.phys_id) {
2008 /* Trident (Gen4) - Ports 48 to 51 maps to 96 to 99 */
2009 case 48: return 96;
2010 case 49: return 97;
2011 case 50: return 98;
2012 case 51: return 99;
2013 /* Hrapoon (Gen5) - Ports 56 to 59 maps to 96 to 99 */
2014 case 56: return 96;
2015 case 57: return 97;
2016 case 58: return 98;
2017 case 59: return 99;
2018 default: return lane;
2019 }
2020}
2021
2030int switchtec_calc_lane_id(struct switchtec_dev *dev, int phys_port_id,
2031 int lane_id, struct switchtec_status *port)
2032{
2033 struct switchtec_status *status;
2034 int ports, i;
2035 int rc = 0;
2036
2037 ports = switchtec_status(dev, &status);
2038 if (ports < 0)
2039 return ports;
2040
2041 for (i = 0; i < ports; i++)
2042 if (status[i].port.phys_id == phys_port_id)
2043 break;
2044
2045 if (i == ports) {
2046 errno = SWITCHTEC_ERR_INVALID_PORT;
2047 rc = -1;
2048 goto out;
2049 }
2050
2051 if (port)
2052 *port = status[i];
2053
2054 rc = __switchtec_calc_lane_id(&status[i], lane_id);
2055
2056out:
2057 switchtec_status_free(status, ports);
2058 return rc;
2059}
2060
2070int switchtec_calc_port_lane(struct switchtec_dev *dev, int lane_id,
2071 int *phys_port_id, int *port_lane_id,
2072 struct switchtec_status *port)
2073{
2074 struct switchtec_status *status;
2075 int ports, i, p, lane;
2076 int rc = 0;
2077
2078 ports = switchtec_status(dev, &status);
2079 if (ports < 0)
2080 return ports;
2081
2082 if (lane_id >= 96) {
2083 if (dev->gen < SWITCHTEC_GEN5)
2084 p = lane_id - 96 + 48;
2085 else
2086 p = lane_id - 96 + 56;
2087
2088 for (i = 0; i < ports; i++)
2089 if (status[i].port.phys_id == p)
2090 break;
2091 } else {
2092 for (i = 0; i < ports; i++) {
2093 p = status[i].port.phys_id * 2;
2094 if (lane_id >= p && lane_id < p + status[i].cfg_lnk_width)
2095 break;
2096 }
2097 }
2098
2099 if (i == ports) {
2100 errno = SWITCHTEC_ERR_INVALID_PORT;
2101 rc = -1;
2102 goto out;
2103 }
2104
2105 if (port)
2106 *port = status[i];
2107
2108 if (phys_port_id)
2109 *phys_port_id = status[i].port.phys_id;
2110
2111 lane = lane_id - status[i].port.phys_id * 2;
2112 if (port->lane_reversal)
2113 lane = status[i].cfg_lnk_width - 1 - lane;
2114
2115 if (port_lane_id)
2116 *port_lane_id = lane;
2117
2118out:
2119 switchtec_status_free(status, ports);
2120 return rc;
2121}
2122
2134int switchtec_calc_lane_mask(struct switchtec_dev *dev, int phys_port_id,
2135 int lane_id, int num_lanes, int *lane_mask,
2136 struct switchtec_status *port)
2137{
2138 struct switchtec_status *status;
2139 int ports, i, l, lane;
2140 int rc = 0;
2141
2142 ports = switchtec_status(dev, &status);
2143 if (ports < 0)
2144 return ports;
2145
2146 for (i = 0; i < ports; i++)
2147 if (status[i].port.phys_id == phys_port_id)
2148 break;
2149
2150 if (i == ports) {
2151 errno = SWITCHTEC_ERR_INVALID_PORT;
2152 rc = -1;
2153 goto out;
2154 }
2155
2156 if (port)
2157 *port = status[i];
2158
2159 for (l = lane_id; l < lane_id + num_lanes; l++) {
2160 lane = __switchtec_calc_lane_id(&status[i], l);
2161 if (lane < 0) {
2162 rc = -1;
2163 goto out;
2164 }
2165
2166 lane_mask[lane >> 5] |= 1 << (lane & 0x1F);
2167 }
2168
2169out:
2170 switchtec_status_free(status, ports);
2171 return rc;
2172}
2173
2181bool switchtec_stack_bif_port_valid(struct switchtec_dev *dev, int stack_id,
2182 int port_id)
2183{
2184 if (dev->gen == SWITCHTEC_GEN4)
2185 return stack_id * 8 + port_id < 52;
2186
2187 return true;
2188}
2189
2197int switchtec_stack_bif_width(struct switchtec_dev *dev, int stack_id,
2198 int port_bif)
2199{
2200 if (!port_bif)
2201 return 1;
2202
2203 if (port_bif != 1 && port_bif != 2 && port_bif != 4 && port_bif != 8 &&
2204 port_bif != 16) {
2205 errno = -EINVAL;
2206 return -1;
2207 }
2208
2209 if (dev->gen == SWITCHTEC_GEN4 && stack_id == 6)
2210 return port_bif;
2211 else
2212 return (port_bif + 1) / 2;
2213}
2214
2222int switchtec_get_stack_bif(struct switchtec_dev *dev, int stack_id,
2223 int port_bif[SWITCHTEC_PORTS_PER_STACK])
2224{
2225 struct switchtec_stackbif out, in = {
2226 .sub_cmd = MRPC_STACKBIF_GET,
2227 .stack_id = stack_id,
2228 };
2229 int ret, i;
2230
2231 ret = switchtec_cmd(dev, MRPC_STACKBIF, &in, sizeof(in), &out,
2232 sizeof(out));
2233 if (ret)
2234 return ret;
2235
2236 for (i = 0; i < SWITCHTEC_PORTS_PER_STACK; i++) {
2237 if (!switchtec_stack_bif_port_valid(dev, stack_id, i)) {
2238 port_bif[i] = -1;
2239 continue;
2240 }
2241
2242 switch (out.code & 0xF) {
2243 case 0x0: port_bif[i] = 0; break;
2244 case 0x1: port_bif[i] = 2; break;
2245 case 0x2: port_bif[i] = 4; break;
2246 case 0x4: port_bif[i] = 8; break;
2247 case 0x8: port_bif[i] = 16; break;
2248 case 0xf: port_bif[i] = 1; break;
2249 default:
2250 errno = -EPROTO;
2251 return -1;
2252 }
2253 out.code >>= 4;
2254 }
2255
2256 return 0;
2257}
2258
2266int switchtec_set_stack_bif(struct switchtec_dev *dev, int stack_id,
2267 int port_bif[SWITCHTEC_PORTS_PER_STACK])
2268{
2269 struct switchtec_stackbif out, in = {
2270 .sub_cmd = MRPC_STACKBIF_SET,
2271 .stack_id = stack_id,
2272 };
2273 int i;
2274
2275 for (i = 0; i < SWITCHTEC_PORTS_PER_STACK; i++) {
2276 switch (port_bif[i]) {
2277 case 0: in.code |= 0x0 << (i * 4); break;
2278 case 1: in.code |= 0xf << (i * 4); break;
2279 case 2: in.code |= 0x1 << (i * 4); break;
2280 case 4: in.code |= 0x2 << (i * 4); break;
2281 case 8: in.code |= 0x4 << (i * 4); break;
2282 case 16: in.code |= 0x8 << (i * 4); break;
2283 default:
2284 errno = -EINVAL;
2285 return -1;
2286 }
2287 }
2288
2289 return switchtec_cmd(dev, MRPC_STACKBIF, &in, sizeof(in), &out,
2290 sizeof(out));
2291}
2292
2300int switchtec_get_gpio(struct switchtec_dev *dev, int pin_id,
2301 int *gpio_val)
2302{
2303 int ret;
2304 struct switchtec_gpio out, in = {
2305 .sub_cmd = MRPC_VGPIO_GET_VAL,
2306 .log_gpio_id = pin_id,
2307 };
2308
2309 ret = switchtec_cmd(dev, MRPC_VGPIO, &in, sizeof(in), &out,
2310 sizeof(out));
2311 if (ret)
2312 return ret;
2313
2314 *gpio_val = out.data;
2315
2316 return 0;
2317}
2318
2326int switchtec_set_gpio(struct switchtec_dev *dev, int pin_id,
2327 int gpio_val)
2328{
2329 struct switchtec_gpio in = {
2330 .sub_cmd = MRPC_VGPIO_SET_VAL,
2331 .log_gpio_id = pin_id,
2332 };
2333
2334 in.data = gpio_val;
2335 return switchtec_cmd(dev, MRPC_VGPIO, &in, sizeof(in), NULL, 0);
2336}
2337
2345int switchtec_get_gpio_direction_cfg(struct switchtec_dev *dev, int pin_id,
2346 int *direction)
2347{
2348 int ret;
2349 struct switchtec_gpio out, in = {
2350 .sub_cmd = MRPC_VGPIO_GET_DIR,
2351 .log_gpio_id = pin_id,
2352 };
2353
2354 ret = switchtec_cmd(dev, MRPC_VGPIO, &in, sizeof(in), &out,
2355 sizeof(out));
2356 if (ret)
2357 return ret;
2358
2359 *direction = out.data;
2360
2361 return 0;
2362}
2363
2371int switchtec_get_gpio_polarity_cfg(struct switchtec_dev *dev, int pin_id,
2372 int *polarity)
2373{
2374 int ret;
2375 struct switchtec_gpio out, in = {
2376 .sub_cmd = MRPC_VGPIO_GET_POL,
2377 .log_gpio_id = pin_id,
2378 };
2379
2380 ret = switchtec_cmd(dev, MRPC_VGPIO, &in, sizeof(in), &out,
2381 sizeof(out));
2382 if (ret)
2383 return ret;
2384
2385 *polarity = out.data;
2386
2387 return 0;
2388}
2389
2397int switchtec_en_dis_interrupt(struct switchtec_dev *dev, int pin_id, int en)
2398{
2399 struct switchtec_gpio in = {
2400 .sub_cmd = MRPC_VGPIO_DIS_INT,
2401 .log_gpio_id = pin_id,
2402 };
2403
2404 if (en)
2405 in.sub_cmd = MRPC_VGPIO_EN_INT;
2406
2407 return switchtec_cmd(dev, MRPC_VGPIO, &in, sizeof(in), NULL, 0);
2408}
2409
2416int switchtec_get_all_pin_sts(struct switchtec_dev *dev, uint32_t *values)
2417{
2418 int ret;
2419 struct switchtec_gpio in = {
2420 .sub_cmd = MRPC_VPGIO_GET_PIN_STS,
2421 };
2422 struct switchtec_gpio_sts_out out;
2423
2424 ret = switchtec_cmd(dev, MRPC_VGPIO, &in, sizeof(in), &out, sizeof(out));
2425 if (ret)
2426 return ret;
2427
2428 memcpy(values, out.pin_values, sizeof(out.pin_values));
2429
2430 return 0;
2431}
2432
struct switchtec_dev * switchtec_open(const char *device)
Open a Switchtec device by string.
Definition switchtec.c:263
void switchtec_list_free(struct switchtec_device_info *devlist)
Free a list of device info structures allocated by switchtec_list().
Definition switchtec.c:241
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:178
void switchtec_perror(const char *str)
Print an error string to stdout.
Definition switchtec.c:743
int mrpc_error_cmd
The MRPC command ID when errno is set.
Definition switchtec.c:608
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:581
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:496
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:396
const char * switchtec_strerror(void)
Return a message coresponding to the last error.
Definition switchtec.c:620
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:348
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:360
_PURE enum switchtec_variant switchtec_variant(struct switchtec_dev *dev)
Get the variant type of the device.
Definition switchtec.c:372
_PURE int switchtec_partition(struct switchtec_dev *dev)
Get the partiton number of the device that was opened.
Definition switchtec.c:406
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:464
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:2197
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:2134
int switchtec_get_gpio(struct switchtec_dev *dev, int pin_id, int *gpio_val)
Get the GPIO pin value.
Definition switchtec.c:2300
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:1513
int switchtec_set_gpio(struct switchtec_dev *dev, int pin_id, int gpio_val)
Set the GPIO pin value.
Definition switchtec.c:2326
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:982
int switchtec_get_gpio_polarity_cfg(struct switchtec_dev *dev, int pin_id, int *polarity)
Get the GPIO pin polarity.
Definition switchtec.c:2371
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:1596
float switchtec_die_temp(struct switchtec_dev *dev)
Get the die temperature of the switchtec device.
Definition switchtec.c:1854
int switchtec_die_temps(struct switchtec_dev *dev, int nr_sensor, float *sensor_readings)
Get the die temperature sensor readings of the switchtec device.
Definition switchtec.c:1898
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:2222
static void free_log_defs(struct log_defs *defs)
Free log definition data.
Definition switchtec.c:802
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:2181
int switchtec_hard_reset(struct switchtec_dev *dev)
Perform an MRPC hard reset command.
Definition switchtec.c:790
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:1721
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:1799
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:873
static int realloc_log_defs(struct log_defs *defs, int num_modules)
Allocate / reallocate log definition data.
Definition switchtec.c:827
int switchtec_en_dis_interrupt(struct switchtec_dev *dev, int pin_id, int en)
Enable/Disable the GPIO pin interrupt.
Definition switchtec.c:2397
int switchtec_echo(struct switchtec_dev *dev, uint32_t input, uint32_t *output)
Perform an MRPC echo command.
Definition switchtec.c:774
static bool parse_int(char *str, int *val)
Parse an integer from a string.
Definition switchtec.c:854
int switchtec_get_all_pin_sts(struct switchtec_dev *dev, uint32_t *values)
Get all GPIO pin status.
Definition switchtec.c:2416
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:2266
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:2030
int switchtec_get_gpio_direction_cfg(struct switchtec_dev *dev, int pin_id, int *direction)
Get the GPIO pin direction.
Definition switchtec.c:2345
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:2070
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:1052
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:147
Information about log file and log definition file.
Definition switchtec.h:235
Port identification.
Definition switchtec.h:160
unsigned char upstream
1 if this is an upstream port
Definition switchtec.h:164
unsigned char partition
Partition the port is in.
Definition switchtec.h:161
unsigned char stk_id
Port number within the stack.
Definition switchtec.h:165
unsigned char log_id
Logical port number.
Definition switchtec.h:167
unsigned char phys_id
Physical port number.
Definition switchtec.h:166
unsigned char stack
Stack number.
Definition switchtec.h:163
Port status structure.
Definition switchtec.h:176
struct switchtec_port_id port
Port ID.
Definition switchtec.h:177
unsigned char link_up
1 if the link is up
Definition switchtec.h:180
unsigned char lane_reversal
Lane reversal.
Definition switchtec.h:184
unsigned int acs_ctrl
ACS Setting of the Port.
Definition switchtec.h:196
const char * lane_reversal_str
Lane reversal as a string.
Definition switchtec.h:185
unsigned char cfg_lnk_width
Configured link width.
Definition switchtec.h:178
unsigned char link_rate
Link rate/gen.
Definition switchtec.h:181
unsigned char first_act_lane
First active lane.
Definition switchtec.h:186
unsigned char neg_lnk_width
Negotiated link width.
Definition switchtec.h:179
uint16_t ltssm
Link state.
Definition switchtec.h:182
const char * ltssm_str
Link state as a string.
Definition switchtec.h:183
Main Switchtec header.
switchtec_log_parse_type
Log types to parse.
Definition switchtec.h:226
switchtec_rev
Device hardware revision.
Definition switchtec.h:101
switchtec_gen
The PCIe generations.
Definition switchtec.h:91
switchtec_log_def_type
Log definition data types.
Definition switchtec.h:249
switchtec_variant
The variant types of Switchtec device.
Definition switchtec.h:132
switchtec_log_type
Describe the type of logs too dump.
Definition switchtec.h:211
switchtec_boot_phase
Device boot phase.
Definition switchtec.h:111
static int switchtec_is_gen4(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 4 device.
Definition switchtec.h:469
static int switchtec_max_supported_ports(struct switchtec_dev *dev)
Return the max number of ports of a Switchtec device.
Definition switchtec.h:485
static int switchtec_is_gen5(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 5 device.
Definition switchtec.h:477
static int switchtec_is_pax_all(struct switchtec_dev *dev)
Return whether a Switchtec device is PAX(A).
Definition switchtec.h:586
static int switchtec_is_gen3(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 3 device.
Definition switchtec.h:461