[66/99] x86/amd-iommu: Workaround for erratum 63

From: Greg KH
Date: Fri Nov 06 2009 - 17:23:33 EST


2.6.31-stable review patch. If anyone has any objections, please let us know.

------------------
From: Joerg Roedel <joerg.roedel@xxxxxxx>

commit c5cca146aa03e1f60fb179df65f0dbaf17bc64ed upstream.

There is an erratum for IOMMU hardware which documents
undefined behavior when forwarding SMI requests from
peripherals and the DTE of that peripheral has a sysmgt
value of 01b. This problem caused weird IO_PAGE_FAULTS in my
case.
This patch implements the suggested workaround for that
erratum into the AMD IOMMU driver. The erratum is
documented with number 63.

Signed-off-by: Joerg Roedel <joerg.roedel@xxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxx>

---
arch/x86/include/asm/amd_iommu.h | 1 +
arch/x86/kernel/amd_iommu.c | 2 ++
arch/x86/kernel/amd_iommu_init.c | 22 ++++++++++++++++++++++
3 files changed, 25 insertions(+)

--- a/arch/x86/include/asm/amd_iommu.h
+++ b/arch/x86/include/asm/amd_iommu.h
@@ -30,6 +30,7 @@ extern irqreturn_t amd_iommu_int_handler
extern void amd_iommu_flush_all_domains(void);
extern void amd_iommu_flush_all_devices(void);
extern void amd_iommu_shutdown(void);
+extern void amd_iommu_apply_erratum_63(u16 devid);
#else
static inline int amd_iommu_init(void) { return -ENODEV; }
static inline void amd_iommu_detect(void) { }
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -1112,6 +1112,8 @@ static void __detach_device(struct prote
amd_iommu_dev_table[devid].data[1] = 0;
amd_iommu_dev_table[devid].data[2] = 0;

+ amd_iommu_apply_erratum_63(devid);
+
/* decrease reference counter */
domain->dev_cnt -= 1;

--- a/arch/x86/kernel/amd_iommu_init.c
+++ b/arch/x86/kernel/amd_iommu_init.c
@@ -509,6 +509,26 @@ static void set_dev_entry_bit(u16 devid,
amd_iommu_dev_table[devid].data[i] |= (1 << _bit);
}

+static int get_dev_entry_bit(u16 devid, u8 bit)
+{
+ int i = (bit >> 5) & 0x07;
+ int _bit = bit & 0x1f;
+
+ return (amd_iommu_dev_table[devid].data[i] & (1 << _bit)) >> _bit;
+}
+
+
+void amd_iommu_apply_erratum_63(u16 devid)
+{
+ int sysmgt;
+
+ sysmgt = get_dev_entry_bit(devid, DEV_ENTRY_SYSMGT1) |
+ (get_dev_entry_bit(devid, DEV_ENTRY_SYSMGT2) << 1);
+
+ if (sysmgt == 0x01)
+ set_dev_entry_bit(devid, DEV_ENTRY_IW);
+}
+
/* Writes the specific IOMMU for a device into the rlookup table */
static void __init set_iommu_for_device(struct amd_iommu *iommu, u16 devid)
{
@@ -537,6 +557,8 @@ static void __init set_dev_entry_from_ac
if (flags & ACPI_DEVFLAG_LINT1)
set_dev_entry_bit(devid, DEV_ENTRY_LINT1_PASS);

+ amd_iommu_apply_erratum_63(devid);
+
set_iommu_for_device(iommu, devid);
}



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/