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