[RESEND PATCH 3/4] iommu/vt-d: Audit IOMMUs for Interrupt Remapping features

From: Kyung Min Park
Date: Wed Sep 30 2020 - 20:12:02 EST


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@xxxxxxxxx>
---
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