diff options
Diffstat (limited to 'mtcr_ul')
| -rw-r--r-- | mtcr_ul/Makefile.am | 17 | ||||
| -rw-r--r-- | mtcr_ul/Makefile.in | 49 | ||||
| -rw-r--r-- | mtcr_ul/fwctrl.c | 5 | ||||
| -rw-r--r-- | mtcr_ul/mtcr_cables.c | 495 | ||||
| -rw-r--r-- | mtcr_ul/mtcr_cables.h | 149 | ||||
| -rw-r--r-- | mtcr_ul/mtcr_common.c | 244 | ||||
| -rw-r--r-- | mtcr_ul/mtcr_gpu.c | 2 | ||||
| -rw-r--r-- | mtcr_ul/mtcr_gpu.h | 6 | ||||
| -rw-r--r-- | mtcr_ul/mtcr_ib_ofed.c | 2 | ||||
| -rw-r--r-- | mtcr_ul/mtcr_nvml.c | 180 | ||||
| -rw-r--r-- | mtcr_ul/mtcr_nvml.h | 43 | ||||
| -rw-r--r-- | mtcr_ul/mtcr_ul.c | 15 | ||||
| -rw-r--r-- | mtcr_ul/mtcr_ul_com.c | 1318 | ||||
| -rw-r--r-- | mtcr_ul/mtcr_ul_com.h | 40 | ||||
| -rw-r--r-- | mtcr_ul/mtcr_ul_icmd_cif.c | 119 |
15 files changed, 2356 insertions, 328 deletions
diff --git a/mtcr_ul/Makefile.am b/mtcr_ul/Makefile.am index 9d193bd..ec63b3c 100644 --- a/mtcr_ul/Makefile.am +++ b/mtcr_ul/Makefile.am @@ -52,6 +52,23 @@ if ENABLE_INBAND libmtcr_ul_la_SOURCES += mtcr_ib_ofed.c endif +libmtcr_ul_la_DEPENDENCIES = $(top_builddir)/vfio_driver_access/libvfio_access_driver.la +libmtcr_ul_la_LDFLAGS = -lstdc++ + +if ENABLE_NVML +libmtcr_ul_la_DEPENDENCIES += $(top_builddir)/$(NVML_DIR)/libnvml_device.la +libmtcr_ul_la_LDFLAGS += -static +endif + +if ENABLE_CABLES +libmtcr_ul_la_SOURCES += mtcr_cables.c mtcr_cables.h +libmtcr_ul_la_DEPENDENCIES += $(top_builddir)/tools_layouts/libcables_layouts.la +libmtcr_ul_la_LDFLAGS += -static +endif + +libmtcr_ul_la_LIBADD = $(libmtcr_ul_la_DEPENDENCIES) + + libraryincludedir=$(includedir)/mstflint libraryinclude_HEADERS = $(top_srcdir)/include/mtcr_ul/mtcr.h $(top_srcdir)/include/mtcr_ul/mtcr_com_defs.h $(top_srcdir)/include/mtcr_ul/mtcr_mf.h diff --git a/mtcr_ul/Makefile.in b/mtcr_ul/Makefile.in index 67271ce..5373a91 100644 --- a/mtcr_ul/Makefile.in +++ b/mtcr_ul/Makefile.in @@ -112,12 +112,17 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @ENABLE_INBAND_TRUE@am__append_1 = mtcr_ib_ofed.c +@ENABLE_NVML_TRUE@am__append_2 = $(top_builddir)/$(NVML_DIR)/libnvml_device.la +@ENABLE_NVML_TRUE@am__append_3 = -static +@ENABLE_CABLES_TRUE@am__append_4 = mtcr_cables.c mtcr_cables.h +@ENABLE_CABLES_TRUE@am__append_5 = $(top_builddir)/tools_layouts/libcables_layouts.la +@ENABLE_CABLES_TRUE@am__append_6 = -static subdir = mtcr_ul DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/config/depcomp $(libraryinclude_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -154,7 +159,6 @@ am__uninstall_files_from_dir = { \ am__installdirs = "$(DESTDIR)$(pkglibdir)" \ "$(DESTDIR)$(libraryincludedir)" LTLIBRARIES = $(pkglib_LTLIBRARIES) -libmtcr_ul_la_LIBADD = am__libmtcr_ul_la_SOURCES_DIST = mtcr_ul.c mtcr_ib.h mtcr_int_defs.h \ mtcr_ib_res_mgt.h mtcr_ib_res_mgt.c mtcr_tools_cif.c \ mtcr_tools_cif.h mtcr_ul_icmd_cif.c mtcr_icmd_cif.h \ @@ -162,8 +166,9 @@ am__libmtcr_ul_la_SOURCES_DIST = mtcr_ul.c mtcr_ib.h mtcr_int_defs.h \ mtcr_ul_com.h mtcr_ul_com.c mtcr_common.h mtcr_common.c \ packets_common.c packets_common.h packets_layout.c \ packets_layout.h fwctrl.c fwctrl.h fwctrl_ioctl.h mtcr_gpu.c \ - mtcr_gpu.h mtcr_ib_ofed.c + mtcr_gpu.h mtcr_ib_ofed.c mtcr_cables.c mtcr_cables.h @ENABLE_INBAND_TRUE@am__objects_1 = libmtcr_ul_la-mtcr_ib_ofed.lo +@ENABLE_CABLES_TRUE@am__objects_2 = libmtcr_ul_la-mtcr_cables.lo am_libmtcr_ul_la_OBJECTS = libmtcr_ul_la-mtcr_ul.lo \ libmtcr_ul_la-mtcr_ib_res_mgt.lo \ libmtcr_ul_la-mtcr_tools_cif.lo \ @@ -171,7 +176,7 @@ am_libmtcr_ul_la_OBJECTS = libmtcr_ul_la-mtcr_ul.lo \ libmtcr_ul_la-mtcr_mem_ops.lo libmtcr_ul_la-mtcr_ul_com.lo \ libmtcr_ul_la-mtcr_common.lo libmtcr_ul_la-packets_common.lo \ libmtcr_ul_la-packets_layout.lo libmtcr_ul_la-fwctrl.lo \ - libmtcr_ul_la-mtcr_gpu.lo $(am__objects_1) + libmtcr_ul_la-mtcr_gpu.lo $(am__objects_1) $(am__objects_2) libmtcr_ul_la_OBJECTS = $(am_libmtcr_ul_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -179,7 +184,7 @@ am__v_lt_0 = --silent am__v_lt_1 = libmtcr_ul_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libmtcr_ul_la_CFLAGS) \ - $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ + $(CFLAGS) $(libmtcr_ul_la_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -253,13 +258,13 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +CABLE_ACCESS_DIR = @CABLE_ACCESS_DIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ COMPILER_FPIC = @COMPILER_FPIC@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ -CURL_INC_DIR = @CURL_INC_DIR@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ @@ -313,6 +318,7 @@ MUPARSER_CFLAGS = @MUPARSER_CFLAGS@ MUPARSER_LIBS = @MUPARSER_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ +NVML_DIR = @NVML_DIR@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OFED_BUILD = @OFED_BUILD@ @@ -326,6 +332,9 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROJECT = @PROJECT@ RANLIB = @RANLIB@ SED = @SED@ @@ -338,6 +347,7 @@ TOOLS_BUILD_TIME = @TOOLS_BUILD_TIME@ TOOLS_CRYPTO = @TOOLS_CRYPTO@ TOOLS_GIT_SHA = @TOOLS_GIT_SHA@ VERSION = @VERSION@ +VFIO_DRIVER_DIR = @VFIO_DRIVER_DIR@ XZ_UTILS_DIR = @XZ_UTILS_DIR@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ @@ -365,6 +375,8 @@ default_en_inband = @default_en_inband@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ +expat_CFLAGS = @expat_CFLAGS@ +expat_LIBS = @expat_LIBS@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ @@ -374,13 +386,23 @@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +libcurl_CFLAGS = @libcurl_CFLAGS@ +libcurl_LIBS = @libcurl_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +liblzma_CFLAGS = @liblzma_CFLAGS@ +liblzma_LIBS = @liblzma_LIBS@ +libxml2_CFLAGS = @libxml2_CFLAGS@ +libxml2_LIBS = @libxml2_LIBS@ +libz_CFLAGS = @libz_CFLAGS@ +libz_LIBS = @libz_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ +openssl_CFLAGS = @openssl_CFLAGS@ +openssl_LIBS = @openssl_LIBS@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -402,8 +424,13 @@ libmtcr_ul_la_SOURCES = mtcr_ul.c mtcr_ib.h mtcr_int_defs.h \ mtcr_ul_com.h mtcr_ul_com.c mtcr_common.h mtcr_common.c \ packets_common.c packets_common.h packets_layout.c \ packets_layout.h fwctrl.c fwctrl.h fwctrl_ioctl.h mtcr_gpu.c \ - mtcr_gpu.h $(am__append_1) + mtcr_gpu.h $(am__append_1) $(am__append_4) libmtcr_ul_la_CFLAGS = -W -Wall -g -MP -MD -fPIC -DMTCR_API="" -DMST_UL +libmtcr_ul_la_DEPENDENCIES = \ + $(top_builddir)/vfio_driver_access/libvfio_access_driver.la \ + $(am__append_2) $(am__append_5) +libmtcr_ul_la_LDFLAGS = -lstdc++ $(am__append_3) $(am__append_6) +libmtcr_ul_la_LIBADD = $(libmtcr_ul_la_DEPENDENCIES) libraryincludedir = $(includedir)/mstflint libraryinclude_HEADERS = $(top_srcdir)/include/mtcr_ul/mtcr.h $(top_srcdir)/include/mtcr_ul/mtcr_com_defs.h $(top_srcdir)/include/mtcr_ul/mtcr_mf.h all: all-am @@ -486,6 +513,7 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmtcr_ul_la-fwctrl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmtcr_ul_la-mtcr_cables.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmtcr_ul_la-mtcr_common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmtcr_ul_la-mtcr_gpu.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmtcr_ul_la-mtcr_ib_ofed.Plo@am__quote@ @@ -606,6 +634,13 @@ libmtcr_ul_la-mtcr_ib_ofed.lo: mtcr_ib_ofed.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmtcr_ul_la_CFLAGS) $(CFLAGS) -c -o libmtcr_ul_la-mtcr_ib_ofed.lo `test -f 'mtcr_ib_ofed.c' || echo '$(srcdir)/'`mtcr_ib_ofed.c +libmtcr_ul_la-mtcr_cables.lo: mtcr_cables.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmtcr_ul_la_CFLAGS) $(CFLAGS) -MT libmtcr_ul_la-mtcr_cables.lo -MD -MP -MF $(DEPDIR)/libmtcr_ul_la-mtcr_cables.Tpo -c -o libmtcr_ul_la-mtcr_cables.lo `test -f 'mtcr_cables.c' || echo '$(srcdir)/'`mtcr_cables.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmtcr_ul_la-mtcr_cables.Tpo $(DEPDIR)/libmtcr_ul_la-mtcr_cables.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mtcr_cables.c' object='libmtcr_ul_la-mtcr_cables.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmtcr_ul_la_CFLAGS) $(CFLAGS) -c -o libmtcr_ul_la-mtcr_cables.lo `test -f 'mtcr_cables.c' || echo '$(srcdir)/'`mtcr_cables.c + mostlyclean-libtool: -rm -f *.lo diff --git a/mtcr_ul/fwctrl.c b/mtcr_ul/fwctrl.c index f000e9e..301ead8 100644 --- a/mtcr_ul/fwctrl.c +++ b/mtcr_ul/fwctrl.c @@ -40,7 +40,9 @@ #include <errno.h> #include <string.h> #include <stddef.h> +#include "mtcr.h" #include "mtcr_mf.h" +#include "mtcr_ul_com.h" #include "fwctrl.h" #include "fwctrl_ioctl.h" @@ -159,6 +161,7 @@ int fwctl_control_access_register(int fd, rpc = (struct fwctl_rpc) { .size = sizeof(rpc), + .scope = 3, .in = (uintptr_t)in, .in_len = inlen, .out = (uintptr_t)out, @@ -192,7 +195,7 @@ int fwctl_control_access_register(int fd, } FWCTL_DEBUG_PRINT(mf, "register id = 0x%x, command status = 0x%x, reg status code: 0x%x, reg status: %s\n", - reg_id, cmd_status, *reg_status, m_err2str(status)); + reg_id, cmd_status, *reg_status, m_err2str(*reg_status)); out: free(out); free(in); diff --git a/mtcr_ul/mtcr_cables.c b/mtcr_ul/mtcr_cables.c new file mode 100644 index 0000000..f741b24 --- /dev/null +++ b/mtcr_ul/mtcr_cables.c @@ -0,0 +1,495 @@ +#include <string.h> +#include <stdlib.h> +#include <dlfcn.h> +#include <stdbool.h> +#include "mtcr_cables.h" +#include "mtcr_int_defs.h" +#include "mtcr_common.h" +#include "reg_access/reg_access.h" +#include "tools_layouts/cables_layouts.h" +#include "mtcr_ul_com.h" + + +#define MAX_PORT_NUM 128 +#define CABLE_I2C_DEVICE_ADDR 0x50 +#define SECOND_SFP_I2C_ADDR 0x51 +#define CABLE_PAGE_SIZE 256 +#define NUM_OF_WRITE_PAGE_RETRIES 5 +#define CBLINFO_MAX_SIZE 48 +#define REG_ID_MCIA 0x9014 +#define CABLEID_ADDR 0x0 +#define SFP_DIGITAL_DIAGNOSTIC_MONITORING_IMPLEMENTED_ADDR 92 +#define SFP_PAGING_IMPLEMENTED_INDICATOR_ADDR 64 + +bool is_cable_burn_flow = false; + +reg_access_status_t reg_access_mcia(mfile* mf, reg_access_method_t method, struct reg_access_hca_mcia_ext* mcia) +{ + int data_size = reg_access_hca_mcia_ext_size(); + int status = 0; + int rc; + int max_data_size = reg_access_hca_mcia_ext_size(); + u_int8_t* data = ((void *)0); + + if ((method != REG_ACCESS_METHOD_GET) && (method != REG_ACCESS_METHOD_SET)) { + return ME_REG_ACCESS_BAD_METHOD; + } + data = (u_int8_t*)malloc(sizeof(u_int8_t) * max_data_size); + if (!data) { + return ME_MEM_ERROR; + } + ; + memset(data, 0, max_data_size); + reg_access_hca_mcia_ext_pack(mcia, data); + ; + + /* printf("=======mcia before: ==========\n"); */ + /* reg_access_hca_mcia_ext_dump(mcia, stdout); */ + /* printf("==============================\n"); */ + + rc = maccess_reg(mf, REG_ID_MCIA, (maccess_reg_method_t)method, data, data_size, data_size, data_size, &status); + if (rc && 0) { + free(data); + } else { + reg_access_hca_mcia_ext_unpack(mcia, data); + /* printf("=======mcia after: ==========\n"); */ + /* reg_access_hca_mcia_ext_dump(mcia, stdout); */ + /* printf("==============================\n"); */ + free(data); + ; + } if (rc || status) { + return (reg_access_status_t)rc; + } + return ME_OK; +} + + +void copy_data(u_int8_t* dest, u_int8_t* src, int size, int be2cpu) +{ + int j = 0; + int last_bytes = size % 4; + + for (j = 0; j < size / 4; j++) { + ((u_int32_t*)dest)[j] = __be32_to_cpu(((u_int32_t*)src)[j]); + } + + if (last_bytes) { + u_int32_t last_dword = __be32_to_cpu(((u_int32_t*)src)[size / 4]); + if (be2cpu) { + memcpy(dest + (size - size % 4), &last_dword, last_bytes); + } else { + ((u_int32_t*)dest)[size / 4] = last_dword; + } + } +} + +/* + * Implementation of the cable access using access_reg for Read/Write + */ +int cable_access_reg_rw(mfile * mf, + u_int16_t page_num, + u_int16_t page_off, + u_int16_t size, + u_int8_t port, + u_int8_t page_lock, + u_int32_t* data, + rw_op_t _rw) +{ + reg_access_method_t op = REG_ACCESS_METHOD_GET; + struct reg_access_hca_mcia_ext cbl_reg_t; + + memset(&cbl_reg_t, 0, sizeof(cbl_reg_t)); + cbl_reg_t.device_address = page_off; + cbl_reg_t.page_number = page_num; + cbl_reg_t.i2c_device_address = ((cable_ctx*)(mf->cable_ctx))->i2c_addr; + cbl_reg_t.module = port; + cbl_reg_t.size = size; + cbl_reg_t.l = page_lock; + if (_rw == WRITE_OP) { + op = REG_ACCESS_METHOD_SET; + copy_data((u_int8_t*)cbl_reg_t.dword, (u_int8_t*)data, size, 0); +/* printf("MCIA write: page: %#x, offset: %#x, size: %d\n", page_num, page_off, size); */ +/* for (ii=0; ii<size; ii++){ */ +/* printf("MCIA write: data[%d] = %#x \n",ii, cbl_reg_t.dword[ii]); */ +/* } */ + } + reg_access_status_t rc = reg_access_mcia(mf, op, &cbl_reg_t); + + if (rc) { + DBG_PRINTF("-D- MCIA Failed with rc: %d\n", (int)rc); + return MCABLES_REG_FAILED; + } + if (_rw == READ_OP) { + copy_data((u_int8_t*)data, (u_int8_t*)cbl_reg_t.dword, size, 1); + DBG_PRINTF("MCIA read: page: %#x, offset: %#x, size: %d\n", page_num, page_off, size); + for (int ii = 0; ii < size; ii++) { + DBG_PRINTF("MCIA read: data[%d] = %#x \n", ii, cbl_reg_t.dword[ii]); + } + } +/* printf("-D- RW: %d offset: %#x, Len: %#x\n", _rw, page_off, size); */ + return 0; +} + +int cable_access_rw(mfile* mf, u_int32_t addr, u_int32_t len, u_int32_t* data, rw_op_t _rw) +{ + MCABLES_ERROR ret = MCABLES_OK; + + if (!mf) { + return MCABLES_BAD_PARAMS; + } + + MType tmp_tp = mf->tp; + u_int16_t page_num = addr / CABLE_PAGE_SIZE; + u_int16_t device_addr = addr % CABLE_PAGE_SIZE; + u_int32_t i = 0; + int recover_i2c_addr = 0; + cable_ctx* ctx = (cable_ctx*)(mf->cable_ctx); + + if (!ctx) { + return MCABLES_ACCESS_ERROR; + } + + u_int8_t page_lock = ctx->page_lock; + + mf->tp = ctx->src_tp; + switch_access_funcs(mf); + if ((ctx->cable_type == DeviceCableSFP51) || (ctx->cable_type == DeviceCableSFP51Paging)) { + if (page_num > 0) { + ctx->i2c_addr = SECOND_SFP_I2C_ADDR; + page_num--; + recover_i2c_addr = 1; + } + } + + while (i < len) { + u_int32_t tmp_size = 0; + u_int32_t page_i = i / CABLE_PAGE_SIZE; + u_int32_t addr_i = i % CABLE_PAGE_SIZE; + tmp_size = ((len - i) > CBLINFO_MAX_SIZE) ? CBLINFO_MAX_SIZE : (len - i); + switch (ctx->cable_access) { + case MLXCABLES_REG_ACCESS: + if (cable_access_reg_rw(mf, page_num + page_i, device_addr + addr_i, tmp_size, ctx->port, page_lock, + data + i / 4, _rw)) { + DBG_PRINTF("cable_access_reg_rw failed\n"); + ret = MCABLES_REG_FAILED; + goto cleanup; + } + break; + + default: + break; + } + i += tmp_size; + } +cleanup: + if (recover_i2c_addr) { + ctx->i2c_addr = CABLE_I2C_DEVICE_ADDR; + } + mf->tp = tmp_tp; + switch_access_funcs(mf); + /* printf("-D- RW: %d Addr: %#x, Len: %#x, DATA[0]: %#x\n", _rw, addr, len, data[0]); */ + return ret; +} + +int mtcr_pciconf_mread4(mfile* mf, unsigned int offset, u_int32_t* value); +int mtcr_pciconf_mwrite4(mfile* mf, unsigned int offset, u_int32_t value); +int mread4_block_pciconf(mfile* mf, unsigned int offset, u_int32_t* value, int byte_len); +int mwrite4_block_pciconf(mfile* mf, unsigned int offset, u_int32_t* value, int byte_len); +int mtcr_pciconf_mclose(mfile* mf); + +int mcables_open(mfile* mf, int port) +{ + cable_ctx* cbl; + + mf->flags = MDEVS_CABLE; + mf->cable_ctx = NULL; + + /* int semaphore_num_of_resources = 1; */ + + if (!mf || (port < 0) || (port > MAX_PORT_NUM)) { + DBG_PRINTF("unable to open cable, invalid args\n"); + return MCABLES_BAD_PARAMS; + } + cbl = (cable_ctx*)malloc(sizeof(cable_ctx)); + if (!cbl) { + return MCABLES_MEM_ERROR; + } + memset(cbl, 0, sizeof(cable_ctx)); + cbl->port = port; + cbl->src_tp = mf->tp; + cbl->cable_access = MLXCABLES_REG_ACCESS; + cbl->i2c_addr = CABLE_I2C_DEVICE_ADDR; + mf->tp = MST_CABLE; + switch_access_funcs(mf); + + /* // Create the semaphore object. */ + /* cbl->semaphore_handle = create_semaphore(); */ + /* if (!cbl->semaphore_handle) */ + /* { */ + /* DPRINTF("failed to create cables semaphore\n"); */ + /* return MCABLES_SEM_CREATE_FAILED; */ + /* } */ + + /* int ret_value = semaphore_init(semaphore_num_of_resources, "mcables_sem", cbl->semaphore_handle); */ + /* if (ret_value != SEM_OK && ret_value != SEM_ALREADY_EXISTS) */ + /* { */ + /* DPRINTF("failed to init cables semaphore\n"); */ + /* free(cbl->semaphore_handle); */ + /* cbl->semaphore_handle = NULL; */ + /* free(cbl); */ + /* return MCABLES_SEM_INIT_FAILED; */ + /* } */ + + /* ret_value = semaphore_lock(cbl->semaphore_handle); */ + /* if (ret_value) */ + /* { */ + /* DPRINTF("failed to lock cables semaphore\n"); */ + /* free(cbl->semaphore_handle); */ + /* cbl->semaphore_handle = NULL; */ + /* free(cbl); */ + /* return MCABLES_SEM_LOCK_FAILED; */ + /* } */ + + mf->cable_ctx = cbl; + + u_int32_t id = 0; + int rw_result = cable_access_rw(mf, 0, 1, (u_int32_t*)&id, READ_OP); + + if (rw_result || (id == 0)) { + DBG_PRINTF("Failed to read ID from device or id is not supported: id 0x%04x rc %d:\n", id, rw_result); + mcables_close(mf); + + return MCABLES_ACCESS_ERROR; + } + + u_int32_t devid = 0; + int rc = get_cable_id(mf, &(cbl->cable_type), &devid); + + DBG_PRINTF("cable type: %d\n", cbl->cable_type); + DBG_PRINTF("devid: %d\n", devid); + + if (rc) { + DBG_PRINTF("Failed to get dev_mgt device id\n"); + mcables_close(mf); + return MCABLES_ACCESS_ERROR; + } + if ((cbl->cable_type == DeviceCableSFP51) || (cbl->cable_type == DeviceCableSFP51Paging)) { + cbl->i2c_addr = SECOND_SFP_I2C_ADDR; + if (cable_access_rw(mf, 0, 1, (u_int32_t*)&id, READ_OP)) { + /* printf("-D- Failed to read from 0x51 -> return SFP\n"); */ + cbl->cable_type = DeviceCableSFP; + } + cbl->i2c_addr = CABLE_I2C_DEVICE_ADDR; + } + + /* // Semaphore unlock */ + /* ret_value = semaphore_unlock(cbl->semaphore_handle); */ + /* if (ret_value) */ + /* { */ + /* DPRINTF("failed to unlock cables semaphore\n"); */ + /* mcables_close(mf); */ + /* return MCABLES_SEM_UNLOCK_FAILED; */ + /* } */ + + DBG_PRINTF("mcables_open finished\n"); + return MCABLES_OK; +} + +int mcables_close(mfile* mf) +{ + cable_ctx* cbl = mf->cable_ctx; + + /* semaphore_close(cbl->semaphore_handle); */ + + /* // Destroy the semaphore object. */ + /* destroy_semaphore(cbl->semaphore_handle); */ + + if (mf && mf->cable_ctx) { + mf->tp = cbl->src_tp; + free(mf->cable_ctx); + mf->cable_ctx = NULL; + } + return MCABLES_OK; +} + + +int mcables_read4(mfile* mf, u_int32_t offset, u_int32_t* value) +{ + if (!mf || !value) { + return MCABLES_BAD_PARAMS; + } + int rc = cable_access_rw(mf, offset, 4, value, READ_OP); + + if (!rc) { + *value = __cpu_to_le32(*value); + rc = 4; + } + return rc; +} + +int mcables_write4(mfile* mf, u_int32_t offset, u_int32_t value) +{ + if (!mf) { + return MCABLES_BAD_PARAMS; + } + int rc = cable_access_rw(mf, offset, 4, &value, WRITE_OP); + + if (!rc) { + rc = 4; + } + return rc; +} + +int mcables_read4_block(mfile* mf, u_int32_t offset, u_int32_t* value, int byte_len) +{ + if (!mf || (byte_len % 4) || !value) { + return MCABLES_BAD_PARAMS; + } + int rc = cable_access_rw(mf, offset, byte_len, value, READ_OP); + + if (!rc) { + int i = 0; + for (; i < byte_len / 4; i++) { + value[i] = __cpu_to_le32(value[i]); + } + rc = byte_len; + } + return rc; +} + +int mcables_write4_block(mfile* mf, u_int32_t offset, u_int32_t* value, int byte_len) +{ + if (!mf || (byte_len % 4) || !value) { + return MCABLES_BAD_PARAMS; + } + int rc = cable_access_rw(mf, offset, byte_len, value, WRITE_OP); + + if (!rc) { + rc = byte_len; + } + return rc; +} + +int mcables_read_bytes(mfile* mf, u_int32_t offset, u_int8_t* value, int byte_len) +{ + if (!mf || !value) { + return (int)MCABLES_BAD_PARAMS; + } + return (int)cable_access_rw(mf, offset, byte_len, (u_int32_t*)value, READ_OP); +} + +int mcables_write_bytes(mfile* mf, u_int32_t offset, u_int8_t* value, int byte_len) +{ + if (!mf || !value) { + return (int)MCABLES_BAD_PARAMS; + } + int rc = (int)cable_access_rw(mf, offset, byte_len, (u_int32_t*)value, WRITE_OP); + + return rc; +} + +dm_dev_id_t mcables_get_dm(mfile* mf) +{ + if (mf && mf->cable_ctx) { + return ((cable_ctx*)(mf->cable_ctx))->cable_type; + } + return DeviceUnknown; +} + +enum dm_dev_type getCableType(u_int8_t id) +{ + switch (id) { + case 0xd: + case 0x11: + case 0xe: + case 0xc: + return DM_QSFP_CABLE; + + case 0x3: + return DM_SFP_CABLE; + + case 0x18: + case 0x19: /* Stallion2 */ + case 0x80: + case 0x22: + case 0x1e: + return DM_CMIS_CABLE; + + default: + return DM_UNKNOWN; + } +} + + +int get_cable_id(mfile* mf, u_int32_t* ptr_hw_dev_id, dm_dev_id_t* ptr_dm_dev_id) +{ + u_int32_t dword = 0; + + /* printf("-D- Getting cable ID\n"); */ + if (mread4(mf, CABLEID_ADDR, &dword) != 4) { + /* printf("FATAL - crspace read (0x%x) failed: %s\n", DEVID_ADDR, strerror(errno)); */ + return GET_DEV_ID_ERROR; + } + /* dword = __cpu_to_le32(dword); // Cable pages are read in LE, no need to swap */ + *ptr_hw_dev_id = 0xffff; + u_int8_t id = EXTRACT(dword, 0, 8); + enum dm_dev_type cbl_type = getCableType(id); + + *ptr_hw_dev_id = id; + u_int8_t paging; + + if (cbl_type == DM_QSFP_CABLE) { + /* Get Byte 2 bit 2 ~ bit 18 (flat_mem : upper memory flat or paged. 0=paging, 1=page 0 only) */ + paging = EXTRACT(dword, 18, 1); + /* printf("DWORD: %#x, paging: %d\n", dword, paging); */ + if (paging == 0) { + *ptr_dm_dev_id = DeviceCableQSFPaging; + } else { + *ptr_dm_dev_id = DeviceCableQSFP; + } + } else if (cbl_type == DM_SFP_CABLE) { + *ptr_dm_dev_id = DeviceCableSFP; + if (mread4(mf, SFP_DIGITAL_DIAGNOSTIC_MONITORING_IMPLEMENTED_ADDR, &dword) != 4) { + /* printf("FATAL - crspace read (0x%x) failed: %s\n", DEVID_ADDR, strerror(errno)); */ + return GET_DEV_ID_ERROR; + } + u_int8_t byte = EXTRACT(dword, 6, 1); /* Byte 92 bit 6 (digital diagnostic monitoring implemented) */ + if (byte) { + *ptr_dm_dev_id = DeviceCableSFP51; + if (mread4(mf, SFP_PAGING_IMPLEMENTED_INDICATOR_ADDR, &dword) != 4) { + /* printf("FATAL - crspace read (0x%x) failed: %s\n", DEVID_ADDR, strerror(errno)); */ + return GET_DEV_ID_ERROR; + } + byte = EXTRACT(dword, 4, 1); /* Byte 64 bit 4 (paging implemented indicator) */ + if (byte) { + *ptr_dm_dev_id = DeviceCableSFP51Paging; + } + } + } else if (cbl_type == DM_CMIS_CABLE) { + /* Get Byte 2 bit 7 ~ bit 23 (flat_mem : upper memory flat or paged. 0=paging, 1=page 0 only) */ + paging = EXTRACT(dword, 23, 1); + if (paging == 0) { + *ptr_dm_dev_id = DeviceCableCMISPaging; + } else { + *ptr_dm_dev_id = DeviceCableCMIS; + } + } else { + *ptr_dm_dev_id = DeviceUnknown; + } + return GET_DEV_ID_SUCCESS; +} + +void mcables_set_burn_flow(bool burn_flow) +{ + is_cable_burn_flow = burn_flow; +} + +MType mcables_get_tp(mfile* mf) +{ + cable_ctx* ctx = (cable_ctx*)(mf->cable_ctx); + + if (!ctx) { + return 0; + } + return ctx->src_tp; +} diff --git a/mtcr_ul/mtcr_cables.h b/mtcr_ul/mtcr_cables.h new file mode 100644 index 0000000..10d99b5 --- /dev/null +++ b/mtcr_ul/mtcr_cables.h @@ -0,0 +1,149 @@ +#ifndef _MTCR_CABLES_H +#define _MTCR_CABLES_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "include/mtcr_ul/mtcr.h" +#include "include/mtcr_ul/mtcr_com_defs.h" +#include "dev_mgt/tools_dev_types.h" + +#define CABLE_DEVICE_STR "_cable_" + +typedef enum { + MCABLES_OK = 0, + MCABLES_BAD_PARAMS, + MCABLES_MEM_ERROR, + MCABLES_REG_FAILED, + MCABLES_MAD_FAILED, + MCABLES_MTUSB_FAILED, + MCABLES_ACCESS_ERROR, + MCABLES_NOT_SUPPORTED, + + /* Semaphore errors. */ + MCABLES_SEM_CREATE_FAILED, + MCABLES_SEM_INIT_FAILED, + MCABLES_SEM_CLOSE_FAILED, + MCABLES_SEM_LOCK_FAILED, + MCABLES_SEM_UNLOCK_FAILED +} MCABLES_ERROR; + +typedef enum { + MLXCABLES_REG_ACCESS = 1, +} cable_access_type_t; + + +typedef struct { + int port; + cable_access_type_t cable_access; + MType src_tp; + int page_lock; + unsigned active; + unsigned oui; + unsigned page; + unsigned fw_gw_version; + unsigned char i2c_addr; + dm_dev_id_t cable_type; + void * semaphore_handle; +} cable_ctx; + + +/* + * @brief mcables_open : open the cable device + * @effect Initialize cable connected to device, update the mfile according + * @param[in/out] mf - mfile pointer of the device + * @param[in] port - the port where the cable is connected + * @return 0 in Success, otherwise in failure + */ +int mcables_open(mfile* mf, int port); + +/* + * @brief mcables_close: close the cable + * @effect finalize the connection to the cable and free the allocated context + * @param[in/out] mf - mfile pointer of the device + * @return 0 in Success, otherwise in failure + */ +int mcables_close(mfile* mf); +/* + * @brief mcables_read4: read 4 bytes from the cable + * @effect Read 4 bytes from the cable pages, the address contain page number and offset + * @param[in] mf - mfile pointer of the device + * @param[in] offset - The address from it to read (0x<PAGE_NUM><PAGE_OFFSET>) + * @param[out] value - a pointer for dword where the data will be read into it + * @return 0 in Success, otherwise in failure + */ +int mcables_read4(mfile* mf, u_int32_t offset, u_int32_t* value); + +/* + * @brief mcables_write4: write 4 bytes to the cable + * @effect Write 4 bytes to the cable pages, the address contain page number and offset + * @param[in] mf - mfile pointer of the device + * @param[in] offset - The address to it will be written (0x<PAGE_NUM><PAGE_OFFSET>) + * @param[out] value - a dword to the written data + * @return 0 in Success, otherwise in failure + */ +int mcables_write4(mfile* mf, u_int32_t offset, u_int32_t value); + +/* + * @brief mcables_read4_block: read dword aligned block from the cable + * @effect Read block of data from the cable pages, the address contain page number and offset + * @param[in] mf - mfile pointer of the device + * @param[in] offset - The address from it to read (0x<PAGE_NUM><PAGE_OFFSET>) + * @param[out] value - a pointer for dwords where the data will be read into it + * @param[out] byte_len - The length of the data (multiples of 4) + * @return 0 in Success, otherwise in failure + */ +int mcables_read4_block(mfile* mf, u_int32_t offset, u_int32_t* value, int byte_len); + +/* + * @brief mcables_write4_block: write dword aligned block from the cable + * @effect Write block of data to the cable pages, the address contain page number and offset + * @param[in] mf - mfile pointer of the device + * @param[in] offset - The address to it will be written (0x<PAGE_NUM><PAGE_OFFSET>) + * @param[out] value - a pointer for dwords where the data to be written + * @param[in] byte_len - The length of the data (multiples of 4) + * @return 0 in Success, otherwise in failure + */ +int mcables_write4_block(mfile* mf, u_int32_t offset, u_int32_t* value, int byte_len); + + +/* + * @brief mcables_read_bytes: General function to read bytes + * @effect Read bytes from the cable pages, the address contain page number and offset + * @param[in] mf - mfile pointer of the device + * @param[in] offset - The address from it to read (0x<PAGE_NUM><PAGE_OFFSET>) + * @param[out] value - a pointer for dword where the data will be read into it + * @param[in] byte_len - The length of the data + * @return 0 in Success, otherwise in failure + */ +int mcables_read_bytes(mfile* mf, u_int32_t offset, u_int8_t* value, int byte_len); + +/* + * @brief mcables_write_bytes: write bytes to the cable + * @effect Write bytes to the cable pages, the address contain page number and offset + * @param[in] mf - mfile pointer of the device + * @param[in] offset - The address to it will be written (0x<PAGE_NUM><PAGE_OFFSET>) + * @param[out] value - a dword to the written data + * @param[in] byte_len - The length of the data + * @return 0 in Success, otherwise in failure + */ +int mcables_write_bytes(mfile* mf, u_int32_t offset, u_int8_t* value, int byte_len); + +/* + * @brief mcables_get_dm: Cable get cable type + * @effect Get the dev mgt type of the cable + * @param[in] mf - mfile pointer of the device + */ +dm_dev_id_t mcables_get_dm(mfile* mf); + +int get_cable_id(mfile* m, u_int32_t* ptr_hw_dev_id, dm_dev_id_t* ptr_dm_dev_id); + +void mcables_set_burn_flow(bool burn_flow); + +MType mcables_get_tp(mfile* mf); +#endif /* _MTCR_CABLES_H */ +#ifdef __cplusplus +} +#endif diff --git a/mtcr_ul/mtcr_common.c b/mtcr_ul/mtcr_common.c index 09efeb4..42e5372 100644 --- a/mtcr_ul/mtcr_common.c +++ b/mtcr_ul/mtcr_common.c @@ -1,3 +1,36 @@ +/* + * Copyright(c) 2025 NVIDIA CORPORATION & AFFILIATES.All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses.You may choose to be licensed under the terms of the GNU + * General Public License(GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * -Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * -Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and / or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + #include "mtcr_common.h" void swap_pci_address_space(mfile* mf) @@ -51,3 +84,214 @@ void swap_pci_address_space(mfile* mf) DBG_PRINTF("mf->address_space swapped to: %x\n", mf->address_space); } + +const char* m_err2str(MError status) +{ + switch (status) { + case ME_OK: + return "Success"; + + case ME_ERROR: + return "General error"; + + case ME_BAD_PARAMS: + return "Bad Parameter error"; + + case ME_CR_ERROR: + return "CRSpace access error"; + + case ME_NOT_IMPLEMENTED: + return "Interface not implemented"; + + case ME_SEM_LOCKED: + return "Semaphore locked"; + + case ME_MEM_ERROR: + return "Memory error"; + + case ME_UNSUPPORTED_OPERATION: + return "Operation not supported"; + + case ME_GMP_MAD_UNSUPPORTED_OPERATION: + return "Sending GMP MAD supports only Get() method, and you are trying to send Set() method\n" + "to a register which is not small enough to send with SMP MAD."; + + case ME_MAD_SEND_FAILED: + return "Failed to send MAD"; + + case ME_UNKOWN_ACCESS_TYPE: + return "Unknown access type"; + + case ME_UNSUPPORTED_ACCESS_TYPE: + return "Unsupported access type"; + + case ME_UNSUPPORTED_DEVICE: + return "Unsupported device"; + + /* Reg access errors */ + case ME_REG_ACCESS_BAD_STATUS_ERR: + return "Register access bad status error"; + + case ME_REG_ACCESS_BAD_METHOD: + return "Bad Reg Access method"; + + case ME_REG_ACCESS_NOT_SUPPORTED: + return "Register access is not supported by the device"; + + case ME_REG_ACCESS_DEV_BUSY: + return "Register access failed, device is busy"; + + case ME_REG_ACCESS_VER_NOT_SUPP: + return "Register access Version not supported"; + + case ME_REG_ACCESS_UNKNOWN_TLV: + return "Register access Unknown TLV"; + + case ME_REG_ACCESS_REG_NOT_SUPP: + return "Register not supported"; + + case ME_REG_ACCESS_CLASS_NOT_SUPP: + return "Register access class not supported"; + + case ME_REG_ACCESS_METHOD_NOT_SUPP: + return "Register access Method not supported"; + + case ME_REG_ACCESS_BAD_PARAM: + return "Register access bad parameter"; + + case ME_REG_ACCESS_RES_NOT_AVLBL: + return "Register access resource unavailable"; + + case ME_REG_ACCESS_MSG_RECPT_ACK: + return "Message receipt ack"; + + case ME_REG_ACCESS_UNKNOWN_ERR: + return "Unknown register error"; + + case ME_REG_ACCESS_SIZE_EXCEEDS_LIMIT: + return "Register is too large"; + + case ME_REG_ACCESS_CONF_CORRUPT: + return "Config Section Corrupted"; + + case ME_REG_ACCESS_LEN_TOO_SMALL: + return "The given Register length is too small for the Tlv"; + + case ME_REG_ACCESS_BAD_CONFIG: + return "The configuration is rejected"; + + case ME_REG_ACCESS_ERASE_EXCEEDED: + return "The erase count exceeds its limit"; + + case ME_REG_ACCESS_INTERNAL_ERROR: + return "Firmware internal error"; + + case ME_REG_ACCESS_NOT_SUPPORTED_BY_SECONDARY: + return "Register Access not supported by secondary"; + + case ME_REG_ACCESS_INSUFFICIENT_PERMISSIONS: + return "Unable to send PRM Register due to permission issue, debug token might be needed."; + + /* ICMD access errors */ + case ME_ICMD_STATUS_CR_FAIL: + return "ICMD failed due to CRSpace access failure"; + + case ME_ICMD_STATUS_SEMAPHORE_TO: + return "Timed out trying to take the ICMD semaphore"; + + case ME_ICMD_STATUS_EXECUTE_TO: + return "Timed out trying to take the ICMD busy-bit"; + + case ME_ICMD_STATUS_IFC_BUSY: + return "ICMD interface busy"; + + case ME_ICMD_STATUS_ICMD_NOT_READY: + return "ICMD interface not ready, please check static_config_not_done bit"; + + case ME_ICMD_UNSUPPORTED_ICMD_VERSION: + return "Current ICMD version is not supported, Please check icmd_version field"; + + case ME_ICMD_NOT_SUPPORTED: + return "ICMD interface is not supported for this device"; + + case ME_ICMD_INVALID_OPCODE: + return "ICMD error 0x1: Invalid ICMD opcode used, Please check icmd.ctrl.status field"; + + case ME_ICMD_INVALID_CMD: + return "ICMD error 0x2: Invalid ICMD command used, Please check icmd.ctrl.status field"; + + case ME_ICMD_OPERATIONAL_ERROR: + return "ICMD error 0x3: ICMD operational error, Please check icmd.ctrl.status field"; + + case ME_ICMD_BAD_PARAM: + return "ICMD error 0x4: ICMD bad parameter given, Please check icmd.ctrl.status field"; + + case ME_ICMD_BUSY: + return "ICMD error 0x5: ICMD busy, Please check icmd.ctrl.status field"; + + case ME_ICMD_ICM_NOT_AVAIL: + return "ICMD ICM not available"; + + case ME_ICMD_WRITE_PROTECT: + return "ICMD write protect"; + + case ME_ICMD_UNKNOWN_STATUS: + return "ICMD unknown status"; + + case ME_ICMD_SIZE_EXCEEDS_LIMIT: + return "ICMD size exceeds limit"; + + case ME_ICMD_UNABLE_TO_TAKE_SEMAOHORE: + return "Failed to take ICMD semaphore (semaphore 62). Semaphore was free (0) but HW failed to set it to locked state when we took it.\nThis might indicate a FW or HW issue.\n"; + + /* TOOLS HCR access errors */ + case ME_CMDIF_BUSY: + return "Tools HCR busy"; + + case ME_CMDIF_TOUT: + return "Tools HCR time out."; + + case ME_CMDIF_BAD_OP: + return "Operation not supported"; + + case ME_CMDIF_NOT_SUPP: + return "Tools HCR not supported"; + + case ME_CMDIF_BAD_SYS: + return "bad system status (driver may be down or Fw does not support this operation)"; + + case ME_CMDIF_UNKN_TLV: + return "Unknown TLV"; + + case ME_CMDIF_RES_STATE: + return "Bad reset state"; + + case ME_CMDIF_UNKN_STATUS: + return "Unknown status"; + + /* MAD IFC errors */ + case ME_MAD_BUSY: + return "Temporarily busy. MAD discarded. This is not an error"; + + case ME_MAD_REDIRECT: + return "Redirection. This is not an error"; + + case ME_MAD_BAD_VER: + return "Bad version"; + + case ME_MAD_METHOD_NOT_SUPP: + return "Method not supported"; + + case ME_MAD_METHOD_ATTR_COMB_NOT_SUPP: + return "Method and attribute combination isn't supported"; + + case ME_MAD_BAD_DATA: + return "Bad attribute modifier or field"; + + case ME_MAD_GENERAL_ERR: + return "Unknown MAD error"; + + default: + return "Unknown error code"; + } +} diff --git a/mtcr_ul/mtcr_gpu.c b/mtcr_ul/mtcr_gpu.c index 2635f43..db52cf0 100644 --- a/mtcr_ul/mtcr_gpu.c +++ b/mtcr_ul/mtcr_gpu.c @@ -31,8 +31,8 @@ * * */ +#include "mtcr_gpu.h" -#include "common/compatibility.h" #include "dev_mgt/tools_dev_types.h" typedef struct pci_id_range_st { diff --git a/mtcr_ul/mtcr_gpu.h b/mtcr_ul/mtcr_gpu.h index 465f5e9..a439ae7 100644 --- a/mtcr_ul/mtcr_gpu.h +++ b/mtcr_ul/mtcr_gpu.h @@ -34,7 +34,13 @@ #ifndef _MTCR_GPU /* guard */ #define _MTCR_GPU +#include <stdint.h> +#include <stdbool.h> + +#include "common/compatibility.h" + int is_gpu_pci_device(u_int16_t pci_device_id); bool is_gpu_device(u_int16_t hw_dev_id); +u_int16_t get_hw_dev_id_by_pci_id(u_int16_t pci_device_id); #endif /* _MTCR_GPU guard */ diff --git a/mtcr_ul/mtcr_ib_ofed.c b/mtcr_ul/mtcr_ib_ofed.c index 0b11d58..153a792 100644 --- a/mtcr_ul/mtcr_ib_ofed.c +++ b/mtcr_ul/mtcr_ib_ofed.c @@ -286,7 +286,7 @@ struct __ibvsmad_hndl_t { ib_portid_t portid; int sock; int tp; - int i2c_slave; + int i2c_secondary; int use_smp; int use_class_a; u_int64_t mkey; diff --git a/mtcr_ul/mtcr_nvml.c b/mtcr_ul/mtcr_nvml.c new file mode 100644 index 0000000..95e6a2d --- /dev/null +++ b/mtcr_ul/mtcr_nvml.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2013-2024 NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <dlfcn.h> +#include <nvml.h> +#include "mtcr_nvml.h" +#include "mtcr_gpu.h" +#include "mtcr_common.h" + +#define MY_DLSYM(dl_ctx, func_name) \ + do \ + { \ + const char* dl_error; \ + dl_ctx->func_name = dlsym(dl_ctx->dl_handle, #func_name); \ + if ((dl_error = dlerror()) != NULL) \ + { \ + DBG_PRINTF(dl_error); \ + return -1; \ + } \ + } while (0) + +typedef void* (*f_nvmlDeviceGetHandleByIndex_v2)(int, nvmlDevice_t*); +typedef nvmlReturn_t (*f_nvmlDeviceGetPciInfo_v3)(nvmlDevice_t, nvmlPciInfo_t*); +typedef const char* (*f_nvmlErrorString)(nvmlReturn_t); +typedef nvmlReturn_t (*f_nvmlInit_v2)(void); +typedef nvmlReturn_t (*f_nvmlShutdown)(void); + +typedef struct nvml_dll_ctx_t { + void * dl_handle; + f_nvmlShutdown nvmlShutdown; + f_nvmlInit_v2 nvmlInit_v2; + f_nvmlDeviceGetHandleByIndex_v2 nvmlDeviceGetHandleByIndex_v2; + f_nvmlDeviceGetPciInfo_v3 nvmlDeviceGetPciInfo_v3; + f_nvmlErrorString nvmlErrorString; +} nvml_dll_ctx; + +int init_nvml_lib_handle(mfile* mf) +{ + nvml_dll_ctx* nvml_ctx = NULL; + + if (!(nvml_ctx = (nvml_dll_ctx*)malloc(sizeof(nvml_dll_ctx)))) { + DBG_PRINTF("Failed to allocate nvml_ctx"); + return -1; + } + memset(nvml_ctx, 0, sizeof(*nvml_ctx)); + + nvml_ctx->dl_handle = dlopen("libnvidia-ml.so", RTLD_LAZY); + + if (!nvml_ctx->dl_handle) { + printf("Failed to load libnvidia-ml.so, %s\n", dlerror()); + return -1; + } + + dlerror(); + + MY_DLSYM(nvml_ctx, nvmlInit_v2); + MY_DLSYM(nvml_ctx, nvmlShutdown); + MY_DLSYM(nvml_ctx, nvmlDeviceGetHandleByIndex_v2); + MY_DLSYM(nvml_ctx, nvmlDeviceGetPciInfo_v3); + MY_DLSYM(nvml_ctx, nvmlErrorString); + + mf->ctx = nvml_ctx; + return 0; +} + +u_int16_t nvml_get_pci_id(mfile* mf) +{ + nvmlPciInfo_t pci; + + memset(&pci, 0, sizeof(pci)); + + nvml_dll_ctx* nvml_dll_handle = (nvml_dll_ctx*)mf->ctx; + nvmlReturn_t ret = nvml_dll_handle->nvmlDeviceGetPciInfo_v3(*(nvmlDevice_t*)mf->nvml_device, &pci); + + if (ret) { + return -1; + } + /* Mask out vendor ID on the lower 16 bits. */ + return ((pci.pciDeviceId & 0xffff0000) >> 16); +} + +void free_nvml_lib_handle(mfile* mf) +{ + if (mf && mf->ctx) { + dlclose(((nvml_dll_ctx*)(mf->ctx))->dl_handle); + free((nvml_dll_ctx*)mf->ctx); + mf->ctx = NULL; + } +} + +int nvml_mclose(mfile* mf) +{ + if (mf) { + nvml_dll_ctx* nvml_dll_handle = (nvml_dll_ctx*)mf->ctx; + if (nvml_dll_handle) { + /* Sutdown NVML SDK. */ + nvml_dll_handle->nvmlShutdown(); + } + + /* Free NVML device handle. */ + free(mf->nvml_device); + mf->nvml_device = NULL; + + /* Free NVML lib handle. */ + free_nvml_lib_handle(mf); + } + return 0; +} + +int init_nvml_ifc(mfile* mf, const char* dev_name) +{ + char *endptr; + unsigned int device_index; + char * device_index_location = strstr(dev_name, "nvidia") + 6; + + device_index = strtoul(device_index_location, &endptr, 10); + + init_nvml_lib_handle(mf); + + mf->nvml_device = malloc(sizeof(nvmlDevice_t)); + + if (!mf->nvml_device) { + DBG_PRINTF("Failed to allocate memory for NVML GPU device"); + return -1; + } + + nvml_dll_ctx* nvml_dll_handle = (nvml_dll_ctx*)mf->ctx; + + /* Init NVML SDK. */ + nvml_dll_handle->nvmlInit_v2(); + + /* Init device handle by index (e.g. /dev/nvidiaX) */ + nvml_dll_handle->nvmlDeviceGetHandleByIndex_v2(device_index, mf->nvml_device); + + if (mf->nvml_device == NULL) { + printf("Failed to open MVNL GPU device by index: %d\n", device_index); + return -1; + } + + return 0; +} + +u_int16_t nvml_get_device_id(mfile* mf) +{ + return get_hw_dev_id_by_pci_id(nvml_get_pci_id(mf)); +} diff --git a/mtcr_ul/mtcr_nvml.h b/mtcr_ul/mtcr_nvml.h new file mode 100644 index 0000000..0142d16 --- /dev/null +++ b/mtcr_ul/mtcr_nvml.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _MTCR_GPU_DRIVER /* guard */ +#define _MTCR_GPU_DRIVER + +#include "mtcr.h" + +int init_nvml_ifc(mfile* mf, const char* dev_name); +int nvml_mclose(mfile* mf); +u_int16_t nvml_get_device_id(mfile* mf); + +#endif /* _MTCR_GPU_DRIVER guard */ diff --git a/mtcr_ul/mtcr_ul.c b/mtcr_ul/mtcr_ul.c index d83ed10..f1a1c8e 100644 --- a/mtcr_ul/mtcr_ul.c +++ b/mtcr_ul/mtcr_ul.c @@ -214,13 +214,6 @@ void get_pci_dev_rdma(mfile* mf, char* buf) } } -unsigned char mset_i2c_slave(mfile* mf, unsigned char new_i2c_slave) -{ - (void)mf; - (void)new_i2c_slave; /* compiler warning */ - fprintf(stderr, "Warning: libmtcr: mset_i2c_slave() is not implemented and has no effect.\n"); - return 0; -} int maccess_reg_mad(mfile* mf, u_int8_t* data) { @@ -279,8 +272,12 @@ int supports_reg_access_gmp(mfile* mf, maccess_reg_method_t reg_method) return supports_reg_access_gmp_ul(mf, reg_method); } -int mget_vsec_supp(mfile* mf) +int is_gw_access(mfile* mf) { + if (mf->tp == MST_BAR0_GW_PCI) + { + return 1; + } return mf->functional_vsec_supp; } @@ -341,4 +338,4 @@ int mvpd_write4(mfile* mf, unsigned int offset, u_int8_t value[4]) (void)offset; (void)value; return ME_UNSUPPORTED_OPERATION; -} +} \ No newline at end of file diff --git a/mtcr_ul/mtcr_ul_com.c b/mtcr_ul/mtcr_ul_com.c index b418c59..e1bae58 100644 --- a/mtcr_ul/mtcr_ul_com.c +++ b/mtcr_ul/mtcr_ul_com.c @@ -53,6 +53,8 @@ #define MTCR_MAP_SIZE 0x4000000 #define GPU_NETIR_CR_SPACE_OFFSET 0x3000000 + + #define DBG_PRINTF(...) \ do \ { \ @@ -62,6 +64,18 @@ } \ } while (0) + +#ifdef ENABLE_MST_DEV_I2C +#include <linux/i2c.h> +#include <linux/i2c-dev.h> +#define MAX_CHUNK_SIZE 32 +#endif + +#ifndef MAX_TRANS_SIZE +#define MAX_TRANS_SIZE 64 +#endif + + #include <stdio.h> #include <dirent.h> #include <string.h> @@ -106,6 +120,15 @@ #include "fwctrl_ioctl.h" #include "kernel/mst.h" #include "tools_dev_types.h" +#include "vfio_driver_access/VFIODriverAccessWrapperC.h" + +#ifdef ENABLE_NVML +#include "nvml_lib/nvml_c_wrapper.h" +#endif + +#ifdef CABLES_SUPPORT +#include "mtcr_cables.h" +#endif #define CX3_SW_ID 4099 #define CX3PRO_SW_ID 4103 @@ -702,16 +725,11 @@ enum { IFC_MAX_RETRIES = 2048 }; -/* PCI operation enum(read or write)*/ -enum { - READ_OP = 0, - WRITE_OP = 1, -}; #define READ4_PCI(mf, val_ptr, pci_offs, err_prefix, action_on_fail) \ do \ { \ - int rc; \ + int rc; \ rc = pread(mf->fd, val_ptr, 4, pci_offs); \ if (rc != 4) \ { \ @@ -845,8 +863,68 @@ static int fwctl_driver_mwrite4_block(mfile* mf, unsigned int offset, u_int32_t* return -1; } +#ifdef ENABLE_NVML +static int nvml_mread4(mfile* mf, unsigned int offset, u_int32_t* value) +{ + (void)mf; + (void)offset; + (void)value; + + DBG_PRINTF("nvml doesn't support VSEC access.\n"); + return -1; +} + +static int nvml_mwrite4(mfile* mf, unsigned int offset, u_int32_t value) +{ + (void)mf; + (void)offset; + (void)value; + + DBG_PRINTF("nvml doesn't support VSEC access.\n"); + return -1; +} + +static int nvml_mread4_block(mfile* mf, unsigned int offset, u_int32_t* data, int length) +{ + (void)mf; + (void)offset; + (void)data; + (void)length; + + DBG_PRINTF("nvml doesn't support VSEC access.\n"); + return -1; +} + +static int nvml_mwrite4_block(mfile* mf, unsigned int offset, u_int32_t* data, int length) +{ + (void)mf; + (void)offset; + (void)data; + (void)length; + + DBG_PRINTF("nvml doesn't support VSEC access.\n"); + return -1; +} +int nvml_mclose(mfile* mf) +{ + if (mf && mf->nvml_device) { + /* Free NVML device handle. */ + + destroy_nvml_device(mf->nvml_device); + } + + return 0; +} + +u_int16_t nvml_get_device_id(mfile* mf) +{ + return get_hw_dev_id_by_pci_id(nvml_get_pci_id(mf)); +} + +#endif /* ifdef ENABLE_NVML */ + int mtcr_driver_cr_mread4(mfile* mf, unsigned int offset, u_int32_t* value) { ul_ctx_t* ctx = mf->ul_ctx; @@ -984,6 +1062,28 @@ static int mtcr_driver_mclose(mfile* mf) return 0; } +static int nvml_open(mfile* mf, const char* name) +{ +#ifdef ENABLE_NVML + ul_ctx_t* ctx = mf->ul_ctx; + ctx->connectx_flush = 0; + ctx->need_flush = 0; + ctx->via_driver = 0; + mf->tp = MST_NVML; + ctx->mread4 = nvml_mread4; + ctx->mwrite4 = nvml_mwrite4; + ctx->mread4_block = nvml_mread4_block; + ctx->mwrite4_block = nvml_mwrite4_block; + ctx->mclose = nvml_mclose; + mf->bar_virtual_addr = NULL; + return init_nvml_device(name, &(mf->nvml_device)); +#else + (void)mf; + (void)name; + errno = ENOSYS; + return -1; +#endif +} static int fwctrl_driver_open(mfile* mf, const char* name) { @@ -1096,6 +1196,7 @@ end: (1 << VCC_ICMD_SPACE_SUPPORTED) | (1 << VCC_ICMD_EXT_SPACE_SUPPORTED)); } mf->tp = MST_PCICONF; + ctx->mread4 = mtcr_driver_mread4; ctx->mwrite4 = mtcr_driver_mwrite4; ctx->mread4_block = driver_mread4_block; @@ -1111,12 +1212,12 @@ static int is_wo_pciconf_gw(mfile* mf) { unsigned offset = DEVID_OFFSET; u_int32_t data = 0; - int rc = pwrite(mf->fd, &offset, 4, PCICONF_ADDR_OFF); + int rc = pwrite(mf->fd, &offset, 4, mf->address_region_addr + PCICONF_ADDR_OFF); if (rc < 0) { return 0; } - rc = pread(mf->fd, &data, 4, PCICONF_ADDR_OFF); + rc = pread(mf->fd, &data, 4, mf->address_region_addr + PCICONF_ADDR_OFF); if (rc < 0) { return 0; } @@ -1585,7 +1686,7 @@ int mtcr_pciconf_mread4_old(mfile* mf, unsigned int offset, u_int32_t* value) if (rc) { goto pciconf_read_cleanup; } - rc = pwrite(mf->fd, &offset, 4, PCICONF_ADDR_OFF); + rc = pwrite(mf->fd, &offset, 4, mf->address_region_addr + PCICONF_ADDR_OFF); if (rc < 0) { perror("write offset"); goto pciconf_read_cleanup; @@ -1595,7 +1696,7 @@ int mtcr_pciconf_mread4_old(mfile* mf, unsigned int offset, u_int32_t* value) goto pciconf_read_cleanup; } - rc = pread(mf->fd, value, 4, PCICONF_DATA_OFF); + rc = pread(mf->fd, value, 4, mf->address_region_addr + PCICONF_DATA_OFF); if (rc < 0) { perror("read value"); goto pciconf_read_cleanup; @@ -1621,7 +1722,7 @@ int mtcr_pciconf_mwrite4_old(mfile* mf, unsigned int offset, u_int32_t value) goto pciconf_write_cleanup; } if (ctx->wo_addr) { - rc = pwrite(mf->fd, &value, 4, PCICONF_DATA_OFF); + rc = pwrite(mf->fd, &value, 4, mf->address_region_addr + PCICONF_DATA_OFF); if (rc < 0) { perror("write value"); goto pciconf_write_cleanup; @@ -1630,13 +1731,13 @@ int mtcr_pciconf_mwrite4_old(mfile* mf, unsigned int offset, u_int32_t value) rc = 0; goto pciconf_write_cleanup; } - rc = pwrite(mf->fd, &offset, 4, PCICONF_ADDR_OFF); + rc = pwrite(mf->fd, &offset, 4, mf->address_region_addr + PCICONF_ADDR_OFF); if (rc < 0) { perror("write offset"); goto pciconf_write_cleanup; } } else { - rc = pwrite(mf->fd, &offset, 4, PCICONF_ADDR_OFF); + rc = pwrite(mf->fd, &offset, 4, mf->address_region_addr + PCICONF_ADDR_OFF); if (rc < 0) { perror("write offset"); goto pciconf_write_cleanup; @@ -1645,7 +1746,7 @@ int mtcr_pciconf_mwrite4_old(mfile* mf, unsigned int offset, u_int32_t value) rc = 0; goto pciconf_write_cleanup; } - rc = pwrite(mf->fd, &value, 4, PCICONF_DATA_OFF); + rc = pwrite(mf->fd, &value, 4, mf->address_region_addr + PCICONF_DATA_OFF); if (rc < 0) { perror("write value"); goto pciconf_write_cleanup; @@ -1736,6 +1837,126 @@ static int get_space_support_status(mfile* mf, u_int16_t space) return status; } +static void init_vsec_cap_mask(mfile* mf) +{ + get_space_support_status(mf, AS_ICMD); + get_space_support_status(mf, AS_NODNIC_INIT_SEG); + get_space_support_status(mf, AS_EXPANSION_ROM); + get_space_support_status(mf, AS_ND_CRSPACE); + get_space_support_status(mf, AS_SCAN_CRSPACE); + get_space_support_status(mf, AS_MAC); + get_space_support_status(mf, AS_ICMD_EXT); + get_space_support_status(mf, AS_SEMAPHORE); + get_space_support_status(mf, AS_CR_SPACE); + get_space_support_status(mf, AS_PCI_ICMD); + get_space_support_status(mf, AS_PCI_CRSPACE); + get_space_support_status(mf, AS_PCI_ALL_ICMD); + get_space_support_status(mf, AS_PCI_SCAN_CRSPACE); + get_space_support_status(mf, AS_PCI_GLOBAL_SEMAPHORE); + get_space_support_status(mf, AS_RECOVERY); + mf->vsec_cap_mask |= (1 << VCC_INITIALIZED); +} + +static int mtcr_vfio_device_open(mfile * mf, + const char* name, + unsigned domain, + unsigned bus, + unsigned dev, + unsigned func) +{ + ul_ctx_t* ctx = mf->ul_ctx; + u_int32_t vsec_type = 0; + + mf->fd = -1; + mf->tp = MST_PCICONF; + + if (GetStartOffsets(domain, bus, dev, func, &mf->fd, &mf->vsec_addr, &mf->address_region_addr) != 0) { + return -1; + } + + if (mf->vsec_addr) { + DBG_PRINTF("VSEC address: 0x%lx\n", mf->vsec_addr); + DBG_PRINTF("Address region address: 0x%lx\n", mf->address_region_addr); + mf->vsec_addr += mf->address_region_addr; + READ4_PCI(mf, &vsec_type, mf->vsec_addr, "read vsc type", return ME_PCI_READ_ERROR); + mf->vsec_type = EXTRACT(vsec_type, MLX_VSC_TYPE_OFFSET, MLX_VSC_TYPE_LEN); + DBG_PRINTF("VSC type: %d\n", mf->vsec_type); + if (mf->vsec_type == FUNCTIONAL_VSC) { + DBG_PRINTF("FUNCTIONAL VSC Supported\n"); + mf->functional_vsec_supp = 1; + } + + init_vsec_cap_mask(mf); + + if (VSEC_SUPPORTED_UL(mf)) { + mf->address_space = AS_CR_SPACE; + ctx->mread4 = mtcr_pciconf_mread4; + ctx->mwrite4 = mtcr_pciconf_mwrite4; + ctx->mread4_block = mread4_block_pciconf; + ctx->mwrite4_block = mwrite4_block_pciconf; + } + + mf->pxir_vsec_supp = 0; + if ((mf->vsec_cap_mask & (1 << space_to_cap_offset(AS_PCI_CRSPACE))) && + (mf->vsec_cap_mask & (1 << space_to_cap_offset(AS_PCI_ALL_ICMD))) && + (mf->vsec_cap_mask & (1 << space_to_cap_offset(AS_PCI_GLOBAL_SEMAPHORE)))) { + mf->pxir_vsec_supp = 1; + } + DBG_PRINTF("mf->pxir_vsec_supp: %d\n", mf->pxir_vsec_supp); + } else { + ctx->wo_addr = is_wo_pciconf_gw(mf); + DBG_PRINTF("Write Only Address: %d\n", ctx->wo_addr); + ctx->mread4 = mtcr_pciconf_mread4_old; + ctx->mwrite4 = mtcr_pciconf_mwrite4_old; + ctx->mread4_block = mread_chunk_as_multi_mread4; + ctx->mwrite4_block = mwrite_chunk_as_multi_mwrite4; + } + + if (init_dev_info_ul(mf, name, domain, bus, dev, func)) { + return -1; + } + + return 0; +} + +bool is_cable_device(const char* name) +{ +#ifdef CABLES_SUPPORT + if (!name) { + return false; + } + if (strlen(name) < sizeof(CABLE_DEVICE_STR)) { + return false; + } + return strstr(name, CABLE_DEVICE_STR) != NULL; +#else + (void)name; + return false; +#endif +} + + +int get_cable_port(const char* name) +{ +#ifdef CABLES_SUPPORT + char* cable_name_ptr = strstr(name, CABLE_DEVICE_STR); + + if (cable_name_ptr) { + char* endptr; + int port = strtol(cable_name_ptr + (sizeof(CABLE_DEVICE_STR) - 1), &endptr, 10); + if ((*endptr != '\0') || (port < 0)) { + DBG_PRINTF("Invalid cable port: %s\n", name); + return -1; + } + return port; + } + return -1; +#else + (void)name; + return -1; +#endif +} + static int mtcr_pciconf_open(mfile* mf, const char* name, u_int32_t adv_opt) { ul_ctx_t* ctx = mf->ul_ctx; @@ -1751,7 +1972,9 @@ static int mtcr_pciconf_open(mfile* mf, const char* name, u_int32_t adv_opt) mf->tp = MST_PCICONF; - if (mf->vsec_addr = pci_find_capability(mf, CAP_ID)) { + + mf->vsec_addr = pci_find_capability(mf, CAP_ID); + if (mf->vsec_addr) { READ4_PCI(mf, &vsec_type, mf->vsec_addr, "read vsc type", return ME_PCI_READ_ERROR); mf->vsec_type = EXTRACT(vsec_type, MLX_VSC_TYPE_OFFSET, MLX_VSC_TYPE_LEN); DBG_PRINTF("in mtcr_pciconf_open function. mf->vsec_type: %d\n", mf->vsec_type); @@ -1769,22 +1992,7 @@ static int mtcr_pciconf_open(mfile* mf, const char* name, u_int32_t adv_opt) return -1; } - get_space_support_status(mf, AS_ICMD); - get_space_support_status(mf, AS_NODNIC_INIT_SEG); - get_space_support_status(mf, AS_EXPANSION_ROM); - get_space_support_status(mf, AS_ND_CRSPACE); - get_space_support_status(mf, AS_SCAN_CRSPACE); - get_space_support_status(mf, AS_MAC); - get_space_support_status(mf, AS_ICMD_EXT); - get_space_support_status(mf, AS_SEMAPHORE); - get_space_support_status(mf, AS_CR_SPACE); - get_space_support_status(mf, AS_PCI_ICMD); - get_space_support_status(mf, AS_PCI_CRSPACE); - get_space_support_status(mf, AS_PCI_ALL_ICMD); - get_space_support_status(mf, AS_PCI_SCAN_CRSPACE); - get_space_support_status(mf, AS_PCI_GLOBAL_SEMAPHORE); - get_space_support_status(mf, AS_RECOVERY); - mf->vsec_cap_mask |= (1 << VCC_INITIALIZED); + init_vsec_cap_mask(mf); mtcr_pciconf_cap9_sem(mf, 0); @@ -1814,6 +2022,17 @@ static int mtcr_pciconf_open(mfile* mf, const char* name, u_int32_t adv_opt) ctx->mwrite4_block = mwrite_chunk_as_multi_mwrite4; } ctx->mclose = mtcr_pciconf_mclose; + + #ifdef CABLES_SUPPORT + if (is_cable_device(mf->dev_name)) { + int cable_port = get_cable_port(mf->dev_name); + if ((cable_port != -1) && (mcables_open(mf, cable_port) != 0)) { + DBG_PRINTF("Failed to open cable device: %s\n", mf->dev_name); + return -1; + } + } + #endif + return 0; } #else /* if CONFIG_ENABLE_PCICONF */ @@ -1856,6 +2075,510 @@ static int mtcr_inband_open(mfile* mf, const char* name) #endif } + +#ifdef ENABLE_MST_DEV_I2C +/* split the data into 64 byte chunks and read each chunk. */ +int mtcr_i2c_mread_chunks(mfile* mf, unsigned int offset, void* data, int length) +{ + u_int8_t addr_width = 0; + int left_size = 0; + int bytes = 0; + void * dest_ptr = data; + int bytes_read = length; + int chunk_size = MAX_TRANS_SIZE; + + for (left_size = length; left_size > 0; left_size -= chunk_size) { + int toread; + toread = (left_size >= chunk_size) ? chunk_size : left_size; + bytes = mread_i2c_chunk(mf, offset, dest_ptr, toread); + if (bytes != toread) { + bytes_read = length - left_size; + break; + } + + offset += chunk_size; + dest_ptr += chunk_size; + } + + if (bytes_read != length) { + DBG_PRINTF("mtcr_i2c_mread_chunks: address: 0x%06x num_bytes attempted to read: %d bytes_read: %d\n", + offset, + length, + bytes_read); + } + return bytes_read; +} + +int mread_i2c_chunk(mfile* mf, unsigned int offset, void* data, int length) +{ + u_int8_t addr_width = 0; + + mget_i2c_addr_width(mf, &addr_width); + + int rc = mread_i2cblock(mf, mf->i2c_secondary, addr_width, offset, data, length); + + if (rc != length) { + return rc; /* The value the ioctl which failed returned. */ + } + + fix_endianness((u_int32_t*)data, length, 1); + return length; +} + +/* split the data to chunks of 32 bytes and write each chunk. */ +int mtcr_i2c_mwrite_chunks(mfile* mf, unsigned int offset, void* data, int length) +{ + int chunk_size; + int left_size; + int bytes; + void* dest_ptr = data; + int bytes_written = length; + + chunk_size = MAX_CHUNK_SIZE; + + for (left_size = length; left_size > 0; left_size -= chunk_size) { + int towrite; + towrite = (left_size >= chunk_size) ? chunk_size : left_size; + bytes = mwrite_i2c_chunk(mf, offset, dest_ptr, towrite); + if (bytes != towrite) { + bytes_written = length - left_size; + break; + } + + offset += chunk_size; + dest_ptr += chunk_size; + } + + if (bytes_written != length) { + DBG_PRINTF("mtcr_i2c_mwrite_chunks: address: 0x%06x num_bytes attempted to write: %d bytes_written: %d\n", + offset, + length, + bytes_written); + } + + return bytes_written; +} + + +int mwrite_i2c_chunk(mfile* mf, unsigned int offset, void* data, int length) +{ + fix_endianness((u_int32_t*)data, length, 1); + + u_int8_t addr_width = 0; + + mget_i2c_addr_width(mf, &addr_width); + + int rc = mwrite_i2cblock(mf, mf->i2c_secondary, addr_width, offset, data, length); + + if (rc != length) { + return rc; /* The value the ioctl which failed returned. */ + } + return length; +} + +void fix_endianness(u_int32_t* buf, int len, int be_mode) +{ + int i; + + for (i = 0; i < (len / 4); ++i) { + if (be_mode) { + /* printf("-D- before: buf[%d] = %#x\n", i, buf[i]); */ + buf[i] = __be32_to_cpu(buf[i]); + /* printf("-D- before: buf[%d] = %#x\n", i, buf[i]); */ + } else { + /* printf("-D- before: buf[%d] = %#x\n", i, buf[i]); */ + buf[i] = __cpu_to_be32(buf[i]); + /* printf("-D- before: buf[%d] = %#x\n", i, buf[i]); */ + } + } +} + + +static int force_i2c_address = -1; + +void set_force_i2c_address(int i2c_address) +{ + force_i2c_address = i2c_address; +} + +static int prepare_i2c_buf(void* maddr, DType dtype, u_int32_t offset) +{ + switch (dtype) { + case MST_TAVOR: + { + u_int32_t offs = __cpu_to_be32(offset); + memcpy(maddr, &offs, 4); + return 4; + } + + case MST_GAMLA: + { + u_int16_t offs = offset & 0xffff; + offs = __cpu_to_be16(offs); + memcpy(maddr, &offs, 2); + return 2; + } + + case MST_DIMM: + { + u_int8_t offs1 = offset & 0xff; + memcpy(maddr, &offs1, 1); + return 1; + } + + default: + return 0; + } +} + +static inline int prepare_i2c_data(unsigned char* buf, DType dtype, u_int32_t offset, void* data, int data_length) +{ + int len; + + len = prepare_i2c_buf(buf, dtype, offset); + memcpy(buf + len, data, data_length); + return data_length + len; +} + +int mtcr_i2c_mread4(mfile* mf, unsigned int offset, u_int32_t* value) +{ + int bytes_read = 4; /* Indicates success */ + struct i2c_rdwr_ioctl_data i2c_rdwr; + struct i2c_msg i2c_msg[2]; + char maddr[4]; + char data[4]; + + i2c_msg[0].addr = mf->i2c_secondary; + i2c_msg[0].flags = 0; + i2c_msg[0].buf = (unsigned char*)(&maddr[0]); + i2c_msg[1].addr = mf->i2c_secondary; + i2c_msg[1].flags = I2C_M_RD; + i2c_msg[1].len = 4; + i2c_msg[1].buf = (unsigned char*)data; + i2c_rdwr.msgs = i2c_msg; + i2c_rdwr.nmsgs = 2; + + i2c_msg[0].len = prepare_i2c_buf(maddr, mf->dtype, offset); + + if (!i2c_msg[0].len) { + i2c_msg[0].flags = I2C_M_RD; + i2c_msg[0].len = 4; + i2c_msg[0].buf = (unsigned char*)data; + i2c_rdwr.nmsgs = 1; + } + int int_rc = ioctl(mf->fd, I2C_RDWR, &i2c_rdwr); + + if (int_rc < 0) { + bytes_read = -1; + DBG_PRINTF("function: %s. I2C ioctl failed: %s\n", __FUNCTION__, strerror(errno)); + } + BYTES_TO_DWORD_BE(value, data); + + DBG_PRINTF("mtcr_i2c_mread4: mf->i2c_secondary: 0x%x offset: 0x%x. value: 0x%x. bytes_read: %d\n", + mf->i2c_secondary, + offset, + value, + bytes_read); + + return bytes_read; +} + +int mtcr_i2c_mwrite4(mfile* mf, unsigned int offset, u_int32_t value) +{ + int bytes_written = 4; /* Indicates success */ + struct i2c_rdwr_ioctl_data i2c_rdwr; + struct i2c_msg i2c_msg[1]; + unsigned char data[8]; /* Buffer for I2C data */ + + memset(data, 0, sizeof(data)); + + i2c_msg[0].addr = mf->i2c_secondary; /* Device address */ + i2c_msg[0].flags = 0; /* Write operation */ + i2c_msg[0].buf = data; /* Pointer to the data buffer */ + + value = __cpu_to_be32(value); + int len = prepare_i2c_data(data, mf->dtype, offset, &value, sizeof(value)); + + i2c_msg[0].len = len; + + /* Set up the ioctl structure */ + i2c_rdwr.msgs = i2c_msg; + i2c_rdwr.nmsgs = 1; + + int int_rc = ioctl(mf->fd, I2C_RDWR, &i2c_rdwr); + + if (int_rc < 0) { + bytes_written = -1; + DBG_PRINTF("function: %s. I2C ioctl failed: %s\n", __FUNCTION__, strerror(errno)); + return bytes_written; + } + + DBG_PRINTF("mtcr_i2c_mwrite4: mf->i2c_secondary: 0x%x offset: 0x%x. value: 0x%x. bytes_written: %d\n", + mf->i2c_secondary, + offset, + value, + bytes_written); + + return bytes_written; +} + +/* reads up to 64 bytes */ +int mread_i2cblock(mfile * mf, + unsigned char i2c_secondary, + u_int8_t addr_width, + unsigned int offset, + void * data, + int length) +{ + int rc; + + if (length > MAX_TRANS_SIZE) { + errno = EINVAL; + return -1; + } + + if (mset_i2c_addr_width(mf, addr_width)) { + errno = EINVAL; + return -1; + } + mf->i2c_secondary = i2c_secondary; + + char maddr[4]; + struct i2c_rdwr_ioctl_data i2c_rdwr; + struct i2c_msg i2c_msg[2]; + + i2c_msg[0].addr = mf->i2c_secondary; + i2c_msg[0].flags = 0; + i2c_msg[0].buf = (unsigned char*)&maddr[0]; + i2c_msg[1].addr = mf->i2c_secondary; + i2c_msg[1].flags = I2C_M_RD; + i2c_msg[1].len = length; + i2c_msg[1].buf = (unsigned char*)data; + i2c_rdwr.msgs = i2c_msg; + i2c_rdwr.nmsgs = 2; + i2c_msg[0].len = prepare_i2c_buf(maddr, mf->dtype, offset); + + if (!i2c_msg[0].len) { + i2c_msg[0].flags = I2C_M_RD; + i2c_msg[0].len = length; + i2c_msg[0].buf = (unsigned char*)data; + i2c_rdwr.nmsgs = 1; + } + rc = ioctl(mf->fd, I2C_RDWR, &i2c_rdwr); + if (rc < 0) { + DBG_PRINTF("function: %s. I2C ioctl failed: %s\n", __FUNCTION__, strerror(errno)); + return rc; + } + return length; +} + +/* writes up to 64 bytes */ +int mwrite_i2cblock(mfile * mf, + unsigned char i2c_secondary, + u_int8_t addr_width, + unsigned int offset, + void * data, + int length) +{ + int rc; + + if (length > MAX_TRANS_SIZE) { + errno = EINVAL; + return -1; + } + + if (mset_i2c_addr_width(mf, addr_width)) { + errno = EINVAL; + return -1; + } + mf->i2c_secondary = i2c_secondary; + + struct i2c_rdwr_ioctl_data i2c_rdwr; + struct i2c_msg i2c_msg[1]; + unsigned char buf[64 + 4]; + + i2c_msg[0].addr = mf->i2c_secondary; + i2c_msg[0].flags = 0; + i2c_msg[0].buf = buf; + i2c_rdwr.msgs = i2c_msg; + i2c_rdwr.nmsgs = 1; + + i2c_msg[0].len = prepare_i2c_data(buf, mf->dtype, offset, data, length); + + rc = ioctl(mf->fd, I2C_RDWR, &i2c_rdwr); + if (rc < 0) { + DBG_PRINTF("function: %s. I2C ioctl failed: %s\n", __FUNCTION__, strerror(errno)); + return rc; + } + + return length; +} + +static int mtcr_i2c_open(mfile* mf, const char* name) +{ + ul_ctx_t* ctx = mf->ul_ctx; + + mf->tp = MST_DEV_I2C; + mf->dtype = MST_TAVOR; /* In MFT devices are opened as MST_TAVOR, this is to ensure correct address_width for the I2C transactions. */ + mf->flags |= MDEVS_DEV_I2C; + mf->i2c_secondary = 0x48; /* Livefish devices and non-secure generation functional devices. */ + + + ctx->mread4 = mtcr_i2c_mread4; + ctx->mwrite4 = mtcr_i2c_mwrite4; + ctx->mread4_block = mtcr_i2c_mread_chunks; + ctx->mwrite4_block = mtcr_i2c_mwrite_chunks; + + if ((mf->fd = open(name, O_RDWR | O_SYNC)) < 0) { + safe_free(&mf); + DBG_PRINTF("mtcr_i2c_open: failed to open %s: %s\n", name, strerror(errno)); + return -1; + } + + /* Support functional devices from secure generation (CX7, Quantum2 and above) */ + if (change_i2c_secondary_address(mf, mf->dtype)) { + DBG_PRINTF("mtcr_i2c_open: failed to determine i2c secondary address\n"); + return -1; + } + + return 0; +} + +u_int32_t secured_devices[] = +{DeviceConnectX7_HwId, DeviceConnectX8_HwId, DeviceConnectX9_HwId, DeviceConnectX8PurePcieSwitch_HwId, + DeviceQuantum2_HwId, DeviceQuantum3_HwId}; + +#define SECURED_DEVICE_ID_TABLE_SIZE (sizeof(secured_devices) / sizeof(u_int32_t)) + +u_int32_t supported_device_ids[] = +{DeviceConnectX3_HwId, DeviceConnectIB_HwId, DeviceConnectX3Pro_HwId, + DeviceSwitchIB_HwId, DeviceSpectrum_HwId, DeviceConnectX4_HwId, + DeviceConnectX4LX_HwId, DeviceConnectX5_HwId, DeviceConnectX6_HwId, + DeviceConnectX6DX_HwId, DeviceConnectX6LX_HwId, DeviceConnectX7_HwId, + DeviceConnectX8_HwId, DeviceBlueField_HwId, DeviceBlueField2_HwId, + DeviceBlueField3_HwId, DeviceBlueField4_HwId, DeviceSwitchIB2_HwId, + DeviceCableQSFP_HwId, DeviceCableQSFPaging_HwId, DeviceCableCMIS_HwId, + DeviceCableCMISPaging_HwId, DeviceCableSFP_HwId, DeviceCableSFP51_HwId, + DeviceCableSFP51Paging_HwId, DeviceSpectrum2_HwId, DeviceQuantum_HwId, + DeviceQuantum2_HwId, DeviceQuantum3_HwId, DeviceArdbeg_HwId, + DeviceBaritone_HwId, DeviceMenhit_HwId, DeviceArcusPTC_HwId, + DeviceArcusP_HwId, DeviceArcusE_HwId, DeviceSecureHost_HwId, + DeviceSpectrum3_HwId, DeviceSpectrum4_HwId, DeviceGearBox_HwId, + DeviceGearBoxManager_HwId, DeviceAbirGearBox_HwId, DeviceGB100_HwId, + DeviceConnectX8PurePcieSwitch_HwId, DeviceConnectX9_HwId}; +#define SUPPORTED_DEVICE_ID_TABLE_SIZE (sizeof(supported_device_ids) / sizeof(u_int32_t)) + +int is_supported_device_id(u_int16_t dev_id) +{ + int counter; + + for (counter = 0; counter < SUPPORTED_DEVICE_ID_TABLE_SIZE; counter++) { + if (supported_device_ids[counter] == dev_id) { + return 1; + } + } + return 0; +} + +int is_secure_debug_access(u_int32_t dev_id) +{ + int counter; + + for (counter = 0; counter < SECURED_DEVICE_ID_TABLE_SIZE; counter++) { + if (secured_devices[counter] == dev_id) { + return 1; + } + } + return 0; +} + +int try_to_read_secure_device(mfile* mf) +{ +#if !defined(__VMKERNEL_UW_NATIVE__) + u_int32_t dev_id_0x47 = 0; + + mf->i2c_secondary = 0x47; + + if (read_device_id(mf, &dev_id_0x47) != 4) { + return 1; + } + + if (!is_secure_debug_access(dev_id_0x47)) { + return 1; + } + + DBG_PRINTF("I2C secondary set to 0x47\n"); + +#endif + + return 0; +} + +int change_i2c_secondary_address(mfile* mf, DType dtype) +{ +#if !defined(__VMKERNEL_UW_NATIVE__) + u_int32_t dev_id_0x48 = 0xffff; + u_int32_t dev_id_0x47 = 0xffff; + int counter = 0; + + switch (mf->tp) { + case MST_DEV_I2C: + break; + + default: + return 0; + } + + if (force_i2c_address != -1) { + mf->i2c_secondary = force_i2c_address; + return 0; + } + + DBG_PRINTF("trying to read from 0x48 to make sure this is the correct secondary address\n"); + if (read_device_id(mf, &dev_id_0x48) != 4) { + return 1; + } + + if (!is_supported_device_id(dev_id_0x48)) { + DBG_PRINTF("Not supported device, trying to read from 0x47\n"); + return try_to_read_secure_device(mf); + } + + if (!is_secure_debug_access(dev_id_0x48)) { + return 0; + } + + mf->i2c_secondary = 0x47; + DBG_PRINTF("I2C secondary set to 0x47\n"); + + if (read_device_id(mf, &dev_id_0x47) != 4) { + return 1; + } + + if (dev_id_0x48 == dev_id_0x47) { + return 0; + } + + do { + if (counter == 100) { + return 1; + } + counter++; + msleep(10); + + if (read_device_id(mf, &dev_id_0x47) != 4) { + return 1; + } + } while (dev_id_0x48 != dev_id_0x47); + + return 0; +#endif /* if !defined(__VMKERNEL_UW_NATIVE__) */ + + return 0; +} +#endif /* ifdef ENABLE_MST_DEV_I2C */ + + static MType mtcr_parse_name(const char* name, int * force, unsigned * domain_p, @@ -1876,6 +2599,40 @@ static MType mtcr_parse_name(const char* name, char driver_conf_name[40]; unsigned len = strlen(name); unsigned tmp; + int is_vfio = strstr(name, "vfio-") != NULL; + int lockdown_enabled = CheckifKernelLockdownIsEnabled(); + + if (strstr(name, "fwctl")) { + return MST_FWCTL_CONTROL_DRIVER; + } + + if (is_vfio || lockdown_enabled) { + if (is_vfio) { + scnt = sscanf(name, "vfio-%x:%x:%x.%x", &my_domain, &my_bus, &my_dev, &my_func); + if (scnt != 4) { + my_domain = 0; + scnt = sscanf(name, "vfio-%x:%x.%x", &my_bus, &my_dev, &my_func); + if (scnt != 3) { + return MST_ERROR; + } + } + } else { + scnt = sscanf(name, "%x:%x:%x.%x", &my_domain, &my_bus, &my_dev, &my_func); + if (scnt != 4) { + my_domain = 0; + scnt = sscanf(name, "%x:%x.%x", &my_bus, &my_dev, &my_func); + if (scnt != 3) { + return MST_ERROR; + } + } + } + + *domain_p = my_domain; + *bus_p = my_bus; + *dev_p = my_dev; + *func_p = my_func; + return MST_VFIO_DEVICE; + } if ((len >= sizeof config) && !strcmp(config, name + len + 1 - sizeof config)) { *force = 1; @@ -1898,6 +2655,11 @@ static MType mtcr_parse_name(const char* name, return MST_IB; } + if ((strstr(name, "/dev/nvidia") != 0)) { + *force = 0; + return MST_NVML; + } + if ((sscanf(name, "mthca%x", &tmp) == 1) || (sscanf(name, "mlx4_%x", &tmp) == 1) || (sscanf(name, "mlx5_%x", &tmp) == 1)) { char mbuf[4048] = {0}; @@ -1956,9 +2718,11 @@ static MType mtcr_parse_name(const char* name, goto name_parsed; } - if (strstr(name, "fwctl")) { - return MST_FWCTL_CONTROL_DRIVER; +#ifdef ENABLE_MST_DEV_I2C + if (strstr(name, "/dev/i2c")) { + return MST_DEV_I2C; } +#endif parse_error: fprintf(stderr, "Unable to parse device name %s\n", name); @@ -2046,6 +2810,7 @@ static long supported_dev_ids[] = {0x1003, /* Connect-X3 */ 0x101f, /* Connect-X6LX */ 0x1021, /* Connect-X7 */ 0x1023, /* Connect-X8 */ + 0x1025, /* Connect-X9 */ 0xcb20, /* Switch-IB */ 0xcb84, /* Spectrum */ 0xcf08, /* Switch-IB2 */ @@ -2058,9 +2823,12 @@ static long supported_dev_ids[] = {0x1003, /* Connect-X3 */ 0xa2de, /* BF4 Family BlueField4 integrated ConnectX-8 network controller */ 0xcf70, /* Spectrum3 */ 0xcf80, /* Spectrum4 */ + 0xcf82, /* Spectrum5 */ 0x1976, /* Schrodinger */ 0x1979, /* Freysa */ - 0x2900, /* BW-00 */ + 0x197d, /* Connect-X8 Bridge */ + 0x197e, /* Connect-X9 Bridge */ + 0x2900, /* GB100 */ 0xd2f4, /* Sunbird */ -1}; @@ -2071,6 +2839,7 @@ static long live_fish_id_database[] = {0x191, 0x246, 0x249, 0x24b, 0x24d, 0x24e, 0x216, /* Connect-X6LX */ 0x218, /* Connect-X7 */ 0x21e, /* Connect-X8 */ + 0x224, /* Connect-X9 */ 0x21C, /* BlueField3 */ 0x220, /* BlueField4 */ 0x250, /* Spectrum3 */ @@ -2199,6 +2968,36 @@ int mdevices_v_ul(char* buf, int len, int mask, int verbosity) } closedir(d); + if (mask & (MDEVS_CABLE)) { + DIR * mstflint_dir; + struct dirent* mstflint_entry; + + mstflint_dir = opendir("/dev/mstflint"); + if (mstflint_dir != NULL) { + while ((mstflint_entry = readdir(mstflint_dir)) != NULL) { + if (mstflint_entry->d_name[0] == '.') { + continue; + } + + if (strstr(mstflint_entry->d_name, "cable_") != NULL) { + int sz = strlen(mstflint_entry->d_name); + int rsz = sz + 1; /* dev name size + place for Null char */ + + if ((pos + rsz) > len) { + ndevs = -1; + closedir(mstflint_dir); + return ndevs; + } + + memcpy(&buf[pos], mstflint_entry->d_name, rsz); + pos += rsz; + ndevs++; + } + } + closedir(mstflint_dir); + } + } + return ndevs; cleanup_file_opened: @@ -2685,6 +3484,7 @@ mfile* mopen_ul_int(const char* name, u_int32_t adv_opt) char pcidev[99] = "XXXX:XX:XX.X"; int err; int rc; + int cable_port = 0; if (geteuid() != 0) { errno = EACCES; @@ -2714,6 +3514,7 @@ mfile* mopen_ul_int(const char* name, u_int32_t adv_opt) mf->res_fd = -1; mf->mpci_change = mpci_change_ul; dev_type = mtcr_parse_name(name, &force, &domain, &bus, &dev, &func); + switch (dev_type) { case MST_DRIVER_CR: case MST_DRIVER_CONF: @@ -2732,12 +3533,40 @@ mfile* mopen_ul_int(const char* name, u_int32_t adv_opt) return mf; break; + case MST_NVML: + rc = nvml_open(mf, name); + if (rc) { + DBG_PRINTF("Failed to open GPU mst driver device"); + goto open_failed; + } + return mf; + break; + + case MST_VFIO_DEVICE: + rc = mtcr_vfio_device_open(mf, name, domain, bus, dev, func); + if (rc) { + goto open_failed; + } + return mf; + break; + +#ifdef ENABLE_MST_DEV_I2C + case MST_DEV_I2C: + rc = mtcr_i2c_open(mf, name); + if (rc) { + DBG_PRINTF("Failed to open I2C device: %s\n", name); + goto open_failed; + } + return mf; +#endif + default: break; } if (dev_type == MST_ERROR) { goto open_failed; } + mf->tp = dev_type; mf->flags = MDEVS_TAVOR_CR; if ((dev_type == MST_PCICONF) || (dev_type == MST_PCI)) { @@ -2789,6 +3618,15 @@ mfile* mopen_ul_int(const char* name, u_int32_t adv_opt) } if (0 == rc) { +#ifdef CABLES_SUPPORT + if (is_cable_device(name)) { + cable_port = get_cable_port(name); + rc = mcables_open(mf, cable_port); + if (rc) { + goto open_failed; + } + } +#endif return mf; } goto open_failed; @@ -3527,6 +4365,15 @@ static int mreg_send_raw(mfile * mf, if (class_to_use == MAD_CLASS_A_REG_ACCESS) { mad_rc = mib_send_cls_a_access_reg_mad_ul(mf, buffer); +#ifdef ENABLE_NVML + } else if (mf->tp == MST_NVML) { + mad_rc = nvml_reg_access(buffer, + reg_size + OP_TLV_SIZE + REG_TLV_HEADER_LEN, + reg_id, + reg_status, + method == MACCESS_REG_METHOD_SET, + mf->nvml_device); +#endif } else { mad_rc = mreg_send_wrapper(mf, buffer, r_size_reg, w_size_reg); } @@ -3543,8 +4390,12 @@ static int mreg_send_raw(mfile * mf, fprintf(stdout, "\tReg Tlv\n"); reg_tlv_dump(&tlv_info, stdout); #endif - /* Check the return value */ - *reg_status = tlv.status; + /* Update the return status. */ + /* in RM Driver, TLV is not returned with updated status and the register status is already handled in RM Driver */ + /* reg access function. */ + if (mf->tp != MST_NVML) { + *reg_status = tlv.status; + } if (mad_rc) { return mad_rc; } @@ -3699,232 +4550,6 @@ int mvpd_read4_ul(mfile* mf, unsigned int offset, u_int8_t value[4]) } } -/************************************ -* Function: m_err2str -************************************/ -const char* m_err2str(MError status) -{ - switch (status) { - case ME_OK: - return "ME_OK"; - - case ME_ERROR: - return "General error"; - - case ME_BAD_PARAMS: - return "ME_BAD_PARAMS"; - - case ME_CR_ERROR: - return "ME_CR_ERROR"; - - case ME_NOT_IMPLEMENTED: - return "ME_NOT_IMPLEMENTED"; - - case ME_SEM_LOCKED: - return "Semaphore locked"; - - case ME_MEM_ERROR: - return "ME_MEM_ERROR"; - - case ME_UNSUPPORTED_OPERATION: - return "ME_UNSUPPORTED_OPERATION"; - - case ME_GMP_MAD_UNSUPPORTED_OPERATION: - return "Sending GMP MAD supports only Get() method, and you are trying to send Set() method\n" - "to a register which is not small enough to send with SMP MAD."; - - case ME_MAD_SEND_FAILED: - return "ME_MAD_SEND_FAILED"; - - case ME_UNKOWN_ACCESS_TYPE: - return "ME_UNKOWN_ACCESS_TYPE"; - - case ME_UNSUPPORTED_ACCESS_TYPE: - return "ME_UNSUPPORTED_ACCESS_TYPE"; - - case ME_UNSUPPORTED_DEVICE: - return "ME_UNSUPPORTED_DEVICE"; - - /* Reg access errors */ - case ME_REG_ACCESS_BAD_STATUS_ERR: - return "ME_REG_ACCESS_BAD_STATUS_ERR"; - - case ME_REG_ACCESS_BAD_METHOD: - return "Bad method"; - - case ME_REG_ACCESS_NOT_SUPPORTED: - return "The Register access is not supported by the device"; - - case ME_REG_ACCESS_DEV_BUSY: - return "Device is busy"; - - case ME_REG_ACCESS_VER_NOT_SUPP: - return "Version not supported"; - - case ME_REG_ACCESS_UNKNOWN_TLV: - return "Unknown TLV"; - - case ME_REG_ACCESS_REG_NOT_SUPP: - return "Register not supported"; - - case ME_REG_ACCESS_CLASS_NOT_SUPP: - return "Class not supported"; - - case ME_REG_ACCESS_METHOD_NOT_SUPP: - return "Method not supported"; - - case ME_REG_ACCESS_BAD_PARAM: - return "Bad parameter"; - - case ME_REG_ACCESS_RES_NOT_AVLBL: - return "Resource unavailable"; - - case ME_REG_ACCESS_MSG_RECPT_ACK: - return "Message receipt ack"; - - case ME_REG_ACCESS_UNKNOWN_ERR: - return "Unknown register error"; - - case ME_REG_ACCESS_SIZE_EXCEEDS_LIMIT: - return "Register is too large"; - - case ME_REG_ACCESS_CONF_CORRUPT: - return "Config Section Corrupted"; - - case ME_REG_ACCESS_LEN_TOO_SMALL: - return "The given Register length is too small for the Tlv"; - - case ME_REG_ACCESS_BAD_CONFIG: - return "The configuration is rejected"; - - case ME_REG_ACCESS_ERASE_EXCEEDED: - return "The erase count exceeds its limit"; - - case ME_REG_ACCESS_INTERNAL_ERROR: - return "Firmware internal error"; - - case ME_REG_ACCESS_NOT_SUPPORTED_BY_SECONDARY: - return "Not supported by secondary"; - - case ME_REG_ACCESS_NOT_READY: - return "The device temporarily cannot execute the command"; - - case ME_REG_ACCESS_EXCEED_LIM: - return "Required capability exceeds device limits"; - - case ME_REG_ACCESS_BAD_RES_STATE: - return "Resource is not in the appropriate state or ownership"; - - case ME_REG_ACCESS_BAD_INDEX: - return " Index out of range"; - - case ME_REG_ACCESS_BAD_INPUT_LEN: - return "Bad command input len"; - - case ME_REG_ACCESS_BAD_OUTPUT_LEN: - return "Bad command output len"; - - /* ICMD access errors */ - case ME_ICMD_STATUS_CR_FAIL: - return "ME_ICMD_STATUS_CR_FAIL"; - - case ME_ICMD_STATUS_SEMAPHORE_TO: - return "ME_ICMD_STATUS_SEMAPHORE_TO"; - - case ME_ICMD_STATUS_EXECUTE_TO: - return "ME_ICMD_STATUS_EXECUTE_TO"; - - case ME_ICMD_STATUS_IFC_BUSY: - return "ME_ICMD_STATUS_IFC_BUSY"; - - case ME_ICMD_STATUS_ICMD_NOT_READY: - return "ME_ICMD_STATUS_ICMD_NOT_READY"; - - case ME_ICMD_UNSUPPORTED_ICMD_VERSION: - return "ME_ICMD_UNSUPPORTED_ICMD_VERSION"; - - case ME_ICMD_NOT_SUPPORTED: - return "ME_REG_ACCESS_ICMD_NOT_SUPPORTED"; - - case ME_ICMD_INVALID_OPCODE: - return "ME_ICMD_INVALID_OPCODE"; - - case ME_ICMD_INVALID_CMD: - return "ME_ICMD_INVALID_CMD"; - - case ME_ICMD_OPERATIONAL_ERROR: - return "ME_ICMD_OPERATIONAL_ERROR"; - - case ME_ICMD_BAD_PARAM: - return "ME_ICMD_BAD_PARAM"; - - case ME_ICMD_BUSY: - return "ME_ICMD_BUSY"; - - case ME_ICMD_ICM_NOT_AVAIL: - return "ME_ICMD_ICM_NOT_AVAIL"; - - case ME_ICMD_WRITE_PROTECT: - return "ME_ICMD_WRITE_PROTECT"; - - case ME_ICMD_UNKNOWN_STATUS: - return "ME_ICMD_UNKNOWN_STATUS"; - - case ME_ICMD_SIZE_EXCEEDS_LIMIT: - return "ME_ICMD_SIZE_EXCEEDS_LIMIT"; - - /* TOOLS HCR access errors */ - case ME_CMDIF_BUSY: - return "Tools HCR busy"; - - case ME_CMDIF_TOUT: - return "Tools HCR time out."; - - case ME_CMDIF_BAD_OP: - return "Operation not supported"; - - case ME_CMDIF_NOT_SUPP: - return "Tools HCR not supported"; - - case ME_CMDIF_BAD_SYS: - return "bad system status (driver may be down or Fw does not support this operation)"; - - case ME_CMDIF_UNKN_TLV: - return "Unknown TLV"; - - case ME_CMDIF_RES_STATE: - return "Bad reset state"; - - case ME_CMDIF_UNKN_STATUS: - return "Unknown status"; - - /* MAD IFC errors */ - case ME_MAD_BUSY: - return "Temporarily busy. MAD discarded. This is not an error"; - - case ME_MAD_REDIRECT: - return "Redirection. This is not an error"; - - case ME_MAD_BAD_VER: - return "Bad version"; - - case ME_MAD_METHOD_NOT_SUPP: - return "Method not supported"; - - case ME_MAD_METHOD_ATTR_COMB_NOT_SUPP: - return "Method and attribute combination isn't supported"; - - case ME_MAD_BAD_DATA: - return "Bad attribute modifier or field"; - - case ME_MAD_GENERAL_ERR: - return "Unknown MAD error"; - - default: - return "Unknown error code"; - } -} - int get_dma_pages(mfile* mf, struct mtcr_page_info* page_info, int page_amount) { #if !defined(__VMKERNEL_UW_NATIVE__) @@ -4112,9 +4737,10 @@ int is_zombiefish_device(mfile* mf) if (mread4(mf, HW_ID_ADDR, &mf->device_hw_id) != 4) { return 0; } - if ((mf->device_hw_id != DeviceConnectX8_HwId) && (mf->device_hw_id != DeviceQuantum3_HwId) && - (mf->device_hw_id != DeviceConnectX9_HwId) && (mf->device_hw_id != DeviceQuantum4_HwId) && - (mf->device_hw_id != DeviceConnectX7_HwId) && (mf->device_hw_id != DeviceBlueField3_HwId)) { + if ((mf->device_hw_id != DeviceConnectX8_HwId) && (mf->device_hw_id != DeviceConnectX8PurePcieSwitch_HwId) && + (mf->device_hw_id != DeviceQuantum3_HwId) && (mf->device_hw_id != DeviceConnectX9_HwId) && + (mf->device_hw_id != DeviceQuantum4_HwId) && (mf->device_hw_id != DeviceConnectX7_HwId) && + (mf->device_hw_id != DeviceBlueField3_HwId)) { return 0; } @@ -4132,73 +4758,181 @@ int is_zombiefish_device(mfile* mf) } } + int read_device_id(mfile* mf, u_int32_t* device_id) { + if (!mf || !device_id) { return -1; } - + int rc = 0; unsigned hw_id_address = mf->cr_space_offset + HW_ID_ADDR; +#ifdef ENABLE_NVML + if (mf->tp == MST_NVML) { + *device_id = nvml_get_device_id(mf->nvml_device); + mf->hw_dev_id = (*device_id & 0xffff); + return 4; + } +#endif + rc = mread4(mf, hw_id_address, device_id); mf->rev_id = EXTRACT(*device_id, 16, 4); *device_id = (*device_id & 0xffff); - mf->hw_dev_id = (*device_id & 0xffff); - return mread4(mf, hw_id_address, device_id); + // Accesing GPU Devices directly via PCIe is not always possible, + // so we need to get the HW device ID from the PCI device ID in case of failure. + if (mf->dinfo && is_gpu_pci_device(mf->dinfo->pci.dev_id) && !is_gpu_device(*device_id)) + { + mf->rev_id = 0; + *device_id = get_hw_dev_id_by_pci_id(mf->dinfo->pci.dev_id); + rc = 4; + } + + mf->hw_dev_id = (*device_id & 0xffff); + DBG_PRINTF("MTCR:read_device_id: mf->hw_dev_id:0x%x\n", mf->hw_dev_id); + return rc; } int is_pcie_switch_device(mfile* mf) { char device_buffer[DEV_NAME_SZ]; char device_path[DEV_NAME_SZ]; - int counter; - - struct pcie_switch_device_id - { + int counter; + struct pcie_switch_device_id { unsigned int device_id; } devs[] = { - {0x1976}, // ConnectX6dx (Schrodinger). - {0x1979} // ConnectX7 (FreysaP1011). + {0x1976}, /* ConnectX6dx (Schrodinger). */ + {0x1979}, /* ConnectX7 (FreysaP1011). */ + {0x197d}, /* ConnectX8 Bridge. */ + {0x197e} /* ConnectX9 Bridge. */ }; - // take care of corrupted input - if (!mf || !mf->dinfo) - { + /* take care of corrupted input */ + if (!mf || !mf->dinfo) { return 0; } - // write to device_path the linux device path + /* write to device_path the linux device path */ snprintf(device_path, DEV_NAME_SZ - 1, "/sys/bus/pci/devices/%04x:%02x:%02x.%x/device", mf->dinfo->pci.domain, mf->dinfo->pci.bus, mf->dinfo->pci.dev, mf->dinfo->pci.func); FILE* device = fopen(device_path, "r"); - if (!device) - { + + if (!device) { return 0; } - // write to device_buffer the device name + /* write to device_buffer the device name */ fgets(device_buffer, DEV_NAME_SZ, (FILE*)device); fclose(device); - char* temp = strchr(device_buffer, '\n'); // Finds first '\n' - if (temp) - { - // Remove '\n' + char* temp = strchr(device_buffer, '\n'); /* Finds first '\n' */ + + if (temp) { + /* Remove '\n' */ *temp = '\0'; } - // Convert id from string to integer - unsigned int dev_id_converted = strtoul(device_buffer, NULL, 16); // convert from hex string to decimal int + unsigned int dev_id_converted = strtoul(device_buffer, NULL, 16); - // iterate over pcie_switch_devices and check if dev_id_converted is there + /* iterate over pcie_switch_devices and check if dev_id_converted is there */ int num_devs = sizeof(devs) / sizeof(struct pcie_switch_device_id); - for (counter = 0; counter < num_devs; counter++) - { - if (devs[counter].device_id == dev_id_converted) - { + + for (counter = 0; counter < num_devs; counter++) { + if (devs[counter].device_id == dev_id_converted) { return 1; } } return 0; } + + +void safe_free(mfile** pmf) +{ + if ((*pmf) != NULL) { + free(*pmf); + (*pmf) = NULL; + } +} + + +#define DATA_WIDTHS_NUM 4 + +typedef struct width2dtype { + u_int8_t addr_width; + DType dtype; +} width2dtype_t; + +width2dtype_t width2dtype_arr[DATA_WIDTHS_NUM] = { + {0, MST_NOADDR}, {1, MST_DIMM}, {2, MST_GAMLA}, {4, MST_TAVOR} +}; + +int mset_i2c_addr_width(mfile* mf, u_int8_t addr_width) +{ + int i; + + for (i = 0; i < DATA_WIDTHS_NUM; i++) { + if (width2dtype_arr[i].addr_width == addr_width) { + mf->dtype = width2dtype_arr[i].dtype; + return 0; + } + } + return 1; +} + +int mget_i2c_addr_width(mfile* mf, u_int8_t* addr_width) +{ + int i; + + for (i = 0; i < DATA_WIDTHS_NUM; i++) { + if (width2dtype_arr[i].dtype == mf->dtype) { + *addr_width = width2dtype_arr[i].addr_width; + return 0; + } + } + return 1; +} + +unsigned char mset_i2c_secondary(mfile* mf, unsigned char new_i2c_secondary) +{ + unsigned char ret; + + if (mf) { + ret = mf->i2c_secondary; + mf->i2c_secondary = new_i2c_secondary; + } else { + ret = 0xff; + } + return ret; +} + +unsigned char mget_i2c_secondary(mfile* mf) +{ + if (mf) { + return mf->i2c_secondary; + } + return 0; +} + +void switch_access_funcs(mfile* mf) +{ +#ifdef CABLES_SUPPORT + ul_ctx_t* ctx = mf->ul_ctx; + + if (mf->tp == MST_CABLE) { + ctx->mread4 = mcables_read4; + ctx->mwrite4 = mcables_write4; + ctx->mread4_block = mcables_read4_block; + ctx->mwrite4_block = mcables_write4_block; + ctx->mclose = mcables_close; + } else { + ctx->mread4 = mtcr_pciconf_mread4; + ctx->mwrite4 = mtcr_pciconf_mwrite4; + ctx->mread4_block = mread4_block_pciconf; + ctx->mwrite4_block = mwrite4_block_pciconf; + ctx->mclose = mtcr_pciconf_mclose; + } +#else + (void)mf; +#endif +} diff --git a/mtcr_ul/mtcr_ul_com.h b/mtcr_ul/mtcr_ul_com.h index 6d502d0..b5c0bc9 100644 --- a/mtcr_ul/mtcr_ul_com.h +++ b/mtcr_ul/mtcr_ul_com.h @@ -165,6 +165,8 @@ int mclear_pci_semaphore_ul(const char* name); int mvpd_read4_ul(mfile* mf, unsigned int offset, u_int8_t value[4]); +int return_by_reg_status(int reg_status); + int space_to_cap_offset(int space); int get_dma_pages(mfile* mf, struct mtcr_page_info* page_info, int page_amount); @@ -178,6 +180,44 @@ void mtcr_fix_endianness(u_int32_t* buf, int len); int is_zombiefish_device(mfile* mf); int read_device_id(mfile* mf, u_int32_t* device_id); + + +#ifdef ENABLE_MST_DEV_I2C +void fix_endianness(u_int32_t* buf, int len, int be_mode); + +int mset_i2c_addr_width(mfile* mf, u_int8_t addr_width); +int mget_i2c_addr_width(mfile* mf, u_int8_t* addr_width); +unsigned char mget_i2c_secondary(mfile* mf); +unsigned char mset_i2c_secondary(mfile* mf, unsigned char new_i2c_secondary); + +void set_force_i2c_address(int i2c_address); + +int mtcr_i2c_mread4(mfile* mf, unsigned int offset, u_int32_t* value); +int mtcr_i2c_mwrite4(mfile* mf, unsigned int offset, u_int32_t value); +int mtcr_i2c_mread_chunks(mfile* mf, unsigned int offset, void* data, int length); +int mtcr_i2c_mwrite_chunks(mfile* mf, unsigned int offset, void* data, int length); +int mread_i2c_chunk(mfile* mf, unsigned int offset, void* data, int length); +int mwrite_i2c_chunk(mfile* mf, unsigned int offset, void* data, int length); +int mread_i2cblock(mfile * mf, + unsigned char i2c_secondary, + u_int8_t addr_width, + unsigned int offset, + void * data, + int length); +int mwrite_i2cblock(mfile * mf, + unsigned char i2c_secondary, + u_int8_t addr_width, + unsigned int offset, + void * data, + int length); + +int is_supported_device_id(u_int16_t dev_id); +int is_secure_debug_access(u_int32_t dev_id); +int try_to_read_secure_device(mfile* mf); +int change_i2c_secondary_address(mfile* mf, DType dtype); +#endif +void switch_access_funcs(mfile* mf); + #ifdef __cplusplus } #endif diff --git a/mtcr_ul/mtcr_ul_icmd_cif.c b/mtcr_ul/mtcr_ul_icmd_cif.c index e0ac0c8..8bede69 100644 --- a/mtcr_ul/mtcr_ul_icmd_cif.c +++ b/mtcr_ul/mtcr_ul_icmd_cif.c @@ -31,13 +31,13 @@ * */ +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> -#if !defined(_MSC_VER) #include <unistd.h> -#endif + #include "common/bit_slice.h" #include "common/tools_time.h" #include "mtcr_icmd_cif.h" @@ -54,6 +54,8 @@ #define ICMD_QUERY_CAP_CMD_ID 0x8400 #define ICMD_QUERY_CAP_CMD_SZ 0x8 #define ICMD_QUERY_CAP_EXMB_ICMD_OFF 0x8 +#define SEMAPHORE_62_LOCKED_INDICATOR 0x1 + /* _DEBUG_MODE // un-comment this to enable debug prints */ @@ -65,6 +67,7 @@ #define STAT_CFG_NOT_DONE_ADDR_CX5 0xb5e04 #define STAT_CFG_NOT_DONE_ADDR_CX6 0xb5f04 #define STAT_CFG_NOT_DONE_ADDR_CX7 0xb5f04 +#define STAT_CFG_NOT_DONE_ADDR_CX8 656132 #define STAT_CFG_NOT_DONE_ADDR_GPU 0x3100010 #define STAT_CFG_NOT_DONE_BITOFF_CIB 31 #define STAT_CFG_NOT_DONE_BITOFF_CX4 31 @@ -80,6 +83,7 @@ #define SEMAPHORE_ADDR_GB100 0xa52f8 #define SEMAPHORE_ADDR_CX5 0xe74e0 #define SEMAPHORE_ADDR_CX7 0xe5660 +#define SEMAPHORE_ADDR_CX8 358016 #define SEMAPHORE_ADDR_GPU 0x308F4F8 #define HCR_ADDR_CIB 0x0 #define HCR_ADDR_CX4 HCR_ADDR_CIB @@ -91,15 +95,18 @@ #define ICMD_VERSION_BITOFF 24 #define ICMD_VERSION_BITOFF_GPU 0 #define ICMD_VERSION_BITLEN 8 +#define ICMD_VERSION_BITLEN_CX8 4 #define CMD_PTR_ADDR_CIB 0x0 #define CMD_PTR_ADDR_SW_IB 0x80000 #define CMD_PTR_ADDR_QUANTUM 0x100000 #define CMD_PTR_ADDR_CX4 CMD_PTR_ADDR_CIB #define CMD_PTR_ADDR_CX5 CMD_PTR_ADDR_CIB #define CMD_PTR_ADDR_CX7 CMD_PTR_ADDR_CIB +#define CMD_PTR_ADDR_CX8 27262976 #define CMD_PTR_ADDR_GPU 0x3100000 #define CMD_PTR_BITOFF 0 #define CMD_PTR_BITLEN 24 +#define CMD_PTR_BITLEN_CX8 28 #define CMD_PTR_BITLEN_GPU 32 #define CTRL_OFFSET 0x3fc #define BUSY_BITOFF 0 @@ -260,6 +267,14 @@ int MREAD4_SEMAPHORE(mfile* mf, int offset, u_int32_t* ptr) return ME_ICMD_STATUS_CR_FAIL; } RESTORE_SPACE(mf); + + // When accessing directly to the device configuration space, the semaphore lock is the last bit in the DWORD. + // When accessing via VSC GW or BAR0 GW, the semaphore lock is the whole dword. + if (!is_gw_access(mf)) + { + *ptr = EXTRACT(*ptr, 31, 1); + } + return ME_OK; } @@ -284,7 +299,7 @@ enum { #define CX6LX_HW_ID 534 #define CX7_HW_ID 536 #define CX8_HW_ID 542 -#define CX9_HW_ID 549 +#define CX9_HW_ID 548 #define BF_HW_ID 529 #define BF2_HW_ID 532 #define BF3_HW_ID 540 @@ -301,6 +316,7 @@ enum { #define GR100_HW_ID 0x3000 #define SPECTRUM4_HW_ID 596 #define AMOS_GBOX_HW_ID 594 +#define CX8_PURE_PCIE_SWITCH_HW_ID 0x222 /***** GLOBALS *****/ int increase_poll_time = 0; @@ -593,12 +609,38 @@ int icmd_clear_semaphore(mfile* mf) return icmd_clear_semaphore_com(mf); } -/* - * icmd_take_semaphore - */ -/* - * icmd_take_semaphore - */ +bool device_supports_sem_lock_verify(unsigned int hw_dev_id) +{ + switch (hw_dev_id) + { + case DeviceConnectX3_HwId: + case DeviceConnectIB_HwId: + case DeviceConnectX3Pro_HwId: + case DeviceSwitchIB_HwId: + case DeviceSpectrum_HwId: + case DeviceConnectX4_HwId: + case DeviceConnectX4LX_HwId: + case DeviceConnectX5_HwId: + case DeviceConnectX6_HwId: + case DeviceConnectX6DX_HwId: + case DeviceConnectX6LX_HwId: + case DeviceConnectX7_HwId: + case DeviceBlueField_HwId: + case DeviceBlueField2_HwId: + case DeviceBlueField3_HwId: + case DeviceSwitchIB2_HwId: + case DeviceQuantum_HwId: + case DeviceQuantum2_HwId: + case DeviceQuantum3_HwId: + case DeviceGB100_HwId: + case DeviceSpectrum2_HwId: + case DeviceSpectrum3_HwId: + case DeviceSpectrum4_HwId: + case DeviceArcusE_HwId: + return false; + } + return true; +} static int icmd_take_semaphore_com(mfile* mf, u_int32_t expected_read_val) { @@ -630,12 +672,31 @@ static int icmd_take_semaphore_com(mfile* mf, u_int32_t expected_read_val) } else #endif { - if (mf->functional_vsec_supp) { - /* write expected val before reading it */ - MWRITE4_SEMAPHORE(mf, mf->icmd.semaphore_addr, expected_read_val); + if (mf->functional_vsec_supp) + { + DBG_PRINTF("ICMD_SEMAPHORE: Writing expected_read_val=0x%x to semaphore\n", expected_read_val); + MWRITE4_SEMAPHORE(mf, mf->icmd.semaphore_addr, + expected_read_val); // Attempt to take the semaphore by writing the PID } MREAD4_SEMAPHORE(mf, mf->icmd.semaphore_addr, &read_val); - if (read_val == expected_read_val) { + DBG_PRINTF("ICMD_SEMAPHORE: read_val=0x%x expected_read_val=0x%x\n", read_val, expected_read_val); + if (read_val == expected_read_val) // Semaphore was free (PID if VSC, 0 if non-VSC) + { + if (!is_gw_access(mf)) + { + // Verify HW has set the semaphore to locked state + MREAD4_SEMAPHORE(mf, mf->icmd.semaphore_addr, &read_val); + if (read_val != SEMAPHORE_62_LOCKED_INDICATOR) + { + DBG_PRINTF("Failed to take ICMD semaphore (semaphore 62). " + "Semaphore was free (0) but HW failed to set it to locked state when we took it." + "This might indicate a FW or HW issue.\n"); + if (device_supports_sem_lock_verify(mf->hw_dev_id)) + { + return ME_ICMD_UNABLE_TO_TAKE_SEMAOHORE; + } + } + } break; } } @@ -922,6 +983,7 @@ static int icmd_init_cr(mfile* mf) /* get device specific addresses */ if (read_device_id(mf, &hw_id) != 4) { + DBG_PRINTF("icmd_init_cr: failed to read device ID.\n"); return ME_ICMD_NOT_SUPPORTED; } @@ -1015,7 +1077,6 @@ static int icmd_init_cr(mfile* mf) case (CX7_HW_ID): case (BF3_HW_ID): - case (CX8_HW_ID): case (BF4_HW_ID): cmd_ptr_addr = CMD_PTR_ADDR_CX7; hcr_address = HCR_ADDR_CX7; @@ -1024,6 +1085,19 @@ static int icmd_init_cr(mfile* mf) mf->icmd.static_cfg_not_done_offs = STAT_CFG_NOT_DONE_BITOFF_CX7; break; + case (CX8_HW_ID): + case (CX9_HW_ID): + case (CX8_PURE_PCIE_SWITCH_HW_ID): + cmd_ptr_addr = CMD_PTR_ADDR_CX8; + mf->icmd.cmd_ptr_bitlen = CMD_PTR_BITLEN_CX8; + mf->icmd.semaphore_addr = SEMAPHORE_ADDR_CX8; + mf->icmd.static_cfg_not_done_addr = STAT_CFG_NOT_DONE_ADDR_CX8; + mf->icmd.static_cfg_not_done_offs = STAT_CFG_NOT_DONE_BITOFF_CX7; + mf->icmd.version_bit_offset = CMD_PTR_BITLEN_CX8; + mf->icmd.version_bitlen = ICMD_VERSION_BITLEN_CX8; + hcr_address = CMD_PTR_ADDR_CX8; /* hcr_address is "version address" */ + break; + case (AMOS_GBOX_HW_ID): mf->icmd.ctrl_addr = GBOX_MAX_DATA_SIZE; @@ -1134,12 +1208,17 @@ static int icmd_init_vcr_crspace_addr(mfile* mf) case (BF3_HW_ID): case (CX7_HW_ID): case (BF4_HW_ID): - case (CX8_HW_ID): - case (CX9_HW_ID): mf->icmd.static_cfg_not_done_addr = STAT_CFG_NOT_DONE_ADDR_CX6; mf->icmd.static_cfg_not_done_offs = STAT_CFG_NOT_DONE_BITOFF_CX5; /* same bit offset as CX5 */ break; + case (CX8_HW_ID): + case (CX8_PURE_PCIE_SWITCH_HW_ID): + case (CX9_HW_ID): + mf->icmd.static_cfg_not_done_addr = STAT_CFG_NOT_DONE_ADDR_CX8; + mf->icmd.static_cfg_not_done_offs = STAT_CFG_NOT_DONE_BITOFF_CX7; + break; + case (AMOS_GBOX_HW_ID): mf->icmd.static_cfg_not_done_addr = STAT_CFG_NOT_DONE_ADDR_CX6; mf->icmd.static_cfg_not_done_offs = STAT_CFG_NOT_DONE_BITOFF_CX5; /* same bit offset as CX5 */ @@ -1261,6 +1340,13 @@ int icmd_open(mfile* mf) if (mf->functional_vsec_supp) { return icmd_init_vcr(mf); } + +#ifdef ENABLE_MST_DEV_I2C + if (mf->tp == MST_DEV_I2C) { + return icmd_init_cr(mf); + } +#endif + if ((mf->tp == MST_IB) || is_gpu_pci_device(mf->dinfo->pci.dev_id)) { return icmd_init_cr(mf); } @@ -1296,4 +1382,3 @@ void icmd_close(mfile* mf) mf->icmd.icmd_opened = 0; } } - |
