summaryrefslogtreecommitdiff
path: root/mtcr_ul
diff options
authorTzafrir Cohen <tzafrir@debian.org>2025-09-17 07:08:47 +0300
committergit-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com>2025-09-17 10:47:15 +0000
commit5c47b3f775633ee4f144f19ba638c2c1073d97b1 (patch)
treef2bb8e840c6e34827a81a5c84e03592da45ae916 /mtcr_ul
parentefcd6aa58a664da726c42ad146004377b7a57c91 (diff)
Imported using git-ubuntu import.
Notes
Notes: * New upstream release (Closes: #1097420). - Remove patches: - dev_mgt-include-missing-function-declaration.patch - fwctrl-fix-reg-status-typo.patch - fwctrl-include-missing-function-declarations.patch - kernel_fallthrough.patch - kernel_ioremap_check_null.patch - kernel_statify.patch * Note that fwctl is supported
Diffstat (limited to 'mtcr_ul')
-rw-r--r--mtcr_ul/Makefile.am17
-rw-r--r--mtcr_ul/Makefile.in49
-rw-r--r--mtcr_ul/fwctrl.c5
-rw-r--r--mtcr_ul/mtcr_cables.c495
-rw-r--r--mtcr_ul/mtcr_cables.h149
-rw-r--r--mtcr_ul/mtcr_common.c244
-rw-r--r--mtcr_ul/mtcr_gpu.c2
-rw-r--r--mtcr_ul/mtcr_gpu.h6
-rw-r--r--mtcr_ul/mtcr_ib_ofed.c2
-rw-r--r--mtcr_ul/mtcr_nvml.c180
-rw-r--r--mtcr_ul/mtcr_nvml.h43
-rw-r--r--mtcr_ul/mtcr_ul.c15
-rw-r--r--mtcr_ul/mtcr_ul_com.c1318
-rw-r--r--mtcr_ul/mtcr_ul_com.h40
-rw-r--r--mtcr_ul/mtcr_ul_icmd_cif.c119
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;
}
}
-