diff options
Diffstat (limited to 'drivers/pci')
| -rw-r--r-- | drivers/pci/dmar.c | 52 | ||||
| -rw-r--r-- | drivers/pci/intel-iommu.c | 39 | ||||
| -rw-r--r-- | drivers/pci/pcie/aspm.c | 6 | ||||
| -rw-r--r-- | drivers/pci/setup-bus.c | 13 |
4 files changed, 86 insertions, 24 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 22b02c6df854..b952ebc7a78b 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c | |||
| @@ -175,15 +175,6 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header) | |||
| 175 | int ret = 0; | 175 | int ret = 0; |
| 176 | 176 | ||
| 177 | drhd = (struct acpi_dmar_hardware_unit *)header; | 177 | drhd = (struct acpi_dmar_hardware_unit *)header; |
| 178 | if (!drhd->address) { | ||
| 179 | /* Promote an attitude of violence to a BIOS engineer today */ | ||
| 180 | WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n" | ||
| 181 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | ||
| 182 | dmi_get_system_info(DMI_BIOS_VENDOR), | ||
| 183 | dmi_get_system_info(DMI_BIOS_VERSION), | ||
| 184 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | ||
| 185 | return -ENODEV; | ||
| 186 | } | ||
| 187 | dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL); | 178 | dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL); |
| 188 | if (!dmaru) | 179 | if (!dmaru) |
| 189 | return -ENOMEM; | 180 | return -ENOMEM; |
| @@ -591,12 +582,53 @@ int __init dmar_table_init(void) | |||
| 591 | return 0; | 582 | return 0; |
| 592 | } | 583 | } |
| 593 | 584 | ||
| 585 | int __init check_zero_address(void) | ||
| 586 | { | ||
| 587 | struct acpi_table_dmar *dmar; | ||
| 588 | struct acpi_dmar_header *entry_header; | ||
| 589 | struct acpi_dmar_hardware_unit *drhd; | ||
| 590 | |||
| 591 | dmar = (struct acpi_table_dmar *)dmar_tbl; | ||
| 592 | entry_header = (struct acpi_dmar_header *)(dmar + 1); | ||
| 593 | |||
| 594 | while (((unsigned long)entry_header) < | ||
| 595 | (((unsigned long)dmar) + dmar_tbl->length)) { | ||
| 596 | /* Avoid looping forever on bad ACPI tables */ | ||
| 597 | if (entry_header->length == 0) { | ||
| 598 | printk(KERN_WARNING PREFIX | ||
| 599 | "Invalid 0-length structure\n"); | ||
| 600 | return 0; | ||
| 601 | } | ||
| 602 | |||
| 603 | if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) { | ||
| 604 | drhd = (void *)entry_header; | ||
| 605 | if (!drhd->address) { | ||
| 606 | /* Promote an attitude of violence to a BIOS engineer today */ | ||
| 607 | WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n" | ||
| 608 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | ||
| 609 | dmi_get_system_info(DMI_BIOS_VENDOR), | ||
| 610 | dmi_get_system_info(DMI_BIOS_VERSION), | ||
| 611 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | ||
| 612 | #ifdef CONFIG_DMAR | ||
| 613 | dmar_disabled = 1; | ||
| 614 | #endif | ||
| 615 | return 0; | ||
| 616 | } | ||
| 617 | break; | ||
| 618 | } | ||
| 619 | |||
| 620 | entry_header = ((void *)entry_header + entry_header->length); | ||
| 621 | } | ||
| 622 | return 1; | ||
| 623 | } | ||
| 624 | |||
| 594 | void __init detect_intel_iommu(void) | 625 | void __init detect_intel_iommu(void) |
| 595 | { | 626 | { |
| 596 | int ret; | 627 | int ret; |
| 597 | 628 | ||
| 598 | ret = dmar_table_detect(); | 629 | ret = dmar_table_detect(); |
| 599 | 630 | if (ret) | |
| 631 | ret = check_zero_address(); | ||
| 600 | { | 632 | { |
| 601 | #ifdef CONFIG_INTR_REMAP | 633 | #ifdef CONFIG_INTR_REMAP |
| 602 | struct acpi_table_dmar *dmar; | 634 | struct acpi_table_dmar *dmar; |
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index b1e97e682500..1840a0578a42 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c | |||
| @@ -2767,7 +2767,15 @@ static void *intel_alloc_coherent(struct device *hwdev, size_t size, | |||
| 2767 | 2767 | ||
| 2768 | size = PAGE_ALIGN(size); | 2768 | size = PAGE_ALIGN(size); |
| 2769 | order = get_order(size); | 2769 | order = get_order(size); |
| 2770 | flags &= ~(GFP_DMA | GFP_DMA32); | 2770 | |
| 2771 | if (!iommu_no_mapping(hwdev)) | ||
| 2772 | flags &= ~(GFP_DMA | GFP_DMA32); | ||
| 2773 | else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) { | ||
| 2774 | if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32)) | ||
| 2775 | flags |= GFP_DMA; | ||
| 2776 | else | ||
| 2777 | flags |= GFP_DMA32; | ||
| 2778 | } | ||
| 2771 | 2779 | ||
| 2772 | vaddr = (void *)__get_free_pages(flags, order); | 2780 | vaddr = (void *)__get_free_pages(flags, order); |
| 2773 | if (!vaddr) | 2781 | if (!vaddr) |
| @@ -3207,6 +3215,33 @@ static int __init init_iommu_sysfs(void) | |||
| 3207 | } | 3215 | } |
| 3208 | #endif /* CONFIG_PM */ | 3216 | #endif /* CONFIG_PM */ |
| 3209 | 3217 | ||
| 3218 | /* | ||
| 3219 | * Here we only respond to action of unbound device from driver. | ||
| 3220 | * | ||
| 3221 | * Added device is not attached to its DMAR domain here yet. That will happen | ||
| 3222 | * when mapping the device to iova. | ||
| 3223 | */ | ||
| 3224 | static int device_notifier(struct notifier_block *nb, | ||
| 3225 | unsigned long action, void *data) | ||
| 3226 | { | ||
| 3227 | struct device *dev = data; | ||
| 3228 | struct pci_dev *pdev = to_pci_dev(dev); | ||
| 3229 | struct dmar_domain *domain; | ||
| 3230 | |||
| 3231 | domain = find_domain(pdev); | ||
| 3232 | if (!domain) | ||
| 3233 | return 0; | ||
| 3234 | |||
| 3235 | if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) | ||
| 3236 | domain_remove_one_dev_info(domain, pdev); | ||
| 3237 | |||
| 3238 | return 0; | ||
| 3239 | } | ||
| 3240 | |||
| 3241 | static struct notifier_block device_nb = { | ||
| 3242 | .notifier_call = device_notifier, | ||
| 3243 | }; | ||
| 3244 | |||
| 3210 | int __init intel_iommu_init(void) | 3245 | int __init intel_iommu_init(void) |
| 3211 | { | 3246 | { |
| 3212 | int ret = 0; | 3247 | int ret = 0; |
| @@ -3259,6 +3294,8 @@ int __init intel_iommu_init(void) | |||
| 3259 | 3294 | ||
| 3260 | register_iommu(&intel_iommu_ops); | 3295 | register_iommu(&intel_iommu_ops); |
| 3261 | 3296 | ||
| 3297 | bus_register_notifier(&pci_bus_type, &device_nb); | ||
| 3298 | |||
| 3262 | return 0; | 3299 | return 0; |
| 3263 | } | 3300 | } |
| 3264 | 3301 | ||
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 745402e8e498..5b7056cec00c 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
| @@ -656,8 +656,10 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) | |||
| 656 | free_link_state(link); | 656 | free_link_state(link); |
| 657 | 657 | ||
| 658 | /* Recheck latencies and configure upstream links */ | 658 | /* Recheck latencies and configure upstream links */ |
| 659 | pcie_update_aspm_capable(root); | 659 | if (parent_link) { |
| 660 | pcie_config_aspm_path(parent_link); | 660 | pcie_update_aspm_capable(root); |
| 661 | pcie_config_aspm_path(parent_link); | ||
| 662 | } | ||
| 661 | out: | 663 | out: |
| 662 | mutex_unlock(&aspm_lock); | 664 | mutex_unlock(&aspm_lock); |
| 663 | up_read(&pci_bus_sem); | 665 | up_read(&pci_bus_sem); |
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 0959430534b2..cb1a027eb552 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
| @@ -299,17 +299,8 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned lon | |||
| 299 | r = bus->resource[i]; | 299 | r = bus->resource[i]; |
| 300 | if (r == &ioport_resource || r == &iomem_resource) | 300 | if (r == &ioport_resource || r == &iomem_resource) |
| 301 | continue; | 301 | continue; |
| 302 | if (r && (r->flags & type_mask) == type) { | 302 | if (r && (r->flags & type_mask) == type && !r->parent) |
| 303 | if (!r->parent) | 303 | return r; |
| 304 | return r; | ||
| 305 | /* | ||
| 306 | * if there is no child under that, we should release | ||
| 307 | * and use it. don't need to reset it, pbus_size_* will | ||
| 308 | * set it again | ||
| 309 | */ | ||
| 310 | if (!r->child && !release_resource(r)) | ||
| 311 | return r; | ||
| 312 | } | ||
| 313 | } | 304 | } |
| 314 | return NULL; | 305 | return NULL; |
| 315 | } | 306 | } |
