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: Joerg Roedel <joerg.roedel@amd.com>
This commit is contained in:
@@ -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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user