Commit c5cca146 authored by Joerg Roedel's avatar Joerg Roedel

x86/amd-iommu: Workaround for erratum 63

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.

Cc: stable@kernel.org
Signed-off-by: default avatarJoerg Roedel <joerg.roedel@amd.com>
parent c7084b35
...@@ -30,6 +30,7 @@ extern irqreturn_t amd_iommu_int_handler(int irq, void *data); ...@@ -30,6 +30,7 @@ extern irqreturn_t amd_iommu_int_handler(int irq, void *data);
extern void amd_iommu_flush_all_domains(void); extern void amd_iommu_flush_all_domains(void);
extern void amd_iommu_flush_all_devices(void); extern void amd_iommu_flush_all_devices(void);
extern void amd_iommu_shutdown(void); extern void amd_iommu_shutdown(void);
extern void amd_iommu_apply_erratum_63(u16 devid);
#else #else
static inline int amd_iommu_init(void) { return -ENODEV; } static inline int amd_iommu_init(void) { return -ENODEV; }
static inline void amd_iommu_detect(void) { } static inline void amd_iommu_detect(void) { }
......
...@@ -1114,6 +1114,8 @@ static void __detach_device(struct protection_domain *domain, u16 devid) ...@@ -1114,6 +1114,8 @@ static void __detach_device(struct protection_domain *domain, u16 devid)
amd_iommu_dev_table[devid].data[1] = 0; amd_iommu_dev_table[devid].data[1] = 0;
amd_iommu_dev_table[devid].data[2] = 0; amd_iommu_dev_table[devid].data[2] = 0;
amd_iommu_apply_erratum_63(devid);
/* decrease reference counter */ /* decrease reference counter */
domain->dev_cnt -= 1; domain->dev_cnt -= 1;
......
...@@ -509,6 +509,26 @@ static void set_dev_entry_bit(u16 devid, u8 bit) ...@@ -509,6 +509,26 @@ static void set_dev_entry_bit(u16 devid, u8 bit)
amd_iommu_dev_table[devid].data[i] |= (1 << _bit); 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 */ /* Writes the specific IOMMU for a device into the rlookup table */
static void __init set_iommu_for_device(struct amd_iommu *iommu, u16 devid) static void __init set_iommu_for_device(struct amd_iommu *iommu, u16 devid)
{ {
...@@ -537,6 +557,8 @@ static void __init set_dev_entry_from_acpi(struct amd_iommu *iommu, ...@@ -537,6 +557,8 @@ static void __init set_dev_entry_from_acpi(struct amd_iommu *iommu,
if (flags & ACPI_DEVFLAG_LINT1) if (flags & ACPI_DEVFLAG_LINT1)
set_dev_entry_bit(devid, DEV_ENTRY_LINT1_PASS); set_dev_entry_bit(devid, DEV_ENTRY_LINT1_PASS);
amd_iommu_apply_erratum_63(devid);
set_iommu_for_device(iommu, devid); set_iommu_for_device(iommu, devid);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment