Skip to content

Commit 048d5cd

Browse files
committed
Add 'switchtec vf-reset' command
This command requests a function level reset for a virtual function
1 parent 54d3892 commit 048d5cd

File tree

2 files changed

+276
-0
lines changed

2 files changed

+276
-0
lines changed

plugins/microchip/switchtec-nvme.c

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ static int scan_pax_dev_filter(const struct dirent *d)
241241

242242
#define NVME_CLASS 0x010802
243243
#define CAP_PF 0x3
244+
#define CAP_VF 0x0
244245

245246
static int pax_enum_ep(struct switchtec_gfms_db_ep_port_ep *ep,
246247
struct switchtec_gfms_db_ep_port_attached_device_function *functions,
@@ -499,3 +500,277 @@ static int switchtec_pax_list(int argc, char **argv, struct command *command,
499500

500501
return 0;
501502
}
503+
504+
#define NOT_FOUND 0
505+
#define IS_PF 1
506+
#define IS_VF 2
507+
static int pax_check_function_pdfid(struct switchtec_gfms_db_ep_port_ep *ep,
508+
uint16_t pdfid)
509+
{
510+
int n;
511+
int j;
512+
int ret = NOT_FOUND;
513+
struct switchtec_gfms_db_ep_port_attached_device_function *function;
514+
515+
n = ep->ep_hdr.function_number;
516+
for (j = 0; j < n; j++) {
517+
function = &ep->functions[j];
518+
if (function->device_class == NVME_CLASS &&
519+
function->pdfid == pdfid) {
520+
if(function->sriov_cap_pf == CAP_PF)
521+
return IS_PF;
522+
else if (function->sriov_cap_pf == CAP_VF)
523+
return IS_VF;
524+
}
525+
}
526+
527+
return ret;
528+
}
529+
530+
static int pax_check_ep_pdfid(struct switchtec_dev *dev, uint16_t pdfid)
531+
{
532+
int i, j;
533+
int ret = NOT_FOUND;
534+
int n;
535+
struct switchtec_gfms_db_pax_all pax_all;
536+
struct switchtec_gfms_db_ep_port *ep_port;
537+
struct switchtec_gfms_db_ep_port_ep *ep;
538+
539+
ret = switchtec_fab_gfms_db_dump_pax_all(dev, &pax_all);
540+
if (ret)
541+
return NOT_FOUND;
542+
543+
for (i = 0; i < pax_all.ep_port_all.ep_port_count; i++) {
544+
ep_port = &pax_all.ep_port_all.ep_ports[i];
545+
if (ep_port->port_hdr.type == SWITCHTEC_GFMS_DB_TYPE_EP) {
546+
ep = &ep_port->ep_ep;
547+
ret = pax_check_function_pdfid(ep, pdfid);
548+
if (ret != NOT_FOUND)
549+
return ret;
550+
} else if (ep_port->port_hdr.type ==
551+
SWITCHTEC_GFMS_DB_TYPE_SWITCH) {
552+
n = ep_port->port_hdr.ep_count;
553+
554+
for (j = 0; j < n; j++) {
555+
ep = ep_port->ep_switch.switch_eps + j;
556+
ret = pax_check_function_pdfid(ep, pdfid);
557+
if (ret != NOT_FOUND)
558+
return ret;
559+
}
560+
}
561+
}
562+
563+
return NOT_FOUND;
564+
}
565+
566+
static int pax_check_pdfid_type(struct switchtec_dev *dev, uint16_t pdfid)
567+
{
568+
int i;
569+
int ret = NOT_FOUND;
570+
uint8_t r_type;
571+
struct switchtec_fab_topo_info topo_info;
572+
struct switchtec_gfms_db_fabric_general fg;
573+
574+
for(i = 0; i < SWITCHTEC_MAX_PORTS; i++)
575+
topo_info.port_info_list[i].phys_port_id = 0xff;
576+
577+
ret = switchtec_set_pax_id(dev, SWITCHTEC_PAX_ID_LOCAL);
578+
if (ret)
579+
return NOT_FOUND;
580+
581+
ret = switchtec_topo_info_dump(dev, &topo_info);
582+
if (ret)
583+
return NOT_FOUND;
584+
585+
ret = switchtec_fab_gfms_db_dump_fabric_general(dev, &fg);
586+
if (ret)
587+
return NOT_FOUND;
588+
589+
for (i = 0; i < 16; i++) {
590+
if (topo_info.route_port[i] == 0xff && fg.hdr.pax_idx != i)
591+
continue;
592+
593+
r_type = fg.body.pax_idx[i].reachable_type;
594+
595+
if (fg.hdr.pax_idx == i ||
596+
r_type == SWITCHTEC_GFMS_DB_REACH_UC) {
597+
ret = switchtec_set_pax_id(dev, i);
598+
if (ret)
599+
continue;
600+
601+
ret = pax_check_ep_pdfid(dev, pdfid);
602+
if (ret != NOT_FOUND)
603+
break;
604+
}
605+
}
606+
607+
switchtec_set_pax_id(dev, SWITCHTEC_PAX_ID_LOCAL);
608+
return ret;
609+
}
610+
611+
#define PCIE_CAPS_OFFSET 0x34
612+
#define PCIE_CAPS_OFFSET_MASK 0xfc
613+
#define PCIE_CAP_ID 0x10
614+
#define PCIE_DEVICE_CTRL_OFFSET 0x08
615+
#define PCIE_DEVICE_RESET_FLAG 0x8000
616+
#define PCIE_NEXT_CAP_OFFSET 0x01
617+
618+
int ask_if_sure(int always_yes)
619+
{
620+
char buf[10];
621+
char *ret;
622+
623+
if (always_yes)
624+
return 0;
625+
626+
fprintf(stderr, "Do you want to continue? [y/N] ");
627+
fflush(stderr);
628+
ret = fgets(buf, sizeof(buf), stdin);
629+
630+
if (!ret)
631+
goto abort;
632+
633+
if (strcmp(buf, "y\n") == 0 || strcmp(buf, "Y\n") == 0)
634+
return 0;
635+
636+
abort:
637+
fprintf(stderr, "Abort.\n");
638+
errno = EINTR;
639+
return -errno;
640+
}
641+
642+
static int switchtec_vf_reset(int argc, char **argv, struct command *command,
643+
struct plugin *plugin)
644+
{
645+
int ret = 0;
646+
uint8_t offset;
647+
uint16_t pdfid;
648+
uint8_t cap_id = 0;
649+
uint16_t flags;
650+
char device_str[64];
651+
char pdfid_str[64];
652+
struct switchtec_dev *dev;
653+
const char *desc = "Perform a Function Level Reset (FLR) on a Virtual Function";
654+
const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command";
655+
struct config {
656+
int force;
657+
} cfg = {};
658+
659+
const struct argconfig_commandline_options opts[] = {
660+
OPT_FLAG("force", 'f', &cfg.force, force),
661+
{NULL}
662+
};
663+
664+
ret = argconfig_parse(argc, argv, desc, opts);
665+
if (ret < 0)
666+
return ret;
667+
668+
if (optind >= argc) {
669+
fprintf(stderr,
670+
"vf-reset: DEVICE is required for this command!\n");
671+
return -1;
672+
}
673+
674+
if (sscanf(argv[optind], "%2049[^@]@%s", pdfid_str, device_str) < 2) {
675+
fprintf(stderr, "vf-reset: invalid device %s\n", argv[optind]);
676+
fprintf(stderr,
677+
"\nNOTE: This command only supports devices in the form of 'PDFID@device',\n"
678+
"where 'device' is your local device file or MOE service handle.\n"
679+
"Example for local device: 0x3b01@/dev/switchtec0\n"
680+
"Example for MOE access: [email protected]:0\n");
681+
fprintf(stderr,
682+
"\nFor RC device, use the reset command provided by your OS instead.\n"
683+
"Example: echo 1 > /sys/bus/pci/devices/${bdf_vf}/reset\n");
684+
return -1;
685+
}
686+
687+
ret = sscanf(pdfid_str, "%hx", &pdfid);
688+
if (!ret) {
689+
fprintf(stderr, "vf-reset: invalid device %s\n", argv[optind]);
690+
return -1;
691+
}
692+
693+
if (!cfg.force) {
694+
fprintf(stderr,
695+
"WARNING: This will reset the Virtual Function for %s\n\n",
696+
argv[optind]);
697+
}
698+
ret = ask_if_sure(cfg.force);
699+
if (ret)
700+
return ret;
701+
702+
dev = switchtec_open(device_str);
703+
if (!dev) {
704+
switchtec_perror(device_str);
705+
return -ENODEV;
706+
}
707+
708+
ret = pax_check_pdfid_type(dev, pdfid);
709+
if (ret == IS_PF) {
710+
fprintf(stderr,
711+
"vf-reset error: the given device %s is a Physical Function\n",
712+
argv[optind]);
713+
goto close;
714+
} else if (ret == NOT_FOUND) {
715+
fprintf(stderr,
716+
"vf-reset error: cannot find function with the given device name: %s\n",
717+
argv[optind]);
718+
goto close;
719+
}
720+
721+
ret = switchtec_set_pax_id(dev, SWITCHTEC_PAX_ID_LOCAL);
722+
if (ret) {
723+
switchtec_perror("vf-reset");
724+
goto close;
725+
}
726+
727+
ret = switchtec_ep_csr_read8(dev, pdfid, PCIE_CAPS_OFFSET, &offset);
728+
if (ret) {
729+
switchtec_perror("vf-reset");
730+
goto close;
731+
}
732+
733+
offset &= PCIE_CAPS_OFFSET_MASK;
734+
while (offset) {
735+
ret = switchtec_ep_csr_read8(dev, pdfid, offset, &cap_id);
736+
if (ret) {
737+
switchtec_perror("vf-reset");
738+
goto close;
739+
}
740+
741+
if (cap_id == PCIE_CAP_ID)
742+
break;
743+
744+
ret = switchtec_ep_csr_read8(dev, pdfid,
745+
offset + PCIE_NEXT_CAP_OFFSET,
746+
&offset);
747+
if (ret) {
748+
switchtec_perror("vf-reset");
749+
goto close;
750+
}
751+
}
752+
753+
if(!offset) {
754+
fprintf(stderr,
755+
"vf-reset: cannot find PCIe Capability Structure for the given device: %s\n",
756+
argv[optind]);
757+
goto close;
758+
}
759+
760+
offset += PCIE_DEVICE_CTRL_OFFSET;
761+
ret = switchtec_ep_csr_read16(dev, pdfid, offset, &flags);
762+
if (ret) {
763+
switchtec_perror("vf-reset");
764+
goto close;
765+
}
766+
767+
flags |= PCIE_DEVICE_RESET_FLAG;
768+
ret = switchtec_ep_csr_write32(dev, pdfid, flags, offset);
769+
if (ret) {
770+
switchtec_perror("vf-reset");
771+
goto close;
772+
}
773+
close:
774+
switchtec_close(dev);
775+
return ret;
776+
}

plugins/microchip/switchtec-nvme.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
PLUGIN(NAME("switchtec", "Switchtec specific extensions"),
3434
COMMAND_LIST(
3535
ENTRY("list", "List all NVMe devices and namespaces attached to Switchtec PAX switches", switchtec_pax_list)
36+
ENTRY("vf-reset", "Perform a Function Level Reset (FLR) on a Virtual Function", switchtec_vf_reset)
3637
)
3738
);
3839

0 commit comments

Comments
 (0)