[PATCH v2 3/3] iommu/vt-d: Disable SVM in the platform when IOMMUs have inconsistencies

From: Kyung Min Park
Date: Sat Dec 05 2020 - 17:20:01 EST


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@xxxxxxxxx>
---
drivers/iommu/intel/cap_audit.c | 11 +++++++++++
drivers/iommu/intel/cap_audit.h | 6 ++++++
drivers/iommu/intel/svm.c | 3 ++-
3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/intel/cap_audit.c b/drivers/iommu/intel/cap_audit.c
index 0bc77a9bdeed..3bbeb4634bc6 100644
--- a/drivers/iommu/intel/cap_audit.c
+++ b/drivers/iommu/intel/cap_audit.c
@@ -130,6 +130,12 @@ static int cap_audit_hotplug(struct intel_iommu *iommu, enum cap_audit_type type
MINIMAL_FEATURE_HOTPLUG(iommu, ecap, mhmv, ECAP_MHMV_MASK, mismatch);
MINIMAL_FEATURE_HOTPLUG(iommu, ecap, iro, ECAP_IRO_MASK, mismatch);

+ if (IS_ENABLED(CONFIG_INTEL_IOMMU_SVM) &&
+ intel_cap_svm_santiy() && !ecap_svm_sanity(iommu->ecap)) {
+ pr_warn("Abort Hot Plug IOMMU: SVM inconsistent\n");
+ mismatch = true;
+ }
+
out:
if (mismatch) {
intel_iommu_cap_sanity = old_cap;
@@ -206,3 +212,8 @@ bool intel_cap_flts_sanity(void)
{
return ecap_flts(intel_iommu_ecap_sanity);
}
+
+bool intel_cap_svm_santiy(void)
+{
+ return ecap_svm_sanity(intel_iommu_ecap_sanity);
+}
diff --git a/drivers/iommu/intel/cap_audit.h b/drivers/iommu/intel/cap_audit.h
index 1ce1dc314950..beb2589e97e0 100644
--- a/drivers/iommu/intel/cap_audit.h
+++ b/drivers/iommu/intel/cap_audit.h
@@ -60,6 +60,11 @@
#define ECAP_QI_MASK BIT_ULL(1)
#define ECAP_C_MASK BIT_ULL(0)

+#define MINIMAL_SVM_ECAP (ECAP_FLTS_MASK | ECAP_PASID_MASK | ECAP_EAFS_MASK | \
+ ECAP_SRS_MASK | ECAP_ERS_MASK | ECAP_PRS_MASK)
+
+#define ecap_svm_sanity(e) (!(((e) & MINIMAL_SVM_ECAP) ^ MINIMAL_SVM_ECAP))
+
#define DO_CHECK_FEATURE_MISMATCH(a, b, cap, feature, MASK) \
do { \
if (cap##_##feature(a) != cap##_##feature(b)) { \
@@ -107,6 +112,7 @@ bool intel_cap_smts_sanity(void);
bool intel_cap_pasid_sanity(void);
bool intel_cap_nest_sanity(void);
bool intel_cap_flts_sanity(void);
+bool intel_cap_svm_santiy(void);

static inline bool scalable_mode_support(void)
{
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index 3242ebd0bca3..7761e40a2d5a 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -22,6 +22,7 @@
#include <asm/fpu/api.h>

#include "pasid.h"
+#include "cap_audit.h"

static irqreturn_t prq_event_thread(int irq, void *d);
static void intel_svm_drain_prq(struct device *dev, u32 pasid);
@@ -98,7 +99,7 @@ static inline bool intel_svm_capable(struct intel_iommu *iommu)

void intel_svm_check(struct intel_iommu *iommu)
{
- if (!pasid_supported(iommu))
+ if (!intel_cap_svm_santiy())
return;

if (cpu_feature_enabled(X86_FEATURE_GBPAGES) &&
--
2.17.1