]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/arm64/mm/dma-mapping.c
Merge tag 'sound-fix-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[karo-tx-linux.git] / arch / arm64 / mm / dma-mapping.c
index 7f8b37e85a2bdba0c633473e8be1c8f3cb04c96b..3216e098c05877178705cdcd659a375e0afec0fd 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/dma-contiguous.h>
 #include <linux/vmalloc.h>
 #include <linux/swiotlb.h>
+#include <linux/pci.h>
 
 #include <asm/cacheflush.h>
 
@@ -308,24 +309,15 @@ static void __swiotlb_sync_sg_for_device(struct device *dev,
                                       sg->length, dir);
 }
 
-static int __swiotlb_mmap(struct device *dev,
-                         struct vm_area_struct *vma,
-                         void *cpu_addr, dma_addr_t dma_addr, size_t size,
-                         unsigned long attrs)
+static int __swiotlb_mmap_pfn(struct vm_area_struct *vma,
+                             unsigned long pfn, size_t size)
 {
        int ret = -ENXIO;
        unsigned long nr_vma_pages = (vma->vm_end - vma->vm_start) >>
                                        PAGE_SHIFT;
        unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
-       unsigned long pfn = dma_to_phys(dev, dma_addr) >> PAGE_SHIFT;
        unsigned long off = vma->vm_pgoff;
 
-       vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot,
-                                            is_device_dma_coherent(dev));
-
-       if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
-               return ret;
-
        if (off < nr_pages && nr_vma_pages <= (nr_pages - off)) {
                ret = remap_pfn_range(vma, vma->vm_start,
                                      pfn + off,
@@ -336,19 +328,43 @@ static int __swiotlb_mmap(struct device *dev,
        return ret;
 }
 
-static int __swiotlb_get_sgtable(struct device *dev, struct sg_table *sgt,
-                                void *cpu_addr, dma_addr_t handle, size_t size,
-                                unsigned long attrs)
+static int __swiotlb_mmap(struct device *dev,
+                         struct vm_area_struct *vma,
+                         void *cpu_addr, dma_addr_t dma_addr, size_t size,
+                         unsigned long attrs)
+{
+       int ret;
+       unsigned long pfn = dma_to_phys(dev, dma_addr) >> PAGE_SHIFT;
+
+       vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot,
+                                            is_device_dma_coherent(dev));
+
+       if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+               return ret;
+
+       return __swiotlb_mmap_pfn(vma, pfn, size);
+}
+
+static int __swiotlb_get_sgtable_page(struct sg_table *sgt,
+                                     struct page *page, size_t size)
 {
        int ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
 
        if (!ret)
-               sg_set_page(sgt->sgl, phys_to_page(dma_to_phys(dev, handle)),
-                           PAGE_ALIGN(size), 0);
+               sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
 
        return ret;
 }
 
+static int __swiotlb_get_sgtable(struct device *dev, struct sg_table *sgt,
+                                void *cpu_addr, dma_addr_t handle, size_t size,
+                                unsigned long attrs)
+{
+       struct page *page = phys_to_page(dma_to_phys(dev, handle));
+
+       return __swiotlb_get_sgtable_page(sgt, page, size);
+}
+
 static int __swiotlb_dma_supported(struct device *hwdev, u64 mask)
 {
        if (swiotlb)
@@ -584,20 +600,7 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
         */
        gfp |= __GFP_ZERO;
 
-       if (gfpflags_allow_blocking(gfp)) {
-               struct page **pages;
-               pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, coherent);
-
-               pages = iommu_dma_alloc(dev, iosize, gfp, attrs, ioprot,
-                                       handle, flush_page);
-               if (!pages)
-                       return NULL;
-
-               addr = dma_common_pages_remap(pages, size, VM_USERMAP, prot,
-                                             __builtin_return_address(0));
-               if (!addr)
-                       iommu_dma_free(dev, pages, iosize, handle);
-       } else {
+       if (!gfpflags_allow_blocking(gfp)) {
                struct page *page;
                /*
                 * In atomic context we can't remap anything, so we'll only
@@ -621,6 +624,45 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
                                __free_from_pool(addr, size);
                        addr = NULL;
                }
+       } else if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
+               pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, coherent);
+               struct page *page;
+
+               page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
+                                                get_order(size), gfp);
+               if (!page)
+                       return NULL;
+
+               *handle = iommu_dma_map_page(dev, page, 0, iosize, ioprot);
+               if (iommu_dma_mapping_error(dev, *handle)) {
+                       dma_release_from_contiguous(dev, page,
+                                                   size >> PAGE_SHIFT);
+                       return NULL;
+               }
+               if (!coherent)
+                       __dma_flush_area(page_to_virt(page), iosize);
+
+               addr = dma_common_contiguous_remap(page, size, VM_USERMAP,
+                                                  prot,
+                                                  __builtin_return_address(0));
+               if (!addr) {
+                       iommu_dma_unmap_page(dev, *handle, iosize, 0, attrs);
+                       dma_release_from_contiguous(dev, page,
+                                                   size >> PAGE_SHIFT);
+               }
+       } else {
+               pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, coherent);
+               struct page **pages;
+
+               pages = iommu_dma_alloc(dev, iosize, gfp, attrs, ioprot,
+                                       handle, flush_page);
+               if (!pages)
+                       return NULL;
+
+               addr = dma_common_pages_remap(pages, size, VM_USERMAP, prot,
+                                             __builtin_return_address(0));
+               if (!addr)
+                       iommu_dma_free(dev, pages, iosize, handle);
        }
        return addr;
 }
@@ -632,7 +674,8 @@ static void __iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
 
        size = PAGE_ALIGN(size);
        /*
-        * @cpu_addr will be one of 3 things depending on how it was allocated:
+        * @cpu_addr will be one of 4 things depending on how it was allocated:
+        * - A remapped array of pages for contiguous allocations.
         * - A remapped array of pages from iommu_dma_alloc(), for all
         *   non-atomic allocations.
         * - A non-cacheable alias from the atomic pool, for atomic
@@ -644,6 +687,12 @@ static void __iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
        if (__in_atomic_pool(cpu_addr, size)) {
                iommu_dma_unmap_page(dev, handle, iosize, 0, 0);
                __free_from_pool(cpu_addr, size);
+       } else if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
+               struct page *page = vmalloc_to_page(cpu_addr);
+
+               iommu_dma_unmap_page(dev, handle, iosize, 0, attrs);
+               dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
+               dma_common_free_remap(cpu_addr, size, VM_USERMAP);
        } else if (is_vmalloc_addr(cpu_addr)){
                struct vm_struct *area = find_vm_area(cpu_addr);
 
@@ -670,6 +719,15 @@ static int __iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
        if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
                return ret;
 
+       if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
+               /*
+                * DMA_ATTR_FORCE_CONTIGUOUS allocations are always remapped,
+                * hence in the vmalloc space.
+                */
+               unsigned long pfn = vmalloc_to_pfn(cpu_addr);
+               return __swiotlb_mmap_pfn(vma, pfn, size);
+       }
+
        area = find_vm_area(cpu_addr);
        if (WARN_ON(!area || !area->pages))
                return -ENXIO;
@@ -684,6 +742,15 @@ static int __iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
        unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        struct vm_struct *area = find_vm_area(cpu_addr);
 
+       if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
+               /*
+                * DMA_ATTR_FORCE_CONTIGUOUS allocations are always remapped,
+                * hence in the vmalloc space.
+                */
+               struct page *page = vmalloc_to_page(cpu_addr);
+               return __swiotlb_get_sgtable_page(sgt, page, size);
+       }
+
        if (WARN_ON(!area || !area->pages))
                return -ENXIO;
 
@@ -813,34 +880,26 @@ static const struct dma_map_ops iommu_dma_ops = {
        .mapping_error = iommu_dma_mapping_error,
 };
 
-/*
- * TODO: Right now __iommu_setup_dma_ops() gets called too early to do
- * everything it needs to - the device is only partially created and the
- * IOMMU driver hasn't seen it yet, so it can't have a group. Thus we
- * need this delayed attachment dance. Once IOMMU probe ordering is sorted
- * to move the arch_setup_dma_ops() call later, all the notifier bits below
- * become unnecessary, and will go away.
- */
-struct iommu_dma_notifier_data {
-       struct list_head list;
-       struct device *dev;
-       const struct iommu_ops *ops;
-       u64 dma_base;
-       u64 size;
-};
-static LIST_HEAD(iommu_dma_masters);
-static DEFINE_MUTEX(iommu_dma_notifier_lock);
+static int __init __iommu_dma_init(void)
+{
+       return iommu_dma_init();
+}
+arch_initcall(__iommu_dma_init);
 
-static bool do_iommu_attach(struct device *dev, const struct iommu_ops *ops,
-                          u64 dma_base, u64 size)
+static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
+                                 const struct iommu_ops *ops)
 {
-       struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
+       struct iommu_domain *domain;
+
+       if (!ops)
+               return;
 
        /*
-        * If the IOMMU driver has the DMA domain support that we require,
-        * then the IOMMU core will have already configured a group for this
-        * device, and allocated the default domain for that group.
+        * The IOMMU core code allocates the default DMA domain, which the
+        * underlying IOMMU driver needs to support via the dma-iommu layer.
         */
+       domain = iommu_get_domain_for_dev(dev);
+
        if (!domain)
                goto out_err;
 
@@ -851,109 +910,11 @@ static bool do_iommu_attach(struct device *dev, const struct iommu_ops *ops,
                dev->dma_ops = &iommu_dma_ops;
        }
 
-       return true;
+       return;
+
 out_err:
-       pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
+        pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
                 dev_name(dev));
-       return false;
-}
-
-static void queue_iommu_attach(struct device *dev, const struct iommu_ops *ops,
-                             u64 dma_base, u64 size)
-{
-       struct iommu_dma_notifier_data *iommudata;
-
-       iommudata = kzalloc(sizeof(*iommudata), GFP_KERNEL);
-       if (!iommudata)
-               return;
-
-       iommudata->dev = dev;
-       iommudata->ops = ops;
-       iommudata->dma_base = dma_base;
-       iommudata->size = size;
-
-       mutex_lock(&iommu_dma_notifier_lock);
-       list_add(&iommudata->list, &iommu_dma_masters);
-       mutex_unlock(&iommu_dma_notifier_lock);
-}
-
-static int __iommu_attach_notifier(struct notifier_block *nb,
-                                  unsigned long action, void *data)
-{
-       struct iommu_dma_notifier_data *master, *tmp;
-
-       if (action != BUS_NOTIFY_BIND_DRIVER)
-               return 0;
-
-       mutex_lock(&iommu_dma_notifier_lock);
-       list_for_each_entry_safe(master, tmp, &iommu_dma_masters, list) {
-               if (data == master->dev && do_iommu_attach(master->dev,
-                               master->ops, master->dma_base, master->size)) {
-                       list_del(&master->list);
-                       kfree(master);
-                       break;
-               }
-       }
-       mutex_unlock(&iommu_dma_notifier_lock);
-       return 0;
-}
-
-static int __init register_iommu_dma_ops_notifier(struct bus_type *bus)
-{
-       struct notifier_block *nb = kzalloc(sizeof(*nb), GFP_KERNEL);
-       int ret;
-
-       if (!nb)
-               return -ENOMEM;
-
-       nb->notifier_call = __iommu_attach_notifier;
-
-       ret = bus_register_notifier(bus, nb);
-       if (ret) {
-               pr_warn("Failed to register DMA domain notifier; IOMMU DMA ops unavailable on bus '%s'\n",
-                       bus->name);
-               kfree(nb);
-       }
-       return ret;
-}
-
-static int __init __iommu_dma_init(void)
-{
-       int ret;
-
-       ret = iommu_dma_init();
-       if (!ret)
-               ret = register_iommu_dma_ops_notifier(&platform_bus_type);
-       if (!ret)
-               ret = register_iommu_dma_ops_notifier(&amba_bustype);
-#ifdef CONFIG_PCI
-       if (!ret)
-               ret = register_iommu_dma_ops_notifier(&pci_bus_type);
-#endif
-       return ret;
-}
-arch_initcall(__iommu_dma_init);
-
-static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
-                                 const struct iommu_ops *ops)
-{
-       struct iommu_group *group;
-
-       if (!ops)
-               return;
-       /*
-        * TODO: As a concession to the future, we're ready to handle being
-        * called both early and late (i.e. after bus_add_device). Once all
-        * the platform bus code is reworked to call us late and the notifier
-        * junk above goes away, move the body of do_iommu_attach here.
-        */
-       group = iommu_group_get(dev);
-       if (group) {
-               do_iommu_attach(dev, ops, dma_base, size);
-               iommu_group_put(group);
-       } else {
-               queue_iommu_attach(dev, ops, dma_base, size);
-       }
 }
 
 void arch_teardown_dma_ops(struct device *dev)