diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2009-10-09 12:31:20 -0400 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2009-10-09 12:37:46 -0400 |
commit | c5cca146aa03e1f60fb179df65f0dbaf17bc64ed (patch) | |
tree | 457cdf7d8b3a12f58328d06a2bfd8665b395b9ba | |
parent | c7084b35eb1a4d3353a501508baf9d3d82822c93 (diff) |
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>
-rw-r--r-- | arch/x86/include/asm/amd_iommu.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/amd_iommu.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/amd_iommu_init.c | 22 |
3 files changed, 25 insertions, 0 deletions
diff --git a/arch/x86/include/asm/amd_iommu.h b/arch/x86/include/asm/amd_iommu.h index bdf96f119f06..9dbd4030f0cd 100644 --- 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(int irq, void *data); | |||
30 | extern void amd_iommu_flush_all_domains(void); | 30 | extern void amd_iommu_flush_all_domains(void); |
31 | extern void amd_iommu_flush_all_devices(void); | 31 | extern void amd_iommu_flush_all_devices(void); |
32 | extern void amd_iommu_shutdown(void); | 32 | extern void amd_iommu_shutdown(void); |
33 | extern void amd_iommu_apply_erratum_63(u16 devid); | ||
33 | #else | 34 | #else |
34 | static inline int amd_iommu_init(void) { return -ENODEV; } | 35 | static inline int amd_iommu_init(void) { return -ENODEV; } |
35 | static inline void amd_iommu_detect(void) { } | 36 | static inline void amd_iommu_detect(void) { } |
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 6c99f5037801..f95dfe526444 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c | |||
@@ -1114,6 +1114,8 @@ static void __detach_device(struct protection_domain *domain, u16 devid) | |||
1114 | amd_iommu_dev_table[devid].data[1] = 0; | 1114 | amd_iommu_dev_table[devid].data[1] = 0; |
1115 | amd_iommu_dev_table[devid].data[2] = 0; | 1115 | amd_iommu_dev_table[devid].data[2] = 0; |
1116 | 1116 | ||
1117 | amd_iommu_apply_erratum_63(devid); | ||
1118 | |||
1117 | /* decrease reference counter */ | 1119 | /* decrease reference counter */ |
1118 | domain->dev_cnt -= 1; | 1120 | domain->dev_cnt -= 1; |
1119 | 1121 | ||
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index c1b17e97252e..498c8c79aaa5 100644 --- 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, u8 bit) | |||
509 | amd_iommu_dev_table[devid].data[i] |= (1 << _bit); | 509 | amd_iommu_dev_table[devid].data[i] |= (1 << _bit); |
510 | } | 510 | } |
511 | 511 | ||
512 | static int get_dev_entry_bit(u16 devid, u8 bit) | ||
513 | { | ||
514 | int i = (bit >> 5) & 0x07; | ||
515 | int _bit = bit & 0x1f; | ||
516 | |||
517 | return (amd_iommu_dev_table[devid].data[i] & (1 << _bit)) >> _bit; | ||
518 | } | ||
519 | |||
520 | |||
521 | void amd_iommu_apply_erratum_63(u16 devid) | ||
522 | { | ||
523 | int sysmgt; | ||
524 | |||
525 | sysmgt = get_dev_entry_bit(devid, DEV_ENTRY_SYSMGT1) | | ||
526 | (get_dev_entry_bit(devid, DEV_ENTRY_SYSMGT2) << 1); | ||
527 | |||
528 | if (sysmgt == 0x01) | ||
529 | set_dev_entry_bit(devid, DEV_ENTRY_IW); | ||
530 | } | ||
531 | |||
512 | /* Writes the specific IOMMU for a device into the rlookup table */ | 532 | /* Writes the specific IOMMU for a device into the rlookup table */ |
513 | static void __init set_iommu_for_device(struct amd_iommu *iommu, u16 devid) | 533 | static void __init set_iommu_for_device(struct amd_iommu *iommu, u16 devid) |
514 | { | 534 | { |
@@ -537,6 +557,8 @@ static void __init set_dev_entry_from_acpi(struct amd_iommu *iommu, | |||
537 | if (flags & ACPI_DEVFLAG_LINT1) | 557 | if (flags & ACPI_DEVFLAG_LINT1) |
538 | set_dev_entry_bit(devid, DEV_ENTRY_LINT1_PASS); | 558 | set_dev_entry_bit(devid, DEV_ENTRY_LINT1_PASS); |
539 | 559 | ||
560 | amd_iommu_apply_erratum_63(devid); | ||
561 | |||
540 | set_iommu_for_device(iommu, devid); | 562 | set_iommu_for_device(iommu, devid); |
541 | } | 563 | } |
542 | 564 | ||