aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/dmar.c5
-rw-r--r--drivers/pci/intel-iommu.c29
-rw-r--r--drivers/pci/intr_remapping.c17
-rw-r--r--include/linux/dmar.h2
4 files changed, 49 insertions, 4 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 932e5e3930f..f1805002e43 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -982,7 +982,7 @@ static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
}
#define PRIMARY_FAULT_REG_LEN (16)
-static irqreturn_t dmar_fault(int irq, void *dev_id)
+irqreturn_t dmar_fault(int irq, void *dev_id)
{
struct intel_iommu *iommu = dev_id;
int reg, fault_index;
@@ -1074,9 +1074,6 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
return 0;
}
- /* Force fault register is cleared */
- dmar_fault(irq, iommu);
-
ret = request_irq(irq, dmar_fault, 0, iommu->name, iommu);
if (ret)
printk(KERN_ERR "IOMMU: can't request irq\n");
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 25fc1df486b..ef167b8b047 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -1855,11 +1855,40 @@ static int __init init_dmars(void)
}
}
+ /*
+ * Start from the sane iommu hardware state.
+ */
for_each_drhd_unit(drhd) {
if (drhd->ignored)
continue;
iommu = drhd->iommu;
+
+ /*
+ * If the queued invalidation is already initialized by us
+ * (for example, while enabling interrupt-remapping) then
+ * we got the things already rolling from a sane state.
+ */
+ if (iommu->qi)
+ continue;
+
+ /*
+ * Clear any previous faults.
+ */
+ dmar_fault(-1, iommu);
+ /*
+ * Disable queued invalidation if supported and already enabled
+ * before OS handover.
+ */
+ dmar_disable_qi(iommu);
+ }
+
+ for_each_drhd_unit(drhd) {
+ if (drhd->ignored)
+ continue;
+
+ iommu = drhd->iommu;
+
if (dmar_enable_qi(iommu)) {
/*
* Queued Invalidate not enabled, use Register Based
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c
index 0d202d73a1a..a84686b2478 100644
--- a/drivers/pci/intr_remapping.c
+++ b/drivers/pci/intr_remapping.c
@@ -499,6 +499,23 @@ int __init enable_intr_remapping(int eim)
struct dmar_drhd_unit *drhd;
int setup = 0;
+ for_each_drhd_unit(drhd) {
+ struct intel_iommu *iommu = drhd->iommu;
+
+ /*
+ * Clear previous faults.
+ */
+ dmar_fault(-1, iommu);
+
+ /*
+ * Disable intr remapping and queued invalidation, if already
+ * enabled prior to OS handover.
+ */
+ disable_intr_remapping(iommu);
+
+ dmar_disable_qi(iommu);
+ }
+
/*
* check for the Interrupt-remapping support
*/
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index c7768330c11..8a035aec14a 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -24,6 +24,7 @@
#include <linux/acpi.h>
#include <linux/types.h>
#include <linux/msi.h>
+#include <linux/irqreturn.h>
#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP)
struct intel_iommu;
@@ -125,6 +126,7 @@ extern void dmar_msi_mask(unsigned int irq);
extern void dmar_msi_read(int irq, struct msi_msg *msg);
extern void dmar_msi_write(int irq, struct msi_msg *msg);
extern int dmar_set_interrupt(struct intel_iommu *iommu);
+extern irqreturn_t dmar_fault(int irq, void *dev_id);
extern int arch_setup_dmar_msi(unsigned int irq);
#ifdef CONFIG_DMAR