Switchtec Userspace  PROJECT_NUMBER = PROJECT_NUMBER=PROJECT_NUMBER = 2.2
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 
40 #include <string.h>
41 #include <unistd.h>
42 #include <errno.h>
43 #include <time.h>
44 
63  unsigned short device_id;
64  enum switchtec_gen gen;
65  enum switchtec_variant var;
66 };
67 
72  {0x8531, SWITCHTEC_GEN3, SWITCHTEC_PFX}, //PFX 24xG3
73  {0x8532, SWITCHTEC_GEN3, SWITCHTEC_PFX}, //PFX 32xG3
74  {0x8533, SWITCHTEC_GEN3, SWITCHTEC_PFX}, //PFX 48xG3
75  {0x8534, SWITCHTEC_GEN3, SWITCHTEC_PFX}, //PFX 64xG3
76  {0x8535, SWITCHTEC_GEN3, SWITCHTEC_PFX}, //PFX 80xG3
77  {0x8536, SWITCHTEC_GEN3, SWITCHTEC_PFX}, //PFX 96xG3
78  {0x8541, SWITCHTEC_GEN3, SWITCHTEC_PSX}, //PSX 24xG3
79  {0x8542, SWITCHTEC_GEN3, SWITCHTEC_PSX}, //PSX 32xG3
80  {0x8543, SWITCHTEC_GEN3, SWITCHTEC_PSX}, //PSX 48xG3
81  {0x8544, SWITCHTEC_GEN3, SWITCHTEC_PSX}, //PSX 64xG3
82  {0x8545, SWITCHTEC_GEN3, SWITCHTEC_PSX}, //PSX 80xG3
83  {0x8546, SWITCHTEC_GEN3, SWITCHTEC_PSX}, //PSX 96xG3
84  {0x8551, SWITCHTEC_GEN3, SWITCHTEC_PAX}, //PAX 24XG3
85  {0x8552, SWITCHTEC_GEN3, SWITCHTEC_PAX}, //PAX 32XG3
86  {0x8553, SWITCHTEC_GEN3, SWITCHTEC_PAX}, //PAX 48XG3
87  {0x8554, SWITCHTEC_GEN3, SWITCHTEC_PAX}, //PAX 64XG3
88  {0x8555, SWITCHTEC_GEN3, SWITCHTEC_PAX}, //PAX 80XG3
89  {0x8556, SWITCHTEC_GEN3, SWITCHTEC_PAX}, //PAX 96XG3
90  {0x8561, SWITCHTEC_GEN3, SWITCHTEC_PFXL}, //PFXL 24XG3
91  {0x8562, SWITCHTEC_GEN3, SWITCHTEC_PFXL}, //PFXL 32XG3
92  {0x8563, SWITCHTEC_GEN3, SWITCHTEC_PFXL}, //PFXL 48XG3
93  {0x8564, SWITCHTEC_GEN3, SWITCHTEC_PFXL}, //PFXL 64XG3
94  {0x8565, SWITCHTEC_GEN3, SWITCHTEC_PFXL}, //PFXL 80XG3
95  {0x8566, SWITCHTEC_GEN3, SWITCHTEC_PFXL}, //PFXL 96XG3
96  {0x8571, SWITCHTEC_GEN3, SWITCHTEC_PFXI}, //PFXI 24XG3
97  {0x8572, SWITCHTEC_GEN3, SWITCHTEC_PFXI}, //PFXI 32XG3
98  {0x8573, SWITCHTEC_GEN3, SWITCHTEC_PFXI}, //PFXI 48XG3
99  {0x8574, SWITCHTEC_GEN3, SWITCHTEC_PFXI}, //PFXI 64XG3
100  {0x8575, SWITCHTEC_GEN3, SWITCHTEC_PFXI}, //PFXI 80XG3
101  {0x8576, SWITCHTEC_GEN3, SWITCHTEC_PFXI}, //PFXI 96XG3
102  {0x4000, SWITCHTEC_GEN4, SWITCHTEC_PFX}, //PFX 100XG4
103  {0x4084, SWITCHTEC_GEN4, SWITCHTEC_PFX}, //PFX 84XG4
104  {0x4068, SWITCHTEC_GEN4, SWITCHTEC_PFX}, //PFX 68XG4
105  {0x4052, SWITCHTEC_GEN4, SWITCHTEC_PFX}, //PFX 52XG4
106  {0x4036, SWITCHTEC_GEN4, SWITCHTEC_PFX}, //PFX 36XG4
107  {0x4028, SWITCHTEC_GEN4, SWITCHTEC_PFX}, //PFX 28XG4
108  {0x4100, SWITCHTEC_GEN4, SWITCHTEC_PSX}, //PSX 100XG4
109  {0x4184, SWITCHTEC_GEN4, SWITCHTEC_PSX}, //PSX 84XG4
110  {0x4168, SWITCHTEC_GEN4, SWITCHTEC_PSX}, //PSX 68XG4
111  {0x4152, SWITCHTEC_GEN4, SWITCHTEC_PSX}, //PSX 52XG4
112  {0x4136, SWITCHTEC_GEN4, SWITCHTEC_PSX}, //PSX 36XG4
113  {0x4128, SWITCHTEC_GEN4, SWITCHTEC_PSX}, //PSX 28XG4
114  {0x4200, SWITCHTEC_GEN4, SWITCHTEC_PAX}, //PAX 100XG4
115  {0x4284, SWITCHTEC_GEN4, SWITCHTEC_PAX}, //PAX 84XG4
116  {0x4268, SWITCHTEC_GEN4, SWITCHTEC_PAX}, //PAX 68XG4
117  {0x4252, SWITCHTEC_GEN4, SWITCHTEC_PAX}, //PAX 52XG4
118  {0x4236, SWITCHTEC_GEN4, SWITCHTEC_PAX}, //PAX 36XG4
119  {0x4228, SWITCHTEC_GEN4, SWITCHTEC_PAX}, //PAX 28XG4
120  {0},
121 };
122 
123 static int set_gen_variant(struct switchtec_dev * dev)
124 {
125  const struct switchtec_device_id *id = switchtec_device_id_tbl;
126  int ret;
127 
128  dev->boot_phase = SWITCHTEC_BOOT_PHASE_FW;
129  dev->gen = SWITCHTEC_GEN_UNKNOWN;
130  dev->var = SWITCHTEC_VAR_UNKNOWN;
131 
132  dev->device_id = dev->ops->get_device_id(dev);
133 
134  while (id->device_id) {
135  if (id->device_id == dev->device_id) {
136  dev->gen = id->gen;
137  dev->var = id->var;
138 
139  return 0;
140  }
141 
142  id++;
143  }
144 
145  ret = switchtec_get_device_info(dev, &dev->boot_phase, &dev->gen, NULL);
146  if (ret)
147  return -1;
148 
149  return 0;
150 }
151 
152 static int set_local_pax_id(struct switchtec_dev *dev)
153 {
154  unsigned char local_pax_id;
155  int ret;
156 
157  dev->local_pax_id = -1;
158 
159  if (!switchtec_is_pax(dev))
160  return 0;
161 
162  ret = switchtec_cmd(dev, MRPC_GET_PAX_ID, NULL, 0,
163  &local_pax_id, sizeof(local_pax_id));
164  if (ret)
165  return -1;
166 
167  dev->local_pax_id = local_pax_id;
168  return 0;
169 }
170 
188 struct switchtec_dev *switchtec_open(const char *device)
189 {
190  int idx;
191  int domain = 0;
192  int bus, dev, func;
193  char path[PATH_MAX];
194  char *endptr;
195  struct switchtec_dev *ret;
196 
197  if (sscanf(device, "%2049[^@]@%i", path, &dev) == 2) {
198  ret = switchtec_open_i2c(path, dev);
199  goto found;
200  }
201 
202  if (device[0] == '/' &&
203  sscanf(device, "%2049[^:]:%i", path, &dev) == 2) {
204  ret = switchtec_open_i2c(path, dev);
205  goto found;
206  }
207 
208  if (strchr(device, '/') || strchr(device, '\\')) {
209  ret = switchtec_open_by_path(device);
210  goto found;
211  }
212 
213  if (sscanf(device, "%x:%x.%x", &bus, &dev, &func) == 3) {
214  ret = switchtec_open_by_pci_addr(domain, bus, dev, func);
215  goto found;
216  }
217 
218  if (sscanf(device, "%x:%x:%x.%x", &domain, &bus, &dev, &func) == 4) {
219  ret = switchtec_open_by_pci_addr(domain, bus, dev, func);
220  goto found;
221  }
222 
223  if (sscanf(device, "%i@%i", &bus, &dev) == 2) {
224  ret = switchtec_open_i2c_by_adapter(bus, dev);
225  goto found;
226  }
227 
228  errno = 0;
229  idx = strtol(device, &endptr, 0);
230  if (!errno && endptr != device) {
231  ret = switchtec_open_by_index(idx);
232  goto found;
233  }
234 
235  if (sscanf(device, "switchtec%d", &idx) == 1) {
236  ret = switchtec_open_by_index(idx);
237  goto found;
238  }
239 
240  errno = ENODEV;
241  return NULL;
242 
243 found:
244  if (!ret) {
245  errno = ENODEV;
246  return NULL;
247  }
248 
249  snprintf(ret->name, sizeof(ret->name), "%s", device);
250 
251  if (set_gen_variant(ret))
252  return NULL;
253 
254  if (set_local_pax_id(ret))
255  return NULL;
256 
257  return ret;
258 }
259 
267 _PURE int switchtec_device_id(struct switchtec_dev *dev)
268 {
269  return dev->device_id;
270 }
271 
279 _PURE enum switchtec_gen switchtec_gen(struct switchtec_dev *dev)
280 {
281  return dev->gen;
282 }
283 
291 _PURE enum switchtec_variant switchtec_variant(struct switchtec_dev *dev)
292 {
293  return dev->var;
294 }
295 
303 _PURE enum switchtec_boot_phase switchtec_boot_phase(struct switchtec_dev *dev)
304 {
305  return dev->boot_phase;
306 }
307 
315 _PURE const char *switchtec_name(struct switchtec_dev *dev)
316 {
317  return dev->name;
318 }
319 
325 _PURE int switchtec_partition(struct switchtec_dev *dev)
326 {
327  return dev->partition;
328 }
329 
330 int switchtec_set_pax_id(struct switchtec_dev *dev, int pax_id)
331 {
332  if (!(switchtec_is_gen4(dev) && switchtec_is_pax(dev)) &&
333  (pax_id != SWITCHTEC_PAX_ID_LOCAL))
334  return -1;
335 
336  if (pax_id == SWITCHTEC_PAX_ID_LOCAL)
337  dev->pax_id = dev->local_pax_id;
338  else
339  dev->pax_id = pax_id;
340 
341  return 0;
342 }
343 
344 static int compare_port_id(const void *aa, const void *bb)
345 {
346  const struct switchtec_port_id *a = aa, *b = bb;
347 
348  if (a->partition != b->partition)
349  return a->partition - b->partition;
350  if (a->upstream != b->upstream)
351  return b->upstream - a->upstream;
352  return a->log_id - b->log_id;
353 }
354 
355 static int compare_status(const void *aa, const void *bb)
356 {
357  const struct switchtec_status *a = aa, *b = bb;
358 
359  return compare_port_id(&a->port, &b->port);
360 }
361 
362 static const char *lane_reversal_str(int link_up,
363  int lane_reversal)
364 {
365  if (!link_up)
366  return "N/A";
367 
368  switch(lane_reversal) {
369  case 0: return "Normal Lane Ordering";
370  case 1: return "x16 (Full) Lane Reversal";
371  case 2: return "x2 Lane Reversal";
372  case 4: return "x4 Lane Reversal";
373  case 8: return "x8 Lane Reversal";
374  default: return "Unknown Lane Ordering";
375  }
376 }
377 
389 int switchtec_status(struct switchtec_dev *dev,
390  struct switchtec_status **status)
391 {
392  uint64_t port_bitmap = 0;
393  int ret;
394  int i, p;
395  int nr_ports = 0;
396  struct switchtec_status *s;
397 
398  if (!status) {
399  errno = EINVAL;
400  return -errno;
401  }
402 
403  struct {
404  uint8_t phys_port_id;
405  uint8_t par_id;
406  uint8_t log_port_id;
407  uint8_t stk_id;
408  uint8_t cfg_lnk_width;
409  uint8_t neg_lnk_width;
410  uint8_t usp_flag;
411  uint8_t linkup_linkrate;
412  uint16_t LTSSM;
413  uint8_t lane_reversal;
414  uint8_t first_act_lane;
415  } ports[SWITCHTEC_MAX_PORTS];
416 
417  ret = switchtec_cmd(dev, MRPC_LNKSTAT, &port_bitmap, sizeof(port_bitmap),
418  ports, sizeof(ports));
419  if (ret)
420  return ret;
421 
422 
423  for (i = 0; i < SWITCHTEC_MAX_PORTS; i++) {
424  if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS)
425  continue;
426  nr_ports++;
427  }
428 
429  s = *status = calloc(nr_ports, sizeof(*s));
430  if (!s)
431  return -ENOMEM;
432 
433  for (i = 0, p = 0; i < SWITCHTEC_MAX_PORTS && p < nr_ports; i++) {
434  if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS)
435  continue;
436 
437  s[p].port.partition = ports[i].par_id;
438  s[p].port.stack = ports[i].stk_id >> 4;
439  s[p].port.upstream = ports[i].usp_flag;
440  s[p].port.stk_id = ports[i].stk_id & 0xF;
441  s[p].port.phys_id = ports[i].phys_port_id;
442  s[p].port.log_id = ports[i].log_port_id;
443 
444  s[p].cfg_lnk_width = ports[i].cfg_lnk_width;
445  s[p].neg_lnk_width = ports[i].neg_lnk_width;
446  s[p].link_up = ports[i].linkup_linkrate >> 7;
447  s[p].link_rate = ports[i].linkup_linkrate & 0x7F;
448  s[p].ltssm = le16toh(ports[i].LTSSM);
449  s[p].ltssm_str = switchtec_ltssm_str(s[i].ltssm, 1);
450  s[p].lane_reversal = ports[i].lane_reversal;
451  s[p].lane_reversal_str = lane_reversal_str(s[p].link_up,
452  s[p].lane_reversal);
453  s[p].first_act_lane = ports[i].first_act_lane & 0xF;
454  s[p].acs_ctrl = -1;
455 
456  p++;
457  }
458 
459  qsort(s, nr_ports, sizeof(*s), compare_status);
460 
461  return nr_ports;
462 }
463 
470 void switchtec_status_free(struct switchtec_status *status, int ports)
471 {
472  int i;
473 
474  for (i = 0; i < ports; i++) {
475  if (status[i].pci_bdf)
476  free(status[i].pci_bdf);
477 
478  if (status[i].pci_bdf_path)
479  free(status[i].pci_bdf_path);
480 
481  if (status[i].pci_dev)
482  free(status[i].pci_dev);
483 
484  if (status[i].class_devices)
485  free(status[i].class_devices);
486  }
487 
488  free(status);
489 }
490 
498 
509 const char *switchtec_strerror(void)
510 {
511  const char *msg = "Unknown MRPC error";
512  int err;
513 
514  if ((errno & SWITCHTEC_ERRNO_MRPC_FLAG_BIT) == 0) {
515  if (errno)
516  return strerror(errno);
517  else
518  return platform_strerror();
519  }
520 
521  err = errno & ~SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
522 
523  switch (err) {
524  case ERR_NO_AVAIL_MRPC_THREAD:
525  msg = "No available MRPC handler thread"; break;
526  case ERR_HANDLER_THREAD_NOT_IDLE:
527  msg = "The handler thread is not idle"; break;
528  case ERR_NO_BG_THREAD:
529  msg = "No background thread run for the command"; break;
530 
531  case ERR_SUBCMD_INVALID: msg = "Invalid subcommand"; break;
532  case ERR_CMD_INVALID: msg = "Invalid command"; break;
533  case ERR_PARAM_INVALID: msg = "Invalid parameter"; break;
534  case ERR_BAD_FW_STATE: msg = "Bad firmware state"; break;
535  case ERR_MRPC_DENIED: msg = "MRPC request denied"; break;
536  case ERR_STACK_INVALID: msg = "Invalid Stack"; break;
537  case ERR_PORT_INVALID: msg = "Invalid Port"; break;
538  case ERR_EVENT_INVALID: msg = "Invalid Event"; break;
539  case ERR_RST_RULE_FAILED: msg = "Reset rule search failed"; break;
540  case ERR_UART_NOT_SUPPORTED:
541  msg = "UART interface not supported for this command"; break;
542  case ERR_ACCESS_REFUSED: msg = "Access Refused"; break;
543 
544  default: break;
545  }
546 
547  switch (mrpc_error_cmd) {
548  case MRPC_PORTPARTP2P:
549  switch (err) {
550  case ERR_PHYC_PORT_ARDY_BIND:
551  msg = "Physical port already bound"; break;
552  case ERR_LOGC_PORT_ARDY_BIND:
553  msg = "Logical bridge instance already bound"; break;
554  case ERR_BIND_PRTT_NOT_EXIST:
555  msg = "Partition does not exist"; break;
556  case ERR_PHYC_PORT_NOT_EXIST:
557  msg = "Physical port does not exist"; break;
558  case ERR_PHYC_PORT_DIS:
559  msg = "Physical port disabled"; break;
560  case ERR_NO_LOGC_PORT:
561  msg = "No logical bridge instance"; break;
562  case ERR_BIND_IN_PROGRESS:
563  msg = "Bind/unbind in progress"; break;
564  case ERR_BIND_TGT_IS_USP:
565  msg = "Bind/unbind target is USP"; break;
566  case ERR_BIND_SUBCMD_INVALID:
567  msg = "Sub-command does not exist"; break;
568  case ERR_PHYC_PORT_LINK_ACT:
569  msg = "Physical port link active"; break;
570  case ERR_LOGC_PORT_NOT_BIND_PHYC_PORT:
571  msg = "Logical bridge not bind to physical port"; break;
572  case ERR_UNBIND_OPT_INVALID:
573  msg = "Invalid unbind option"; break;
574  case ERR_BIND_CHECK_FAIL:
575  msg = "Port bind checking failed"; break;
576  default: break;
577  }
578  break;
579  default: break;
580  }
581 
582  return msg;
583 }
584 
592 void switchtec_perror(const char *str)
593 {
594  const char *msg = switchtec_strerror();
595  int is_mrpc = errno & SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
596  int err = errno & ~SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
597 
598  if (is_mrpc)
599  fprintf(stderr, "%s: %s (MRPC: 0x%x, error: 0x%x)\n",
600  str, msg, mrpc_error_cmd, err);
601  else
602  fprintf(stderr, "%s: %s\n", str, msg);
603 }
604 
623 int switchtec_echo(struct switchtec_dev *dev, uint32_t input,
624  uint32_t *output)
625 {
626  return switchtec_cmd(dev, MRPC_ECHO, &input, sizeof(input),
627  output, sizeof(*output));
628 }
629 
639 int switchtec_hard_reset(struct switchtec_dev *dev)
640 {
641  uint32_t subcmd = 0;
642 
643  return switchtec_cmd(dev, MRPC_RESET, &subcmd, sizeof(subcmd),
644  NULL, 0);
645 }
646 
647 static int log_a_to_file(struct switchtec_dev *dev, int sub_cmd_id, int fd)
648 {
649  int ret;
650  int read = 0;
651  struct log_a_retr_result res;
652  struct log_a_retr cmd = {
653  .sub_cmd_id = sub_cmd_id,
654  .start = -1,
655  };
656 
657  res.hdr.remain = 1;
658 
659  while (res.hdr.remain) {
660  ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
661  &res, sizeof(res));
662  if (ret)
663  return -1;
664 
665  ret = write(fd, res.data, sizeof(*res.data) * res.hdr.count);
666  if (ret < 0)
667  return ret;
668 
669  read += le32toh(res.hdr.count);
670  cmd.start = res.hdr.next_start;
671  }
672 
673  return read;
674 }
675 
676 static int log_b_to_file(struct switchtec_dev *dev, int sub_cmd_id, int fd)
677 {
678  int ret;
679  int read = 0;
680  struct log_b_retr_result res;
681  struct log_b_retr cmd = {
682  .sub_cmd_id = sub_cmd_id,
683  .offset = 0,
684  .length = htole32(sizeof(res.data)),
685  };
686 
687  res.hdr.remain = sizeof(res.data);
688 
689  while (res.hdr.remain) {
690  ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
691  &res, sizeof(res));
692  if (ret)
693  return -1;
694 
695  ret = write(fd, res.data, res.hdr.length);
696  if (ret < 0)
697  return ret;
698 
699  read += le32toh(res.hdr.length);
700  cmd.offset = htole32(read);
701  }
702 
703  return read;
704 }
705 
706 static int log_c_to_file(struct switchtec_dev *dev, int sub_cmd_id, int fd)
707 {
708  int ret;
709  struct log_cmd {
710  uint8_t subcmd;
711  uint8_t rsvd[3];
712  } cmd = {};
713 
714  struct log_reply {
715  uint8_t reason;
716  uint8_t rsvd[3];
717  uint32_t nvlog_version;
718  uint32_t thread_handle;
719  uint32_t fw_version;
720  uint32_t timestamp1;
721  uint32_t timestamp2;
722  } reply;
723 
724  cmd.subcmd = sub_cmd_id;
725 
726  ret = switchtec_cmd(dev, MRPC_FWLOGRD, &cmd, sizeof(cmd),
727  &reply, sizeof(reply));
728  if (ret)
729  return -1;
730 
731  ret = write(fd, &reply, sizeof(reply));
732  if (ret < 0)
733  return ret;
734 
735  return 0;
736 }
737 
745 int switchtec_log_to_file(struct switchtec_dev *dev,
746  enum switchtec_log_type type,
747  int fd)
748 {
749  switch (type) {
750  case SWITCHTEC_LOG_RAM:
751  return log_a_to_file(dev, MRPC_FWLOGRD_RAM, fd);
752  case SWITCHTEC_LOG_FLASH:
753  return log_a_to_file(dev, MRPC_FWLOGRD_FLASH, fd);
754  case SWITCHTEC_LOG_MEMLOG:
755  return log_b_to_file(dev, MRPC_FWLOGRD_MEMLOG, fd);
756  case SWITCHTEC_LOG_REGS:
757  return log_b_to_file(dev, MRPC_FWLOGRD_REGS, fd);
758  case SWITCHTEC_LOG_THRD_STACK:
759  return log_b_to_file(dev, MRPC_FWLOGRD_THRD_STACK, fd);
760  case SWITCHTEC_LOG_SYS_STACK:
761  return log_b_to_file(dev, MRPC_FWLOGRD_SYS_STACK, fd);
762  case SWITCHTEC_LOG_THRD:
763  return log_b_to_file(dev, MRPC_FWLOGRD_THRD, fd);
764  case SWITCHTEC_LOG_NVHDR:
765  return log_c_to_file(dev, MRPC_FWLOGRD_NVHDR, fd);
766  };
767 
768  errno = EINVAL;
769  return -errno;
770 }
771 
772 static enum switchtec_gen map_to_gen(uint32_t gen)
773 {
774  enum switchtec_gen ret = SWITCHTEC_GEN_UNKNOWN;
775 
776  switch (gen) {
777  case 0:
778  ret = SWITCHTEC_GEN4;
779  break;
780  default:
781  ret = SWITCHTEC_GEN_UNKNOWN;
782  break;
783  }
784 
785  return ret;
786 }
787 
796 int switchtec_get_device_info(struct switchtec_dev *dev,
797  enum switchtec_boot_phase *phase,
798  enum switchtec_gen *gen,
799  enum switchtec_rev *rev)
800 {
801  int ret;
802  uint32_t ping_dw = 0;
803  uint32_t dev_info;
804  struct get_dev_info_reply {
805  uint32_t dev_info;
806  uint32_t ping_reply;
807  } reply;
808 
809  ping_dw = time(NULL);
810  ret = switchtec_cmd(dev, MRPC_GET_DEV_INFO, &ping_dw,
811  sizeof(ping_dw),
812  &reply, sizeof(reply));
813  if (ret == 0) {
814  if (ping_dw != ~reply.ping_reply)
815  return -1;
816 
817  dev_info = le32toh(reply.dev_info);
818  if (phase)
819  *phase = dev_info & 0xff;
820  if (rev)
821  *rev = (dev_info >> 8) & 0x0f;
822  if (gen)
823  *gen = map_to_gen((dev_info >> 12) & 0x0f);
824  } else if (ERRNO_MRPC(errno) == ERR_MPRC_UNSUPPORTED) {
825  if (phase)
826  *phase = SWITCHTEC_BOOT_PHASE_FW;
827  if (gen)
828  *gen = SWITCHTEC_GEN3;
829  if (rev)
830  *rev = SWITCHTEC_REV_UNKNOWN;
831 
832  errno = 0;
833  } else {
834  return -1;
835  }
836 
837  return 0;
838 }
839 
846 float switchtec_die_temp(struct switchtec_dev *dev)
847 {
848  int ret;
849  uint32_t sub_cmd_id;
850  uint32_t temp;
851 
852  if (!switchtec_is_gen3(dev) && !switchtec_is_gen4(dev)) {
853  errno = ENOTSUP;
854  return -100.0;
855  }
856 
857  if (switchtec_is_gen3(dev)) {
858  sub_cmd_id = MRPC_DIETEMP_SET_MEAS;
859  ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
860  sizeof(sub_cmd_id), NULL, 0);
861  if (ret)
862  return -100.0;
863 
864  sub_cmd_id = MRPC_DIETEMP_GET;
865  ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
866  sizeof(sub_cmd_id), &temp, sizeof(temp));
867  if (ret)
868  return -100.0;
869  } else {
870  sub_cmd_id = MRPC_DIETEMP_GET_GEN4;
871  ret = switchtec_cmd(dev, MRPC_DIETEMP, &sub_cmd_id,
872  sizeof(sub_cmd_id), &temp, sizeof(temp));
873  if (ret)
874  return -100.0;
875  }
876 
877  return temp / 100.;
878 }
879 
880 int switchtec_bind_info(struct switchtec_dev *dev,
881  struct switchtec_bind_status_out *status, int phy_port)
882 {
883  struct switchtec_bind_status_in sub_cmd_id = {
884  .sub_cmd = MRPC_PORT_INFO,
885  .phys_port_id = phy_port
886  };
887 
888  return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
889  sizeof(sub_cmd_id), status, sizeof(*status));
890 }
891 
892 int switchtec_bind(struct switchtec_dev *dev, int par_id, int log_port,
893  int phy_port)
894 {
895  uint32_t output;
896 
897  struct switchtec_bind_in sub_cmd_id = {
898  .sub_cmd = MRPC_PORT_BIND,
899  .par_id = par_id,
900  .log_port_id = log_port,
901  .phys_port_id = phy_port
902  };
903 
904  return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
905  sizeof(sub_cmd_id), &output, sizeof(output));
906 }
907 
908 int switchtec_unbind(struct switchtec_dev *dev, int par_id, int log_port)
909 {
910  uint32_t output;
911 
912  struct switchtec_unbind_in sub_cmd_id = {
913  .sub_cmd = MRPC_PORT_UNBIND,
914  .par_id = par_id,
915  .log_port_id = log_port,
916  .opt = 2
917  };
918 
919  return switchtec_cmd(dev, MRPC_PORTPARTP2P, &sub_cmd_id,
920  sizeof(sub_cmd_id), &output, sizeof(output));
921 }
unsigned char cfg_lnk_width
Configured link width.
Definition: switchtec.h:155
unsigned char neg_lnk_width
Negotiated link width.
Definition: switchtec.h:156
unsigned int acs_ctrl
ACS Setting of the Port.
Definition: switchtec.h:172
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:470
unsigned char upstream
1 if this is an upstream port
Definition: switchtec.h:141
unsigned char link_rate
Link rate/gen.
Definition: switchtec.h:158
_PURE int switchtec_device_id(struct switchtec_dev *dev)
Get the device id of the device.
Definition: switchtec.c:267
Port identification.
Definition: switchtec.h:137
struct switchtec_port_id port
Port ID.
Definition: switchtec.h:154
unsigned char partition
Partition the port is in.
Definition: switchtec.h:138
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:389
switchtec_gen
The PCIe generations.
Definition: switchtec.h:83
unsigned char stk_id
Port number within the stack.
Definition: switchtec.h:142
unsigned char first_act_lane
First active lane.
Definition: switchtec.h:163
switchtec_boot_phase
Device boot phase.
Definition: switchtec.h:102
Definition: log.h:62
static const struct switchtec_device_id switchtec_device_id_tbl[]
Supported Switchtec device id table.
Definition: switchtec.c:71
unsigned char phys_id
Physical port number.
Definition: switchtec.h:143
static int switchtec_is_pax(struct switchtec_dev *dev)
Return whether a Switchtec device is PAX.
Definition: switchtec.h:432
switchtec_log_type
Describe the type of logs too dump.
Definition: switchtec.h:187
float switchtec_die_temp(struct switchtec_dev *dev)
Get the die temperature of the switchtec device.
Definition: switchtec.c:846
Main Switchtec header.
static int switchtec_is_gen4(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 4 device.
Definition: switchtec.h:374
_PURE int switchtec_partition(struct switchtec_dev *dev)
Get the partiton number of the device that was opened.
Definition: switchtec.c:325
_PURE enum switchtec_gen switchtec_gen(struct switchtec_dev *dev)
Get the generation of the device.
Definition: switchtec.c:279
unsigned char stack
Stack number.
Definition: switchtec.h:140
const char * lane_reversal_str
Lane reversal as a string.
Definition: switchtec.h:162
const char * switchtec_strerror(void)
Return a message coresponding to the last error.
Definition: switchtec.c:509
int switchtec_echo(struct switchtec_dev *dev, uint32_t input, uint32_t *output)
Perform an MRPC echo command.
Definition: switchtec.c:623
Switchtec device id to generation/variant mapping.
Definition: switchtec.c:62
Port status structure.
Definition: switchtec.h:153
_PURE enum switchtec_variant switchtec_variant(struct switchtec_dev *dev)
Get the variant type of the device.
Definition: switchtec.c:291
unsigned char lane_reversal
Lane reversal.
Definition: switchtec.h:161
switchtec_variant
The variant types of Switchtec device.
Definition: switchtec.h:112
const char * ltssm_str
Link state as a string.
Definition: switchtec.h:160
struct switchtec_dev * switchtec_open_by_path(const char *path)
Open a switchtec device by path.
static int switchtec_is_gen3(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 3 device.
Definition: switchtec.h:366
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:796
void switchtec_perror(const char *str)
Print an error string to stdout.
Definition: switchtec.c:592
switchtec_rev
Device hardware revision.
Definition: switchtec.h:92
struct switchtec_dev * switchtec_open(const char *device)
Open a Switchtec device by string.
Definition: switchtec.c:188
_PURE const char * switchtec_name(struct switchtec_dev *dev)
Get the string that was used to open the deviec.
Definition: switchtec.c:315
int mrpc_error_cmd
The MRPC command ID when errno is set.
Definition: switchtec.c:497
int switchtec_log_to_file(struct switchtec_dev *dev, enum switchtec_log_type type, int fd)
Dump the Switchtec log data to a file.
Definition: switchtec.c:745
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:132
unsigned char log_id
Logical port number.
Definition: switchtec.h:144
struct switchtec_dev * switchtec_open_i2c(const char *path, int i2c_addr)
Open a switchtec device behind an I2C device.
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:303
unsigned char link_up
1 if the link is up
Definition: switchtec.h:157
int switchtec_hard_reset(struct switchtec_dev *dev)
Perform an MRPC hard reset command.
Definition: switchtec.c:639
uint16_t ltssm
Link state.
Definition: switchtec.h:159