Merge branch 'core-iommu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 5 Dec 2009 17:49:07 +0000 (09:49 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 5 Dec 2009 17:49:07 +0000 (09:49 -0800)
* 'core-iommu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (63 commits)
  x86, Calgary IOMMU quirk: Find nearest matching Calgary while walking up the PCI tree
  x86/amd-iommu: Remove amd_iommu_pd_table
  x86/amd-iommu: Move reset_iommu_command_buffer out of locked code
  x86/amd-iommu: Cleanup DTE flushing code
  x86/amd-iommu: Introduce iommu_flush_device() function
  x86/amd-iommu: Cleanup attach/detach_device code
  x86/amd-iommu: Keep devices per domain in a list
  x86/amd-iommu: Add device bind reference counting
  x86/amd-iommu: Use dev->arch->iommu to store iommu related information
  x86/amd-iommu: Remove support for domain sharing
  x86/amd-iommu: Rearrange dma_ops related functions
  x86/amd-iommu: Move some pte allocation functions in the right section
  x86/amd-iommu: Remove iommu parameter from dma_ops_domain_alloc
  x86/amd-iommu: Use get_device_id and check_device where appropriate
  x86/amd-iommu: Move find_protection_domain to helper functions
  x86/amd-iommu: Simplify get_device_resources()
  x86/amd-iommu: Let domain_for_device handle aliases
  x86/amd-iommu: Remove iommu specific handling from dma_ops path
  x86/amd-iommu: Remove iommu parameter from __(un)map_single
  x86/amd-iommu: Make alloc_new_range aware of multiple IOMMUs
  ...

1  2 
drivers/pci/dmar.c
drivers/pci/intel-iommu.c

diff --combined drivers/pci/dmar.c
index b952ebc7a78b67776d985f006fb33633be43b80b,437399667e5afb093f965a930f2cc67f3c89faf0..416f6ac65b761080a2e81a8ace5c5d442a8ea2d1
@@@ -175,6 -175,15 +175,6 @@@ dmar_parse_one_drhd(struct acpi_dmar_he
        int ret = 0;
  
        drhd = (struct acpi_dmar_hardware_unit *)header;
 -      if (!drhd->address) {
 -              /* Promote an attitude of violence to a BIOS engineer today */
 -              WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n"
 -                   "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
 -                   dmi_get_system_info(DMI_BIOS_VENDOR),
 -                   dmi_get_system_info(DMI_BIOS_VERSION),
 -                   dmi_get_system_info(DMI_PRODUCT_VERSION));
 -              return -ENODEV;
 -      }
        dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL);
        if (!dmaru)
                return -ENOMEM;
@@@ -582,53 -591,12 +582,53 @@@ int __init dmar_table_init(void
        return 0;
  }
  
 +int __init check_zero_address(void)
 +{
 +      struct acpi_table_dmar *dmar;
 +      struct acpi_dmar_header *entry_header;
 +      struct acpi_dmar_hardware_unit *drhd;
 +
 +      dmar = (struct acpi_table_dmar *)dmar_tbl;
 +      entry_header = (struct acpi_dmar_header *)(dmar + 1);
 +
 +      while (((unsigned long)entry_header) <
 +                      (((unsigned long)dmar) + dmar_tbl->length)) {
 +              /* Avoid looping forever on bad ACPI tables */
 +              if (entry_header->length == 0) {
 +                      printk(KERN_WARNING PREFIX
 +                              "Invalid 0-length structure\n");
 +                      return 0;
 +              }
 +
 +              if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) {
 +                      drhd = (void *)entry_header;
 +                      if (!drhd->address) {
 +                              /* Promote an attitude of violence to a BIOS engineer today */
 +                              WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n"
 +                                   "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
 +                                   dmi_get_system_info(DMI_BIOS_VENDOR),
 +                                   dmi_get_system_info(DMI_BIOS_VERSION),
 +                                   dmi_get_system_info(DMI_PRODUCT_VERSION));
 +#ifdef CONFIG_DMAR
 +                              dmar_disabled = 1;
 +#endif
 +                              return 0;
 +                      }
 +                      break;
 +              }
 +
 +              entry_header = ((void *)entry_header + entry_header->length);
 +      }
 +      return 1;
 +}
 +
  void __init detect_intel_iommu(void)
  {
        int ret;
  
        ret = dmar_table_detect();
 -
 +      if (ret)
 +              ret = check_zero_address();
        {
  #ifdef CONFIG_INTR_REMAP
                struct acpi_table_dmar *dmar;
                               "x2apic and Intr-remapping.\n");
  #endif
  #ifdef CONFIG_DMAR
-               if (ret && !no_iommu && !iommu_detected && !swiotlb &&
-                   !dmar_disabled)
+               if (ret && !no_iommu && !iommu_detected && !dmar_disabled)
                        iommu_detected = 1;
+ #endif
+ #ifdef CONFIG_X86
+               if (ret)
+                       x86_init.iommu.iommu_init = intel_iommu_init;
  #endif
        }
        early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size);
index 1840a0578a429366874ca049d05af748a1f88c09,43d755a2e14aa8908a22a3ff54c046b86794c4ff..9261327b49f308941c07af292a31bc379b7cb6b9
@@@ -2767,15 -2767,7 +2767,15 @@@ static void *intel_alloc_coherent(struc
  
        size = PAGE_ALIGN(size);
        order = get_order(size);
 -      flags &= ~(GFP_DMA | GFP_DMA32);
 +
 +      if (!iommu_no_mapping(hwdev))
 +              flags &= ~(GFP_DMA | GFP_DMA32);
 +      else if (hwdev->coherent_dma_mask < dma_get_required_mask(hwdev)) {
 +              if (hwdev->coherent_dma_mask < DMA_BIT_MASK(32))
 +                      flags |= GFP_DMA;
 +              else
 +                      flags |= GFP_DMA32;
 +      }
  
        vaddr = (void *)__get_free_pages(flags, order);
        if (!vaddr)
@@@ -3215,33 -3207,6 +3215,33 @@@ static int __init init_iommu_sysfs(void
  }
  #endif        /* CONFIG_PM */
  
 +/*
 + * Here we only respond to action of unbound device from driver.
 + *
 + * Added device is not attached to its DMAR domain here yet. That will happen
 + * when mapping the device to iova.
 + */
 +static int device_notifier(struct notifier_block *nb,
 +                                unsigned long action, void *data)
 +{
 +      struct device *dev = data;
 +      struct pci_dev *pdev = to_pci_dev(dev);
 +      struct dmar_domain *domain;
 +
 +      domain = find_domain(pdev);
 +      if (!domain)
 +              return 0;
 +
 +      if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through)
 +              domain_remove_one_dev_info(domain, pdev);
 +
 +      return 0;
 +}
 +
 +static struct notifier_block device_nb = {
 +      .notifier_call = device_notifier,
 +};
 +
  int __init intel_iommu_init(void)
  {
        int ret = 0;
         * Check the need for DMA-remapping initialization now.
         * Above initialization will also be used by Interrupt-remapping.
         */
-       if (no_iommu || swiotlb || dmar_disabled)
+       if (no_iommu || dmar_disabled)
                return -ENODEV;
  
        iommu_init_mempool();
        "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
  
        init_timer(&unmap_timer);
-       force_iommu = 1;
+ #ifdef CONFIG_SWIOTLB
+       swiotlb = 0;
+ #endif
        dma_ops = &intel_dma_ops;
  
        init_iommu_sysfs();
  
        register_iommu(&intel_iommu_ops);
  
 +      bus_register_notifier(&pci_bus_type, &device_nb);
 +
        return 0;
  }