aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-11-14 16:05:27 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-11-14 16:05:27 -0500
commita9366e61b03f55a6e009e687ad10e706714c9907 (patch)
treeb68f510ae8924db3385eae783a1294d0af03ae37 /drivers
parent24dfb2b5867df24ba03b6c4418312e23b1300aa8 (diff)
parent99dcadede42f8898d4c963ef69192ef4b9b76ba8 (diff)
Merge git://git.infradead.org/users/dwmw2/iommu-2.6.32
* git://git.infradead.org/users/dwmw2/iommu-2.6.32: intel-iommu: Support PCIe hot-plug intel-iommu: Obey coherent_dma_mask for alloc_coherent on passthrough intel-iommu: Check for 'DMAR at zero' BIOS error earlier.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/dmar.c49
-rw-r--r--drivers/pci/intel-iommu.c39
2 files changed, 77 insertions, 11 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 22b02c6df854..e5f8fc164fd3 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,50 @@ int __init dmar_table_init(void)
591 return 0; 582 return 0;
592} 583}
593 584
585int __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 return 0;
613 }
614 break;
615 }
616
617 entry_header = ((void *)entry_header + entry_header->length);
618 }
619 return 1;
620}
621
594void __init detect_intel_iommu(void) 622void __init detect_intel_iommu(void)
595{ 623{
596 int ret; 624 int ret;
597 625
598 ret = dmar_table_detect(); 626 ret = dmar_table_detect();
599 627 if (ret)
628 ret = check_zero_address();
600 { 629 {
601#ifdef CONFIG_INTR_REMAP 630#ifdef CONFIG_INTR_REMAP
602 struct acpi_table_dmar *dmar; 631 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 */
3224static 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
3241static struct notifier_block device_nb = {
3242 .notifier_call = device_notifier,
3243};
3244
3210int __init intel_iommu_init(void) 3245int __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