[RESEND PATCH 1/4] iommu/vt-d: Disable SVM in the platform when IOMMUs have inconsistencies

2020-09-30 Thread Kyung Min Park
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 
---
 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 ..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 
+ */
+
+#define pr_fmt(fmt)"DMAR: " fmt
+
+#include 
+#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 ..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 
+ */
+
+/*
+ * Extended Capability Register Mask
+ */
+#define ECAP_FLTS_MASK BIT(47)
+#define ECAP_PASID_MASKBIT(40)
+#define ECAP_EAFS_MASK BIT(34)
+#define ECAP_SRS_MASK

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

2020-09-22 Thread Kyung Min Park
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 
---
 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 ..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 
+ */
+
+#define pr_fmt(fmt)"DMAR: " fmt
+
+#include 
+#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 ..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 
+ */
+
+/*
+ * Extended Capability Register Mask
+ */
+#define ECAP_FLTS_MASK BIT(47)
+#define ECAP_PASID_MASKBIT(40)
+#define ECAP_EAFS_MASK BIT(34)
+#define ECAP_SRS_MASK