@@ -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
245246static 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+ }
0 commit comments