aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Roedel <joerg.roedel@amd.com>2009-10-09 12:31:20 -0400
committerJoerg Roedel <joerg.roedel@amd.com>2009-10-09 12:37:46 -0400
commitc5cca146aa03e1f60fb179df65f0dbaf17bc64ed (patch)
tree457cdf7d8b3a12f58328d06a2bfd8665b395b9ba
parentc7084b35eb1a4d3353a501508baf9d3d82822c93 (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.h1
-rw-r--r--arch/x86/kernel/amd_iommu.c2
-rw-r--r--arch/x86/kernel/amd_iommu_init.c22
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);
30extern void amd_iommu_flush_all_domains(void); 30extern void amd_iommu_flush_all_domains(void);
31extern void amd_iommu_flush_all_devices(void); 31extern void amd_iommu_flush_all_devices(void);
32extern void amd_iommu_shutdown(void); 32extern void amd_iommu_shutdown(void);
33extern void amd_iommu_apply_erratum_63(u16 devid);
33#else 34#else
34static inline int amd_iommu_init(void) { return -ENODEV; } 35static inline int amd_iommu_init(void) { return -ENODEV; }
35static inline void amd_iommu_detect(void) { } 36static 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
512static 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
521void 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 */
513static void __init set_iommu_for_device(struct amd_iommu *iommu, u16 devid) 533static 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