Commit 4b350707 authored by Mingbao Sun's avatar Mingbao Sun Committed by Jim Harris
Browse files

env_dpdk: fix IOMMU checking for non-Intel CPUs



In the function 'build_eal_cmdline', one of the jobs is to determine the arg
'--iova-mode' to pass to the function 'rte_eal_init'.
In case the underlying CPU supports IOMMU, the arg would be "--iova-mode=va".
Otherwise, the arg would be "--iova-mode=pa".
However, for non-Intel X86_64 CPUs, the IOMMU checking logic does not
work well.

I noticed the following 2 commits:
9ffb0497
1473d3b8
I tested them under AMD CPUs, but found they had not resolved the issue #2683.

Per the comments under issue #2683, for AMD CPU, currently, there is no way
to obtain the IOMMU virtual address width from sysfs entries.
Also, per the comments, non-Intel X86_64 CPUs are assumed to support IOMMU,
which is just the approach adopted in the source code of DPDK.

Thus, this commit fixes this issue by adopting the same approach.

Fixes #2683

Change-Id: I37c9bd08d907c4885610fe5bc59cc31a57bcef68
Signed-off-by: default avatarMingbao Sun <tyler.sun@dell.com>
Reviewed-on: https://review.spdk.io/c/spdk/spdk/+/26056


Tested-by: default avatarSPDK Automated Test System <spdkbot@gmail.com>
Reviewed-by: default avatarBen Walker <ben@nvidia.com>
Reviewed-by: default avatarJim Harris <jim.harris@nvidia.com>
parent 7f02c59e
Loading
Loading
Loading
Loading
+74 −17
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include "spdk/env_dpdk.h"
#include "spdk/log.h"
#include "spdk/config.h"
#include "spdk/string.h"

#include <openssl/ssl.h>
#include <openssl/err.h>
@@ -159,6 +160,62 @@ push_arg(char *args[], int *argcount, char *arg)
	return tmp;
}

static int
get_cpu_vendor_name(char *vendor_name_buf, size_t buf_len)
{
	const char *file_path = "/proc/cpuinfo";
	FILE *file;
	char line[256];
	char *target_substr = NULL;
	char *vendor_name;
	int ret;

	file = fopen(file_path, "r");
	if (file == NULL) {
		SPDK_ERRLOG("open file (read_only) %s failed, errno=%d.\n", file_path, errno);
		return -errno;
	}

	while (NULL != fgets(line, sizeof(line), file)) {
		target_substr = strcasestr(line, "vendor_id");
		if (target_substr != NULL) {
			break;
		}
	}

	if (target_substr == NULL) {
		SPDK_ERRLOG("field %s not found in file %s.\n", "vendor_id", file_path);
		return -ESRCH;
	}

	target_substr = strstr(line, ":");
	if (target_substr == NULL) {
		SPDK_ERRLOG("separator char ':' not found in field line: %s.\n", line);
		return -EINVAL;
	}

	*target_substr = 0; /* eliminate the separator ':'. */
	vendor_name = target_substr + 1; /* point to the field value. */
	spdk_str_trim(vendor_name);

	if (strlen(vendor_name) == 0) {
		SPDK_ERRLOG("cpu vendor name not found in field line: %s.\n", line);
		return -EINVAL;
	}

	ret = snprintf(vendor_name_buf, buf_len, "%s", vendor_name);
	if (ret < 0) {
		SPDK_ERRLOG("copy CPU vendor name to output buf failed, ret=%d, errno=%d.\n",
			    ret, errno);
		return -errno;
	} else if ((size_t)ret >= buf_len) {
		SPDK_WARNLOG("CPU vendor_name truncated from %s to %s\n",
			     vendor_name, vendor_name_buf);
	}

	return 0;
}

#if defined(__linux__) && defined(__x86_64__)

/* TODO: Can likely get this value from rlimits in the future */
@@ -169,14 +226,13 @@ push_arg(char *args[], int *argcount, char *arg)
#define RD_AMD_CAP_VASIZE_MASK (0x7F << RD_AMD_CAP_VASIZE_SHIFT)

static int
get_iommu_width(void)
get_intel_iommu_width(void)
{
	int width = 0;
	glob_t glob_results = {};

	/* Break * and / into separate strings to appease check_format.sh comment style check. */
	glob("/sys/devices/virtual/iommu/dmar*" "/intel-iommu/cap", 0, NULL, &glob_results);
	glob("/sys/class/iommu/ivhd*" "/amd-iommu/cap", GLOB_APPEND, NULL, &glob_results);

	for (size_t i = 0; i < glob_results.gl_pathc; i++) {
		const char *filename = glob_results.gl_pathv[0];
@@ -188,22 +244,12 @@ get_iommu_width(void)
		}

		if (fscanf(file, "%" PRIx64, &cap_reg) == 1) {
			if (strstr(filename, "intel-iommu") != NULL) {
				/* We have an Intel IOMMU */
			int mgaw = ((cap_reg & VTD_CAP_MGAW_MASK) >> VTD_CAP_MGAW_SHIFT) + 1;

				if (width == 0 || (mgaw > 0 && mgaw < width)) {
					width = mgaw;
				}
			} else if (strstr(filename, "amd-iommu") != NULL) {
				/* We have an AMD IOMMU */
				int mgaw = ((cap_reg & RD_AMD_CAP_VASIZE_MASK) >> RD_AMD_CAP_VASIZE_SHIFT) + 1;

			if (width == 0 || (mgaw > 0 && mgaw < width)) {
				width = mgaw;
			}
		}
		}

		fclose(file);
	}
@@ -215,7 +261,18 @@ get_iommu_width(void)
static bool
x86_cpu_support_iommu(void)
{
	return get_iommu_width() >= SPDK_IOMMU_VA_REQUIRED_WIDTH;
	int rc;
	char cpu_vendor_name[64];

	rc = get_cpu_vendor_name(cpu_vendor_name, sizeof(cpu_vendor_name));
	if (rc != 0) {
		SPDK_ERRLOG("get_cpu_vendor_name failed, return value=%d.\n", rc);
	} else if (strcasestr(cpu_vendor_name, "GenuineIntel") == NULL) {
		/* An X86_64 CPU not from Intel, assume IOMMU supported */
		return true;
	}

	return get_intel_iommu_width() >= SPDK_IOMMU_VA_REQUIRED_WIDTH;
}

#endif