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