x86, dmar: start with sane state while enabling dma and interrupt-remapping
authorSuresh Siddha <suresh.b.siddha@intel.com>
Tue, 17 Mar 2009 00:04:57 +0000 (17:04 -0700)
committerH. Peter Anvin <hpa@linux.intel.com>
Tue, 17 Mar 2009 22:39:58 +0000 (15:39 -0700)
Impact: cleanup/sanitization

Start from a sane state while enabling dma and interrupt-remapping, by
clearing the previous recorded faults and disabling previously
enabled queued invalidation and interrupt-remapping.

Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
drivers/pci/dmar.c
drivers/pci/intel-iommu.c
drivers/pci/intr_remapping.c
include/linux/dmar.h

index 932e5e3..f180500 100644 (file)
@@ -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");
index 25fc1df..ef167b8 100644 (file)
@@ -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
index 0d202d7..a84686b 100644 (file)
@@ -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
         */
index c776833..8a035ae 100644 (file)
@@ -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