Switchtec Userspace PROJECT_NUMBER = 4.4
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 {0x6048, SWITCHTEC_GEN6, SWITCHTEC_PFX}, //PFXs 48XG6
184 {0x6064, SWITCHTEC_GEN6, SWITCHTEC_PFX}, //PFXs 64XG6
185 {0x6044, SWITCHTEC_GEN6, SWITCHTEC_PFX}, //PFXs 144XG6
186 {0x6060, SWITCHTEC_GEN6, SWITCHTEC_PFX}, //PFXs 160XG6
187 {0x6148, SWITCHTEC_GEN6, SWITCHTEC_PSX}, //PSXs 48XG6
188 {0x6164, SWITCHTEC_GEN6, SWITCHTEC_PSX}, //PSXs 64XG6
189 {0x6144, SWITCHTEC_GEN6, SWITCHTEC_PSX}, //PSXs 144XG6
190 {0x6160, SWITCHTEC_GEN6, SWITCHTEC_PSX}, //PSXs 160XG6
191 {0x6248, SWITCHTEC_GEN6, SWITCHTEC_PFX}, //PFX 48XG6
192 {0x6264, SWITCHTEC_GEN6, SWITCHTEC_PFX}, //PFX 64XG6
193 {0x6244, SWITCHTEC_GEN6, SWITCHTEC_PFX}, //PFX 144XG6
194 {0x6260, SWITCHTEC_GEN6, SWITCHTEC_PFX}, //PFX 160XG6
195 {0x6348, SWITCHTEC_GEN6, SWITCHTEC_PSX}, //PSX 48XG6
196 {0x6364, SWITCHTEC_GEN6, SWITCHTEC_PSX}, //PSX 64XG6
197 {0x6344, SWITCHTEC_GEN6, SWITCHTEC_PSX}, //PSX 144XG6
198 {0x6360, SWITCHTEC_GEN6, SWITCHTEC_PSX}, //PSX 160XG6
199 {0},
200};
201
202static int set_gen_variant(struct switchtec_dev * dev)
203{
205 int ret;
206
207 dev->boot_phase = SWITCHTEC_BOOT_PHASE_FW;
208 dev->gen = SWITCHTEC_GEN_UNKNOWN;
209 dev->var = SWITCHTEC_VAR_UNKNOWN;
210 dev->device_id = dev->ops->get_device_id(dev);
211 if (!dev->device_id)
212 switchtec_get_device_id_bl2(dev,
213 (unsigned short *)&dev->device_id);
214
215 while (id->device_id) {
216 if (id->device_id == dev->device_id) {
217 dev->gen = id->gen;
218 dev->var = id->var;
219
220 break;
221 }
222
223 id++;
224 }
225
226 dev->pax_id = SWITCHTEC_PAX_ID_LOCAL;
227 ret = switchtec_get_device_info(dev, &dev->boot_phase, &dev->gen, NULL);
228 if (ret)
229 return -1;
230
231 return 0;
232}
233
234static int set_local_pax_id(struct switchtec_dev *dev)
235{
236 unsigned char local_pax_id;
237 int ret;
238
239 dev->local_pax_id = -1;
240
241 if (!switchtec_is_pax_all(dev))
242 return 0;
243
244 ret = switchtec_cmd(dev, MRPC_GET_PAX_ID, NULL, 0,
245 &local_pax_id, sizeof(local_pax_id));
246 if (ret)
247 return -1;
248
249 dev->local_pax_id = local_pax_id;
250 return 0;
251}
252
258{
259 free(devlist);
260}
261
279struct switchtec_dev *switchtec_open(const char *device)
280{
281 int idx;
282 int domain = 0;
283 int bus, dev, func;
284 char path[PATH_MAX];
285 int inst;
286 char *endptr;
287 struct switchtec_dev *ret;
288
289 if (sscanf(device, "%i@%i", &bus, &dev) == 2) {
290 ret = switchtec_open_i2c_by_adapter(bus, dev);
291 goto found;
292 }
293
294 if (sscanf(device, "%2049[^@]@%i", path, &dev) == 2) {
295 ret = switchtec_open_i2c(path, dev);
296 goto found;
297 }
298
299 if (device[0] == '/' &&
300 sscanf(device, "%2049[^:]:%i", path, &dev) == 2) {
301 ret = switchtec_open_i2c(path, dev);
302 goto found;
303 }
304
305 if (strchr(device, '/') || strchr(device, '\\')) {
306 ret = switchtec_open_by_path(device);
307 goto found;
308 }
309
310 if (sscanf(device, "%x:%x.%x", &bus, &dev, &func) == 3) {
311 ret = switchtec_open_by_pci_addr(domain, bus, dev, func);
312 goto found;
313 }
314
315 if (sscanf(device, "%x:%x:%x.%x", &domain, &bus, &dev, &func) == 4) {
316 ret = switchtec_open_by_pci_addr(domain, bus, dev, func);
317 goto found;
318 }
319
320 if (sscanf(device, "%2049[^:]:%i", path, &inst) == 2) {
321 ret = switchtec_open_eth(path, inst);
322 goto found;
323 }
324
325 errno = 0;
326 idx = strtol(device, &endptr, 0);
327 if (!errno && endptr != device) {
328 ret = switchtec_open_by_index(idx);
329 goto found;
330 }
331
332 if (sscanf(device, "switchtec%d", &idx) == 1) {
333 ret = switchtec_open_by_index(idx);
334 goto found;
335 }
336
337 errno = ENODEV;
338 return NULL;
339
340found:
341 if (!ret) {
342 errno = ENODEV;
343 return NULL;
344 }
345
346 snprintf(ret->name, sizeof(ret->name), "%s", device);
347
348 if (set_gen_variant(ret))
349 return NULL;
350
351 if (set_local_pax_id(ret))
352 return NULL;
353
354 return ret;
355}
356
364_PURE int switchtec_device_id(struct switchtec_dev *dev)
365{
366 return dev->device_id;
367}
368
376_PURE enum switchtec_gen switchtec_gen(struct switchtec_dev *dev)
377{
378 return dev->gen;
379}
380
388_PURE enum switchtec_variant switchtec_variant(struct switchtec_dev *dev)
389{
390 return dev->var;
391}
392
400_PURE enum switchtec_boot_phase switchtec_boot_phase(struct switchtec_dev *dev)
401{
402 return dev->boot_phase;
403}
404
412_PURE const char *switchtec_name(struct switchtec_dev *dev)
413{
414 return dev->name;
415}
416
422_PURE int switchtec_partition(struct switchtec_dev *dev)
423{
424 return dev->partition;
425}
426
427int switchtec_set_pax_id(struct switchtec_dev *dev, int pax_id)
428{
429 if (!switchtec_is_pax_all(dev) && (pax_id != SWITCHTEC_PAX_ID_LOCAL))
430 return -1;
431
432 if (pax_id == SWITCHTEC_PAX_ID_LOCAL)
433 dev->pax_id = dev->local_pax_id;
434 else
435 dev->pax_id = pax_id;
436
437 return 0;
438}
439
440static int compare_port_id(const void *aa, const void *bb)
441{
442 const struct switchtec_port_id *a = aa, *b = bb;
443
444 if (a->partition != b->partition)
445 return a->partition - b->partition;
446 if (a->upstream != b->upstream)
447 return b->upstream - a->upstream;
448 return a->log_id - b->log_id;
449}
450
451static int compare_status(const void *aa, const void *bb)
452{
453 const struct switchtec_status *a = aa, *b = bb;
454
455 return compare_port_id(&a->port, &b->port);
456}
457
458static const char *lane_reversal_str(int link_up,
459 int lane_reversal)
460{
461 if (!link_up)
462 return "N/A";
463
464 switch (lane_reversal) {
465 case 0: return "Normal Lane Ordering";
466 case 1: return "x16 (Full) Lane Reversal";
467 case 2: return "x2 Lane Reversal";
468 case 4: return "x4 Lane Reversal";
469 case 8: return "x8 Lane Reversal";
470 default: return "Unknown Lane Ordering";
471 }
472}
473
474static const char *lane_reversal_str_gen6(int link_up,
475 int lane_reversal)
476{
477 if (!link_up)
478 return "N/A";
479
480 switch (lane_reversal) {
481 case 0: return "Normal Lane Ordering";
482 case 1: return "Lane Reversal in effect";
483 default: return "Unknown Lane Ordering";
484 }
485}
486
487
488static void generate_lane_str(struct switchtec_status *s)
489{
490 int i, l;
491
492 for (i = 0; i < s->cfg_lnk_width; i++)
493 s->lanes[i] = 'x';
494
495 if (!s->link_up)
496 return;
497
498 l = s->first_act_lane;
499 if (!l && s->lane_reversal)
500 l += s->neg_lnk_width - 1;
501
502 for (i = 0; i < s->neg_lnk_width; i++) {
503 if (l < 0)
504 break;
505
506 if (i < 10)
507 s->lanes[l] = '0' + i;
508 else
509 s->lanes[l] = 'a' + i - 10;
510
511 l += s->lane_reversal ? -1 : 1;
512 }
513}
514
515static int switchtec_status_gen345(struct switchtec_dev *dev,
516 struct switchtec_status **status)
517{
518 uint64_t port_bitmap = 0;
519 int ret;
520 int i, p;
521 int nr_ports = 0;
522 struct switchtec_status *s;
523 int max_ports;
524
525 if (!status) {
526 errno = EINVAL;
527 return -errno;
528 }
529
530 max_ports = switchtec_max_supported_ports(dev);
531
532 struct {
533 uint8_t phys_port_id;
534 uint8_t par_id;
535 uint8_t log_port_id;
536 uint8_t stk_id;
537 uint8_t cfg_lnk_width;
538 uint8_t neg_lnk_width;
539 uint8_t usp_flag;
540 uint8_t linkup_linkrate;
541 uint16_t LTSSM;
542 uint8_t lane_reversal;
543 uint8_t first_act_lane;
544 } ports[max_ports];
545
546 ret = switchtec_cmd(dev, MRPC_LNKSTAT, &port_bitmap, sizeof(port_bitmap),
547 ports, sizeof(ports));
548 if (ret)
549 return -1;
550
551
552 for (i = 0; i < max_ports; i++) {
553 if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS)
554 continue;
555 nr_ports++;
556 }
557
558 s = *status = calloc(nr_ports, sizeof(*s));
559 if (!s)
560 return -ENOMEM;
561
562 for (i = 0, p = 0; i < max_ports && p < nr_ports; i++) {
563 if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS)
564 continue;
565
566 s[p].port.partition = ports[i].par_id;
567 s[p].port.stack = ports[i].stk_id >> 4;
568 s[p].port.upstream = ports[i].usp_flag;
569 s[p].port.stk_id = ports[i].stk_id & 0xF;
570 s[p].port.phys_id = ports[i].phys_port_id;
571 s[p].port.log_id = ports[i].log_port_id;
572
573 s[p].cfg_lnk_width = ports[i].cfg_lnk_width;
574 s[p].neg_lnk_width = ports[i].neg_lnk_width;
575 s[p].link_up = ports[i].linkup_linkrate >> 7;
576 s[p].link_rate = ports[i].linkup_linkrate & 0x7F;
577 s[p].ltssm = le16toh(ports[i].LTSSM);
578 s[p].ltssm_str = switchtec_ltssm_str(s[p].ltssm, 1, dev);
579 s[p].lane_reversal = ports[i].lane_reversal;
580 s[p].lane_reversal_str = lane_reversal_str(s[p].link_up,
581 s[p].lane_reversal);
582 s[p].first_act_lane = ports[i].first_act_lane & 0xF;
583 s[p].acs_ctrl = -1;
584 generate_lane_str(&s[p]);
585
586 p++;
587 }
588
589 qsort(s, nr_ports, sizeof(*s), compare_status);
590
591 return nr_ports;
592}
593
594static int switchtec_status_gen6(struct switchtec_dev *dev,
595 struct switchtec_status **status)
596{
597 struct {
598 uint64_t map1;
599 uint16_t map2;
600 uint16_t rsvrd1;
601 uint32_t rsvrd2;
602 } port_bitmap = {
603 .map1 = 0,
604 .map2 = 0
605 };
606
607 int ret;
608 int i, p;
609 int nr_ports = 0;
610 struct switchtec_status *s;
611 int max_ports;
612
613 if (!status) {
614 errno = EINVAL;
615 return -errno;
616 }
617
618 max_ports = switchtec_max_supported_ports(dev);
619
620 struct {
621 uint8_t phys_port_id;
622 uint8_t par_id;
623 uint8_t log_port_id;
624 uint8_t stk_id;
625 uint8_t cfg_lnk_width;
626 uint8_t neg_lnk_width;
627 uint8_t usp_flag;
628 uint8_t linkup_linkrate;
629 uint8_t ltssm_major;
630 uint8_t ltssm_minor;
631 uint8_t lane_reversal;
632 uint8_t first_act_lane;
633 } ports[max_ports];
634
635 ret = switchtec_cmd(dev, MRPC_LNKSTAT, &port_bitmap, sizeof(port_bitmap),
636 ports, sizeof(ports));
637 if (ret)
638 return -1;
639
640
641 for (i = 0; i < max_ports; i++) {
642 if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS)
643 continue;
644 nr_ports++;
645 }
646
647 s = *status = calloc(nr_ports, sizeof(*s));
648 if (!s)
649 return -ENOMEM;
650
651 for (i = 0, p = 0; i < max_ports && p < nr_ports; i++) {
652 if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS)
653 continue;
654
655 s[p].port.partition = ports[i].par_id;
656 s[p].port.stack = ports[i].stk_id >> 4;
657 s[p].port.upstream = ports[i].usp_flag;
658 s[p].port.stk_id = ports[i].stk_id & 0xF;
659 s[p].port.phys_id = ports[i].phys_port_id;
660 s[p].port.log_id = ports[i].log_port_id;
661
662 s[p].cfg_lnk_width = ports[i].cfg_lnk_width;
663 s[p].neg_lnk_width = ports[i].neg_lnk_width;
664 s[p].link_up = ports[i].linkup_linkrate >> 7;
665 s[p].link_rate = ports[i].linkup_linkrate & 0x7F;
666 s[p].ltssm = le16toh(ports[i].ltssm_major);
667 s[p].ltssm_str = switchtec_ltssm_str(s[p].ltssm, 1, dev);
668 s[p].lane_reversal = ports[i].lane_reversal;
669 s[p].lane_reversal_str = lane_reversal_str_gen6(s[p].link_up,
670 s[p].lane_reversal);
671 s[p].first_act_lane = ports[i].first_act_lane & 0xF;
672 s[p].acs_ctrl = -1;
673 generate_lane_str(&s[p]);
674
675 p++;
676 }
677
678 qsort(s, nr_ports, sizeof(*s), compare_status);
679
680 return nr_ports;
681}
682
694int switchtec_status(struct switchtec_dev *dev,
695 struct switchtec_status **status)
696{
697 if (switchtec_is_gen6(dev))
698 return switchtec_status_gen6(dev, status);
699 else
700 return switchtec_status_gen345(dev, status);
701}
702
709void switchtec_status_free(struct switchtec_status *status, int ports)
710{
711 int i;
712
713 for (i = 0; i < ports; i++) {
714 if (status[i].pci_bdf)
715 free(status[i].pci_bdf);
716
717 if (status[i].pci_bdf_path)
718 free(status[i].pci_bdf_path);
719
720 if (status[i].pci_dev)
721 free(status[i].pci_dev);
722
723 if (status[i].class_devices)
724 free(status[i].class_devices);
725 }
726
727 free(status);
728}
729
737
748const char *switchtec_strerror(void)
749{
750 const char *msg = "Unknown MRPC error";
751 int err;
752
753 if ((errno & (SWITCHTEC_ERRNO_MRPC_FLAG_BIT |
754 SWITCHTEC_ERRNO_GENERAL_FLAG_BIT)) == 0) {
755 if (errno)
756 return strerror(errno);
757 else
758 return platform_strerror();
759 }
760
761 if (errno & SWITCHTEC_ERRNO_GENERAL_FLAG_BIT) {
762 switch (errno) {
763 case SWITCHTEC_ERR_LOG_DEF_READ_ERROR:
764 msg = "Error reading log definition file"; break;
765 case SWITCHTEC_ERR_BIN_LOG_READ_ERROR:
766 msg = "Error reading binary log file"; break;
767 case SWITCHTEC_ERR_PARSED_LOG_WRITE_ERROR:
768 msg = "Error writing parsed log file"; break;
769 case SWITCHTEC_ERR_LOG_DEF_DATA_INVAL:
770 msg = "Invalid log definition data"; break;
771 case SWITCHTEC_ERR_INVALID_PORT:
772 msg = "Invalid port specified"; break;
773 case SWITCHTEC_ERR_INVALID_LANE:
774 msg = "Invalid lane specified"; break;
775 default:
776 msg = "Unknown Switchtec error"; break;
777 }
778
779 return msg;
780 }
781
782 err = errno & ~SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
783
784 switch (err) {
785 case ERR_NO_AVAIL_MRPC_THREAD:
786 msg = "No available MRPC handler thread"; break;
787 case ERR_HANDLER_THREAD_NOT_IDLE:
788 msg = "The handler thread is not idle"; break;
789 case ERR_NO_BG_THREAD:
790 msg = "No background thread run for the command"; break;
791
792 case ERR_REFCLK_SUBCMD_INVALID:
793 case ERR_STACKBIF_SUBCMD_INVALID:
794 case ERR_SUBCMD_INVALID: msg = "Invalid subcommand"; break;
795 case ERR_CMD_INVALID: msg = "Invalid command"; break;
796 case ERR_PARAM_INVALID: msg = "Invalid parameter"; break;
797 case ERR_BAD_FW_STATE: msg = "Bad firmware state"; break;
798 case ERR_MRPC_DENIED: msg = "MRPC request denied"; break;
799 case ERR_MRPC_NO_PREV_DATA:
800 msg = "No previous adaptation object data";
801 break;
802 case ERR_REFCLK_STACK_ID_INVALID:
803 case ERR_STACKBIF_STACK_ID_INVALID:
804 case ERR_STACK_INVALID: msg = "Invalid Stack"; break;
805 case ERR_LOOPBACK_PORT_INVALID:
806 case ERR_PORT_INVALID: msg = "Invalid Port"; break;
807 case ERR_EVENT_INVALID: msg = "Invalid Event"; break;
808 case ERR_RST_RULE_FAILED: msg = "Reset rule search failed"; break;
809 case ERR_UART_NOT_SUPPORTED:
810 msg = "UART interface not supported for this command"; break;
811 case ERR_XML_VERSION_MISMATCH:
812 msg = "XML version mismatch between MAIN and CFG partition";
813 break;
814 case ERR_ACCESS_REFUSED: msg = "Access Refused"; break;
815
816 case ERR_STACKBIF_CODE_INVALID:
817 msg = "Stack bifurcation code invalid"; break;
818 break;
819 case ERR_STACKBIF_PORT_BOUND:
820 msg = "Port already bound"; break;
821 break;
822
823 default: break;
824 }
825
826 switch (mrpc_error_cmd) {
827 case MRPC_PORTPARTP2P:
828 switch (err) {
829 case ERR_PHYC_PORT_ARDY_BIND:
830 msg = "Physical port already bound"; break;
831 case ERR_LOGC_PORT_ARDY_BIND:
832 msg = "Logical bridge instance already bound"; break;
833 case ERR_BIND_PRTT_NOT_EXIST:
834 msg = "Partition does not exist"; break;
835 case ERR_PHYC_PORT_NOT_EXIST:
836 msg = "Physical port does not exist"; break;
837 case ERR_PHYC_PORT_DIS:
838 msg = "Physical port disabled"; break;
839 case ERR_NO_LOGC_PORT:
840 msg = "No logical bridge instance"; break;
841 case ERR_BIND_IN_PROGRESS:
842 msg = "Bind/unbind in progress"; break;
843 case ERR_BIND_TGT_IS_USP:
844 msg = "Bind/unbind target is USP"; break;
845 case ERR_BIND_SUBCMD_INVALID:
846 msg = "Sub-command does not exist"; break;
847 case ERR_PHYC_PORT_LINK_ACT:
848 msg = "Physical port link active"; break;
849 case ERR_LOGC_PORT_NOT_BIND_PHYC_PORT:
850 msg = "Logical bridge not bind to physical port"; break;
851 case ERR_UNBIND_OPT_INVALID:
852 msg = "Invalid unbind option"; break;
853 case ERR_BIND_CHECK_FAIL:
854 msg = "Port bind checking failed"; break;
855 default: break;
856 }
857 break;
858 default: break;
859 }
860
861 return msg;
862}
863
871void switchtec_perror(const char *str)
872{
873 const char *msg = switchtec_strerror();
874 int is_mrpc = errno & SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
875 int err = errno & ~SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
876
877 if (is_mrpc)
878 fprintf(stderr, "%s: %s (MRPC: 0x%x, error: 0x%x)\n",
879 str, msg, mrpc_error_cmd, err);
880 else
881 fprintf(stderr, "%s: %s\n", str, msg);
882}
883
885
891
902int switchtec_echo(struct switchtec_dev *dev, uint32_t input,
903 uint32_t *output)
904{
905 return switchtec_cmd(dev, MRPC_ECHO, &input, sizeof(input),
906 output, sizeof(*output));
907}
908
918int switchtec_hard_reset(struct switchtec_dev *dev)
919{
920 uint32_t subcmd = 0;
921
922 return switchtec_cmd(dev, MRPC_RESET, &subcmd, sizeof(subcmd),
923 NULL, 0);
924}
925
930static void free_log_defs(struct log_defs *defs)
931{
932 int i, j;
933
934 if (!defs->module_defs)
935 return;
936
937 for (i = 0; i < defs->num_alloc; i++) {
938 free(defs->module_defs[i].mod_name);
939
940 for (j = 0; j < defs->module_defs[i].num_entries; j++)
941 free(defs->module_defs[i].entries[j]);
942
943 free(defs->module_defs[i].entries);
944 }
945
946 free(defs->module_defs);
947}
948
955static int realloc_log_defs(struct log_defs *defs, int num_modules)
956{
957 int i;
958
959 defs->module_defs = realloc(defs->module_defs,
960 (num_modules *
961 sizeof(struct module_log_defs)));
962 if (!defs->module_defs) {
963 free_log_defs(defs);
964 return -1;
965 }
966
967 for (i = defs->num_alloc; i < num_modules; i++)
968 memset(&defs->module_defs[i], 0,
969 sizeof(struct module_log_defs));
970
971 defs->num_alloc = num_modules;
972
973 return 0;
974}
975
982static bool parse_int(char *str, int *val)
983{
984 char *endptr;
985
986 errno = 0;
987 *val = strtol(str, &endptr, 0);
988
989 if ((endptr == str) || (*endptr != '\0') || (errno != 0))
990 return false;
991
992 return true;
993}
994
1001static int read_app_log_defs(FILE *log_def_file, struct log_defs *defs)
1002{
1003 int ret;
1004 char line[512];
1005 char *tok;
1006 int mod_id;
1007 struct module_log_defs *mod_defs;
1008 int num_entries;
1009 int i;
1010
1011 /* allocate some log definition entries */
1012 ret = realloc_log_defs(defs, 200);
1013 if (ret < 0)
1014 return ret;
1015
1016 while (fgets(line, sizeof(line), log_def_file)) {
1017
1018 /* ignore comments */
1019 if (line[0] == '#')
1020 continue;
1021
1022 /* strip any newline characters */
1023 line[strcspn(line, "\r\n")] = '\0';
1024
1025 /*
1026 * Tokenize and parse the line. Module headings are of the form:
1027 * mod_name mod_id num_entries
1028 */
1029 tok = strtok(line, " \t");
1030 if (!tok)
1031 continue;
1032
1033 tok = strtok(NULL, " \t");
1034 if (!tok)
1035 continue;
1036
1037 if (!parse_int(tok, &mod_id)) {
1038 errno = SWITCHTEC_ERR_LOG_DEF_DATA_INVAL;
1039 goto err_free_log_defs;
1040 }
1041
1042 /* reallocate more log definition entries if needed */
1043 if (mod_id > defs->num_alloc) {
1044 ret = realloc_log_defs(defs, mod_id * 2);
1045 if (ret < 0)
1046 return ret;
1047 }
1048
1049 mod_defs = &defs->module_defs[mod_id];
1050
1051 tok = strtok(NULL, " \t");
1052 if (!tok)
1053 continue;
1054
1055 if (!parse_int(tok, &num_entries)) {
1056 errno = SWITCHTEC_ERR_LOG_DEF_DATA_INVAL;
1057 goto err_free_log_defs;
1058 }
1059
1060 /*
1061 * Skip this module if it has already been done. This can happen
1062 * if the module is duplicated in the log definition file.
1063 */
1064 if (mod_defs->mod_name != NULL) {
1065 for (i = 0; i < num_entries; i++) {
1066 if (!fgets(line, sizeof(line),
1067 log_def_file))
1068 break;
1069 }
1070 continue;
1071 }
1072
1073 mod_defs->mod_name = strdup(line);
1074 mod_defs->num_entries = num_entries;
1075 mod_defs->entries = calloc(mod_defs->num_entries,
1076 sizeof(*mod_defs->entries));
1077 if (!mod_defs->entries)
1078 goto err_free_log_defs;
1079
1080 for (i = 0; i < mod_defs->num_entries; i++) {
1081 if (fgets(line, sizeof(line), log_def_file) == NULL) {
1082 errno = SWITCHTEC_ERR_LOG_DEF_READ_ERROR;
1083 goto err_free_log_defs;
1084 }
1085
1086 mod_defs->entries[i] = strdup(line);
1087 if (!mod_defs->entries[i])
1088 goto err_free_log_defs;
1089 }
1090 }
1091
1092 if (ferror(log_def_file)) {
1093 errno = SWITCHTEC_ERR_LOG_DEF_READ_ERROR;
1094 goto err_free_log_defs;
1095 }
1096
1097 return 0;
1098
1099err_free_log_defs:
1100 free_log_defs(defs);
1101 return -1;
1102}
1103
1110static int read_mailbox_log_defs(FILE *log_def_file, struct log_defs *defs)
1111{
1112 int ret;
1113 char line[512];
1114 struct module_log_defs *mod_defs;
1115 int num_entries_alloc;
1116
1117 /*
1118 * The mailbox log definitions don't keep track of modules. Allocate a
1119 * single log definition entry for all definitions.
1120 */
1121 ret = realloc_log_defs(defs, 1);
1122 if (ret < 0)
1123 return ret;
1124
1125 mod_defs = &defs->module_defs[0];
1126 mod_defs->num_entries = 0;
1127
1128 /* allocate some entries */
1129 num_entries_alloc = 100;
1130 mod_defs->entries = calloc(num_entries_alloc,
1131 sizeof(*mod_defs->entries));
1132 if (!mod_defs->entries)
1133 goto err_free_log_defs;
1134
1135 while (fgets(line, sizeof(line), log_def_file)) {
1136 /* ignore comments */
1137 if (line[0] == '#')
1138 continue;
1139
1140 if (mod_defs->num_entries >= num_entries_alloc) {
1141 /* allocate more entries */
1142 num_entries_alloc *= 2;
1143 mod_defs->entries = realloc(mod_defs->entries,
1144 (num_entries_alloc *
1145 sizeof(*mod_defs->entries)));
1146 if (!mod_defs->entries)
1147 goto err_free_log_defs;
1148 }
1149
1150 mod_defs->entries[mod_defs->num_entries] = strdup(line);
1151 if (!mod_defs->entries[mod_defs->num_entries])
1152 goto err_free_log_defs;
1153
1154 mod_defs->num_entries++;
1155 }
1156
1157 if (ferror(log_def_file)) {
1158 errno = SWITCHTEC_ERR_LOG_DEF_READ_ERROR;
1159 goto err_free_log_defs;
1160 }
1161
1162 return 0;
1163
1164err_free_log_defs:
1165 free_log_defs(defs);
1166 return -1;
1167}
1168
1180static int write_parsed_log(struct log_a_data log_data[],
1181 size_t count, int init_entry_idx,
1182 struct log_defs *defs,
1183 enum switchtec_log_parse_type log_type,
1184 FILE *log_file, int ts_factor)
1185{
1186 int i;
1187 int ret;
1188 int entry_idx = init_entry_idx;
1189 unsigned long long time;
1190 unsigned int nanos, micros, millis, secs, mins, hours, days;
1191 unsigned int entry_num;
1192 unsigned int mod_id;
1193 unsigned int log_sev = 0;
1194 const char *log_sev_strs[] = {"DISABLED", "HIGHEST", "HIGH", "MEDIUM",
1195 "LOW", "LOWEST"};
1196 bool is_bl1;
1197 struct module_log_defs *mod_defs;
1198
1199 if (entry_idx == 0) {
1200 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP || log_type == SWITCHTEC_LOG_PARSE_TYPE_FTDC)
1201 fputs(" #|Timestamp |Module |Severity |Event ID |Event\n",
1202 log_file);
1203 else
1204 fputs(" #|Timestamp |Source |Event ID |Event\n",
1205 log_file);
1206 }
1207
1208 for (i = 0; i < count; i ++) {
1209 /* timestamp is in the first 2 DWords */
1210 time = (((unsigned long long)log_data[i].data[0] << 32) |
1211 log_data[i].data[1]) * ts_factor/100;
1212 nanos = time % 1000;
1213 time /= 1000;
1214 micros = time % 1000;
1215 time /= 1000;
1216 millis = time % 1000;
1217 time /= 1000;
1218 secs = time % 60;
1219 time /= 60;
1220 mins = time % 60;
1221 time /= 60;
1222 hours = time % 24;
1223 days = time / 24;
1224
1225 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP || log_type == SWITCHTEC_LOG_PARSE_TYPE_FTDC) {
1226 /*
1227 * app log: module ID and log severity are in the 3rd
1228 * DWord
1229 */
1230 mod_id = (log_data[i].data[2] >> 16) & 0xFFF;
1231 log_sev = (log_data[i].data[2] >> 28) & 0xF;
1232
1233 if ((mod_id > defs->num_alloc) ||
1234 (defs->module_defs[mod_id].mod_name == NULL) ||
1235 (strlen(defs->module_defs[mod_id].mod_name) == 0)) {
1236 if (fprintf(log_file, "(Invalid module ID: 0x%x)\n",
1237 mod_id) < 0)
1238 goto ret_print_error;
1239 continue;
1240 }
1241
1242 if (log_sev >= ARRAY_SIZE(log_sev_strs)) {
1243 if (fprintf(log_file, "(Invalid log severity: %d)\n",
1244 log_sev) < 0)
1245 goto ret_print_error;
1246 continue;
1247 }
1248 } else {
1249 /*
1250 * mailbox log: BL1/BL2 indication is in the 3rd
1251 * DWord
1252 */
1253 is_bl1 = (((log_data[i].data[2] >> 27) & 1) == 0);
1254
1255 /* mailbox log definitions are all in the first entry */
1256 mod_id = 0;
1257 }
1258
1259 mod_defs = &defs->module_defs[mod_id];
1260
1261 /* entry number is in the 3rd DWord */
1262 entry_num = log_data[i].data[2] & 0x0000FFFF;
1263
1264 if (entry_num >= mod_defs->num_entries) {
1265 if (fprintf(log_file,
1266 "(Invalid log entry number: %d (module 0x%x))\n",
1267 entry_num, mod_id) < 0)
1268 goto ret_print_error;
1269 continue;
1270 }
1271
1272 /* print the entry index and timestamp */
1273 if (ts_factor == 0)
1274 ret = fprintf(log_file,
1275 "%04d|xxxd xx:xx:xx.xxx,xxx,xxx|",
1276 entry_idx);
1277 else
1278 ret = fprintf(log_file,
1279 "%04d|%03dd %02d:%02d:%02d.%03d,%03d,%03d|",
1280 entry_idx, days, hours, mins, secs,
1281 millis, micros, nanos);
1282
1283 if (ret < 0)
1284 goto ret_print_error;
1285
1286 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP || log_type == SWITCHTEC_LOG_PARSE_TYPE_FTDC) {
1287 /* print the module name and log severity */
1288 if (fprintf(log_file, "%-12s |%-8s |0x%04x |",
1289 mod_defs->mod_name, log_sev_strs[log_sev],
1290 entry_num) < 0)
1291 goto ret_print_error;
1292 } else {
1293 /* print the log source (BL1/BL2) */
1294 if (fprintf(log_file, "%-6s |0x%04x |",
1295 (is_bl1 ? "BL1" : "BL2"), entry_num) < 0)
1296 goto ret_print_error;
1297 }
1298
1299 /* print the log entry */
1300 if (fprintf(log_file, mod_defs->entries[entry_num],
1301 log_data[i].data[3], log_data[i].data[4],
1302 log_data[i].data[5], log_data[i].data[6],
1303 log_data[i].data[7]) < 0)
1304 goto ret_print_error;
1305
1306 entry_idx++;
1307 }
1308
1309 if (fflush(log_file) != 0)
1310 return -1;
1311
1312 return 0;
1313
1314ret_print_error:
1315 errno = SWITCHTEC_ERR_PARSED_LOG_WRITE_ERROR;
1316 return -1;
1317}
1318
1319static int parse_def_header(FILE *log_def_file, uint32_t *fw_version,
1320 uint32_t *sdk_version)
1321{
1322 char line[512];
1323 int i;
1324
1325 *fw_version = 0;
1326 *sdk_version = 0;
1327 while (fgets(line, sizeof(line), log_def_file)) {
1328 if (line[0] != '#')
1329 continue;
1330
1331 i = 0;
1332 while (line[i] == ' ' || line[i] == '#') i++;
1333
1334 if (strncasecmp(line + i, "SDK Version:", 12) == 0) {
1335 i += 12;
1336 while (line[i] == ' ') i++;
1337 sscanf(line + i, "%i", (int*)sdk_version);
1338 }
1339 else if (strncasecmp(line + i, "FW Version:", 11) == 0) {
1340 i += 11;
1341 while (line[i] == ' ') i++;
1342 sscanf(line + i, "%i", (int*)fw_version);
1343 }
1344 }
1345
1346 rewind(log_def_file);
1347 return 0;
1348}
1349
1350static int append_ftdc_log_header(int fd, uint32_t sdk_def_version,
1351 uint32_t fw_def_version)
1352{
1353 int ret;
1354 char hdr_str_fmt[] = "##########################################\n"
1355 "## Parsed with FTDC log file from definition:\n"
1356 "## FW def version %08x\n"
1357 "## SDK def version %08x\n"
1358 "##########################################\n\n";
1359 char hdr_str[512];
1360
1361 snprintf(hdr_str, 512, hdr_str_fmt, fw_def_version, sdk_def_version);
1362 ret = write(fd, hdr_str, strlen(hdr_str));
1363
1364 return ret;
1365}
1366
1367static int append_log_header(int fd, uint32_t sdk_version,
1368 uint32_t fw_version, int binary)
1369{
1370 int ret;
1371 struct log_header {
1372 uint8_t magic[8];
1373 uint32_t fw_version;
1374 uint32_t sdk_version;
1375 uint32_t flags;
1376 uint32_t rsvd[3];
1377 } header = {
1378 .magic = {'S', 'W', 'M', 'C', 'L', 'O', 'G', 'F'},
1379 .fw_version = fw_version,
1380 .sdk_version = sdk_version
1381 };
1382 char hdr_str_fmt[] = "####################################\n"
1383 "## Parsed with definition file for\n"
1384 "## FW version %08x\n"
1385 "## SDK version %08x\n"
1386 "####################################\n\n";
1387 char hdr_str[512];
1388
1389 if (binary) {
1390 ret = write(fd, &header, sizeof(header));
1391 } else {
1392 snprintf(hdr_str, 512, hdr_str_fmt, fw_version, sdk_version);
1393 ret = write(fd, hdr_str, strlen(hdr_str));
1394 }
1395
1396 return ret;
1397}
1398
1399static int get_ts_factor(enum switchtec_gen gen)
1400{
1401 if (gen == SWITCHTEC_GEN_UNKNOWN)
1402 return 0;
1403 else if (gen == SWITCHTEC_GEN3)
1404 return 1000;
1405 else
1406 return 833;
1407}
1408
1409static int log_a_to_file(struct switchtec_dev *dev, int sub_cmd_id,
1410 int fd, FILE *log_def_file,
1411 struct switchtec_log_file_info *info)
1412{
1413 int ret = -1;
1414 int read = 0;
1415 struct log_a_retr_result res;
1416 struct log_a_retr cmd = {
1417 .sub_cmd_id = sub_cmd_id,
1418 .start = -1,
1419 };
1420 struct log_defs defs = {
1421 .module_defs = NULL,
1422 .num_alloc = 0};
1423 FILE *log_file;
1424 int entry_idx = 0;
1425 uint32_t fw_version = 0;
1426 uint32_t sdk_version = 0;
1427
1428 if (log_def_file != NULL) {
1429 ret = parse_def_header(log_def_file, &fw_version,
1430 &sdk_version);
1431 if (ret)
1432 return ret;
1433 /* read the log definition file into defs */
1434 ret = read_app_log_defs(log_def_file, &defs);
1435 if (ret < 0)
1436 return ret;
1437 }
1438
1439 res.hdr.remain = 1;
1440
1441 while (res.hdr.remain) {
1442 ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
1443 &res, sizeof(res));
1444 if (ret)
1445 goto ret_free_log_defs;
1446 if (res.hdr.overflow && info)
1447 info->overflow = 1;
1448 if (read == 0) {
1449 if (dev->gen < SWITCHTEC_GEN5) {
1450 res.hdr.sdk_version = 0;
1451 res.hdr.fw_version = 0;
1452 }
1453
1454 if (info) {
1455 info->def_fw_version = fw_version;
1456 info->def_sdk_version = sdk_version;
1457 info->log_fw_version = res.hdr.fw_version;
1458 info->log_sdk_version = res.hdr.sdk_version;
1459 }
1460
1461 if (res.hdr.sdk_version != sdk_version ||
1462 res.hdr.fw_version != fw_version) {
1463 if (info && log_def_file)
1464 info->version_mismatch = true;
1465
1466 }
1467
1468 append_log_header(fd, res.hdr.sdk_version,
1469 res.hdr.fw_version,
1470 log_def_file == NULL? 1 : 0);
1471 }
1472
1473 if (log_def_file == NULL) {
1474 /* write the binary log data to a file */
1475 ret = write(fd, res.data,
1476 sizeof(*res.data) * res.hdr.count);
1477 if (ret < 0)
1478 return ret;
1479 } else {
1480 log_file = fdopen(fd, "w");
1481 if (!log_file)
1482 goto ret_free_log_defs;
1483
1484 /* parse the log data and write it to a file */
1485 ret = write_parsed_log(res.data, res.hdr.count,
1486 entry_idx, &defs,
1487 SWITCHTEC_LOG_PARSE_TYPE_APP,
1488 log_file,
1489 get_ts_factor(dev->gen));
1490 if (ret < 0)
1491 goto ret_free_log_defs;
1492
1493 entry_idx += res.hdr.count;
1494 }
1495
1496 read += le32toh(res.hdr.count);
1497 cmd.start = res.hdr.next_start;
1498 }
1499
1500 ret = 0;
1501
1502ret_free_log_defs:
1503 free_log_defs(&defs);
1504 return ret;
1505}
1506
1507static int log_b_to_file(struct switchtec_dev *dev, int sub_cmd_id, int fd)
1508{
1509 int ret;
1510 int read = 0;
1511 struct log_b_retr_result res;
1512 struct log_b_retr cmd = {
1513 .sub_cmd_id = sub_cmd_id,
1514 .offset = 0,
1515 .length = htole32(sizeof(res.data)),
1516 };
1517
1518 res.hdr.remain = sizeof(res.data);
1519
1520 while (res.hdr.remain) {
1521 ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
1522 &res, sizeof(res));
1523 if (ret)
1524 return -1;
1525
1526 ret = write(fd, res.data, res.hdr.length);
1527 if (ret < 0)
1528 return ret;
1529
1530 read += le32toh(res.hdr.length);
1531 cmd.offset = htole32(read);
1532 }
1533
1534 return 0;
1535}
1536
1537static int log_c_to_file(struct switchtec_dev *dev, int sub_cmd_id, int fd)
1538{
1539 int ret;
1540 struct log_cmd {
1541 uint8_t subcmd;
1542 uint8_t rsvd[3];
1543 } cmd = {};
1544
1545 struct log_reply {
1546 uint8_t reason;
1547 uint8_t rsvd[3];
1548 uint32_t nvlog_version;
1549 uint32_t thread_handle;
1550 uint32_t fw_version;
1551 uint32_t timestamp1;
1552 uint32_t timestamp2;
1553 } reply;
1554
1555 cmd.subcmd = sub_cmd_id;
1556
1557 ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
1558 &reply, sizeof(reply));
1559 if (ret)
1560 return -1;
1561
1562 ret = write(fd, &reply, sizeof(reply));
1563 if (ret < 0)
1564 return ret;
1565
1566 return 0;
1567}
1568
1569static int log_d_to_file(struct switchtec_dev *dev, int sub_cmd_id, int fd)
1570{
1571 int ret;
1572 int read = 0;
1573
1574 struct log_ftdc_retr_result res;
1575 struct log_ftdc_retr cmd = {
1576 .sub_cmd_id = sub_cmd_id,
1577 .reserved = 0,
1578 .req_seq = 0,
1579 };
1580 uint32_t length = sizeof(res.data);
1581
1582 cmd.req_seq = 0;
1583 res.data[1] = 0;
1584
1585 while ( !(res.data[1]) ) {
1586 ret = switchtec_cmd(dev, MRPC_FTDC_LOG_DUMP, &cmd, sizeof(cmd),
1587 &res, sizeof(res));
1588 if (ret)
1589 return -1;
1590
1591 ret = write(fd, res.data, (res.data[0]+1)*4);
1592 if (ret < 0)
1593 return ret;
1594
1595 read += length;
1596 cmd.req_seq++;
1597 }
1598
1599 return 0;
1600}
1601
1602static int log_ram_flash_to_file(struct switchtec_dev *dev,
1603 int gen5_cmd, int gen4_cmd, int gen4_cmd_lgcy,
1604 int fd, FILE *log_def_file,
1605 struct switchtec_log_file_info *info)
1606{
1607 int ret;
1608
1609 if (switchtec_is_gen5(dev)) {
1610 return log_a_to_file(dev, gen5_cmd, fd, log_def_file,
1611 info);
1612 } else {
1613 ret = log_a_to_file(dev, gen4_cmd, fd, log_def_file,
1614 info);
1615
1616 /* somehow hardware returns ERR_LOGC_PORT_ARDY_BIND
1617 * instead of ERR_SUBCMD_INVALID if this subcommand
1618 * is not supported, so we fall back to legacy
1619 * subcommand on ERR_LOGC_PORT_ARDY_BIND error as well
1620 */
1621 if (ret > 0 &&
1622 (ERRNO_MRPC(errno) == ERR_LOGC_PORT_ARDY_BIND ||
1623 ERRNO_MRPC(errno) == ERR_SUBCMD_INVALID))
1624 ret = log_a_to_file(dev, gen4_cmd_lgcy, fd,
1625 log_def_file, info);
1626
1627 return ret;
1628 }
1629}
1630
1640int switchtec_log_to_file(struct switchtec_dev *dev,
1641 enum switchtec_log_type type, int fd, FILE *log_def_file,
1642 struct switchtec_log_file_info *info)
1643{
1644 if (info)
1645 memset(info, 0, sizeof(*info));
1646
1647 switch (type) {
1648 case SWITCHTEC_LOG_RAM:
1649 return log_ram_flash_to_file(dev,
1650 MRPC_FWLOGRD_RAM_GEN5,
1651 MRPC_FWLOGRD_RAM_WITH_FLAG,
1652 MRPC_FWLOGRD_RAM,
1653 fd, log_def_file, info);
1654 case SWITCHTEC_LOG_FLASH:
1655 return log_ram_flash_to_file(dev,
1656 MRPC_FWLOGRD_FLASH_GEN5,
1657 MRPC_FWLOGRD_FLASH_WITH_FLAG,
1658 MRPC_FWLOGRD_FLASH,
1659 fd, log_def_file, info);
1660 case SWITCHTEC_LOG_FTDC:
1661 return log_d_to_file(dev, MRPC_FWLOGRD_RAM, fd);
1662 case SWITCHTEC_LOG_MEMLOG:
1663 return log_b_to_file(dev, MRPC_FWLOGRD_MEMLOG, fd);
1664 case SWITCHTEC_LOG_REGS:
1665 return log_b_to_file(dev, MRPC_FWLOGRD_REGS, fd);
1666 case SWITCHTEC_LOG_THRD_STACK:
1667 return log_b_to_file(dev, MRPC_FWLOGRD_THRD_STACK, fd);
1668 case SWITCHTEC_LOG_SYS_STACK:
1669 return log_b_to_file(dev, MRPC_FWLOGRD_SYS_STACK, fd);
1670 case SWITCHTEC_LOG_THRD:
1671 return log_b_to_file(dev, MRPC_FWLOGRD_THRD, fd);
1672 case SWITCHTEC_LOG_NVHDR:
1673 return log_c_to_file(dev, MRPC_FWLOGRD_NVHDR, fd);
1674 };
1675
1676 errno = EINVAL;
1677 return -errno;
1678}
1679
1680static int parse_log_header(FILE *bin_log_file, uint32_t *fw_version,
1681 uint32_t *sdk_version)
1682{
1683 struct log_header {
1684 uint8_t magic[8];
1685 uint32_t fw_version;
1686 uint32_t sdk_version;
1687 uint32_t flags;
1688 uint32_t rsvd[3];
1689 } header;
1690
1691 char sig[8] = {'S', 'W', 'M', 'C', 'L', 'O', 'G', 'F'};
1692 int ret;
1693
1694 ret = fread(&header, sizeof(header), 1, bin_log_file);
1695 if (ret <= 0) {
1696 errno = EBADF;
1697 return -EBADF;
1698 }
1699
1700 if (memcmp(sig, header.magic, 8)) {
1701 rewind(bin_log_file);
1702 *fw_version = 0;
1703 *sdk_version = 0;
1704 return 0;
1705 }
1706
1707 *fw_version = header.fw_version;
1708 *sdk_version = header.sdk_version;
1709
1710 return 0;
1711}
1712
1723int switchtec_parse_log(FILE *bin_log_file, FILE *log_def_file,
1724 FILE *parsed_log_file,
1725 enum switchtec_log_parse_type log_type,
1726 enum switchtec_gen gen,
1727 struct switchtec_log_file_info *info)
1728{
1729 int ret;
1730 struct log_a_data log_data;
1731 struct log_defs defs = {
1732 .module_defs = NULL,
1733 .num_alloc = 0};
1734 int entry_idx = 0;
1735 uint32_t fw_version_log = 0;
1736 uint32_t sdk_version_log = 0;
1737 uint32_t fw_version_def;
1738 uint32_t sdk_version_def;
1739 enum switchtec_gen gen_file;
1740
1741 if (info)
1742 memset(info, 0, sizeof(*info));
1743
1744 if ((log_type != SWITCHTEC_LOG_PARSE_TYPE_APP) &&
1745 (log_type != SWITCHTEC_LOG_PARSE_TYPE_MAILBOX) &&
1746 (log_type != SWITCHTEC_LOG_PARSE_TYPE_FTDC)) {
1747 errno = EINVAL;
1748 return -errno;
1749 }
1750
1751 if (log_type != SWITCHTEC_LOG_PARSE_TYPE_FTDC)
1752 {
1753 ret = parse_log_header(bin_log_file, &fw_version_log,
1754 &sdk_version_log);
1755 if (ret)
1756 return ret;
1757 }
1758
1759 ret = parse_def_header(log_def_file, &fw_version_def,
1760 &sdk_version_def);
1761 if (ret)
1762 return ret;
1763
1764 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_MAILBOX) {
1765 fw_version_log = fw_version_def;
1766 sdk_version_log = sdk_version_def;
1767 }
1768
1769 if (info) {
1770 info->def_fw_version = fw_version_def;
1771 info->def_sdk_version = sdk_version_def;
1772
1773 info->log_fw_version = fw_version_log;
1774 info->log_sdk_version = sdk_version_log;
1775 }
1776 /* read the log definition file into defs */
1777 if (log_type == SWITCHTEC_LOG_PARSE_TYPE_APP || log_type == SWITCHTEC_LOG_PARSE_TYPE_FTDC)
1778 ret = read_app_log_defs(log_def_file, &defs);
1779 else
1780 ret = read_mailbox_log_defs(log_def_file, &defs);
1781
1782 if (ret < 0)
1783 return ret;
1784
1785 if (log_type != SWITCHTEC_LOG_PARSE_TYPE_FTDC)
1786 ret = append_log_header(fileno(parsed_log_file), sdk_version_log,
1787 fw_version_log, 0);
1788 else
1789 ret = append_ftdc_log_header(fileno(parsed_log_file), sdk_version_def,
1790 fw_version_def);
1791
1792 if (ret < 0)
1793 return ret;
1794
1795 /* parse each log entry */
1796 while (fread(&log_data, sizeof(struct log_a_data), 1,
1797 bin_log_file) == 1) {
1798 if (fw_version_log)
1799 gen_file = switchtec_fw_version_to_gen(fw_version_log);
1800 else
1801 gen_file = switchtec_fw_version_to_gen(fw_version_def);
1802
1803 if (gen_file != SWITCHTEC_GEN_UNKNOWN &&
1804 gen != SWITCHTEC_GEN_UNKNOWN) {
1805 if (info)
1806 info->gen_ignored = true;
1807 } else if (gen_file == SWITCHTEC_GEN_UNKNOWN &&
1808 gen == SWITCHTEC_GEN_UNKNOWN) {
1809 if (info)
1810 info->gen_unknown = true;
1811 } else if (gen != SWITCHTEC_GEN_UNKNOWN) {
1812 gen_file = gen;
1813 }
1814
1815 ret = write_parsed_log(&log_data, 1, entry_idx, &defs,
1816 log_type, parsed_log_file,
1817 get_ts_factor(gen_file));
1818 if (ret < 0)
1819 goto ret_free_log_defs;
1820
1821 entry_idx++;
1822 }
1823
1824 if (ferror(bin_log_file)) {
1825 errno = SWITCHTEC_ERR_BIN_LOG_READ_ERROR;
1826 ret = -1;
1827 }
1828
1829 if (fw_version_def != fw_version_log ||
1830 sdk_version_def != sdk_version_log) {
1831 if (info)
1832 info->version_mismatch = true;
1833 ret = ENOEXEC;
1834 }
1835
1836ret_free_log_defs:
1837 free_log_defs(&defs);
1838 return ret;
1839}
1840
1848int switchtec_log_def_to_file(struct switchtec_dev *dev,
1849 enum switchtec_log_def_type type,
1850 FILE* file)
1851{
1852 int ret;
1853 struct log_cmd {
1854 uint8_t subcmd;
1855 uint8_t rsvd[3];
1856 uint16_t idx;
1857 uint16_t mod_id;
1858 } cmd = {};
1859
1860 struct log_reply {
1861 uint16_t end_of_data;
1862 uint16_t data_len;
1863 uint16_t next_idx;
1864 uint16_t next_mod_id;
1865 uint8_t data[MRPC_MAX_DATA_LEN - 16];
1866 } reply = {};
1867
1868 switch (type) {
1869 case SWITCHTEC_LOG_DEF_TYPE_APP:
1870 cmd.subcmd = MRPC_LOG_DEF_APP;
1871 break;
1872
1873 case SWITCHTEC_LOG_DEF_TYPE_MAILBOX:
1874 cmd.subcmd = MRPC_LOG_DEF_MAILBOX;
1875 break;
1876
1877 default:
1878 errno = EINVAL;
1879 return -errno;
1880 }
1881
1882 do {
1883 ret = switchtec_cmd(dev, MRPC_LOG_DEF_GET, &cmd, sizeof(cmd),
1884 &reply, sizeof(reply));
1885 if (ret)
1886 return -1;
1887
1888 ret = fwrite(reply.data, reply.data_len, 1, file);
1889 if (ret < 0)
1890 return ret;
1891
1892 cmd.idx = reply.next_idx;
1893 cmd.mod_id = reply.next_mod_id;
1894 } while (!reply.end_of_data);
1895
1896 return 0;
1897}
1898
1899static enum switchtec_gen map_to_gen(uint32_t gen)
1900{
1901 enum switchtec_gen ret = SWITCHTEC_GEN_UNKNOWN;
1902
1903 switch (gen) {
1904 case 0:
1905 ret = SWITCHTEC_GEN4;
1906 break;
1907 case 1:
1908 ret = SWITCHTEC_GEN5;
1909 break;
1910 case 2:
1911 ret = SWITCHTEC_GEN6;
1912 break;
1913 default:
1914 ret = SWITCHTEC_GEN_UNKNOWN;
1915 break;
1916 }
1917
1918 return ret;
1919}
1920
1929int switchtec_get_device_info(struct switchtec_dev *dev,
1930 enum switchtec_boot_phase *phase,
1931 enum switchtec_gen *gen,
1932 enum switchtec_rev *rev)
1933{
1934 int ret;
1935 uint32_t ping_dw = 0;
1936 uint32_t dev_info;
1937 struct get_dev_info_reply {
1938 uint32_t dev_info;
1939 uint32_t ping_reply;
1940 } reply;
1941
1942 ping_dw = time(NULL);
1943
1944 /*
1945 * The I2C TWI Ping command also dumps information about the
1946 * revision and image phase.
1947 */
1948 ret = switchtec_cmd(dev, MRPC_I2C_TWI_PING, &ping_dw,
1949 sizeof(ping_dw),
1950 &reply, sizeof(reply));
1951 if (ret == 0) {
1952 if (ping_dw != ~reply.ping_reply)
1953 return -1;
1954
1955 dev_info = le32toh(reply.dev_info);
1956 if (phase)
1957 *phase = dev_info & 0xff;
1958 if (rev)
1959 *rev = (dev_info >> 8) & 0x0f;
1960 if (gen)
1961 *gen = map_to_gen((dev_info >> 12) & 0x0f);
1962 } else if (errno == EBADMSG || ERRNO_MRPC(errno) == ERR_CMD_INVALID) {
1963 if (phase)
1964 *phase = SWITCHTEC_BOOT_PHASE_FW;
1965 if (gen)
1966 *gen = SWITCHTEC_GEN3;
1967 if (rev)
1968 *rev = SWITCHTEC_REV_UNKNOWN;
1969
1970 errno = 0;
1971 } else {
1972 return -1;
1973 }
1974
1975 return 0;
1976}
1977
1984float switchtec_die_temp(struct switchtec_dev *dev)
1985{
1986 int ret;
1987 uint32_t sub_cmd_id;
1988 uint32_t temp;
1989
1990 if (switchtec_is_gen3(dev)) {
1991 sub_cmd_id = MRPC_DIETEMP_SET_MEAS;
1992 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1993 sizeof(sub_cmd_id), NULL, 0);
1994 if (ret)
1995 return -100.0;
1996
1997 sub_cmd_id = MRPC_DIETEMP_GET;
1998 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
1999 sizeof(sub_cmd_id), &temp, sizeof(temp));
2000 if (ret)
2001 return -100.0;
2002 } else if (switchtec_is_gen4(dev)) {
2003 sub_cmd_id = MRPC_DIETEMP_GET_GEN4;
2004 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
2005 sizeof(sub_cmd_id), &temp, sizeof(temp));
2006 if (ret)
2007 return -100.0;
2008 } else {
2009 sub_cmd_id = MRPC_DIETEMP_GET_GEN5;
2010 uint32_t temps[4];
2011 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
2012 sizeof(sub_cmd_id), temps, sizeof(temps));
2013 if (ret)
2014 return -100.0;
2015 temp = (temps[0] + temps[1] + temps[2] + temps[3]) / 4;
2016 }
2017
2018 return le32toh(temp) / 100.;
2019}
2020
2028int switchtec_die_temps(struct switchtec_dev *dev, int nr_sensor,
2029 float *sensor_readings)
2030{
2031 int ret;
2032 uint32_t sub_cmd_id;
2033 uint32_t temp;
2034
2035 if (nr_sensor <= 0 || !sensor_readings)
2036 return 0;
2037
2038 if (switchtec_is_gen3(dev)) {
2039 sub_cmd_id = MRPC_DIETEMP_SET_MEAS;
2040 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
2041 sizeof(sub_cmd_id), NULL, 0);
2042 if (ret)
2043 return -100.0;
2044
2045 sub_cmd_id = MRPC_DIETEMP_GET;
2046 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
2047 sizeof(sub_cmd_id), &temp, sizeof(temp));
2048 if (ret)
2049 return -100.0;
2050
2051 sensor_readings[0] = le32toh(temp) / 100.;
2052 return 1;
2053 } else if (switchtec_is_gen4(dev)) {
2054 sub_cmd_id = MRPC_DIETEMP_GET_GEN4;
2055 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
2056 sizeof(sub_cmd_id), &temp, sizeof(temp));
2057 if (ret)
2058 return -100.0;
2059
2060 sensor_readings[0] = le32toh(temp) / 100.;
2061 return 1;
2062 } else {
2063 sub_cmd_id = MRPC_DIETEMP_GET_GEN5;
2064 uint32_t temps[4];
2065 int i;
2066
2067 ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
2068 sizeof(sub_cmd_id), temps, sizeof(temps));
2069 if (ret)
2070 return -100.0;
2071
2072 for (i = 0; i < nr_sensor && i < 4; i++)
2073 sensor_readings[i] = le32toh(temps[i]) / 100.;
2074
2075 return i;
2076 }
2077}
2078
2079int switchtec_bind_info(struct switchtec_dev *dev,
2080 struct switchtec_bind_status_out *status, int phy_port)
2081{
2082 struct switchtec_bind_status_in sub_cmd_id = {
2083 .sub_cmd = MRPC_PORT_INFO,
2084 .phys_port_id = phy_port
2085 };
2086
2087 return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
2088 sizeof(sub_cmd_id), status, sizeof(*status));
2089}
2090
2091int switchtec_bind(struct switchtec_dev *dev, int par_id, int log_port,
2092 int phy_port)
2093{
2094 uint32_t output;
2095
2096 struct switchtec_bind_in sub_cmd_id = {
2097 .sub_cmd = MRPC_PORT_BIND,
2098 .par_id = par_id,
2099 .log_port_id = log_port,
2100 .phys_port_id = phy_port
2101 };
2102
2103 return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
2104 sizeof(sub_cmd_id), &output, sizeof(output));
2105}
2106
2107int switchtec_unbind(struct switchtec_dev *dev, int par_id, int log_port)
2108{
2109 uint32_t output;
2110
2111 struct switchtec_unbind_in sub_cmd_id = {
2112 .sub_cmd = MRPC_PORT_UNBIND,
2113 .par_id = par_id,
2114 .log_port_id = log_port,
2115 .opt = 2
2116 };
2117
2118 return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
2119 sizeof(sub_cmd_id), &output, sizeof(output));
2120}
2121
2122static int __switchtec_calc_lane_id(struct switchtec_status *port, int lane_id)
2123{
2124 int lane;
2125
2126 if (lane_id >= port->neg_lnk_width) {
2127 errno = SWITCHTEC_ERR_INVALID_LANE;
2128 return -1;
2129 }
2130
2131 lane = port->port.phys_id * 2;
2132 if (!port->lane_reversal)
2133 lane += lane_id;
2134 else
2135 lane += port->cfg_lnk_width - 1 - lane_id;
2136
2137 switch (port->port.phys_id) {
2138 /* Trident (Gen4) - Ports 48 to 51 maps to 96 to 99 */
2139 case 48: return 96;
2140 case 49: return 97;
2141 case 50: return 98;
2142 case 51: return 99;
2143 /* Hrapoon (Gen5) - Ports 56 to 59 maps to 96 to 99 */
2144 case 56: return 96;
2145 case 57: return 97;
2146 case 58: return 98;
2147 case 59: return 99;
2148 default: return lane;
2149 }
2150}
2151
2160int switchtec_calc_lane_id(struct switchtec_dev *dev, int phys_port_id,
2161 int lane_id, struct switchtec_status *port)
2162{
2163 struct switchtec_status *status;
2164 int ports, i;
2165 int rc = 0;
2166
2167 ports = switchtec_status(dev, &status);
2168 if (ports < 0)
2169 return ports;
2170
2171 for (i = 0; i < ports; i++)
2172 if (status[i].port.phys_id == phys_port_id)
2173 break;
2174
2175 if (i == ports) {
2176 errno = SWITCHTEC_ERR_INVALID_PORT;
2177 rc = -1;
2178 goto out;
2179 }
2180
2181 if (port)
2182 *port = status[i];
2183
2184 rc = __switchtec_calc_lane_id(&status[i], lane_id);
2185
2186out:
2187 switchtec_status_free(status, ports);
2188 return rc;
2189}
2190
2200int switchtec_calc_port_lane(struct switchtec_dev *dev, int lane_id,
2201 int *phys_port_id, int *port_lane_id,
2202 struct switchtec_status *port)
2203{
2204 struct switchtec_status *status;
2205 int ports, i, p, lane;
2206 int rc = 0;
2207
2208 ports = switchtec_status(dev, &status);
2209 if (ports < 0)
2210 return ports;
2211
2212 if (lane_id >= 96) {
2213 if (dev->gen < SWITCHTEC_GEN5)
2214 p = lane_id - 96 + 48;
2215 else
2216 p = lane_id - 96 + 56;
2217
2218 for (i = 0; i < ports; i++)
2219 if (status[i].port.phys_id == p)
2220 break;
2221 } else {
2222 for (i = 0; i < ports; i++) {
2223 p = status[i].port.phys_id * 2;
2224 if (lane_id >= p && lane_id < p + status[i].cfg_lnk_width)
2225 break;
2226 }
2227 }
2228
2229 if (i == ports) {
2230 errno = SWITCHTEC_ERR_INVALID_PORT;
2231 rc = -1;
2232 goto out;
2233 }
2234
2235 if (port)
2236 *port = status[i];
2237
2238 if (phys_port_id)
2239 *phys_port_id = status[i].port.phys_id;
2240
2241 lane = lane_id - status[i].port.phys_id * 2;
2242 if (port->lane_reversal)
2243 lane = status[i].cfg_lnk_width - 1 - lane;
2244
2245 if (port_lane_id)
2246 *port_lane_id = lane;
2247
2248out:
2249 switchtec_status_free(status, ports);
2250 return rc;
2251}
2252
2264int switchtec_calc_lane_mask(struct switchtec_dev *dev, int phys_port_id,
2265 int lane_id, int num_lanes, int *lane_mask,
2266 struct switchtec_status *port)
2267{
2268 struct switchtec_status *status;
2269 int ports, i, l, lane;
2270 int rc = 0;
2271
2272 ports = switchtec_status(dev, &status);
2273 if (ports < 0)
2274 return ports;
2275
2276 for (i = 0; i < ports; i++)
2277 if (status[i].port.phys_id == phys_port_id)
2278 break;
2279
2280 if (i == ports) {
2281 errno = SWITCHTEC_ERR_INVALID_PORT;
2282 rc = -1;
2283 goto out;
2284 }
2285
2286 if (port)
2287 *port = status[i];
2288
2289 for (l = lane_id; l < lane_id + num_lanes; l++) {
2290 lane = __switchtec_calc_lane_id(&status[i], l);
2291 if (lane < 0) {
2292 rc = -1;
2293 goto out;
2294 }
2295
2296 lane_mask[lane >> 5] |= 1 << (lane & 0x1F);
2297 }
2298
2299out:
2300 switchtec_status_free(status, ports);
2301 return rc;
2302}
2303
2311bool switchtec_stack_bif_port_valid(struct switchtec_dev *dev, int stack_id,
2312 int port_id)
2313{
2314 if (dev->gen == SWITCHTEC_GEN4)
2315 return stack_id * 8 + port_id < 52;
2316
2317 return true;
2318}
2319
2327int switchtec_stack_bif_width(struct switchtec_dev *dev, int stack_id,
2328 int port_bif)
2329{
2330 if (!port_bif)
2331 return 1;
2332
2333 if (port_bif != 1 && port_bif != 2 && port_bif != 4 && port_bif != 8 &&
2334 port_bif != 16) {
2335 errno = -EINVAL;
2336 return -1;
2337 }
2338
2339 if (dev->gen == SWITCHTEC_GEN4 && stack_id == 6)
2340 return port_bif;
2341 else
2342 return (port_bif + 1) / 2;
2343}
2344
2352int switchtec_get_stack_bif(struct switchtec_dev *dev, int stack_id,
2353 int port_bif[SWITCHTEC_PORTS_PER_STACK])
2354{
2355 struct switchtec_stackbif out, in = {
2356 .sub_cmd = MRPC_STACKBIF_GET,
2357 .stack_id = stack_id,
2358 };
2359 int ret, i;
2360
2361 ret = switchtec_cmd(dev, MRPC_STACKBIF, &in, sizeof(in), &out,
2362 sizeof(out));
2363 if (ret)
2364 return ret;
2365
2366 for (i = 0; i < SWITCHTEC_PORTS_PER_STACK; i++) {
2367 if (!switchtec_stack_bif_port_valid(dev, stack_id, i)) {
2368 port_bif[i] = -1;
2369 continue;
2370 }
2371
2372 switch (out.code & 0xF) {
2373 case 0x0: port_bif[i] = 0; break;
2374 case 0x1: port_bif[i] = 2; break;
2375 case 0x2: port_bif[i] = 4; break;
2376 case 0x4: port_bif[i] = 8; break;
2377 case 0x8: port_bif[i] = 16; break;
2378 case 0xf: port_bif[i] = 1; break;
2379 default:
2380 errno = -EPROTO;
2381 return -1;
2382 }
2383 out.code >>= 4;
2384 }
2385
2386 return 0;
2387}
2388
2396int switchtec_set_stack_bif(struct switchtec_dev *dev, int stack_id,
2397 int port_bif[SWITCHTEC_PORTS_PER_STACK])
2398{
2399 struct switchtec_stackbif out, in = {
2400 .sub_cmd = MRPC_STACKBIF_SET,
2401 .stack_id = stack_id,
2402 };
2403 int i;
2404
2405 for (i = 0; i < SWITCHTEC_PORTS_PER_STACK; i++) {
2406 switch (port_bif[i]) {
2407 case 0: in.code |= 0x0 << (i * 4); break;
2408 case 1: in.code |= 0xf << (i * 4); break;
2409 case 2: in.code |= 0x1 << (i * 4); break;
2410 case 4: in.code |= 0x2 << (i * 4); break;
2411 case 8: in.code |= 0x4 << (i * 4); break;
2412 case 16: in.code |= 0x8 << (i * 4); break;
2413 default:
2414 errno = -EINVAL;
2415 return -1;
2416 }
2417 }
2418
2419 return switchtec_cmd(dev, MRPC_STACKBIF, &in, sizeof(in), &out,
2420 sizeof(out));
2421}
2422
2430int switchtec_get_gpio(struct switchtec_dev *dev, int pin_id,
2431 int *gpio_val)
2432{
2433 int ret;
2434 struct switchtec_gpio out, in = {
2435 .sub_cmd = MRPC_VGPIO_GET_VAL,
2436 .log_gpio_id = pin_id,
2437 };
2438
2439 ret = switchtec_cmd(dev, MRPC_VGPIO, &in, sizeof(in), &out,
2440 sizeof(out));
2441 if (ret)
2442 return ret;
2443
2444 *gpio_val = out.data;
2445
2446 return 0;
2447}
2448
2456int switchtec_set_gpio(struct switchtec_dev *dev, int pin_id,
2457 int gpio_val)
2458{
2459 struct switchtec_gpio in = {
2460 .sub_cmd = MRPC_VGPIO_SET_VAL,
2461 .log_gpio_id = pin_id,
2462 };
2463
2464 in.data = gpio_val;
2465 return switchtec_cmd(dev, MRPC_VGPIO, &in, sizeof(in), NULL, 0);
2466}
2467
2475int switchtec_get_gpio_direction_cfg(struct switchtec_dev *dev, int pin_id,
2476 int *direction)
2477{
2478 int ret;
2479 struct switchtec_gpio out, in = {
2480 .sub_cmd = MRPC_VGPIO_GET_DIR,
2481 .log_gpio_id = pin_id,
2482 };
2483
2484 ret = switchtec_cmd(dev, MRPC_VGPIO, &in, sizeof(in), &out,
2485 sizeof(out));
2486 if (ret)
2487 return ret;
2488
2489 *direction = out.data;
2490
2491 return 0;
2492}
2493
2501int switchtec_get_gpio_polarity_cfg(struct switchtec_dev *dev, int pin_id,
2502 int *polarity)
2503{
2504 int ret;
2505 struct switchtec_gpio out, in = {
2506 .sub_cmd = MRPC_VGPIO_GET_POL,
2507 .log_gpio_id = pin_id,
2508 };
2509
2510 ret = switchtec_cmd(dev, MRPC_VGPIO, &in, sizeof(in), &out,
2511 sizeof(out));
2512 if (ret)
2513 return ret;
2514
2515 *polarity = out.data;
2516
2517 return 0;
2518}
2519
2527int switchtec_en_dis_interrupt(struct switchtec_dev *dev, int pin_id, int en)
2528{
2529 struct switchtec_gpio in = {
2530 .sub_cmd = MRPC_VGPIO_DIS_INT,
2531 .log_gpio_id = pin_id,
2532 };
2533
2534 if (en)
2535 in.sub_cmd = MRPC_VGPIO_EN_INT;
2536
2537 return switchtec_cmd(dev, MRPC_VGPIO, &in, sizeof(in), NULL, 0);
2538}
2539
2546int switchtec_get_all_pin_sts(struct switchtec_dev *dev, uint32_t *values)
2547{
2548 int ret;
2549 struct switchtec_gpio in = {
2550 .sub_cmd = MRPC_VPGIO_GET_PIN_STS,
2551 };
2552 struct switchtec_gpio_sts_out out;
2553
2554 ret = switchtec_cmd(dev, MRPC_VGPIO, &in, sizeof(in), &out, sizeof(out));
2555 if (ret)
2556 return ret;
2557
2558 memcpy(values, out.pin_values, sizeof(out.pin_values));
2559
2560 return 0;
2561}
2562
2568int switchtec_rtc_counter_reset(struct switchtec_dev *dev)
2569{
2570 int ret;
2571 struct switchtec_rtc in, out;
2572 in.sub_cmd = MRPC_RTC_RESET;
2573 in.rtc_counter = 0;
2574
2575 ret = switchtec_cmd(dev, MRPC_RTC, &in, sizeof(in), &out, sizeof(out));
2576 if (ret)
2577 return ret;
2578
2579 return 0;
2580}
2581
2588int switchtec_rtc_counter_set(struct switchtec_dev *dev, uint64_t *rtc_counter)
2589{
2590 int ret;
2591 struct switchtec_rtc in, out;
2592
2593 in.sub_cmd = MRPC_RTC_SET;
2594 in.rtc_counter = *rtc_counter;
2595
2596 ret = switchtec_cmd(dev, MRPC_RTC, &in, sizeof(in), &out, sizeof(out));
2597 if (ret)
2598 return ret;
2599
2600 return 0;
2601}
2602
2609int switchtec_rtc_counter_get(struct switchtec_dev *dev, uint64_t *rtc_counter)
2610{
2611 int ret;
2612 struct switchtec_rtc in, out;
2613
2614 in.sub_cmd = MRPC_RTC_GET;
2615
2616 ret = switchtec_cmd(dev, MRPC_RTC, &in, sizeof(in), &out, sizeof(out));
2617 if (ret)
2618 return ret;
2619
2620 *rtc_counter = out.rtc_counter;
2621
2622 return 0;
2623}
2624
2637int switchtec_twi_access_write(struct switchtec_dev *dev, uint8_t twi_port,
2638 uint16_t slave_addr, uint32_t offset,
2639 uint8_t offset_size, uint8_t slave_addr_size,
2640 uint16_t num_bytes, uint32_t *data)
2641{
2642 int ret;
2643 struct switchtec_twi_access_rdwr input;
2644
2645 memset(&input, 0, sizeof(input));
2646 input.sub_cmd = TWI_ACCESS_WRITE;
2647 input.twi_port = twi_port;
2648 input.slave_addr = slave_addr;
2649 input.offset = offset;
2650 input.offset_size = offset_size;
2651 input.slave_addr_size = slave_addr_size;
2652 input.num_of_bytes = num_bytes;
2653
2654 if (data && num_bytes > 0) {
2655 int num_dwords = (num_bytes + 3) / 4;
2656 if (num_dwords > 253)
2657 num_dwords = 253;
2658 memcpy(input.data, data, num_dwords * sizeof(uint32_t));
2659 }
2660
2661 ret = switchtec_cmd(dev, MRPC_TWI, &input, sizeof(input), NULL, 0);
2662
2663 if (ret) {
2664 switchtec_perror("twi_write");
2665 return ret;
2666 }
2667
2668 return 0;
2669}
2670
2683int switchtec_twi_access_read(struct switchtec_dev *dev, uint8_t twi_port,
2684 uint16_t slave_addr, uint32_t offset,
2685 uint8_t offset_size, uint8_t slave_addr_size,
2686 uint16_t num_bytes, uint32_t *output)
2687{
2688 int ret;
2689 struct switchtec_twi_access_rdwr input;
2690 uint32_t output_buf[256] = {0};
2691
2692 memset(&input, 0, sizeof(input));
2693 input.sub_cmd = TWI_ACCESS_READ;
2694 input.twi_port = twi_port;
2695 input.slave_addr = slave_addr;
2696 input.offset = offset;
2697 input.offset_size = offset_size;
2698 input.slave_addr_size = slave_addr_size;
2699 input.num_of_bytes = num_bytes;
2700
2701 ret = switchtec_cmd(dev, MRPC_TWI, &input, sizeof(input),
2702 output_buf, sizeof(output_buf));
2703
2704 if (ret) {
2705 switchtec_perror("twi_read");
2706 return ret;
2707 }
2708
2709 if (output) {
2710 memcpy(output, output_buf, sizeof(output_buf));
2711 }
2712
2713 return 0;
2714}
2715
2724int switchtec_twi_access_reset(struct switchtec_dev *dev, uint8_t master_recov,
2725 uint8_t twi_port, uint32_t duration_ms)
2726{
2727 int ret;
2728 struct switchtec_twi_access_reset input;
2729 input.duration_ms = duration_ms;
2730 input.master_recov = master_recov;
2731 input.twi_port = twi_port;
2732 input.sub_cmd = TWI_ACCESS_RESET;
2733
2734 ret = switchtec_cmd(dev, MRPC_TWI, &input, sizeof(input), NULL, 0);
2735
2736 if (ret) {
2737 switchtec_perror("twi_reset");
2738 return ret;
2739 }
2740 return 0;
2741}
2742
struct switchtec_dev * switchtec_open(const char *device)
Open a Switchtec device by string.
Definition switchtec.c:279
void switchtec_list_free(struct switchtec_device_info *devlist)
Free a list of device info structures allocated by switchtec_list().
Definition switchtec.c:257
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:871
int mrpc_error_cmd
The MRPC command ID when errno is set.
Definition switchtec.c:736
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:709
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:694
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:412
const char * switchtec_strerror(void)
Return a message coresponding to the last error.
Definition switchtec.c:748
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:364
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:376
_PURE enum switchtec_variant switchtec_variant(struct switchtec_dev *dev)
Get the variant type of the device.
Definition switchtec.c:388
_PURE int switchtec_partition(struct switchtec_dev *dev)
Get the partiton number of the device that was opened.
Definition switchtec.c:422
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:623
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:2327
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:2264
int switchtec_get_gpio(struct switchtec_dev *dev, int pin_id, int *gpio_val)
Get the GPIO pin value.
Definition switchtec.c:2430
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:1640
int switchtec_twi_access_reset(struct switchtec_dev *dev, uint8_t master_recov, uint8_t twi_port, uint32_t duration_ms)
Reset the TWI bus using TWI Access MRPC.
Definition switchtec.c:2724
int switchtec_set_gpio(struct switchtec_dev *dev, int pin_id, int gpio_val)
Set the GPIO pin value.
Definition switchtec.c:2456
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:1110
int switchtec_get_gpio_polarity_cfg(struct switchtec_dev *dev, int pin_id, int *polarity)
Get the GPIO pin polarity.
Definition switchtec.c:2501
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:1723
float switchtec_die_temp(struct switchtec_dev *dev)
Get the die temperature of the switchtec device.
Definition switchtec.c:1984
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:2028
int switchtec_rtc_counter_set(struct switchtec_dev *dev, uint64_t *rtc_counter)
Set the RTC counter.
Definition switchtec.c:2588
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:2352
static void free_log_defs(struct log_defs *defs)
Free log definition data.
Definition switchtec.c:930
int switchtec_twi_access_write(struct switchtec_dev *dev, uint8_t twi_port, uint16_t slave_addr, uint32_t offset, uint8_t offset_size, uint8_t slave_addr_size, uint16_t num_bytes, uint32_t *data)
Write to the TWI bus using TWI Access MRPC.
Definition switchtec.c:2637
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:2311
int switchtec_hard_reset(struct switchtec_dev *dev)
Perform an MRPC hard reset command.
Definition switchtec.c:918
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:1848
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:1929
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:1001
static int realloc_log_defs(struct log_defs *defs, int num_modules)
Allocate / reallocate log definition data.
Definition switchtec.c:955
int switchtec_twi_access_read(struct switchtec_dev *dev, uint8_t twi_port, uint16_t slave_addr, uint32_t offset, uint8_t offset_size, uint8_t slave_addr_size, uint16_t num_bytes, uint32_t *output)
Read from the TWI bus using TWI Access MRPC.
Definition switchtec.c:2683
int switchtec_en_dis_interrupt(struct switchtec_dev *dev, int pin_id, int en)
Enable/Disable the GPIO pin interrupt.
Definition switchtec.c:2527
int switchtec_rtc_counter_reset(struct switchtec_dev *dev)
Perform a reset operation on the RTC counter.
Definition switchtec.c:2568
int switchtec_echo(struct switchtec_dev *dev, uint32_t input, uint32_t *output)
Perform an MRPC echo command.
Definition switchtec.c:902
static bool parse_int(char *str, int *val)
Parse an integer from a string.
Definition switchtec.c:982
int switchtec_get_all_pin_sts(struct switchtec_dev *dev, uint32_t *values)
Get all GPIO pin status.
Definition switchtec.c:2546
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:2396
int switchtec_rtc_counter_get(struct switchtec_dev *dev, uint64_t *rtc_counter)
Get the RTC counter.
Definition switchtec.c:2609
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:2160
int switchtec_get_gpio_direction_cfg(struct switchtec_dev *dev, int pin_id, int *direction)
Get the GPIO pin direction.
Definition switchtec.c:2475
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:2200
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:1180
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:152
Information about log file and log definition file.
Definition switchtec.h:240
Port identification.
Definition switchtec.h:165
unsigned char upstream
1 if this is an upstream port
Definition switchtec.h:169
unsigned char partition
Partition the port is in.
Definition switchtec.h:166
unsigned char stk_id
Port number within the stack.
Definition switchtec.h:170
unsigned char log_id
Logical port number.
Definition switchtec.h:172
unsigned char phys_id
Physical port number.
Definition switchtec.h:171
unsigned char stack
Stack number.
Definition switchtec.h:168
Port status structure.
Definition switchtec.h:181
struct switchtec_port_id port
Port ID.
Definition switchtec.h:182
unsigned char link_up
1 if the link is up
Definition switchtec.h:185
unsigned char lane_reversal
Lane reversal.
Definition switchtec.h:189
unsigned int acs_ctrl
ACS Setting of the Port.
Definition switchtec.h:201
const char * lane_reversal_str
Lane reversal as a string.
Definition switchtec.h:190
unsigned char cfg_lnk_width
Configured link width.
Definition switchtec.h:183
unsigned char link_rate
Link rate/gen.
Definition switchtec.h:186
unsigned char first_act_lane
First active lane.
Definition switchtec.h:191
unsigned char neg_lnk_width
Negotiated link width.
Definition switchtec.h:184
uint16_t ltssm
Link state.
Definition switchtec.h:187
const char * ltssm_str
Link state as a string.
Definition switchtec.h:188
Main Switchtec header.
switchtec_log_parse_type
Log types to parse.
Definition switchtec.h:231
switchtec_rev
Device hardware revision.
Definition switchtec.h:105
switchtec_gen
The PCIe generations.
Definition switchtec.h:94
switchtec_log_def_type
Log definition data types.
Definition switchtec.h:254
switchtec_variant
The variant types of Switchtec device.
Definition switchtec.h:137
static int switchtec_is_gen6(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 6 device.
Definition switchtec.h:524
switchtec_log_type
Describe the type of logs too dump.
Definition switchtec.h:216
switchtec_boot_phase
Device boot phase.
Definition switchtec.h:116
static int switchtec_is_gen4(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 4 device.
Definition switchtec.h:508
static int switchtec_max_supported_ports(struct switchtec_dev *dev)
Return the max number of ports of a Switchtec device.
Definition switchtec.h:532
static int switchtec_is_gen5(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 5 device.
Definition switchtec.h:516
static int switchtec_is_pax_all(struct switchtec_dev *dev)
Return whether a Switchtec device is PAX(A).
Definition switchtec.h:641
static int switchtec_is_gen3(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 3 device.
Definition switchtec.h:500