diff options
Diffstat (limited to 'drivers/iommu/intel_irq_remapping.c')
-rw-r--r-- | drivers/iommu/intel_irq_remapping.c | 252 |
1 files changed, 158 insertions, 94 deletions
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index 80f1d1486247..f15692a410c7 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c | |||
@@ -1,3 +1,6 @@ | |||
1 | |||
2 | #define pr_fmt(fmt) "DMAR-IR: " fmt | ||
3 | |||
1 | #include <linux/interrupt.h> | 4 | #include <linux/interrupt.h> |
2 | #include <linux/dmar.h> | 5 | #include <linux/dmar.h> |
3 | #include <linux/spinlock.h> | 6 | #include <linux/spinlock.h> |
@@ -9,6 +12,7 @@ | |||
9 | #include <linux/intel-iommu.h> | 12 | #include <linux/intel-iommu.h> |
10 | #include <linux/acpi.h> | 13 | #include <linux/acpi.h> |
11 | #include <linux/irqdomain.h> | 14 | #include <linux/irqdomain.h> |
15 | #include <linux/crash_dump.h> | ||
12 | #include <asm/io_apic.h> | 16 | #include <asm/io_apic.h> |
13 | #include <asm/smp.h> | 17 | #include <asm/smp.h> |
14 | #include <asm/cpu.h> | 18 | #include <asm/cpu.h> |
@@ -74,8 +78,28 @@ static struct hpet_scope ir_hpet[MAX_HPET_TBS]; | |||
74 | static DEFINE_RAW_SPINLOCK(irq_2_ir_lock); | 78 | static DEFINE_RAW_SPINLOCK(irq_2_ir_lock); |
75 | static struct irq_domain_ops intel_ir_domain_ops; | 79 | static struct irq_domain_ops intel_ir_domain_ops; |
76 | 80 | ||
81 | static void iommu_disable_irq_remapping(struct intel_iommu *iommu); | ||
77 | static int __init parse_ioapics_under_ir(void); | 82 | static int __init parse_ioapics_under_ir(void); |
78 | 83 | ||
84 | static bool ir_pre_enabled(struct intel_iommu *iommu) | ||
85 | { | ||
86 | return (iommu->flags & VTD_FLAG_IRQ_REMAP_PRE_ENABLED); | ||
87 | } | ||
88 | |||
89 | static void clear_ir_pre_enabled(struct intel_iommu *iommu) | ||
90 | { | ||
91 | iommu->flags &= ~VTD_FLAG_IRQ_REMAP_PRE_ENABLED; | ||
92 | } | ||
93 | |||
94 | static void init_ir_status(struct intel_iommu *iommu) | ||
95 | { | ||
96 | u32 gsts; | ||
97 | |||
98 | gsts = readl(iommu->reg + DMAR_GSTS_REG); | ||
99 | if (gsts & DMA_GSTS_IRES) | ||
100 | iommu->flags |= VTD_FLAG_IRQ_REMAP_PRE_ENABLED; | ||
101 | } | ||
102 | |||
79 | static int alloc_irte(struct intel_iommu *iommu, int irq, | 103 | static int alloc_irte(struct intel_iommu *iommu, int irq, |
80 | struct irq_2_iommu *irq_iommu, u16 count) | 104 | struct irq_2_iommu *irq_iommu, u16 count) |
81 | { | 105 | { |
@@ -93,8 +117,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, | |||
93 | } | 117 | } |
94 | 118 | ||
95 | if (mask > ecap_max_handle_mask(iommu->ecap)) { | 119 | if (mask > ecap_max_handle_mask(iommu->ecap)) { |
96 | printk(KERN_ERR | 120 | pr_err("Requested mask %x exceeds the max invalidation handle" |
97 | "Requested mask %x exceeds the max invalidation handle" | ||
98 | " mask value %Lx\n", mask, | 121 | " mask value %Lx\n", mask, |
99 | ecap_max_handle_mask(iommu->ecap)); | 122 | ecap_max_handle_mask(iommu->ecap)); |
100 | return -1; | 123 | return -1; |
@@ -268,7 +291,7 @@ static int set_ioapic_sid(struct irte *irte, int apic) | |||
268 | up_read(&dmar_global_lock); | 291 | up_read(&dmar_global_lock); |
269 | 292 | ||
270 | if (sid == 0) { | 293 | if (sid == 0) { |
271 | pr_warning("Failed to set source-id of IOAPIC (%d)\n", apic); | 294 | pr_warn("Failed to set source-id of IOAPIC (%d)\n", apic); |
272 | return -1; | 295 | return -1; |
273 | } | 296 | } |
274 | 297 | ||
@@ -295,7 +318,7 @@ static int set_hpet_sid(struct irte *irte, u8 id) | |||
295 | up_read(&dmar_global_lock); | 318 | up_read(&dmar_global_lock); |
296 | 319 | ||
297 | if (sid == 0) { | 320 | if (sid == 0) { |
298 | pr_warning("Failed to set source-id of HPET block (%d)\n", id); | 321 | pr_warn("Failed to set source-id of HPET block (%d)\n", id); |
299 | return -1; | 322 | return -1; |
300 | } | 323 | } |
301 | 324 | ||
@@ -359,11 +382,59 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) | |||
359 | return 0; | 382 | return 0; |
360 | } | 383 | } |
361 | 384 | ||
385 | static int iommu_load_old_irte(struct intel_iommu *iommu) | ||
386 | { | ||
387 | struct irte *old_ir_table; | ||
388 | phys_addr_t irt_phys; | ||
389 | unsigned int i; | ||
390 | size_t size; | ||
391 | u64 irta; | ||
392 | |||
393 | if (!is_kdump_kernel()) { | ||
394 | pr_warn("IRQ remapping was enabled on %s but we are not in kdump mode\n", | ||
395 | iommu->name); | ||
396 | clear_ir_pre_enabled(iommu); | ||
397 | iommu_disable_irq_remapping(iommu); | ||
398 | return -EINVAL; | ||
399 | } | ||
400 | |||
401 | /* Check whether the old ir-table has the same size as ours */ | ||
402 | irta = dmar_readq(iommu->reg + DMAR_IRTA_REG); | ||
403 | if ((irta & INTR_REMAP_TABLE_REG_SIZE_MASK) | ||
404 | != INTR_REMAP_TABLE_REG_SIZE) | ||
405 | return -EINVAL; | ||
406 | |||
407 | irt_phys = irta & VTD_PAGE_MASK; | ||
408 | size = INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte); | ||
409 | |||
410 | /* Map the old IR table */ | ||
411 | old_ir_table = ioremap_cache(irt_phys, size); | ||
412 | if (!old_ir_table) | ||
413 | return -ENOMEM; | ||
414 | |||
415 | /* Copy data over */ | ||
416 | memcpy(iommu->ir_table->base, old_ir_table, size); | ||
417 | |||
418 | __iommu_flush_cache(iommu, iommu->ir_table->base, size); | ||
419 | |||
420 | /* | ||
421 | * Now check the table for used entries and mark those as | ||
422 | * allocated in the bitmap | ||
423 | */ | ||
424 | for (i = 0; i < INTR_REMAP_TABLE_ENTRIES; i++) { | ||
425 | if (iommu->ir_table->base[i].present) | ||
426 | bitmap_set(iommu->ir_table->bitmap, i, 1); | ||
427 | } | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | |||
362 | static void iommu_set_irq_remapping(struct intel_iommu *iommu, int mode) | 433 | static void iommu_set_irq_remapping(struct intel_iommu *iommu, int mode) |
363 | { | 434 | { |
435 | unsigned long flags; | ||
364 | u64 addr; | 436 | u64 addr; |
365 | u32 sts; | 437 | u32 sts; |
366 | unsigned long flags; | ||
367 | 438 | ||
368 | addr = virt_to_phys((void *)iommu->ir_table->base); | 439 | addr = virt_to_phys((void *)iommu->ir_table->base); |
369 | 440 | ||
@@ -380,10 +451,16 @@ static void iommu_set_irq_remapping(struct intel_iommu *iommu, int mode) | |||
380 | raw_spin_unlock_irqrestore(&iommu->register_lock, flags); | 451 | raw_spin_unlock_irqrestore(&iommu->register_lock, flags); |
381 | 452 | ||
382 | /* | 453 | /* |
383 | * global invalidation of interrupt entry cache before enabling | 454 | * Global invalidation of interrupt entry cache to make sure the |
384 | * interrupt-remapping. | 455 | * hardware uses the new irq remapping table. |
385 | */ | 456 | */ |
386 | qi_global_iec(iommu); | 457 | qi_global_iec(iommu); |
458 | } | ||
459 | |||
460 | static void iommu_enable_irq_remapping(struct intel_iommu *iommu) | ||
461 | { | ||
462 | unsigned long flags; | ||
463 | u32 sts; | ||
387 | 464 | ||
388 | raw_spin_lock_irqsave(&iommu->register_lock, flags); | 465 | raw_spin_lock_irqsave(&iommu->register_lock, flags); |
389 | 466 | ||
@@ -449,6 +526,37 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu) | |||
449 | ir_table->base = page_address(pages); | 526 | ir_table->base = page_address(pages); |
450 | ir_table->bitmap = bitmap; | 527 | ir_table->bitmap = bitmap; |
451 | iommu->ir_table = ir_table; | 528 | iommu->ir_table = ir_table; |
529 | |||
530 | /* | ||
531 | * If the queued invalidation is already initialized, | ||
532 | * shouldn't disable it. | ||
533 | */ | ||
534 | if (!iommu->qi) { | ||
535 | /* | ||
536 | * Clear previous faults. | ||
537 | */ | ||
538 | dmar_fault(-1, iommu); | ||
539 | dmar_disable_qi(iommu); | ||
540 | |||
541 | if (dmar_enable_qi(iommu)) { | ||
542 | pr_err("Failed to enable queued invalidation\n"); | ||
543 | goto out_free_bitmap; | ||
544 | } | ||
545 | } | ||
546 | |||
547 | init_ir_status(iommu); | ||
548 | |||
549 | if (ir_pre_enabled(iommu)) { | ||
550 | if (iommu_load_old_irte(iommu)) | ||
551 | pr_err("Failed to copy IR table for %s from previous kernel\n", | ||
552 | iommu->name); | ||
553 | else | ||
554 | pr_info("Copied IR table for %s from previous kernel\n", | ||
555 | iommu->name); | ||
556 | } | ||
557 | |||
558 | iommu_set_irq_remapping(iommu, eim_mode); | ||
559 | |||
452 | return 0; | 560 | return 0; |
453 | 561 | ||
454 | out_free_bitmap: | 562 | out_free_bitmap: |
@@ -457,6 +565,9 @@ out_free_pages: | |||
457 | __free_pages(pages, INTR_REMAP_PAGE_ORDER); | 565 | __free_pages(pages, INTR_REMAP_PAGE_ORDER); |
458 | out_free_table: | 566 | out_free_table: |
459 | kfree(ir_table); | 567 | kfree(ir_table); |
568 | |||
569 | iommu->ir_table = NULL; | ||
570 | |||
460 | return -ENOMEM; | 571 | return -ENOMEM; |
461 | } | 572 | } |
462 | 573 | ||
@@ -534,17 +645,17 @@ static void __init intel_cleanup_irq_remapping(void) | |||
534 | } | 645 | } |
535 | 646 | ||
536 | if (x2apic_supported()) | 647 | if (x2apic_supported()) |
537 | pr_warn("Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n"); | 648 | pr_warn("Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n"); |
538 | } | 649 | } |
539 | 650 | ||
540 | static int __init intel_prepare_irq_remapping(void) | 651 | static int __init intel_prepare_irq_remapping(void) |
541 | { | 652 | { |
542 | struct dmar_drhd_unit *drhd; | 653 | struct dmar_drhd_unit *drhd; |
543 | struct intel_iommu *iommu; | 654 | struct intel_iommu *iommu; |
655 | int eim = 0; | ||
544 | 656 | ||
545 | if (irq_remap_broken) { | 657 | if (irq_remap_broken) { |
546 | printk(KERN_WARNING | 658 | pr_warn("This system BIOS has enabled interrupt remapping\n" |
547 | "This system BIOS has enabled interrupt remapping\n" | ||
548 | "on a chipset that contains an erratum making that\n" | 659 | "on a chipset that contains an erratum making that\n" |
549 | "feature unstable. To maintain system stability\n" | 660 | "feature unstable. To maintain system stability\n" |
550 | "interrupt remapping is being disabled. Please\n" | 661 | "interrupt remapping is being disabled. Please\n" |
@@ -560,7 +671,7 @@ static int __init intel_prepare_irq_remapping(void) | |||
560 | return -ENODEV; | 671 | return -ENODEV; |
561 | 672 | ||
562 | if (parse_ioapics_under_ir() != 1) { | 673 | if (parse_ioapics_under_ir() != 1) { |
563 | printk(KERN_INFO "Not enabling interrupt remapping\n"); | 674 | pr_info("Not enabling interrupt remapping\n"); |
564 | goto error; | 675 | goto error; |
565 | } | 676 | } |
566 | 677 | ||
@@ -569,10 +680,34 @@ static int __init intel_prepare_irq_remapping(void) | |||
569 | if (!ecap_ir_support(iommu->ecap)) | 680 | if (!ecap_ir_support(iommu->ecap)) |
570 | goto error; | 681 | goto error; |
571 | 682 | ||
572 | /* Do the allocations early */ | 683 | /* Detect remapping mode: lapic or x2apic */ |
573 | for_each_iommu(iommu, drhd) | 684 | if (x2apic_supported()) { |
574 | if (intel_setup_irq_remapping(iommu)) | 685 | eim = !dmar_x2apic_optout(); |
686 | if (!eim) { | ||
687 | pr_info("x2apic is disabled because BIOS sets x2apic opt out bit."); | ||
688 | pr_info("Use 'intremap=no_x2apic_optout' to override the BIOS setting.\n"); | ||
689 | } | ||
690 | } | ||
691 | |||
692 | for_each_iommu(iommu, drhd) { | ||
693 | if (eim && !ecap_eim_support(iommu->ecap)) { | ||
694 | pr_info("%s does not support EIM\n", iommu->name); | ||
695 | eim = 0; | ||
696 | } | ||
697 | } | ||
698 | |||
699 | eim_mode = eim; | ||
700 | if (eim) | ||
701 | pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n"); | ||
702 | |||
703 | /* Do the initializations early */ | ||
704 | for_each_iommu(iommu, drhd) { | ||
705 | if (intel_setup_irq_remapping(iommu)) { | ||
706 | pr_err("Failed to setup irq remapping for %s\n", | ||
707 | iommu->name); | ||
575 | goto error; | 708 | goto error; |
709 | } | ||
710 | } | ||
576 | 711 | ||
577 | return 0; | 712 | return 0; |
578 | 713 | ||
@@ -606,68 +741,13 @@ static int __init intel_enable_irq_remapping(void) | |||
606 | struct dmar_drhd_unit *drhd; | 741 | struct dmar_drhd_unit *drhd; |
607 | struct intel_iommu *iommu; | 742 | struct intel_iommu *iommu; |
608 | bool setup = false; | 743 | bool setup = false; |
609 | int eim = 0; | ||
610 | |||
611 | if (x2apic_supported()) { | ||
612 | eim = !dmar_x2apic_optout(); | ||
613 | if (!eim) | ||
614 | pr_info("x2apic is disabled because BIOS sets x2apic opt out bit. You can use 'intremap=no_x2apic_optout' to override the BIOS setting.\n"); | ||
615 | } | ||
616 | |||
617 | for_each_iommu(iommu, drhd) { | ||
618 | /* | ||
619 | * If the queued invalidation is already initialized, | ||
620 | * shouldn't disable it. | ||
621 | */ | ||
622 | if (iommu->qi) | ||
623 | continue; | ||
624 | |||
625 | /* | ||
626 | * Clear previous faults. | ||
627 | */ | ||
628 | dmar_fault(-1, iommu); | ||
629 | |||
630 | /* | ||
631 | * Disable intr remapping and queued invalidation, if already | ||
632 | * enabled prior to OS handover. | ||
633 | */ | ||
634 | iommu_disable_irq_remapping(iommu); | ||
635 | |||
636 | dmar_disable_qi(iommu); | ||
637 | } | ||
638 | |||
639 | /* | ||
640 | * check for the Interrupt-remapping support | ||
641 | */ | ||
642 | for_each_iommu(iommu, drhd) | ||
643 | if (eim && !ecap_eim_support(iommu->ecap)) { | ||
644 | printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, " | ||
645 | " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap); | ||
646 | eim = 0; | ||
647 | } | ||
648 | eim_mode = eim; | ||
649 | if (eim) | ||
650 | pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n"); | ||
651 | |||
652 | /* | ||
653 | * Enable queued invalidation for all the DRHD's. | ||
654 | */ | ||
655 | for_each_iommu(iommu, drhd) { | ||
656 | int ret = dmar_enable_qi(iommu); | ||
657 | |||
658 | if (ret) { | ||
659 | printk(KERN_ERR "DRHD %Lx: failed to enable queued, " | ||
660 | " invalidation, ecap %Lx, ret %d\n", | ||
661 | drhd->reg_base_addr, iommu->ecap, ret); | ||
662 | goto error; | ||
663 | } | ||
664 | } | ||
665 | 744 | ||
666 | /* | 745 | /* |
667 | * Setup Interrupt-remapping for all the DRHD's now. | 746 | * Setup Interrupt-remapping for all the DRHD's now. |
668 | */ | 747 | */ |
669 | for_each_iommu(iommu, drhd) { | 748 | for_each_iommu(iommu, drhd) { |
670 | iommu_set_irq_remapping(iommu, eim); | 749 | if (!ir_pre_enabled(iommu)) |
750 | iommu_enable_irq_remapping(iommu); | ||
671 | setup = true; | 751 | setup = true; |
672 | } | 752 | } |
673 | 753 | ||
@@ -678,9 +758,9 @@ static int __init intel_enable_irq_remapping(void) | |||
678 | 758 | ||
679 | set_irq_posting_cap(); | 759 | set_irq_posting_cap(); |
680 | 760 | ||
681 | pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic"); | 761 | pr_info("Enabled IRQ remapping in %s mode\n", eim_mode ? "x2apic" : "xapic"); |
682 | 762 | ||
683 | return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; | 763 | return eim_mode ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; |
684 | 764 | ||
685 | error: | 765 | error: |
686 | intel_cleanup_irq_remapping(); | 766 | intel_cleanup_irq_remapping(); |
@@ -905,6 +985,7 @@ static int reenable_irq_remapping(int eim) | |||
905 | 985 | ||
906 | /* Set up interrupt remapping for iommu.*/ | 986 | /* Set up interrupt remapping for iommu.*/ |
907 | iommu_set_irq_remapping(iommu, eim); | 987 | iommu_set_irq_remapping(iommu, eim); |
988 | iommu_enable_irq_remapping(iommu); | ||
908 | setup = true; | 989 | setup = true; |
909 | } | 990 | } |
910 | 991 | ||
@@ -1169,7 +1250,6 @@ static void intel_free_irq_resources(struct irq_domain *domain, | |||
1169 | struct irq_2_iommu *irq_iommu; | 1250 | struct irq_2_iommu *irq_iommu; |
1170 | unsigned long flags; | 1251 | unsigned long flags; |
1171 | int i; | 1252 | int i; |
1172 | |||
1173 | for (i = 0; i < nr_irqs; i++) { | 1253 | for (i = 0; i < nr_irqs; i++) { |
1174 | irq_data = irq_domain_get_irq_data(domain, virq + i); | 1254 | irq_data = irq_domain_get_irq_data(domain, virq + i); |
1175 | if (irq_data && irq_data->chip_data) { | 1255 | if (irq_data && irq_data->chip_data) { |
@@ -1317,28 +1397,12 @@ static int dmar_ir_add(struct dmar_drhd_unit *dmaru, struct intel_iommu *iommu) | |||
1317 | /* Setup Interrupt-remapping now. */ | 1397 | /* Setup Interrupt-remapping now. */ |
1318 | ret = intel_setup_irq_remapping(iommu); | 1398 | ret = intel_setup_irq_remapping(iommu); |
1319 | if (ret) { | 1399 | if (ret) { |
1320 | pr_err("DRHD %Lx: failed to allocate resource\n", | 1400 | pr_err("Failed to setup irq remapping for %s\n", |
1321 | iommu->reg_phys); | 1401 | iommu->name); |
1322 | ir_remove_ioapic_hpet_scope(iommu); | ||
1323 | return ret; | ||
1324 | } | ||
1325 | |||
1326 | if (!iommu->qi) { | ||
1327 | /* Clear previous faults. */ | ||
1328 | dmar_fault(-1, iommu); | ||
1329 | iommu_disable_irq_remapping(iommu); | ||
1330 | dmar_disable_qi(iommu); | ||
1331 | } | ||
1332 | |||
1333 | /* Enable queued invalidation */ | ||
1334 | ret = dmar_enable_qi(iommu); | ||
1335 | if (!ret) { | ||
1336 | iommu_set_irq_remapping(iommu, eim); | ||
1337 | } else { | ||
1338 | pr_err("DRHD %Lx: failed to enable queued invalidation, ecap %Lx, ret %d\n", | ||
1339 | iommu->reg_phys, iommu->ecap, ret); | ||
1340 | intel_teardown_irq_remapping(iommu); | 1402 | intel_teardown_irq_remapping(iommu); |
1341 | ir_remove_ioapic_hpet_scope(iommu); | 1403 | ir_remove_ioapic_hpet_scope(iommu); |
1404 | } else { | ||
1405 | iommu_enable_irq_remapping(iommu); | ||
1342 | } | 1406 | } |
1343 | 1407 | ||
1344 | return ret; | 1408 | return ret; |