iommu.lists.linux-foundation.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] Audit Capability and Extended Capability among IOMMUs
@ 2020-09-22 21:02 Kyung Min Park
  2020-09-22 21:02 ` [PATCH 1/4] iommu/vt-d: Disable SVM in the platform when IOMMUs have inconsistencies Kyung Min Park
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Kyung Min Park @ 2020-09-22 21:02 UTC (permalink / raw)
  To: linux-kernel, iommu
  Cc: ravi.v.shankar, kevin.tian, ashok.raj, ricardo.neri,
	Kyung Min Park, dwmw2

Modern platforms have more than one IOMMU. Each IOMMU has its own
feature set. Some of these features must be consistent among IOMMUs.
Otherwise, these differences can lead to improper behavior in the system.
On the other hand, for some features, each IOMMU can have different
capacity values. So, different actions are required to deal with the
inconsistencies depending on the IOMMU features.

Currently, some inconsistencies are ignored by the IOMMU driver.
This patchset checks IOMMU capabilities and extended capabilities
centralizedly during boot and take different actions according to
the impacts caused by the mismatches.

For example:
 1. Disable Shared Virtual Memory.
 2. Use common capacity values (normally the lowest capacity value) for
    all IOMMUs.
 3. Report feature mismatches.

Detailed information on the IOMMU Capability / Extended Capability can
be found in Intel VT-d Specification.

Link: https://software.intel.com/sites/default/files/managed/c5/15/vt-directed-io-spec.pdf

Kyung Min Park (4):
  iommu/vt-d: Disable SVM in the platform when IOMMUs have
    inconsistencies
  iommu/vt-d: Report out when IOMMU features have inconsistencies
  iommu/vt-d: Audit IOMMUs for Interrupt Remapping features
  iommu/vt-d: Scale capability to the lowest supported between the
    IOMMUs

 drivers/iommu/intel/Makefile        |   4 +-
 drivers/iommu/intel/audit.c         | 193 ++++++++++++++++++++++++++++
 drivers/iommu/intel/audit.h         | 103 +++++++++++++++
 drivers/iommu/intel/iommu.c         |  12 +-
 drivers/iommu/intel/irq_remapping.c |   8 ++
 include/linux/intel-iommu.h         |   3 +
 6 files changed, 320 insertions(+), 3 deletions(-)
 create mode 100644 drivers/iommu/intel/audit.c
 create mode 100644 drivers/iommu/intel/audit.h

-- 
2.17.1

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/4] iommu/vt-d: Disable SVM in the platform when IOMMUs have inconsistencies
  2020-09-22 21:02 [PATCH 0/4] Audit Capability and Extended Capability among IOMMUs Kyung Min Park
@ 2020-09-22 21:02 ` Kyung Min Park
  2020-09-22 21:02 ` [PATCH 2/4] iommu/vt-d: Report out when IOMMU features " Kyung Min Park
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Kyung Min Park @ 2020-09-22 21:02 UTC (permalink / raw)
  To: linux-kernel, iommu
  Cc: ravi.v.shankar, kevin.tian, ashok.raj, ricardo.neri,
	Kyung Min Park, dwmw2

Some IOMMU Capabilities must be consistent for Shared Virtual Memory (SVM).
Audit IOMMU Capability/Extended Capabilities and check if IOMMUs have
the consistent value for features as below. When the features are not
matched among IOMMUs, disable SVMs in the platform during DMAR
initialization. Audit IOMMUs again when a device is hot plugged.

Disable Shared Virtual Memory when below features are mistmatched:
  - First Level Translation Support (FLTS)
  - Process Address Space ID Support (PASID)
  - Extended Accessed Flag Support (EAFS)
  - Supervisor Support (SRS)
  - Execute Request Support (ERS)
  - Page Request Support (PRS)

Signed-off-by: Kyung Min Park <kyung.min.park@intel.com>
---
 drivers/iommu/intel/Makefile |  2 +-
 drivers/iommu/intel/audit.c  | 95 ++++++++++++++++++++++++++++++++++++
 drivers/iommu/intel/audit.h  | 29 +++++++++++
 drivers/iommu/intel/iommu.c  | 12 ++++-
 4 files changed, 136 insertions(+), 2 deletions(-)
 create mode 100644 drivers/iommu/intel/audit.c
 create mode 100644 drivers/iommu/intel/audit.h

diff --git a/drivers/iommu/intel/Makefile b/drivers/iommu/intel/Makefile
index fb8e1e8c8029..02c26acb479f 100644
--- a/drivers/iommu/intel/Makefile
+++ b/drivers/iommu/intel/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_DMAR_TABLE) += dmar.o
-obj-$(CONFIG_INTEL_IOMMU) += iommu.o pasid.o
+obj-$(CONFIG_INTEL_IOMMU) += iommu.o pasid.o audit.o
 obj-$(CONFIG_INTEL_IOMMU) += trace.o
 obj-$(CONFIG_INTEL_IOMMU_DEBUGFS) += debugfs.o
 obj-$(CONFIG_INTEL_IOMMU_SVM) += svm.o
diff --git a/drivers/iommu/intel/audit.c b/drivers/iommu/intel/audit.c
new file mode 100644
index 000000000000..2893170f5b6c
--- /dev/null
+++ b/drivers/iommu/intel/audit.c
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * audit.c - audit iommu capabilities for boot time and hot plug
+ *
+ * Copyright (C) 2020 Intel Corporation
+ *
+ * Author: Kyung Min Park <kyung.min.park@intel.com>
+ */
+
+#define pr_fmt(fmt)	"DMAR: " fmt
+
+#include <linux/intel-iommu.h>
+#include "audit.h"
+
+static bool svm_sanity_check = true;
+static u64 intel_iommu_ecap_sanity = ~0ULL;
+
+static void set_cap_audit_svm_sanity(bool svm_sanity)
+{
+	svm_sanity_check = svm_sanity;
+}
+
+bool get_cap_audit_svm_sanity(void)
+{
+	return svm_sanity_check;
+}
+
+static inline void check_dmar_capabilities(struct intel_iommu *a,
+					   struct intel_iommu *b)
+{
+	if (MINIMAL_SVM_ECAP & (a->ecap ^ b->ecap))
+		set_cap_audit_svm_sanity(false);
+}
+
+static int audit_iommu_capabilities_hotplug(struct intel_iommu *hot_iommu)
+{
+	bool mismatch = false;
+
+	if (!IS_ENABLED(CONFIG_INTEL_IOMMU_SVM))
+		goto out;
+
+	if (!get_cap_audit_svm_sanity() && (hot_iommu->flags & VTD_FLAG_SVM_CAPABLE)) {
+		pr_warn("Disable SVM in the IOMMU: SVM disabled at boot time.\n");
+		hot_iommu->flags = hot_iommu->flags & ~VTD_FLAG_SVM_CAPABLE;
+	} else if (get_cap_audit_svm_sanity() && (MINIMAL_SVM_ECAP &
+		   (hot_iommu->ecap ^ intel_iommu_ecap_sanity))) {
+		pr_warn("Abort Hot Plug IOMMU: SVM inconsistent.\n");
+		mismatch = true;
+	}
+
+out:
+	if (mismatch)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int audit_iommu_capabilities(void)
+{
+	struct dmar_drhd_unit *first_drhd, *drhd;
+	struct intel_iommu *iommu;
+	int ret = -EFAULT;
+
+	rcu_read_lock();
+	first_drhd = list_first_or_null_rcu(&dmar_drhd_units, typeof(*drhd),
+					    list);
+	if (!first_drhd) {
+		ret = 0;
+		goto out;
+	}
+
+	for_each_active_iommu(iommu, drhd)
+		check_dmar_capabilities(first_drhd->iommu, iommu);
+
+	if (get_cap_audit_svm_sanity())
+		intel_iommu_ecap_sanity = (intel_iommu_ecap_sanity & ~MINIMAL_SVM_ECAP) |
+					   (first_drhd->iommu->ecap & MINIMAL_SVM_ECAP);
+
+	ret = 0;
+out:
+	rcu_read_unlock();
+	return ret;
+}
+
+int intel_iommu_audit_capabilities(enum cap_audit_type type, struct intel_iommu *iommu)
+{
+	switch (type) {
+	case CAP_AUDIT_STATIC_DMAR:
+		return audit_iommu_capabilities();
+	case CAP_AUDIT_HOTPLUG_DMAR:
+		return audit_iommu_capabilities_hotplug(iommu);
+	default:
+		return -EFAULT;
+	}
+}
diff --git a/drivers/iommu/intel/audit.h b/drivers/iommu/intel/audit.h
new file mode 100644
index 000000000000..887900d9517d
--- /dev/null
+++ b/drivers/iommu/intel/audit.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * audit.h - audit iommu capabilities header
+ *
+ * Copyright (C) 2020 Intel Corporation
+ *
+ * Author: Kyung Min Park <kyung.min.park@intel.com>
+ */
+
+/*
+ * Extended Capability Register Mask
+ */
+#define ECAP_FLTS_MASK		BIT(47)
+#define ECAP_PASID_MASK		BIT(40)
+#define ECAP_EAFS_MASK		BIT(34)
+#define ECAP_SRS_MASK		BIT(31)
+#define ECAP_ERS_MASK		BIT(30)
+#define ECAP_PRS_MASK		BIT(29)
+
+#define MINIMAL_SVM_ECAP (ECAP_FLTS_MASK | ECAP_PASID_MASK | ECAP_EAFS_MASK | \
+			  ECAP_SRS_MASK | ECAP_ERS_MASK | ECAP_PRS_MASK)
+
+enum cap_audit_type {
+	CAP_AUDIT_STATIC_DMAR,
+	CAP_AUDIT_HOTPLUG_DMAR,
+};
+
+int intel_iommu_audit_capabilities(enum cap_audit_type type, struct intel_iommu *iommu);
+bool get_cap_audit_svm_sanity(void);
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 87b17bac04c2..ab8300ee9791 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -49,6 +49,7 @@
 
 #include "../irq_remapping.h"
 #include "pasid.h"
+#include "audit.h"
 
 #define ROOT_SIZE		VTD_PAGE_SIZE
 #define CONTEXT_SIZE		VTD_PAGE_SIZE
@@ -3230,6 +3231,10 @@ static int __init init_dmars(void)
 		goto error;
 	}
 
+	ret = intel_iommu_audit_capabilities(CAP_AUDIT_STATIC_DMAR, NULL);
+	if (ret)
+		goto free_iommu;
+
 	for_each_iommu(iommu, drhd) {
 		if (drhd->ignored) {
 			iommu_disable_translation(iommu);
@@ -3300,7 +3305,8 @@ static int __init init_dmars(void)
 
 		if (!ecap_pass_through(iommu->ecap))
 			hw_pass_through = 0;
-		intel_svm_check(iommu);
+		if (get_cap_audit_svm_sanity())
+			intel_svm_check(iommu);
 	}
 
 	/*
@@ -4366,6 +4372,10 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru)
 	if (g_iommus[iommu->seq_id])
 		return 0;
 
+	ret = intel_iommu_audit_capabilities(CAP_AUDIT_HOTPLUG_DMAR, iommu);
+	if (ret)
+		goto out;
+
 	if (hw_pass_through && !ecap_pass_through(iommu->ecap)) {
 		pr_warn("%s: Doesn't support hardware pass through.\n",
 			iommu->name);
-- 
2.17.1

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/4] iommu/vt-d: Report out when IOMMU features have inconsistencies
  2020-09-22 21:02 [PATCH 0/4] Audit Capability and Extended Capability among IOMMUs Kyung Min Park
  2020-09-22 21:02 ` [PATCH 1/4] iommu/vt-d: Disable SVM in the platform when IOMMUs have inconsistencies Kyung Min Park
@ 2020-09-22 21:02 ` Kyung Min Park
  2020-09-22 21:02 ` [PATCH 3/4] iommu/vt-d: Audit IOMMUs for Interrupt Remapping features Kyung Min Park
  2020-09-22 21:02 ` [PATCH 4/4] iommu/vt-d: Scale capability to the lowest supported between the IOMMUs Kyung Min Park
  3 siblings, 0 replies; 5+ messages in thread
From: Kyung Min Park @ 2020-09-22 21:02 UTC (permalink / raw)
  To: linux-kernel, iommu
  Cc: ravi.v.shankar, kevin.tian, ashok.raj, ricardo.neri,
	Kyung Min Park, dwmw2

IOMMU features as below can have incompatibilities among IOMMUs.
Audit IOMMU Capability/Extended Capability and check if the IOMMUs have
the consistent value for features as below. Report out when features as
below have incompatibility among IOMMUs.

Report out features when below features are mismatched:
  - First Level 5 Level Paging Support (FL5LP)
  - First Level 1 GByte Page Support (FL1GP)
  - Read Draining (DRD)
  - Write Draining (DWD)
  - Page Selective Invalidation (PSI)
  - Caching Mode (CM)
  - Protected High/Low-Memory Region (PHMR/PLMR)
  - Scalable Mode Page Walk Coherency (SMPWC)
  - First Level Translation Support (FLTS)
  - Second Level Translation Support (SLTS)
  - Second Level Accessed/Dirty Support (SLADS)
  - Virtual Command Support (VCS)
  - Scalable Mode Translation Support (SMTS)
  - Device TLB Invalidation Throttle (DIT)
  - Page Drain Support (PDS)
  - Nested Translation Support (NEST)
  - Snoop Control (SC)
  - Pass Through (PT)
  - Device TLB Support (DT)
  - Queued Invalidation (QI)
  - Page walk Coherency (C)

Signed-off-by: Kyung Min Park <kyung.min.park@intel.com>
---
 drivers/iommu/intel/audit.c | 48 +++++++++++++++++++++++++++++++++++++
 drivers/iommu/intel/audit.h | 43 +++++++++++++++++++++++++++++++++
 include/linux/intel-iommu.h |  2 ++
 3 files changed, 93 insertions(+)

diff --git a/drivers/iommu/intel/audit.c b/drivers/iommu/intel/audit.c
index 2893170f5b6c..f783acabb402 100644
--- a/drivers/iommu/intel/audit.c
+++ b/drivers/iommu/intel/audit.c
@@ -13,6 +13,8 @@
 #include "audit.h"
 
 static bool svm_sanity_check = true;
+/* global variables that hold feature consistency and minimum features */
+static u64 intel_iommu_cap_sanity = ~0ULL;
 static u64 intel_iommu_ecap_sanity = ~0ULL;
 
 static void set_cap_audit_svm_sanity(bool svm_sanity)
@@ -30,12 +32,58 @@ static inline void check_dmar_capabilities(struct intel_iommu *a,
 {
 	if (MINIMAL_SVM_ECAP & (a->ecap ^ b->ecap))
 		set_cap_audit_svm_sanity(false);
+
+	CHECK_FEATURE_MISMATCH(a, b, cap, 5lp_support, CAP_FL5LP_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, cap, fl1gp_support, CAP_FL1GP_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, cap, read_drain, CAP_RD_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, cap, write_drain, CAP_WD_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, cap, pgsel_inv, CAP_PSI_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, cap, caching_mode, CAP_CM_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, cap, phmr, CAP_PHMR_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, cap, plmr, CAP_PLMR_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, smpwc, ECAP_SMPWC_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, flts, ECAP_FLTS_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, slts, ECAP_SLTS_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, slads, ECAP_SLADS_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, vcs, ECAP_VCS_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, smts, ECAP_SMTS_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, pds, ECAP_PDS_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, dit, ECAP_DIT_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, nest, ECAP_NEST_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, sc_support, ECAP_SC_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, pass_through, ECAP_PT_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, dev_iotlb_support, ECAP_DT_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, qis, ECAP_QI_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, coherent, ECAP_C_MASK);
 }
 
 static int audit_iommu_capabilities_hotplug(struct intel_iommu *hot_iommu)
 {
 	bool mismatch = false;
 
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, cap, 5lp_support, CAP_FL5LP_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, cap, fl1gp_support, CAP_FL1GP_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, cap, read_drain, CAP_RD_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, cap, write_drain, CAP_WD_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, cap, pgsel_inv, CAP_PSI_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, cap, caching_mode, CAP_CM_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, cap, phmr, CAP_PHMR_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, cap, plmr, CAP_PLMR_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, smpwc, ECAP_SMPWC_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, flts, ECAP_FLTS_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, slts, ECAP_SLTS_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, slads, ECAP_SLADS_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, vcs, ECAP_VCS_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, smts, ECAP_SMTS_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, pds, ECAP_PDS_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, dit, ECAP_DIT_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, nest, ECAP_NEST_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, sc_support, ECAP_SC_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, pass_through, ECAP_PT_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, dev_iotlb_support, ECAP_DT_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, qis, ECAP_QI_MASK);
+	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, coherent, ECAP_C_MASK);
+
 	if (!IS_ENABLED(CONFIG_INTEL_IOMMU_SVM))
 		goto out;
 
diff --git a/drivers/iommu/intel/audit.h b/drivers/iommu/intel/audit.h
index 887900d9517d..e3a370405f82 100644
--- a/drivers/iommu/intel/audit.h
+++ b/drivers/iommu/intel/audit.h
@@ -7,19 +7,62 @@
  * Author: Kyung Min Park <kyung.min.park@intel.com>
  */
 
+/*
+ * Capability Register Mask
+ */
+#define CAP_FL5LP_MASK		BIT(60)
+#define CAP_FL1GP_MASK		BIT(56)
+#define CAP_RD_MASK		BIT(55)
+#define CAP_WD_MASK		BIT(54)
+#define CAP_PSI_MASK		BIT(39)
+#define CAP_CM_MASK		BIT(7)
+#define CAP_PHMR_MASK		BIT(6)
+#define CAP_PLMR_MASK		BIT(5)
+
 /*
  * Extended Capability Register Mask
  */
+#define ECAP_SMPWC_MASK		BIT(48)
 #define ECAP_FLTS_MASK		BIT(47)
+#define ECAP_SLTS_MASK		BIT(46)
+#define ECAP_SLADS_MASK		BIT(45)
+#define ECAP_VCS_MASK		BIT(44)
+#define ECAP_SMTS_MASK		BIT(43)
+#define ECAP_PDS_MASK		BIT(42)
+#define ECAP_DIT_MASK		BIT(41)
 #define ECAP_PASID_MASK		BIT(40)
 #define ECAP_EAFS_MASK		BIT(34)
 #define ECAP_SRS_MASK		BIT(31)
 #define ECAP_ERS_MASK		BIT(30)
 #define ECAP_PRS_MASK		BIT(29)
+#define ECAP_NEST_MASK		BIT(26)
+#define ECAP_SC_MASK		BIT(7)
+#define ECAP_PT_MASK		BIT(6)
+#define ECAP_DT_MASK		BIT(2)
+#define ECAP_QI_MASK		BIT(1)
+#define ECAP_C_MASK		BIT(0)
 
 #define MINIMAL_SVM_ECAP (ECAP_FLTS_MASK | ECAP_PASID_MASK | ECAP_EAFS_MASK | \
 			  ECAP_SRS_MASK | ECAP_ERS_MASK | ECAP_PRS_MASK)
 
+#define DO_CHECK_FEATURE_MISMATCH(a, b, cap, feature, MASK) \
+do { \
+	if (cap##_##feature(a) != cap##_##feature(b)) { \
+		intel_iommu_##cap##_sanity &= ~(MASK); \
+		pr_info("IOMMU feature %s inconsistent.", #feature); \
+	} \
+} while (0)
+
+#define CHECK_FEATURE_MISMATCH(a, b, cap, feature, MASK) \
+	DO_CHECK_FEATURE_MISMATCH((a)->cap, (b)->cap, cap, feature, MASK)
+
+#define CHECK_FEATURE_MISMATCH_HOTPLUG(b, cap, feature, MASK) \
+do { \
+	if (cap##_##feature(intel_iommu_##cap##_sanity)) \
+		DO_CHECK_FEATURE_MISMATCH(intel_iommu_##cap##_sanity, \
+					  (b)->cap, cap, feature, MASK); \
+} while (0)
+
 enum cap_audit_type {
 	CAP_AUDIT_STATIC_DMAR,
 	CAP_AUDIT_HOTPLUG_DMAR,
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index b1ed2f25f7c0..6744f00a144a 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -171,8 +171,10 @@
 #define ecap_smpwc(e)		(((e) >> 48) & 0x1)
 #define ecap_flts(e)		(((e) >> 47) & 0x1)
 #define ecap_slts(e)		(((e) >> 46) & 0x1)
+#define ecap_slads(e)		(((e) >> 45) & 0x1)
 #define ecap_vcs(e)		(((e) >> 44) & 0x1)
 #define ecap_smts(e)		(((e) >> 43) & 0x1)
+#define ecap_pds(e)		(((e) >> 42) & 0x1)
 #define ecap_dit(e)		((e >> 41) & 0x1)
 #define ecap_pasid(e)		((e >> 40) & 0x1)
 #define ecap_pss(e)		((e >> 35) & 0x1f)
-- 
2.17.1

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/4] iommu/vt-d: Audit IOMMUs for Interrupt Remapping features
  2020-09-22 21:02 [PATCH 0/4] Audit Capability and Extended Capability among IOMMUs Kyung Min Park
  2020-09-22 21:02 ` [PATCH 1/4] iommu/vt-d: Disable SVM in the platform when IOMMUs have inconsistencies Kyung Min Park
  2020-09-22 21:02 ` [PATCH 2/4] iommu/vt-d: Report out when IOMMU features " Kyung Min Park
@ 2020-09-22 21:02 ` Kyung Min Park
  2020-09-22 21:02 ` [PATCH 4/4] iommu/vt-d: Scale capability to the lowest supported between the IOMMUs Kyung Min Park
  3 siblings, 0 replies; 5+ messages in thread
From: Kyung Min Park @ 2020-09-22 21:02 UTC (permalink / raw)
  To: linux-kernel, iommu
  Cc: ravi.v.shankar, kevin.tian, ashok.raj, ricardo.neri,
	Kyung Min Park, dwmw2

Audit IOMMU Capability/Extended Capabilities for Interrupt Remapping.
Check if the IOMMUs have the consistent value for the features as below.
When the features are not matched among IOMMUs, report out the IOMMU
features during irq remapping initialization. Audit IOMMUs again
when a device is hot plugged.

Report out features when below features are mismatched:
  - Posted Interrupts (PI)
  - Extended Interrupt Mode (EIM)

Signed-off-by: Kyung Min Park <kyung.min.park@intel.com>
---
 drivers/iommu/intel/Makefile        |  2 +-
 drivers/iommu/intel/audit.c         | 39 ++++++++++++++++++++++++-----
 drivers/iommu/intel/audit.h         |  4 +++
 drivers/iommu/intel/irq_remapping.c |  8 ++++++
 4 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/intel/Makefile b/drivers/iommu/intel/Makefile
index 02c26acb479f..b5760c4abc54 100644
--- a/drivers/iommu/intel/Makefile
+++ b/drivers/iommu/intel/Makefile
@@ -4,4 +4,4 @@ obj-$(CONFIG_INTEL_IOMMU) += iommu.o pasid.o audit.o
 obj-$(CONFIG_INTEL_IOMMU) += trace.o
 obj-$(CONFIG_INTEL_IOMMU_DEBUGFS) += debugfs.o
 obj-$(CONFIG_INTEL_IOMMU_SVM) += svm.o
-obj-$(CONFIG_IRQ_REMAP) += irq_remapping.o
+obj-$(CONFIG_IRQ_REMAP) += irq_remapping.o audit.o
diff --git a/drivers/iommu/intel/audit.c b/drivers/iommu/intel/audit.c
index f783acabb402..e005bc61770a 100644
--- a/drivers/iommu/intel/audit.c
+++ b/drivers/iommu/intel/audit.c
@@ -27,6 +27,13 @@ bool get_cap_audit_svm_sanity(void)
 	return svm_sanity_check;
 }
 
+static inline void check_irq_capabilities(struct intel_iommu *a,
+					  struct intel_iommu *b)
+{
+	CHECK_FEATURE_MISMATCH(a, b, cap, pi_support, CAP_PI_MASK);
+	CHECK_FEATURE_MISMATCH(a, b, ecap, eim_support, ECAP_EIM_MASK);
+}
+
 static inline void check_dmar_capabilities(struct intel_iommu *a,
 					   struct intel_iommu *b)
 {
@@ -57,10 +64,17 @@ static inline void check_dmar_capabilities(struct intel_iommu *a,
 	CHECK_FEATURE_MISMATCH(a, b, ecap, coherent, ECAP_C_MASK);
 }
 
-static int audit_iommu_capabilities_hotplug(struct intel_iommu *hot_iommu)
+static int audit_iommu_capabilities_hotplug(struct intel_iommu *hot_iommu,
+					    bool audit_irq)
 {
 	bool mismatch = false;
 
+	if (audit_irq) {
+		CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, cap, pi_support, CAP_PI_MASK);
+		CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, eim_support, ECAP_EIM_MASK);
+		goto out;
+	}
+
 	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, cap, 5lp_support, CAP_FL5LP_MASK);
 	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, cap, fl1gp_support, CAP_FL1GP_MASK);
 	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, cap, read_drain, CAP_RD_MASK);
@@ -103,7 +117,7 @@ static int audit_iommu_capabilities_hotplug(struct intel_iommu *hot_iommu)
 	return 0;
 }
 
-static int audit_iommu_capabilities(void)
+static int audit_iommu_capabilities(bool audit_irq)
 {
 	struct dmar_drhd_unit *first_drhd, *drhd;
 	struct intel_iommu *iommu;
@@ -117,8 +131,17 @@ static int audit_iommu_capabilities(void)
 		goto out;
 	}
 
-	for_each_active_iommu(iommu, drhd)
-		check_dmar_capabilities(first_drhd->iommu, iommu);
+	for_each_active_iommu(iommu, drhd) {
+		if (audit_irq)
+			check_irq_capabilities(first_drhd->iommu, iommu);
+		else
+			check_dmar_capabilities(first_drhd->iommu, iommu);
+	}
+
+	if (audit_irq) {
+		ret = 0;
+		goto out;
+	}
 
 	if (get_cap_audit_svm_sanity())
 		intel_iommu_ecap_sanity = (intel_iommu_ecap_sanity & ~MINIMAL_SVM_ECAP) |
@@ -134,9 +157,13 @@ int intel_iommu_audit_capabilities(enum cap_audit_type type, struct intel_iommu
 {
 	switch (type) {
 	case CAP_AUDIT_STATIC_DMAR:
-		return audit_iommu_capabilities();
+		return audit_iommu_capabilities(false);
+	case CAP_AUDIT_STATIC_IRQR:
+		return audit_iommu_capabilities(true);
 	case CAP_AUDIT_HOTPLUG_DMAR:
-		return audit_iommu_capabilities_hotplug(iommu);
+		return audit_iommu_capabilities_hotplug(iommu, false);
+	case CAP_AUDIT_HOTPLUG_IRQR:
+		return audit_iommu_capabilities_hotplug(iommu, true);
 	default:
 		return -EFAULT;
 	}
diff --git a/drivers/iommu/intel/audit.h b/drivers/iommu/intel/audit.h
index e3a370405f82..6dfebe8e8fbe 100644
--- a/drivers/iommu/intel/audit.h
+++ b/drivers/iommu/intel/audit.h
@@ -11,6 +11,7 @@
  * Capability Register Mask
  */
 #define CAP_FL5LP_MASK		BIT(60)
+#define CAP_PI_MASK		BIT(59)
 #define CAP_FL1GP_MASK		BIT(56)
 #define CAP_RD_MASK		BIT(55)
 #define CAP_WD_MASK		BIT(54)
@@ -38,6 +39,7 @@
 #define ECAP_NEST_MASK		BIT(26)
 #define ECAP_SC_MASK		BIT(7)
 #define ECAP_PT_MASK		BIT(6)
+#define ECAP_EIM_MASK		BIT(4)
 #define ECAP_DT_MASK		BIT(2)
 #define ECAP_QI_MASK		BIT(1)
 #define ECAP_C_MASK		BIT(0)
@@ -65,7 +67,9 @@ do { \
 
 enum cap_audit_type {
 	CAP_AUDIT_STATIC_DMAR,
+	CAP_AUDIT_STATIC_IRQR,
 	CAP_AUDIT_HOTPLUG_DMAR,
+	CAP_AUDIT_HOTPLUG_IRQR,
 };
 
 int intel_iommu_audit_capabilities(enum cap_audit_type type, struct intel_iommu *iommu);
diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c
index 8f4ce72570ce..7c77e0754896 100644
--- a/drivers/iommu/intel/irq_remapping.c
+++ b/drivers/iommu/intel/irq_remapping.c
@@ -23,6 +23,7 @@
 #include <asm/msidef.h>
 
 #include "../irq_remapping.h"
+#include "audit.h"
 
 enum irq_mode {
 	IRQ_REMAPPING,
@@ -737,6 +738,9 @@ static int __init intel_prepare_irq_remapping(void)
 	if (dmar_table_init() < 0)
 		return -ENODEV;
 
+	if (intel_iommu_audit_capabilities(CAP_AUDIT_STATIC_IRQR, NULL))
+		goto error;
+
 	if (!dmar_ir_support())
 		return -ENODEV;
 
@@ -1470,6 +1474,10 @@ static int dmar_ir_add(struct dmar_drhd_unit *dmaru, struct intel_iommu *iommu)
 	int ret;
 	int eim = x2apic_enabled();
 
+	ret = intel_iommu_audit_capabilities(CAP_AUDIT_HOTPLUG_IRQR, iommu);
+	if (ret)
+		return ret;
+
 	if (eim && !ecap_eim_support(iommu->ecap)) {
 		pr_info("DRHD %Lx: EIM not supported by DRHD, ecap %Lx\n",
 			iommu->reg_phys, iommu->ecap);
-- 
2.17.1

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 4/4] iommu/vt-d: Scale capability to the lowest supported between the IOMMUs
  2020-09-22 21:02 [PATCH 0/4] Audit Capability and Extended Capability among IOMMUs Kyung Min Park
                   ` (2 preceding siblings ...)
  2020-09-22 21:02 ` [PATCH 3/4] iommu/vt-d: Audit IOMMUs for Interrupt Remapping features Kyung Min Park
@ 2020-09-22 21:02 ` Kyung Min Park
  3 siblings, 0 replies; 5+ messages in thread
From: Kyung Min Park @ 2020-09-22 21:02 UTC (permalink / raw)
  To: linux-kernel, iommu
  Cc: ravi.v.shankar, kevin.tian, ashok.raj, ricardo.neri,
	Kyung Min Park, dwmw2

Audit IOMMU Capability/Extended Capabilities and check if the IOMMUs
have the consistent value for features as below. Find common denominator
for the features and set to the lowest supported value for each IOMMU.

Abort hot plug when the hot plugged IOMMU does not meet the aforementioned
common denominator.

Set capability to the lowest supported when below features are mismatched:
  - Maximum Address Mask Value (MAMV)
  - Second Level Large Page Support (SLLPS)
  - Maximum Guest Address Width (MGAW)
  - Supported Adjusted Guest Address Width (SAGAW)
  - Number of Domains supported (ND)
  - Pasid Size Supported (PSS)

Signed-off-by: Kyung Min Park <kyung.min.park@intel.com>
---
 drivers/iommu/intel/audit.c | 23 +++++++++++++++++++++++
 drivers/iommu/intel/audit.h | 27 +++++++++++++++++++++++++++
 include/linux/intel-iommu.h |  1 +
 3 files changed, 51 insertions(+)

diff --git a/drivers/iommu/intel/audit.c b/drivers/iommu/intel/audit.c
index e005bc61770a..7e12c963c2b7 100644
--- a/drivers/iommu/intel/audit.c
+++ b/drivers/iommu/intel/audit.c
@@ -40,6 +40,13 @@ static inline void check_dmar_capabilities(struct intel_iommu *a,
 	if (MINIMAL_SVM_ECAP & (a->ecap ^ b->ecap))
 		set_cap_audit_svm_sanity(false);
 
+	MINIMAL_FEATURE_IOMMU(b, cap, CAP_MAMV_MASK);
+	MINIMAL_FEATURE_IOMMU(b, cap, CAP_SLLPS_MASK);
+	MINIMAL_FEATURE_IOMMU(b, cap, CAP_MGAW_MASK);
+	MINIMAL_FEATURE_IOMMU(b, cap, CAP_SAGAW_MASK);
+	MINIMAL_FEATURE_IOMMU(b, cap, CAP_NDOMS_MASK);
+	MINIMAL_FEATURE_IOMMU(b, ecap, ECAP_PSS_MASK);
+
 	CHECK_FEATURE_MISMATCH(a, b, cap, 5lp_support, CAP_FL5LP_MASK);
 	CHECK_FEATURE_MISMATCH(a, b, cap, fl1gp_support, CAP_FL1GP_MASK);
 	CHECK_FEATURE_MISMATCH(a, b, cap, read_drain, CAP_RD_MASK);
@@ -98,6 +105,14 @@ static int audit_iommu_capabilities_hotplug(struct intel_iommu *hot_iommu,
 	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, qis, ECAP_QI_MASK);
 	CHECK_FEATURE_MISMATCH_HOTPLUG(hot_iommu, ecap, coherent, ECAP_C_MASK);
 
+	/* Abort hot plug if the hot plug iommu feature is smaller than global */
+	MINIMAL_FEATURE_HOTPLUG(hot_iommu, cap, mamv, CAP_MAMV_MASK, mismatch);
+	MINIMAL_FEATURE_HOTPLUG(hot_iommu, cap, super_page_val, CAP_SLLPS_MASK, mismatch);
+	MINIMAL_FEATURE_HOTPLUG(hot_iommu, cap, mgaw, CAP_MGAW_MASK, mismatch);
+	MINIMAL_FEATURE_HOTPLUG(hot_iommu, cap, sagaw, CAP_SAGAW_MASK, mismatch);
+	MINIMAL_FEATURE_HOTPLUG(hot_iommu, cap, ndoms, CAP_NDOMS_MASK, mismatch);
+	MINIMAL_FEATURE_HOTPLUG(hot_iommu, ecap, pss, ECAP_PSS_MASK, mismatch);
+
 	if (!IS_ENABLED(CONFIG_INTEL_IOMMU_SVM))
 		goto out;
 
@@ -147,6 +162,14 @@ static int audit_iommu_capabilities(bool audit_irq)
 		intel_iommu_ecap_sanity = (intel_iommu_ecap_sanity & ~MINIMAL_SVM_ECAP) |
 					   (first_drhd->iommu->ecap & MINIMAL_SVM_ECAP);
 
+	/* scale capability to the lowest supported value */
+	for_each_active_iommu(iommu, drhd) {
+		iommu->cap = (intel_iommu_cap_sanity & MINIMAL_FEATURE_CAP) |
+			     (~MINIMAL_FEATURE_CAP & iommu->cap);
+		iommu->ecap = (intel_iommu_ecap_sanity & ECAP_PSS_MASK) |
+			      (~ECAP_PSS_MASK & iommu->ecap);
+	}
+
 	ret = 0;
 out:
 	rcu_read_unlock();
diff --git a/drivers/iommu/intel/audit.h b/drivers/iommu/intel/audit.h
index 6dfebe8e8fbe..a293e71ce9ab 100644
--- a/drivers/iommu/intel/audit.h
+++ b/drivers/iommu/intel/audit.h
@@ -13,9 +13,14 @@
 #define CAP_FL5LP_MASK		BIT(60)
 #define CAP_PI_MASK		BIT(59)
 #define CAP_FL1GP_MASK		BIT(56)
+#define CAP_MAMV_MASK		GENMASK_ULL(53, 48)
 #define CAP_RD_MASK		BIT(55)
 #define CAP_WD_MASK		BIT(54)
 #define CAP_PSI_MASK		BIT(39)
+#define CAP_SLLPS_MASK		GENMASK_ULL(37, 34)
+#define CAP_MGAW_MASK		GENMASK_ULL(21, 16)
+#define CAP_SAGAW_MASK		GENMASK_ULL(12, 8)
+#define CAP_NDOMS_MASK		GENMASK_ULL(2, 0)
 #define CAP_CM_MASK		BIT(7)
 #define CAP_PHMR_MASK		BIT(6)
 #define CAP_PLMR_MASK		BIT(5)
@@ -32,6 +37,7 @@
 #define ECAP_PDS_MASK		BIT(42)
 #define ECAP_DIT_MASK		BIT(41)
 #define ECAP_PASID_MASK		BIT(40)
+#define ECAP_PSS_MASK		GENMASK_ULL(39, 35)
 #define ECAP_EAFS_MASK		BIT(34)
 #define ECAP_SRS_MASK		BIT(31)
 #define ECAP_ERS_MASK		BIT(30)
@@ -47,6 +53,9 @@
 #define MINIMAL_SVM_ECAP (ECAP_FLTS_MASK | ECAP_PASID_MASK | ECAP_EAFS_MASK | \
 			  ECAP_SRS_MASK | ECAP_ERS_MASK | ECAP_PRS_MASK)
 
+#define MINIMAL_FEATURE_CAP (CAP_MAMV_MASK | CAP_SLLPS_MASK | CAP_MGAW_MASK | \
+			     CAP_SAGAW_MASK | CAP_NDOMS_MASK)
+
 #define DO_CHECK_FEATURE_MISMATCH(a, b, cap, feature, MASK) \
 do { \
 	if (cap##_##feature(a) != cap##_##feature(b)) { \
@@ -65,6 +74,24 @@ do { \
 					  (b)->cap, cap, feature, MASK); \
 } while (0)
 
+#define MINIMAL_FEATURE_IOMMU(iommu, cap, MASK) \
+do { \
+	u64 min_feature = intel_iommu_##cap##_sanity & MASK; \
+	min_feature = min_t(u64, min_feature, (iommu)->cap & (MASK)); \
+	intel_iommu_##cap##_sanity = (intel_iommu_##cap##_sanity & ~(MASK)) | \
+				     min_feature; \
+} while (0)
+
+#define MINIMAL_FEATURE_HOTPLUG(iommu, cap, feature, MASK, mismatch) \
+do { \
+	if ((intel_iommu_##cap##_sanity & (MASK)) > \
+	    (cap##_##feature((iommu)->cap))) \
+		mismatch = true; \
+	else \
+		(iommu)->cap = ((iommu)->cap & ~(MASK)) | \
+		(intel_iommu_##cap##_sanity & (MASK)); \
+} while (0)
+
 enum cap_audit_type {
 	CAP_AUDIT_STATIC_DMAR,
 	CAP_AUDIT_STATIC_IRQR,
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 6744f00a144a..297a10091bb5 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -154,6 +154,7 @@
 #define cap_max_fault_reg_offset(c) \
 	(cap_fault_reg_offset(c) + cap_num_fault_regs(c) * 16)
 
+#define cap_mamv(c)		(((c) >> 48) & 0x3f)
 #define cap_zlr(c)		(((c) >> 22) & 1)
 #define cap_isoch(c)		(((c) >> 23) & 1)
 #define cap_mgaw(c)		((((c) >> 16) & 0x3f) + 1)
-- 
2.17.1

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-09-22 21:21 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-22 21:02 [PATCH 0/4] Audit Capability and Extended Capability among IOMMUs Kyung Min Park
2020-09-22 21:02 ` [PATCH 1/4] iommu/vt-d: Disable SVM in the platform when IOMMUs have inconsistencies Kyung Min Park
2020-09-22 21:02 ` [PATCH 2/4] iommu/vt-d: Report out when IOMMU features " Kyung Min Park
2020-09-22 21:02 ` [PATCH 3/4] iommu/vt-d: Audit IOMMUs for Interrupt Remapping features Kyung Min Park
2020-09-22 21:02 ` [PATCH 4/4] iommu/vt-d: Scale capability to the lowest supported between the IOMMUs Kyung Min Park

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).