30 #define SWITCHTEC_LIB_CORE 32 #include "switchtec_priv.h" 35 #include "switchtec/mrpc.h" 36 #include "switchtec/errors.h" 37 #include "switchtec/log.h" 38 #include "switchtec/endian.h" 63 unsigned short device_id;
72 {0x8531, SWITCHTEC_GEN3, SWITCHTEC_PFX},
73 {0x8532, SWITCHTEC_GEN3, SWITCHTEC_PFX},
74 {0x8533, SWITCHTEC_GEN3, SWITCHTEC_PFX},
75 {0x8534, SWITCHTEC_GEN3, SWITCHTEC_PFX},
76 {0x8535, SWITCHTEC_GEN3, SWITCHTEC_PFX},
77 {0x8536, SWITCHTEC_GEN3, SWITCHTEC_PFX},
78 {0x8541, SWITCHTEC_GEN3, SWITCHTEC_PSX},
79 {0x8542, SWITCHTEC_GEN3, SWITCHTEC_PSX},
80 {0x8543, SWITCHTEC_GEN3, SWITCHTEC_PSX},
81 {0x8544, SWITCHTEC_GEN3, SWITCHTEC_PSX},
82 {0x8545, SWITCHTEC_GEN3, SWITCHTEC_PSX},
83 {0x8546, SWITCHTEC_GEN3, SWITCHTEC_PSX},
84 {0x8551, SWITCHTEC_GEN3, SWITCHTEC_PAX},
85 {0x8552, SWITCHTEC_GEN3, SWITCHTEC_PAX},
86 {0x8553, SWITCHTEC_GEN3, SWITCHTEC_PAX},
87 {0x8554, SWITCHTEC_GEN3, SWITCHTEC_PAX},
88 {0x8555, SWITCHTEC_GEN3, SWITCHTEC_PAX},
89 {0x8556, SWITCHTEC_GEN3, SWITCHTEC_PAX},
90 {0x8561, SWITCHTEC_GEN3, SWITCHTEC_PFXL},
91 {0x8562, SWITCHTEC_GEN3, SWITCHTEC_PFXL},
92 {0x8563, SWITCHTEC_GEN3, SWITCHTEC_PFXL},
93 {0x8564, SWITCHTEC_GEN3, SWITCHTEC_PFXL},
94 {0x8565, SWITCHTEC_GEN3, SWITCHTEC_PFXL},
95 {0x8566, SWITCHTEC_GEN3, SWITCHTEC_PFXL},
96 {0x8571, SWITCHTEC_GEN3, SWITCHTEC_PFXI},
97 {0x8572, SWITCHTEC_GEN3, SWITCHTEC_PFXI},
98 {0x8573, SWITCHTEC_GEN3, SWITCHTEC_PFXI},
99 {0x8574, SWITCHTEC_GEN3, SWITCHTEC_PFXI},
100 {0x8575, SWITCHTEC_GEN3, SWITCHTEC_PFXI},
101 {0x8576, SWITCHTEC_GEN3, SWITCHTEC_PFXI},
102 {0x4000, SWITCHTEC_GEN4, SWITCHTEC_PFX},
103 {0x4084, SWITCHTEC_GEN4, SWITCHTEC_PFX},
104 {0x4068, SWITCHTEC_GEN4, SWITCHTEC_PFX},
105 {0x4052, SWITCHTEC_GEN4, SWITCHTEC_PFX},
106 {0x4036, SWITCHTEC_GEN4, SWITCHTEC_PFX},
107 {0x4028, SWITCHTEC_GEN4, SWITCHTEC_PFX},
108 {0x4100, SWITCHTEC_GEN4, SWITCHTEC_PSX},
109 {0x4184, SWITCHTEC_GEN4, SWITCHTEC_PSX},
110 {0x4168, SWITCHTEC_GEN4, SWITCHTEC_PSX},
111 {0x4152, SWITCHTEC_GEN4, SWITCHTEC_PSX},
112 {0x4136, SWITCHTEC_GEN4, SWITCHTEC_PSX},
113 {0x4128, SWITCHTEC_GEN4, SWITCHTEC_PSX},
114 {0x4200, SWITCHTEC_GEN4, SWITCHTEC_PAX},
115 {0x4284, SWITCHTEC_GEN4, SWITCHTEC_PAX},
116 {0x4268, SWITCHTEC_GEN4, SWITCHTEC_PAX},
117 {0x4252, SWITCHTEC_GEN4, SWITCHTEC_PAX},
118 {0x4236, SWITCHTEC_GEN4, SWITCHTEC_PAX},
119 {0x4228, SWITCHTEC_GEN4, SWITCHTEC_PAX},
123 static int set_gen_variant(
struct switchtec_dev * dev)
128 dev->boot_phase = SWITCHTEC_BOOT_PHASE_FW;
129 dev->gen = SWITCHTEC_GEN_UNKNOWN;
130 dev->var = SWITCHTEC_VAR_UNKNOWN;
132 dev->device_id = dev->ops->get_device_id(dev);
134 while (id->device_id) {
135 if (id->device_id == dev->device_id) {
152 static int set_local_pax_id(
struct switchtec_dev *dev)
154 unsigned char local_pax_id;
157 dev->local_pax_id = -1;
163 &local_pax_id,
sizeof(local_pax_id));
167 dev->local_pax_id = local_pax_id;
195 struct switchtec_dev *ret;
197 if (sscanf(device,
"%2049[^@]@%i", path, &dev) == 2) {
202 if (device[0] ==
'/' &&
203 sscanf(device,
"%2049[^:]:%i", path, &dev) == 2) {
208 if (strchr(device,
'/') || strchr(device,
'\\')) {
213 if (sscanf(device,
"%x:%x.%x", &bus, &dev, &func) == 3) {
218 if (sscanf(device,
"%x:%x:%x.%x", &domain, &bus, &dev, &func) == 4) {
223 if (sscanf(device,
"%i@%i", &bus, &dev) == 2) {
224 ret = switchtec_open_i2c_by_adapter(bus, dev);
229 idx = strtol(device, &endptr, 0);
230 if (!errno && endptr != device) {
235 if (sscanf(device,
"switchtec%d", &idx) == 1) {
249 snprintf(ret->name,
sizeof(ret->name),
"%s", device);
251 if (set_gen_variant(ret))
254 if (set_local_pax_id(ret))
269 return dev->device_id;
305 return dev->boot_phase;
327 return dev->partition;
330 int switchtec_set_pax_id(
struct switchtec_dev *dev,
int pax_id)
333 (pax_id != SWITCHTEC_PAX_ID_LOCAL))
336 if (pax_id == SWITCHTEC_PAX_ID_LOCAL)
337 dev->pax_id = dev->local_pax_id;
339 dev->pax_id = pax_id;
344 static int compare_port_id(
const void *aa,
const void *bb)
352 return a->
log_id - b->log_id;
355 static int compare_status(
const void *aa,
const void *bb)
359 return compare_port_id(&a->
port, &b->port);
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";
392 uint64_t port_bitmap = 0;
404 uint8_t phys_port_id;
408 uint8_t cfg_lnk_width;
409 uint8_t neg_lnk_width;
411 uint8_t linkup_linkrate;
413 uint8_t lane_reversal;
414 uint8_t first_act_lane;
415 } ports[SWITCHTEC_MAX_PORTS];
417 ret =
switchtec_cmd(dev, MRPC_LNKSTAT, &port_bitmap,
sizeof(port_bitmap),
418 ports,
sizeof(ports));
423 for (i = 0; i < SWITCHTEC_MAX_PORTS; i++) {
424 if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS)
429 s = *status = calloc(nr_ports,
sizeof(*s));
433 for (i = 0, p = 0; i < SWITCHTEC_MAX_PORTS && p < nr_ports; i++) {
434 if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS)
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);
459 qsort(s, nr_ports,
sizeof(*s), compare_status);
474 for (i = 0; i < ports; i++) {
475 if (status[i].pci_bdf)
476 free(status[i].pci_bdf);
478 if (status[i].pci_bdf_path)
479 free(status[i].pci_bdf_path);
481 if (status[i].pci_dev)
482 free(status[i].pci_dev);
484 if (status[i].class_devices)
485 free(status[i].class_devices);
511 const char *msg =
"Unknown MRPC error";
514 if ((errno & SWITCHTEC_ERRNO_MRPC_FLAG_BIT) == 0) {
516 return strerror(errno);
518 return platform_strerror();
521 err = errno & ~SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
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;
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;
548 case MRPC_PORTPARTP2P:
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;
595 int is_mrpc = errno & SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
596 int err = errno & ~SWITCHTEC_ERRNO_MRPC_FLAG_BIT;
599 fprintf(stderr,
"%s: %s (MRPC: 0x%x, error: 0x%x)\n",
602 fprintf(stderr,
"%s: %s\n", str, msg);
627 output,
sizeof(*output));
643 return switchtec_cmd(dev, MRPC_RESET, &subcmd,
sizeof(subcmd),
647 static int log_a_to_file(
struct switchtec_dev *dev,
int sub_cmd_id,
int fd)
653 .sub_cmd_id = sub_cmd_id,
659 while (res.hdr.remain) {
665 ret = write(fd, res.data,
sizeof(*res.data) * res.hdr.count);
669 read += le32toh(res.hdr.count);
670 cmd.start = res.hdr.next_start;
676 static int log_b_to_file(
struct switchtec_dev *dev,
int sub_cmd_id,
int fd)
682 .sub_cmd_id = sub_cmd_id,
684 .length = htole32(
sizeof(res.data)),
687 res.hdr.remain =
sizeof(res.data);
689 while (res.hdr.remain) {
695 ret = write(fd, res.data, res.hdr.length);
699 read += le32toh(res.hdr.length);
700 cmd.offset = htole32(read);
706 static int log_c_to_file(
struct switchtec_dev *dev,
int sub_cmd_id,
int fd)
717 uint32_t nvlog_version;
718 uint32_t thread_handle;
724 cmd.subcmd = sub_cmd_id;
727 &reply,
sizeof(reply));
731 ret = write(fd, &reply,
sizeof(reply));
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);
778 ret = SWITCHTEC_GEN4;
781 ret = SWITCHTEC_GEN_UNKNOWN;
802 uint32_t ping_dw = 0;
804 struct get_dev_info_reply {
809 ping_dw = time(NULL);
812 &reply,
sizeof(reply));
814 if (ping_dw != ~reply.ping_reply)
817 dev_info = le32toh(reply.dev_info);
819 *phase = dev_info & 0xff;
821 *rev = (dev_info >> 8) & 0x0f;
823 *gen = map_to_gen((dev_info >> 12) & 0x0f);
824 }
else if (ERRNO_MRPC(errno) == ERR_MPRC_UNSUPPORTED) {
826 *phase = SWITCHTEC_BOOT_PHASE_FW;
828 *gen = SWITCHTEC_GEN3;
830 *rev = SWITCHTEC_REV_UNKNOWN;
858 sub_cmd_id = MRPC_DIETEMP_SET_MEAS;
860 sizeof(sub_cmd_id), NULL, 0);
864 sub_cmd_id = MRPC_DIETEMP_GET;
866 sizeof(sub_cmd_id), &temp,
sizeof(temp));
870 sub_cmd_id = MRPC_DIETEMP_GET_GEN4;
872 sizeof(sub_cmd_id), &temp,
sizeof(temp));
880 int switchtec_bind_info(
struct switchtec_dev *dev,
884 .sub_cmd = MRPC_PORT_INFO,
885 .phys_port_id = phy_port
889 sizeof(sub_cmd_id), status,
sizeof(*status));
892 int switchtec_bind(
struct switchtec_dev *dev,
int par_id,
int log_port,
898 .sub_cmd = MRPC_PORT_BIND,
900 .log_port_id = log_port,
901 .phys_port_id = phy_port
905 sizeof(sub_cmd_id), &output,
sizeof(output));
908 int switchtec_unbind(
struct switchtec_dev *dev,
int par_id,
int log_port)
913 .sub_cmd = MRPC_PORT_UNBIND,
915 .log_port_id = log_port,
920 sizeof(sub_cmd_id), &output,
sizeof(output));
unsigned char cfg_lnk_width
Configured link width.
unsigned char neg_lnk_width
Negotiated link width.
unsigned int acs_ctrl
ACS Setting of the Port.
void switchtec_status_free(struct switchtec_status *status, int ports)
Free a list of status structures allocated by switchtec_status()
unsigned char upstream
1 if this is an upstream port
unsigned char link_rate
Link rate/gen.
_PURE int switchtec_device_id(struct switchtec_dev *dev)
Get the device id of the device.
struct switchtec_port_id port
Port ID.
unsigned char partition
Partition the port is in.
int switchtec_status(struct switchtec_dev *dev, struct switchtec_status **status)
Get the status of all the ports on a switchtec device.
switchtec_gen
The PCIe generations.
unsigned char stk_id
Port number within the stack.
unsigned char first_act_lane
First active lane.
switchtec_boot_phase
Device boot phase.
static const struct switchtec_device_id switchtec_device_id_tbl[]
Supported Switchtec device id table.
unsigned char phys_id
Physical port number.
static int switchtec_is_pax(struct switchtec_dev *dev)
Return whether a Switchtec device is PAX.
switchtec_log_type
Describe the type of logs too dump.
float switchtec_die_temp(struct switchtec_dev *dev)
Get the die temperature of the switchtec device.
static int switchtec_is_gen4(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 4 device.
_PURE int switchtec_partition(struct switchtec_dev *dev)
Get the partiton number of the device that was opened.
_PURE enum switchtec_gen switchtec_gen(struct switchtec_dev *dev)
Get the generation of the device.
unsigned char stack
Stack number.
const char * lane_reversal_str
Lane reversal as a string.
const char * switchtec_strerror(void)
Return a message coresponding to the last error.
int switchtec_echo(struct switchtec_dev *dev, uint32_t input, uint32_t *output)
Perform an MRPC echo command.
Switchtec device id to generation/variant mapping.
_PURE enum switchtec_variant switchtec_variant(struct switchtec_dev *dev)
Get the variant type of the device.
unsigned char lane_reversal
Lane reversal.
switchtec_variant
The variant types of Switchtec device.
const char * ltssm_str
Link state as a string.
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.
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.
void switchtec_perror(const char *str)
Print an error string to stdout.
switchtec_rev
Device hardware revision.
struct switchtec_dev * switchtec_open(const char *device)
Open a Switchtec device by string.
_PURE const char * switchtec_name(struct switchtec_dev *dev)
Get the string that was used to open the deviec.
int mrpc_error_cmd
The MRPC command ID when errno is set.
int switchtec_log_to_file(struct switchtec_dev *dev, enum switchtec_log_type type, int fd)
Dump the Switchtec log data to a file.
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.
unsigned char log_id
Logical port number.
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.
unsigned char link_up
1 if the link is up
int switchtec_hard_reset(struct switchtec_dev *dev)
Perform an MRPC hard reset command.
uint16_t ltssm
Link state.