Merge git://git.infradead.org/iommu-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Apr 2011 16:56:35 +0000 (09:56 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Apr 2011 16:56:35 +0000 (09:56 -0700)
* git://git.infradead.org/iommu-2.6:
  intel_iommu: disable all VT-d PMRs when TXT launched
  intel-iommu: Fix get_domain_for_dev() error path
  intel-iommu: Unlink domain from iommu
  intel-iommu: Fix use after release during device attach

1  2 
drivers/pci/intel-iommu.c

@@@ -36,7 -36,7 +36,7 @@@
  #include <linux/iova.h>
  #include <linux/iommu.h>
  #include <linux/intel-iommu.h>
 -#include <linux/sysdev.h>
 +#include <linux/syscore_ops.h>
  #include <linux/tboot.h>
  #include <linux/dmi.h>
  #include <asm/cacheflush.h>
@@@ -1206,7 -1206,7 +1206,7 @@@ void free_dmar_iommu(struct intel_iomm
                iommu_disable_translation(iommu);
  
        if (iommu->irq) {
 -              set_irq_data(iommu->irq, NULL);
 +              irq_set_handler_data(iommu->irq, NULL);
                /* This will mask the irq */
                free_irq(iommu->irq, iommu);
                destroy_irq(iommu->irq);
@@@ -1299,7 -1299,7 +1299,7 @@@ static void iommu_detach_domain(struct 
  static struct iova_domain reserved_iova_list;
  static struct lock_class_key reserved_rbtree_key;
  
- static void dmar_init_reserved_ranges(void)
+ static int dmar_init_reserved_ranges(void)
  {
        struct pci_dev *pdev = NULL;
        struct iova *iova;
        /* IOAPIC ranges shouldn't be accessed by DMA */
        iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
                IOVA_PFN(IOAPIC_RANGE_END));
-       if (!iova)
+       if (!iova) {
                printk(KERN_ERR "Reserve IOAPIC range failed\n");
+               return -ENODEV;
+       }
  
        /* Reserve all PCI MMIO to avoid peer-to-peer access */
        for_each_pci_dev(pdev) {
                        iova = reserve_iova(&reserved_iova_list,
                                            IOVA_PFN(r->start),
                                            IOVA_PFN(r->end));
-                       if (!iova)
+                       if (!iova) {
                                printk(KERN_ERR "Reserve iova failed\n");
+                               return -ENODEV;
+                       }
                }
        }
+       return 0;
  }
  
  static void domain_reserve_special_ranges(struct dmar_domain *domain)
@@@ -1835,7 -1839,7 +1839,7 @@@ static struct dmar_domain *get_domain_f
  
        ret = iommu_attach_domain(domain, iommu);
        if (ret) {
-               domain_exit(domain);
+               free_domain_mem(domain);
                goto error;
        }
  
@@@ -2213,7 -2217,7 +2217,7 @@@ static int __init iommu_prepare_static_
        return 0;
  }
  
int __init init_dmars(void)
static int __init init_dmars(int force_on)
  {
        struct dmar_drhd_unit *drhd;
        struct dmar_rmrr_unit *rmrr;
                /*
                 * TBD:
                 * we could share the same root & context tables
 -               * amoung all IOMMU's. Need to Split it later.
 +               * among all IOMMU's. Need to Split it later.
                 */
                ret = iommu_alloc_root_entry(iommu);
                if (ret) {
         *   enable translation
         */
        for_each_drhd_unit(drhd) {
-               if (drhd->ignored)
+               if (drhd->ignored) {
+                       /*
+                        * we always have to disable PMRs or DMA may fail on
+                        * this device
+                        */
+                       if (force_on)
+                               iommu_disable_protect_mem_regions(drhd->iommu);
                        continue;
+               }
                iommu = drhd->iommu;
  
                iommu_flush_write_buffer(iommu);
@@@ -3135,7 -3146,7 +3146,7 @@@ static void iommu_flush_all(void
        }
  }
  
 -static int iommu_suspend(struct sys_device *dev, pm_message_t state)
 +static int iommu_suspend(void)
  {
        struct dmar_drhd_unit *drhd;
        struct intel_iommu *iommu = NULL;
@@@ -3175,7 -3186,7 +3186,7 @@@ nomem
        return -ENOMEM;
  }
  
 -static int iommu_resume(struct sys_device *dev)
 +static void iommu_resume(void)
  {
        struct dmar_drhd_unit *drhd;
        struct intel_iommu *iommu = NULL;
  
        if (init_iommu_hw()) {
                WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
 -              return -EIO;
 +              return;
        }
  
        for_each_active_iommu(iommu, drhd) {
  
        for_each_active_iommu(iommu, drhd)
                kfree(iommu->iommu_state);
 -
 -      return 0;
  }
  
 -static struct sysdev_class iommu_sysclass = {
 -      .name           = "iommu",
 +static struct syscore_ops iommu_syscore_ops = {
        .resume         = iommu_resume,
        .suspend        = iommu_suspend,
  };
  
 -static struct sys_device device_iommu = {
 -      .cls    = &iommu_sysclass,
 -};
 -
 -static int __init init_iommu_sysfs(void)
 +static void __init init_iommu_pm_ops(void)
  {
 -      int error;
 -
 -      error = sysdev_class_register(&iommu_sysclass);
 -      if (error)
 -              return error;
 -
 -      error = sysdev_register(&device_iommu);
 -      if (error)
 -              sysdev_class_unregister(&iommu_sysclass);
 -
 -      return error;
 +      register_syscore_ops(&iommu_syscore_ops);
  }
  
  #else
 -static int __init init_iommu_sysfs(void)
 -{
 -      return 0;
 -}
 +static inline int init_iommu_pm_ops(void) { }
  #endif        /* CONFIG_PM */
  
  /*
@@@ -3240,9 -3271,15 +3251,15 @@@ static int device_notifier(struct notif
        if (!domain)
                return 0;
  
-       if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through)
+       if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) {
                domain_remove_one_dev_info(domain, pdev);
  
+               if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
+                   !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
+                   list_empty(&domain->devices))
+                       domain_exit(domain);
+       }
        return 0;
  }
  
@@@ -3277,12 -3314,21 +3294,21 @@@ int __init intel_iommu_init(void
        if (no_iommu || dmar_disabled)
                return -ENODEV;
  
-       iommu_init_mempool();
-       dmar_init_reserved_ranges();
+       if (iommu_init_mempool()) {
+               if (force_on)
+                       panic("tboot: Failed to initialize iommu memory\n");
+               return  -ENODEV;
+       }
+       if (dmar_init_reserved_ranges()) {
+               if (force_on)
+                       panic("tboot: Failed to reserve iommu ranges\n");
+               return  -ENODEV;
+       }
  
        init_no_remapping_devices();
  
-       ret = init_dmars();
+       ret = init_dmars(force_on);
        if (ret) {
                if (force_on)
                        panic("tboot: Failed to initialize DMARs\n");
  #endif
        dma_ops = &intel_dma_ops;
  
 -      init_iommu_sysfs();
 +      init_iommu_pm_ops();
  
        register_iommu(&intel_iommu_ops);
  
@@@ -3391,6 -3437,11 +3417,11 @@@ static void domain_remove_one_dev_info(
                domain->iommu_count--;
                domain_update_iommu_cap(domain);
                spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
+               spin_lock_irqsave(&iommu->lock, tmp_flags);
+               clear_bit(domain->id, iommu->domain_ids);
+               iommu->domains[domain->id] = NULL;
+               spin_unlock_irqrestore(&iommu->lock, tmp_flags);
        }
  
        spin_unlock_irqrestore(&device_domain_lock, flags);
@@@ -3607,9 -3658,9 +3638,9 @@@ static int intel_iommu_attach_device(st
  
                pte = dmar_domain->pgd;
                if (dma_pte_present(pte)) {
-                       free_pgtable_page(dmar_domain->pgd);
                        dmar_domain->pgd = (struct dma_pte *)
                                phys_to_virt(dma_pte_addr(pte));
+                       free_pgtable_page(pte);
                }
                dmar_domain->agaw--;
        }