Merge branch 'topic/core-cleanup' into for-linus
[safe/jmp/linux-2.6] / arch / x86 / kernel / amd_iommu.c
index b75fcd9..f854d89 100644 (file)
@@ -18,8 +18,8 @@
  */
 
 #include <linux/pci.h>
-#include <linux/gfp.h>
-#include <linux/bitops.h>
+#include <linux/bitmap.h>
+#include <linux/slab.h>
 #include <linux/debugfs.h>
 #include <linux/scatterlist.h>
 #include <linux/dma-mapping.h>
@@ -118,7 +118,7 @@ static bool check_device(struct device *dev)
                return false;
 
        /* No device or no PCI device */
-       if (!dev || dev->bus != &pci_bus_type)
+       if (dev->bus != &pci_bus_type)
                return false;
 
        devid = get_device_id(dev);
@@ -166,6 +166,43 @@ static void iommu_uninit_device(struct device *dev)
 {
        kfree(dev->archdata.iommu);
 }
+
+void __init amd_iommu_uninit_devices(void)
+{
+       struct pci_dev *pdev = NULL;
+
+       for_each_pci_dev(pdev) {
+
+               if (!check_device(&pdev->dev))
+                       continue;
+
+               iommu_uninit_device(&pdev->dev);
+       }
+}
+
+int __init amd_iommu_init_devices(void)
+{
+       struct pci_dev *pdev = NULL;
+       int ret = 0;
+
+       for_each_pci_dev(pdev) {
+
+               if (!check_device(&pdev->dev))
+                       continue;
+
+               ret = iommu_init_device(&pdev->dev);
+               if (ret)
+                       goto out_free;
+       }
+
+       return 0;
+
+out_free:
+
+       amd_iommu_uninit_devices();
+
+       return ret;
+}
 #ifdef CONFIG_AMD_IOMMU_STATS
 
 /*
@@ -355,6 +392,7 @@ static int __iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
        u32 tail, head;
        u8 *target;
 
+       WARN_ON(iommu->cmd_buf_size & CMD_BUFFER_UNINITIALIZED);
        tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
        target = iommu->cmd_buf + tail;
        memcpy_toio(target, cmd, sizeof(*cmd));
@@ -943,7 +981,7 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom,
 {
        int index = dma_dom->aperture_size >> APERTURE_RANGE_SHIFT;
        struct amd_iommu *iommu;
-       int i;
+       unsigned long i;
 
 #ifdef CONFIG_IOMMU_STRESS
        populate = false;
@@ -1125,7 +1163,7 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom,
 
        address = (address % APERTURE_RANGE_SIZE) >> PAGE_SHIFT;
 
-       iommu_area_free(range->bitmap, address, pages);
+       bitmap_clear(range->bitmap, address, pages);
 
 }
 
@@ -1309,8 +1347,6 @@ static void set_dte_entry(u16 devid, struct protection_domain *domain)
 {
        u64 pte_root = virt_to_phys(domain->pt_root);
 
-       BUG_ON(amd_iommu_pd_table[devid] != NULL);
-
        pte_root |= (domain->mode & DEV_ENTRY_MODE_MASK)
                    << DEV_ENTRY_MODE_SHIFT;
        pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | IOMMU_PTE_TV;
@@ -1318,20 +1354,10 @@ static void set_dte_entry(u16 devid, struct protection_domain *domain)
        amd_iommu_dev_table[devid].data[2] = domain->id;
        amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root);
        amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root);
-
-       amd_iommu_pd_table[devid] = domain;
-
 }
 
 static void clear_dte_entry(u16 devid)
 {
-       struct protection_domain *domain = amd_iommu_pd_table[devid];
-
-       BUG_ON(domain == NULL);
-
-       /* remove domain from the lookup table */
-       amd_iommu_pd_table[devid] = NULL;
-
        /* remove entry from the device table seen by the hardware */
        amd_iommu_dev_table[devid].data[0] = IOMMU_PTE_P | IOMMU_PTE_TV;
        amd_iommu_dev_table[devid].data[1] = 0;
@@ -1464,11 +1490,14 @@ static void __detach_device(struct device *dev)
 {
        struct iommu_dev_data *dev_data = get_dev_data(dev);
        struct iommu_dev_data *alias_data;
+       struct protection_domain *domain;
        unsigned long flags;
 
        BUG_ON(!dev_data->domain);
 
-       spin_lock_irqsave(&dev_data->domain->lock, flags);
+       domain = dev_data->domain;
+
+       spin_lock_irqsave(&domain->lock, flags);
 
        if (dev_data->alias != dev) {
                alias_data = get_dev_data(dev_data->alias);
@@ -1479,13 +1508,15 @@ static void __detach_device(struct device *dev)
        if (atomic_dec_and_test(&dev_data->bind))
                do_detach(dev);
 
-       spin_unlock_irqrestore(&dev_data->domain->lock, flags);
+       spin_unlock_irqrestore(&domain->lock, flags);
 
        /*
         * If we run in passthrough mode the device must be assigned to the
-        * passthrough domain if it is detached from any other domain
+        * passthrough domain if it is detached from any other domain.
+        * Make sure we can deassign from the pt_domain itself.
         */
-       if (iommu_pass_through && dev_data->domain == NULL)
+       if (iommu_pass_through &&
+           (dev_data->domain == NULL && domain != pt_domain))
                __attach_device(dev, pt_domain);
 }
 
@@ -1599,6 +1630,11 @@ static struct notifier_block device_nb = {
        .notifier_call = device_change_notifier,
 };
 
+void amd_iommu_init_notifier(void)
+{
+       bus_register_notifier(&pci_bus_type, &device_nb);
+}
+
 /*****************************************************************************
  *
  * The next functions belong to the dma_ops mapping/unmapping code.
@@ -1641,15 +1677,11 @@ static struct protection_domain *get_domain(struct device *dev)
 
 static void update_device_table(struct protection_domain *domain)
 {
-       unsigned long flags;
-       int i;
+       struct iommu_dev_data *dev_data;
 
-       for (i = 0; i <= amd_iommu_last_bdf; ++i) {
-               if (amd_iommu_pd_table[i] != domain)
-                       continue;
-               write_lock_irqsave(&amd_iommu_devtable_lock, flags);
-               set_dte_entry(i, domain);
-               write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
+       list_for_each_entry(dev_data, &domain->dev_list, list) {
+               u16 devid = get_device_id(dev_data->dev);
+               set_dte_entry(devid, domain);
        }
 }
 
@@ -1799,7 +1831,7 @@ retry:
                        goto out;
 
                /*
-                * aperture was sucessfully enlarged by 128 MB, try
+                * aperture was successfully enlarged by 128 MB, try
                 * allocation again
                 */
                goto retry;
@@ -2155,14 +2187,12 @@ static void prealloc_protection_domains(void)
        struct dma_ops_domain *dma_dom;
        u16 devid;
 
-       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+       for_each_pci_dev(dev) {
 
                /* Do we handle this device? */
                if (!check_device(&dev->dev))
                        continue;
 
-               iommu_init_device(&dev->dev);
-
                /* Is there already any domain for it? */
                if (domain_for_device(&dev->dev))
                        continue;
@@ -2194,6 +2224,12 @@ static struct dma_map_ops amd_iommu_dma_ops = {
 /*
  * The function which clues the AMD IOMMU driver into dma_ops.
  */
+
+void __init amd_iommu_init_api(void)
+{
+       register_iommu(&amd_iommu_ops);
+}
+
 int __init amd_iommu_init_dma_ops(void)
 {
        struct amd_iommu *iommu;
@@ -2229,10 +2265,6 @@ int __init amd_iommu_init_dma_ops(void)
        /* Make the driver finally visible to the drivers */
        dma_ops = &amd_iommu_dma_ops;
 
-       register_iommu(&amd_iommu_ops);
-
-       bus_register_notifier(&pci_bus_type, &device_nb);
-
        amd_iommu_stats_init();
 
        return 0;
@@ -2259,14 +2291,17 @@ free_domains:
 
 static void cleanup_domain(struct protection_domain *domain)
 {
+       struct iommu_dev_data *dev_data, *next;
        unsigned long flags;
-       u16 devid;
 
        write_lock_irqsave(&amd_iommu_devtable_lock, flags);
 
-       for (devid = 0; devid <= amd_iommu_last_bdf; ++devid)
-               if (amd_iommu_pd_table[devid] == domain)
-                       clear_dte_entry(devid);
+       list_for_each_entry_safe(dev_data, next, &domain->dev_list, list) {
+               struct device *dev = dev_data->dev;
+
+               __detach_device(dev);
+               atomic_set(&dev_data->bind, 0);
+       }
 
        write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
 }
@@ -2293,6 +2328,7 @@ static struct protection_domain *protection_domain_alloc(void)
                return NULL;
 
        spin_lock_init(&domain->lock);
+       mutex_init(&domain->api_lock);
        domain->id = domain_id_alloc();
        if (!domain->id)
                goto out_err;
@@ -2345,9 +2381,7 @@ static void amd_iommu_domain_destroy(struct iommu_domain *dom)
 
        free_pagetable(domain);
 
-       domain_id_free(domain->id);
-
-       kfree(domain);
+       protection_domain_free(domain);
 
        dom->priv = NULL;
 }
@@ -2422,6 +2456,8 @@ static int amd_iommu_map_range(struct iommu_domain *dom,
        iova  &= PAGE_MASK;
        paddr &= PAGE_MASK;
 
+       mutex_lock(&domain->api_lock);
+
        for (i = 0; i < npages; ++i) {
                ret = iommu_map_page(domain, iova, paddr, prot, PM_MAP_4k);
                if (ret)
@@ -2431,6 +2467,8 @@ static int amd_iommu_map_range(struct iommu_domain *dom,
                paddr += PAGE_SIZE;
        }
 
+       mutex_unlock(&domain->api_lock);
+
        return 0;
 }
 
@@ -2443,12 +2481,16 @@ static void amd_iommu_unmap_range(struct iommu_domain *dom,
 
        iova  &= PAGE_MASK;
 
+       mutex_lock(&domain->api_lock);
+
        for (i = 0; i < npages; ++i) {
                iommu_unmap_page(domain, iova, PM_MAP_4k);
                iova  += PAGE_SIZE;
        }
 
        iommu_flush_tlb_pde(domain);
+
+       mutex_unlock(&domain->api_lock);
 }
 
 static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom,
@@ -2503,7 +2545,7 @@ int __init amd_iommu_init_passthrough(void)
        struct pci_dev *dev = NULL;
        u16 devid;
 
-       /* allocate passthroug domain */
+       /* allocate passthrough domain */
        pt_domain = protection_domain_alloc();
        if (!pt_domain)
                return -ENOMEM;