diff options
Diffstat (limited to 'drivers/pci/dmar.c')
-rw-r--r-- | drivers/pci/dmar.c | 123 |
1 files changed, 105 insertions, 18 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index b952ebc7a78b..33ead97f0c4b 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/interrupt.h> | 35 | #include <linux/interrupt.h> |
36 | #include <linux/tboot.h> | 36 | #include <linux/tboot.h> |
37 | #include <linux/dmi.h> | 37 | #include <linux/dmi.h> |
38 | #include <linux/slab.h> | ||
38 | 39 | ||
39 | #define PREFIX "DMAR: " | 40 | #define PREFIX "DMAR: " |
40 | 41 | ||
@@ -320,7 +321,7 @@ found: | |||
320 | for (bus = dev->bus; bus; bus = bus->parent) { | 321 | for (bus = dev->bus; bus; bus = bus->parent) { |
321 | struct pci_dev *bridge = bus->self; | 322 | struct pci_dev *bridge = bus->self; |
322 | 323 | ||
323 | if (!bridge || !bridge->is_pcie || | 324 | if (!bridge || !pci_is_pcie(bridge) || |
324 | bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) | 325 | bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) |
325 | return 0; | 326 | return 0; |
326 | 327 | ||
@@ -339,6 +340,35 @@ found: | |||
339 | } | 340 | } |
340 | #endif | 341 | #endif |
341 | 342 | ||
343 | #ifdef CONFIG_ACPI_NUMA | ||
344 | static int __init | ||
345 | dmar_parse_one_rhsa(struct acpi_dmar_header *header) | ||
346 | { | ||
347 | struct acpi_dmar_rhsa *rhsa; | ||
348 | struct dmar_drhd_unit *drhd; | ||
349 | |||
350 | rhsa = (struct acpi_dmar_rhsa *)header; | ||
351 | for_each_drhd_unit(drhd) { | ||
352 | if (drhd->reg_base_addr == rhsa->base_address) { | ||
353 | int node = acpi_map_pxm_to_node(rhsa->proximity_domain); | ||
354 | |||
355 | if (!node_online(node)) | ||
356 | node = -1; | ||
357 | drhd->iommu->node = node; | ||
358 | return 0; | ||
359 | } | ||
360 | } | ||
361 | WARN(1, "Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n" | ||
362 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | ||
363 | drhd->reg_base_addr, | ||
364 | dmi_get_system_info(DMI_BIOS_VENDOR), | ||
365 | dmi_get_system_info(DMI_BIOS_VERSION), | ||
366 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | #endif | ||
371 | |||
342 | static void __init | 372 | static void __init |
343 | dmar_table_print_dmar_entry(struct acpi_dmar_header *header) | 373 | dmar_table_print_dmar_entry(struct acpi_dmar_header *header) |
344 | { | 374 | { |
@@ -458,7 +488,9 @@ parse_dmar_table(void) | |||
458 | #endif | 488 | #endif |
459 | break; | 489 | break; |
460 | case ACPI_DMAR_HARDWARE_AFFINITY: | 490 | case ACPI_DMAR_HARDWARE_AFFINITY: |
461 | /* We don't do anything with RHSA (yet?) */ | 491 | #ifdef CONFIG_ACPI_NUMA |
492 | ret = dmar_parse_one_rhsa(entry_header); | ||
493 | #endif | ||
462 | break; | 494 | break; |
463 | default: | 495 | default: |
464 | printk(KERN_WARNING PREFIX | 496 | printk(KERN_WARNING PREFIX |
@@ -582,6 +614,8 @@ int __init dmar_table_init(void) | |||
582 | return 0; | 614 | return 0; |
583 | } | 615 | } |
584 | 616 | ||
617 | static int bios_warned; | ||
618 | |||
585 | int __init check_zero_address(void) | 619 | int __init check_zero_address(void) |
586 | { | 620 | { |
587 | struct acpi_table_dmar *dmar; | 621 | struct acpi_table_dmar *dmar; |
@@ -601,6 +635,9 @@ int __init check_zero_address(void) | |||
601 | } | 635 | } |
602 | 636 | ||
603 | if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) { | 637 | if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) { |
638 | void __iomem *addr; | ||
639 | u64 cap, ecap; | ||
640 | |||
604 | drhd = (void *)entry_header; | 641 | drhd = (void *)entry_header; |
605 | if (!drhd->address) { | 642 | if (!drhd->address) { |
606 | /* Promote an attitude of violence to a BIOS engineer today */ | 643 | /* Promote an attitude of violence to a BIOS engineer today */ |
@@ -609,17 +646,40 @@ int __init check_zero_address(void) | |||
609 | dmi_get_system_info(DMI_BIOS_VENDOR), | 646 | dmi_get_system_info(DMI_BIOS_VENDOR), |
610 | dmi_get_system_info(DMI_BIOS_VERSION), | 647 | dmi_get_system_info(DMI_BIOS_VERSION), |
611 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | 648 | dmi_get_system_info(DMI_PRODUCT_VERSION)); |
612 | #ifdef CONFIG_DMAR | 649 | bios_warned = 1; |
613 | dmar_disabled = 1; | 650 | goto failed; |
614 | #endif | 651 | } |
615 | return 0; | 652 | |
653 | addr = early_ioremap(drhd->address, VTD_PAGE_SIZE); | ||
654 | if (!addr ) { | ||
655 | printk("IOMMU: can't validate: %llx\n", drhd->address); | ||
656 | goto failed; | ||
657 | } | ||
658 | cap = dmar_readq(addr + DMAR_CAP_REG); | ||
659 | ecap = dmar_readq(addr + DMAR_ECAP_REG); | ||
660 | early_iounmap(addr, VTD_PAGE_SIZE); | ||
661 | if (cap == (uint64_t)-1 && ecap == (uint64_t)-1) { | ||
662 | /* Promote an attitude of violence to a BIOS engineer today */ | ||
663 | WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n" | ||
664 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | ||
665 | drhd->address, | ||
666 | dmi_get_system_info(DMI_BIOS_VENDOR), | ||
667 | dmi_get_system_info(DMI_BIOS_VERSION), | ||
668 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | ||
669 | bios_warned = 1; | ||
670 | goto failed; | ||
616 | } | 671 | } |
617 | break; | ||
618 | } | 672 | } |
619 | 673 | ||
620 | entry_header = ((void *)entry_header + entry_header->length); | 674 | entry_header = ((void *)entry_header + entry_header->length); |
621 | } | 675 | } |
622 | return 1; | 676 | return 1; |
677 | |||
678 | failed: | ||
679 | #ifdef CONFIG_DMAR | ||
680 | dmar_disabled = 1; | ||
681 | #endif | ||
682 | return 0; | ||
623 | } | 683 | } |
624 | 684 | ||
625 | void __init detect_intel_iommu(void) | 685 | void __init detect_intel_iommu(void) |
@@ -645,9 +705,15 @@ void __init detect_intel_iommu(void) | |||
645 | "x2apic and Intr-remapping.\n"); | 705 | "x2apic and Intr-remapping.\n"); |
646 | #endif | 706 | #endif |
647 | #ifdef CONFIG_DMAR | 707 | #ifdef CONFIG_DMAR |
648 | if (ret && !no_iommu && !iommu_detected && !swiotlb && | 708 | if (ret && !no_iommu && !iommu_detected && !dmar_disabled) { |
649 | !dmar_disabled) | ||
650 | iommu_detected = 1; | 709 | iommu_detected = 1; |
710 | /* Make sure ACS will be enabled */ | ||
711 | pci_request_acs(); | ||
712 | } | ||
713 | #endif | ||
714 | #ifdef CONFIG_X86 | ||
715 | if (ret) | ||
716 | x86_init.iommu.iommu_init = intel_iommu_init; | ||
651 | #endif | 717 | #endif |
652 | } | 718 | } |
653 | early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size); | 719 | early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size); |
@@ -664,6 +730,18 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) | |||
664 | int agaw = 0; | 730 | int agaw = 0; |
665 | int msagaw = 0; | 731 | int msagaw = 0; |
666 | 732 | ||
733 | if (!drhd->reg_base_addr) { | ||
734 | if (!bios_warned) { | ||
735 | WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n" | ||
736 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | ||
737 | dmi_get_system_info(DMI_BIOS_VENDOR), | ||
738 | dmi_get_system_info(DMI_BIOS_VERSION), | ||
739 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | ||
740 | bios_warned = 1; | ||
741 | } | ||
742 | return -EINVAL; | ||
743 | } | ||
744 | |||
667 | iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); | 745 | iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); |
668 | if (!iommu) | 746 | if (!iommu) |
669 | return -ENOMEM; | 747 | return -ENOMEM; |
@@ -680,13 +758,16 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) | |||
680 | iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); | 758 | iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); |
681 | 759 | ||
682 | if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) { | 760 | if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) { |
683 | /* Promote an attitude of violence to a BIOS engineer today */ | 761 | if (!bios_warned) { |
684 | WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n" | 762 | /* Promote an attitude of violence to a BIOS engineer today */ |
685 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | 763 | WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n" |
686 | drhd->reg_base_addr, | 764 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", |
687 | dmi_get_system_info(DMI_BIOS_VENDOR), | 765 | drhd->reg_base_addr, |
688 | dmi_get_system_info(DMI_BIOS_VERSION), | 766 | dmi_get_system_info(DMI_BIOS_VENDOR), |
689 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | 767 | dmi_get_system_info(DMI_BIOS_VERSION), |
768 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | ||
769 | bios_warned = 1; | ||
770 | } | ||
690 | goto err_unmap; | 771 | goto err_unmap; |
691 | } | 772 | } |
692 | 773 | ||
@@ -709,6 +790,8 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) | |||
709 | iommu->agaw = agaw; | 790 | iommu->agaw = agaw; |
710 | iommu->msagaw = msagaw; | 791 | iommu->msagaw = msagaw; |
711 | 792 | ||
793 | iommu->node = -1; | ||
794 | |||
712 | /* the registers might be more than one page */ | 795 | /* the registers might be more than one page */ |
713 | map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), | 796 | map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), |
714 | cap_max_fault_reg_offset(iommu->cap)); | 797 | cap_max_fault_reg_offset(iommu->cap)); |
@@ -1050,6 +1133,7 @@ static void __dmar_enable_qi(struct intel_iommu *iommu) | |||
1050 | int dmar_enable_qi(struct intel_iommu *iommu) | 1133 | int dmar_enable_qi(struct intel_iommu *iommu) |
1051 | { | 1134 | { |
1052 | struct q_inval *qi; | 1135 | struct q_inval *qi; |
1136 | struct page *desc_page; | ||
1053 | 1137 | ||
1054 | if (!ecap_qis(iommu->ecap)) | 1138 | if (!ecap_qis(iommu->ecap)) |
1055 | return -ENOENT; | 1139 | return -ENOENT; |
@@ -1066,13 +1150,16 @@ int dmar_enable_qi(struct intel_iommu *iommu) | |||
1066 | 1150 | ||
1067 | qi = iommu->qi; | 1151 | qi = iommu->qi; |
1068 | 1152 | ||
1069 | qi->desc = (void *)(get_zeroed_page(GFP_ATOMIC)); | 1153 | |
1070 | if (!qi->desc) { | 1154 | desc_page = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO, 0); |
1155 | if (!desc_page) { | ||
1071 | kfree(qi); | 1156 | kfree(qi); |
1072 | iommu->qi = 0; | 1157 | iommu->qi = 0; |
1073 | return -ENOMEM; | 1158 | return -ENOMEM; |
1074 | } | 1159 | } |
1075 | 1160 | ||
1161 | qi->desc = page_address(desc_page); | ||
1162 | |||
1076 | qi->desc_status = kmalloc(QI_LENGTH * sizeof(int), GFP_ATOMIC); | 1163 | qi->desc_status = kmalloc(QI_LENGTH * sizeof(int), GFP_ATOMIC); |
1077 | if (!qi->desc_status) { | 1164 | if (!qi->desc_status) { |
1078 | free_page((unsigned long) qi->desc); | 1165 | free_page((unsigned long) qi->desc); |