x86, dmar: start with sane state while enabling dma and interrupt-remapping
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>
This commit is contained in:
committed by
H. Peter Anvin
parent
eba67e5da6
commit
1531a6a6b8
@@ -982,7 +982,7 @@ static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define PRIMARY_FAULT_REG_LEN (16)
|
#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;
|
struct intel_iommu *iommu = dev_id;
|
||||||
int reg, fault_index;
|
int reg, fault_index;
|
||||||
@@ -1074,9 +1074,6 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Force fault register is cleared */
|
|
||||||
dmar_fault(irq, iommu);
|
|
||||||
|
|
||||||
ret = request_irq(irq, dmar_fault, 0, iommu->name, iommu);
|
ret = request_irq(irq, dmar_fault, 0, iommu->name, iommu);
|
||||||
if (ret)
|
if (ret)
|
||||||
printk(KERN_ERR "IOMMU: can't request irq\n");
|
printk(KERN_ERR "IOMMU: can't request irq\n");
|
||||||
|
@@ -1855,11 +1855,40 @@ static int __init init_dmars(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start from the sane iommu hardware state.
|
||||||
|
*/
|
||||||
for_each_drhd_unit(drhd) {
|
for_each_drhd_unit(drhd) {
|
||||||
if (drhd->ignored)
|
if (drhd->ignored)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
iommu = drhd->iommu;
|
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)) {
|
if (dmar_enable_qi(iommu)) {
|
||||||
/*
|
/*
|
||||||
* Queued Invalidate not enabled, use Register Based
|
* Queued Invalidate not enabled, use Register Based
|
||||||
|
@@ -499,6 +499,23 @@ int __init enable_intr_remapping(int eim)
|
|||||||
struct dmar_drhd_unit *drhd;
|
struct dmar_drhd_unit *drhd;
|
||||||
int setup = 0;
|
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
|
* check for the Interrupt-remapping support
|
||||||
*/
|
*/
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/msi.h>
|
#include <linux/msi.h>
|
||||||
|
#include <linux/irqreturn.h>
|
||||||
|
|
||||||
#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP)
|
#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP)
|
||||||
struct intel_iommu;
|
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_read(int irq, struct msi_msg *msg);
|
||||||
extern void dmar_msi_write(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 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);
|
extern int arch_setup_dmar_msi(unsigned int irq);
|
||||||
|
|
||||||
#ifdef CONFIG_DMAR
|
#ifdef CONFIG_DMAR
|
||||||
|
Reference in New Issue
Block a user