diff options
Diffstat (limited to 'arch/x86/kernel/amd_iommu.c')
-rw-r--r-- | arch/x86/kernel/amd_iommu.c | 119 |
1 files changed, 91 insertions, 28 deletions
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 6c99f5037801..8c93b7c7735e 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c | |||
@@ -41,9 +41,7 @@ static DEFINE_RWLOCK(amd_iommu_devtable_lock); | |||
41 | static LIST_HEAD(iommu_pd_list); | 41 | static LIST_HEAD(iommu_pd_list); |
42 | static DEFINE_SPINLOCK(iommu_pd_list_lock); | 42 | static DEFINE_SPINLOCK(iommu_pd_list_lock); |
43 | 43 | ||
44 | #ifdef CONFIG_IOMMU_API | ||
45 | static struct iommu_ops amd_iommu_ops; | 44 | static struct iommu_ops amd_iommu_ops; |
46 | #endif | ||
47 | 45 | ||
48 | /* | 46 | /* |
49 | * general struct to manage commands send to an IOMMU | 47 | * general struct to manage commands send to an IOMMU |
@@ -61,10 +59,7 @@ static u64* alloc_pte(struct protection_domain *dom, | |||
61 | static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, | 59 | static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, |
62 | unsigned long start_page, | 60 | unsigned long start_page, |
63 | unsigned int pages); | 61 | unsigned int pages); |
64 | 62 | static void reset_iommu_command_buffer(struct amd_iommu *iommu); | |
65 | #ifndef BUS_NOTIFY_UNBOUND_DRIVER | ||
66 | #define BUS_NOTIFY_UNBOUND_DRIVER 0x0005 | ||
67 | #endif | ||
68 | 63 | ||
69 | #ifdef CONFIG_AMD_IOMMU_STATS | 64 | #ifdef CONFIG_AMD_IOMMU_STATS |
70 | 65 | ||
@@ -138,7 +133,25 @@ static int iommu_has_npcache(struct amd_iommu *iommu) | |||
138 | * | 133 | * |
139 | ****************************************************************************/ | 134 | ****************************************************************************/ |
140 | 135 | ||
141 | static void iommu_print_event(void *__evt) | 136 | static void dump_dte_entry(u16 devid) |
137 | { | ||
138 | int i; | ||
139 | |||
140 | for (i = 0; i < 8; ++i) | ||
141 | pr_err("AMD-Vi: DTE[%d]: %08x\n", i, | ||
142 | amd_iommu_dev_table[devid].data[i]); | ||
143 | } | ||
144 | |||
145 | static void dump_command(unsigned long phys_addr) | ||
146 | { | ||
147 | struct iommu_cmd *cmd = phys_to_virt(phys_addr); | ||
148 | int i; | ||
149 | |||
150 | for (i = 0; i < 4; ++i) | ||
151 | pr_err("AMD-Vi: CMD[%d]: %08x\n", i, cmd->data[i]); | ||
152 | } | ||
153 | |||
154 | static void iommu_print_event(struct amd_iommu *iommu, void *__evt) | ||
142 | { | 155 | { |
143 | u32 *event = __evt; | 156 | u32 *event = __evt; |
144 | int type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK; | 157 | int type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK; |
@@ -147,7 +160,7 @@ static void iommu_print_event(void *__evt) | |||
147 | int flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK; | 160 | int flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK; |
148 | u64 address = (u64)(((u64)event[3]) << 32) | event[2]; | 161 | u64 address = (u64)(((u64)event[3]) << 32) | event[2]; |
149 | 162 | ||
150 | printk(KERN_ERR "AMD IOMMU: Event logged ["); | 163 | printk(KERN_ERR "AMD-Vi: Event logged ["); |
151 | 164 | ||
152 | switch (type) { | 165 | switch (type) { |
153 | case EVENT_TYPE_ILL_DEV: | 166 | case EVENT_TYPE_ILL_DEV: |
@@ -155,6 +168,7 @@ static void iommu_print_event(void *__evt) | |||
155 | "address=0x%016llx flags=0x%04x]\n", | 168 | "address=0x%016llx flags=0x%04x]\n", |
156 | PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid), | 169 | PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid), |
157 | address, flags); | 170 | address, flags); |
171 | dump_dte_entry(devid); | ||
158 | break; | 172 | break; |
159 | case EVENT_TYPE_IO_FAULT: | 173 | case EVENT_TYPE_IO_FAULT: |
160 | printk("IO_PAGE_FAULT device=%02x:%02x.%x " | 174 | printk("IO_PAGE_FAULT device=%02x:%02x.%x " |
@@ -176,6 +190,8 @@ static void iommu_print_event(void *__evt) | |||
176 | break; | 190 | break; |
177 | case EVENT_TYPE_ILL_CMD: | 191 | case EVENT_TYPE_ILL_CMD: |
178 | printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address); | 192 | printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address); |
193 | reset_iommu_command_buffer(iommu); | ||
194 | dump_command(address); | ||
179 | break; | 195 | break; |
180 | case EVENT_TYPE_CMD_HARD_ERR: | 196 | case EVENT_TYPE_CMD_HARD_ERR: |
181 | printk("COMMAND_HARDWARE_ERROR address=0x%016llx " | 197 | printk("COMMAND_HARDWARE_ERROR address=0x%016llx " |
@@ -209,7 +225,7 @@ static void iommu_poll_events(struct amd_iommu *iommu) | |||
209 | tail = readl(iommu->mmio_base + MMIO_EVT_TAIL_OFFSET); | 225 | tail = readl(iommu->mmio_base + MMIO_EVT_TAIL_OFFSET); |
210 | 226 | ||
211 | while (head != tail) { | 227 | while (head != tail) { |
212 | iommu_print_event(iommu->evt_buf + head); | 228 | iommu_print_event(iommu, iommu->evt_buf + head); |
213 | head = (head + EVENT_ENTRY_SIZE) % iommu->evt_buf_size; | 229 | head = (head + EVENT_ENTRY_SIZE) % iommu->evt_buf_size; |
214 | } | 230 | } |
215 | 231 | ||
@@ -296,8 +312,11 @@ static void __iommu_wait_for_completion(struct amd_iommu *iommu) | |||
296 | status &= ~MMIO_STATUS_COM_WAIT_INT_MASK; | 312 | status &= ~MMIO_STATUS_COM_WAIT_INT_MASK; |
297 | writel(status, iommu->mmio_base + MMIO_STATUS_OFFSET); | 313 | writel(status, iommu->mmio_base + MMIO_STATUS_OFFSET); |
298 | 314 | ||
299 | if (unlikely(i == EXIT_LOOP_COUNT)) | 315 | if (unlikely(i == EXIT_LOOP_COUNT)) { |
300 | panic("AMD IOMMU: Completion wait loop failed\n"); | 316 | spin_unlock(&iommu->lock); |
317 | reset_iommu_command_buffer(iommu); | ||
318 | spin_lock(&iommu->lock); | ||
319 | } | ||
301 | } | 320 | } |
302 | 321 | ||
303 | /* | 322 | /* |
@@ -445,37 +464,67 @@ static void iommu_flush_tlb_pde(struct amd_iommu *iommu, u16 domid) | |||
445 | } | 464 | } |
446 | 465 | ||
447 | /* | 466 | /* |
467 | * This function flushes one domain on one IOMMU | ||
468 | */ | ||
469 | static void flush_domain_on_iommu(struct amd_iommu *iommu, u16 domid) | ||
470 | { | ||
471 | struct iommu_cmd cmd; | ||
472 | unsigned long flags; | ||
473 | |||
474 | __iommu_build_inv_iommu_pages(&cmd, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, | ||
475 | domid, 1, 1); | ||
476 | |||
477 | spin_lock_irqsave(&iommu->lock, flags); | ||
478 | __iommu_queue_command(iommu, &cmd); | ||
479 | __iommu_completion_wait(iommu); | ||
480 | __iommu_wait_for_completion(iommu); | ||
481 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
482 | } | ||
483 | |||
484 | static void flush_all_domains_on_iommu(struct amd_iommu *iommu) | ||
485 | { | ||
486 | int i; | ||
487 | |||
488 | for (i = 1; i < MAX_DOMAIN_ID; ++i) { | ||
489 | if (!test_bit(i, amd_iommu_pd_alloc_bitmap)) | ||
490 | continue; | ||
491 | flush_domain_on_iommu(iommu, i); | ||
492 | } | ||
493 | |||
494 | } | ||
495 | |||
496 | /* | ||
448 | * This function is used to flush the IO/TLB for a given protection domain | 497 | * This function is used to flush the IO/TLB for a given protection domain |
449 | * on every IOMMU in the system | 498 | * on every IOMMU in the system |
450 | */ | 499 | */ |
451 | static void iommu_flush_domain(u16 domid) | 500 | static void iommu_flush_domain(u16 domid) |
452 | { | 501 | { |
453 | unsigned long flags; | ||
454 | struct amd_iommu *iommu; | 502 | struct amd_iommu *iommu; |
455 | struct iommu_cmd cmd; | ||
456 | 503 | ||
457 | INC_STATS_COUNTER(domain_flush_all); | 504 | INC_STATS_COUNTER(domain_flush_all); |
458 | 505 | ||
459 | __iommu_build_inv_iommu_pages(&cmd, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, | 506 | for_each_iommu(iommu) |
460 | domid, 1, 1); | 507 | flush_domain_on_iommu(iommu, domid); |
461 | |||
462 | for_each_iommu(iommu) { | ||
463 | spin_lock_irqsave(&iommu->lock, flags); | ||
464 | __iommu_queue_command(iommu, &cmd); | ||
465 | __iommu_completion_wait(iommu); | ||
466 | __iommu_wait_for_completion(iommu); | ||
467 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
468 | } | ||
469 | } | 508 | } |
470 | 509 | ||
471 | void amd_iommu_flush_all_domains(void) | 510 | void amd_iommu_flush_all_domains(void) |
472 | { | 511 | { |
512 | struct amd_iommu *iommu; | ||
513 | |||
514 | for_each_iommu(iommu) | ||
515 | flush_all_domains_on_iommu(iommu); | ||
516 | } | ||
517 | |||
518 | static void flush_all_devices_for_iommu(struct amd_iommu *iommu) | ||
519 | { | ||
473 | int i; | 520 | int i; |
474 | 521 | ||
475 | for (i = 1; i < MAX_DOMAIN_ID; ++i) { | 522 | for (i = 0; i <= amd_iommu_last_bdf; ++i) { |
476 | if (!test_bit(i, amd_iommu_pd_alloc_bitmap)) | 523 | if (iommu != amd_iommu_rlookup_table[i]) |
477 | continue; | 524 | continue; |
478 | iommu_flush_domain(i); | 525 | |
526 | iommu_queue_inv_dev_entry(iommu, i); | ||
527 | iommu_completion_wait(iommu); | ||
479 | } | 528 | } |
480 | } | 529 | } |
481 | 530 | ||
@@ -485,8 +534,6 @@ void amd_iommu_flush_all_devices(void) | |||
485 | int i; | 534 | int i; |
486 | 535 | ||
487 | for (i = 0; i <= amd_iommu_last_bdf; ++i) { | 536 | for (i = 0; i <= amd_iommu_last_bdf; ++i) { |
488 | if (amd_iommu_pd_table[i] == NULL) | ||
489 | continue; | ||
490 | 537 | ||
491 | iommu = amd_iommu_rlookup_table[i]; | 538 | iommu = amd_iommu_rlookup_table[i]; |
492 | if (!iommu) | 539 | if (!iommu) |
@@ -497,6 +544,22 @@ void amd_iommu_flush_all_devices(void) | |||
497 | } | 544 | } |
498 | } | 545 | } |
499 | 546 | ||
547 | static void reset_iommu_command_buffer(struct amd_iommu *iommu) | ||
548 | { | ||
549 | pr_err("AMD-Vi: Resetting IOMMU command buffer\n"); | ||
550 | |||
551 | if (iommu->reset_in_progress) | ||
552 | panic("AMD-Vi: ILLEGAL_COMMAND_ERROR while resetting command buffer\n"); | ||
553 | |||
554 | iommu->reset_in_progress = true; | ||
555 | |||
556 | amd_iommu_reset_cmd_buffer(iommu); | ||
557 | flush_all_devices_for_iommu(iommu); | ||
558 | flush_all_domains_on_iommu(iommu); | ||
559 | |||
560 | iommu->reset_in_progress = false; | ||
561 | } | ||
562 | |||
500 | /**************************************************************************** | 563 | /**************************************************************************** |
501 | * | 564 | * |
502 | * The functions below are used the create the page table mappings for | 565 | * The functions below are used the create the page table mappings for |