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