diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2009-09-03 09:01:43 -0400 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2009-09-03 09:55:34 -0400 |
commit | a345b23b79f1900e7d87c3165182504419180de4 (patch) | |
tree | 4dc0b858369520bc2125ba9bde9f388edc0777dd /arch/x86/kernel/amd_iommu.c | |
parent | 93f1cc67cf3196174412adca87321b25c1c986b0 (diff) |
x86/amd-iommu: Reset command buffer on ILLEGAL_COMMAND_ERROR
On an ILLEGAL_COMMAND_ERROR the IOMMU stops executing
further commands. This patch changes the code to handle this
case better by resetting the command buffer in the IOMMU.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'arch/x86/kernel/amd_iommu.c')
-rw-r--r-- | arch/x86/kernel/amd_iommu.c | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 2dc093370d2d..2333d615f5ee 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c | |||
@@ -61,6 +61,7 @@ static u64* alloc_pte(struct protection_domain *dom, | |||
61 | static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, | 61 | static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, |
62 | unsigned long start_page, | 62 | unsigned long start_page, |
63 | unsigned int pages); | 63 | unsigned int pages); |
64 | static void reset_iommu_command_buffer(struct amd_iommu *iommu); | ||
64 | 65 | ||
65 | #ifndef BUS_NOTIFY_UNBOUND_DRIVER | 66 | #ifndef BUS_NOTIFY_UNBOUND_DRIVER |
66 | #define BUS_NOTIFY_UNBOUND_DRIVER 0x0005 | 67 | #define BUS_NOTIFY_UNBOUND_DRIVER 0x0005 |
@@ -156,7 +157,7 @@ static void dump_command(unsigned long phys_addr) | |||
156 | pr_err("AMD-Vi: CMD[%d]: %08x\n", i, cmd->data[i]); | 157 | pr_err("AMD-Vi: CMD[%d]: %08x\n", i, cmd->data[i]); |
157 | } | 158 | } |
158 | 159 | ||
159 | static void iommu_print_event(void *__evt) | 160 | static void iommu_print_event(struct amd_iommu *iommu, void *__evt) |
160 | { | 161 | { |
161 | u32 *event = __evt; | 162 | u32 *event = __evt; |
162 | int type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK; | 163 | int type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK; |
@@ -195,6 +196,7 @@ static void iommu_print_event(void *__evt) | |||
195 | break; | 196 | break; |
196 | case EVENT_TYPE_ILL_CMD: | 197 | case EVENT_TYPE_ILL_CMD: |
197 | printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address); | 198 | printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address); |
199 | reset_iommu_command_buffer(iommu); | ||
198 | dump_command(address); | 200 | dump_command(address); |
199 | break; | 201 | break; |
200 | case EVENT_TYPE_CMD_HARD_ERR: | 202 | case EVENT_TYPE_CMD_HARD_ERR: |
@@ -229,7 +231,7 @@ static void iommu_poll_events(struct amd_iommu *iommu) | |||
229 | tail = readl(iommu->mmio_base + MMIO_EVT_TAIL_OFFSET); | 231 | tail = readl(iommu->mmio_base + MMIO_EVT_TAIL_OFFSET); |
230 | 232 | ||
231 | while (head != tail) { | 233 | while (head != tail) { |
232 | iommu_print_event(iommu->evt_buf + head); | 234 | iommu_print_event(iommu, iommu->evt_buf + head); |
233 | head = (head + EVENT_ENTRY_SIZE) % iommu->evt_buf_size; | 235 | head = (head + EVENT_ENTRY_SIZE) % iommu->evt_buf_size; |
234 | } | 236 | } |
235 | 237 | ||
@@ -547,6 +549,15 @@ void amd_iommu_flush_all_devices(void) | |||
547 | } | 549 | } |
548 | } | 550 | } |
549 | 551 | ||
552 | static void reset_iommu_command_buffer(struct amd_iommu *iommu) | ||
553 | { | ||
554 | pr_err("AMD-Vi: Resetting IOMMU command buffer\n"); | ||
555 | |||
556 | amd_iommu_reset_cmd_buffer(iommu); | ||
557 | flush_all_devices_for_iommu(iommu); | ||
558 | flush_all_domains_on_iommu(iommu); | ||
559 | } | ||
560 | |||
550 | /**************************************************************************** | 561 | /**************************************************************************** |
551 | * | 562 | * |
552 | * The functions below are used the create the page table mappings for | 563 | * The functions below are used the create the page table mappings for |