dma-mapping: move all DMA mapping code to kernel/dma
authorChristoph Hellwig <hch@lst.de>
Tue, 12 Jun 2018 17:01:45 +0000 (19:01 +0200)
committerChristoph Hellwig <hch@lst.de>
Thu, 14 Jun 2018 06:50:37 +0000 (08:50 +0200)
Currently the code is split over various files with dma- prefixes in the
lib/ and drives/base directories, and the number of files keeps growing.
Move them into a single directory to keep the code together and remove
the file name prefixes.  To match the irq infrastructure this directory
is placed under the kernel/ directory.

Signed-off-by: Christoph Hellwig <hch@lst.de>
26 files changed:
Documentation/driver-api/infrastructure.rst
MAINTAINERS
drivers/base/Makefile
drivers/base/dma-coherent.c [deleted file]
drivers/base/dma-contiguous.c [deleted file]
drivers/base/dma-mapping.c [deleted file]
include/linux/dma-contiguous.h
init/Kconfig
kernel/Makefile
kernel/dma/Kconfig [new file with mode: 0644]
kernel/dma/Makefile [new file with mode: 0644]
kernel/dma/coherent.c [new file with mode: 0644]
kernel/dma/contiguous.c [new file with mode: 0644]
kernel/dma/debug.c [new file with mode: 0644]
kernel/dma/direct.c [new file with mode: 0644]
kernel/dma/mapping.c [new file with mode: 0644]
kernel/dma/noncoherent.c [new file with mode: 0644]
kernel/dma/swiotlb.c [new file with mode: 0644]
kernel/dma/virt.c [new file with mode: 0644]
lib/Kconfig
lib/Makefile
lib/dma-debug.c [deleted file]
lib/dma-direct.c [deleted file]
lib/dma-noncoherent.c [deleted file]
lib/dma-virt.c [deleted file]
lib/swiotlb.c [deleted file]

index bee1b9a1702f1cc6c89811aff6b8bdbc1eefb0b0..6172f3cc3d0b2109916cfccda2da1836065f8766 100644 (file)
@@ -49,10 +49,10 @@ Device Drivers Base
 Device Drivers DMA Management
 -----------------------------
 
-.. kernel-doc:: drivers/base/dma-coherent.c
+.. kernel-doc:: kernel/dma/coherent.c
    :export:
 
-.. kernel-doc:: drivers/base/dma-mapping.c
+.. kernel-doc:: kernel/dma/mapping.c
    :export:
 
 Device drivers PnP support
index c13b9fb3be0bb70a50cb9a88dfaa27b15f9c25dc..a6844a9e2f64034a3e86e4968239bacfd115f595 100644 (file)
@@ -4359,12 +4359,7 @@ L:       iommu@lists.linux-foundation.org
 T:     git git://git.infradead.org/users/hch/dma-mapping.git
 W:     http://git.infradead.org/users/hch/dma-mapping.git
 S:     Supported
-F:     lib/dma-debug.c
-F:     lib/dma-direct.c
-F:     lib/dma-noncoherent.c
-F:     lib/dma-virt.c
-F:     drivers/base/dma-mapping.c
-F:     drivers/base/dma-coherent.c
+F:     kernel/dma/
 F:     include/asm-generic/dma-mapping.h
 F:     include/linux/dma-direct.h
 F:     include/linux/dma-mapping.h
@@ -13642,7 +13637,7 @@ M:      Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
 L:     iommu@lists.linux-foundation.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/konrad/swiotlb.git
 S:     Supported
-F:     lib/swiotlb.c
+F:     kernel/dma/swiotlb.c
 F:     arch/*/kernel/pci-swiotlb.c
 F:     include/linux/swiotlb.h
 
index b074f242a43594fc3d3a383a9dce5d126e8f3a78..704f442958103545aa89ad0e986130aa6ebc5b06 100644 (file)
@@ -8,10 +8,7 @@ obj-y                  := component.o core.o bus.o dd.o syscore.o \
                           topology.o container.o property.o cacheinfo.o \
                           devcon.o
 obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
-obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
 obj-y                  += power/
-obj-$(CONFIG_HAS_DMA)  += dma-mapping.o
-obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
 obj-$(CONFIG_ISA_BUS_API)      += isa.o
 obj-y                          += firmware_loader/
 obj-$(CONFIG_NUMA)     += node.o
diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c
deleted file mode 100644 (file)
index 597d408..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Coherent per-device memory handling.
- * Borrowed from i386
- */
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-
-struct dma_coherent_mem {
-       void            *virt_base;
-       dma_addr_t      device_base;
-       unsigned long   pfn_base;
-       int             size;
-       int             flags;
-       unsigned long   *bitmap;
-       spinlock_t      spinlock;
-       bool            use_dev_dma_pfn_offset;
-};
-
-static struct dma_coherent_mem *dma_coherent_default_memory __ro_after_init;
-
-static inline struct dma_coherent_mem *dev_get_coherent_memory(struct device *dev)
-{
-       if (dev && dev->dma_mem)
-               return dev->dma_mem;
-       return NULL;
-}
-
-static inline dma_addr_t dma_get_device_base(struct device *dev,
-                                            struct dma_coherent_mem * mem)
-{
-       if (mem->use_dev_dma_pfn_offset)
-               return (mem->pfn_base - dev->dma_pfn_offset) << PAGE_SHIFT;
-       else
-               return mem->device_base;
-}
-
-static int dma_init_coherent_memory(
-       phys_addr_t phys_addr, dma_addr_t device_addr, size_t size, int flags,
-       struct dma_coherent_mem **mem)
-{
-       struct dma_coherent_mem *dma_mem = NULL;
-       void __iomem *mem_base = NULL;
-       int pages = size >> PAGE_SHIFT;
-       int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
-       int ret;
-
-       if (!size) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       mem_base = memremap(phys_addr, size, MEMREMAP_WC);
-       if (!mem_base) {
-               ret = -EINVAL;
-               goto out;
-       }
-       dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
-       if (!dma_mem) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
-       if (!dma_mem->bitmap) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       dma_mem->virt_base = mem_base;
-       dma_mem->device_base = device_addr;
-       dma_mem->pfn_base = PFN_DOWN(phys_addr);
-       dma_mem->size = pages;
-       dma_mem->flags = flags;
-       spin_lock_init(&dma_mem->spinlock);
-
-       *mem = dma_mem;
-       return 0;
-
-out:
-       kfree(dma_mem);
-       if (mem_base)
-               memunmap(mem_base);
-       return ret;
-}
-
-static void dma_release_coherent_memory(struct dma_coherent_mem *mem)
-{
-       if (!mem)
-               return;
-
-       memunmap(mem->virt_base);
-       kfree(mem->bitmap);
-       kfree(mem);
-}
-
-static int dma_assign_coherent_memory(struct device *dev,
-                                     struct dma_coherent_mem *mem)
-{
-       if (!dev)
-               return -ENODEV;
-
-       if (dev->dma_mem)
-               return -EBUSY;
-
-       dev->dma_mem = mem;
-       return 0;
-}
-
-int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
-                               dma_addr_t device_addr, size_t size, int flags)
-{
-       struct dma_coherent_mem *mem;
-       int ret;
-
-       ret = dma_init_coherent_memory(phys_addr, device_addr, size, flags, &mem);
-       if (ret)
-               return ret;
-
-       ret = dma_assign_coherent_memory(dev, mem);
-       if (ret)
-               dma_release_coherent_memory(mem);
-       return ret;
-}
-EXPORT_SYMBOL(dma_declare_coherent_memory);
-
-void dma_release_declared_memory(struct device *dev)
-{
-       struct dma_coherent_mem *mem = dev->dma_mem;
-
-       if (!mem)
-               return;
-       dma_release_coherent_memory(mem);
-       dev->dma_mem = NULL;
-}
-EXPORT_SYMBOL(dma_release_declared_memory);
-
-void *dma_mark_declared_memory_occupied(struct device *dev,
-                                       dma_addr_t device_addr, size_t size)
-{
-       struct dma_coherent_mem *mem = dev->dma_mem;
-       unsigned long flags;
-       int pos, err;
-
-       size += device_addr & ~PAGE_MASK;
-
-       if (!mem)
-               return ERR_PTR(-EINVAL);
-
-       spin_lock_irqsave(&mem->spinlock, flags);
-       pos = PFN_DOWN(device_addr - dma_get_device_base(dev, mem));
-       err = bitmap_allocate_region(mem->bitmap, pos, get_order(size));
-       spin_unlock_irqrestore(&mem->spinlock, flags);
-
-       if (err != 0)
-               return ERR_PTR(err);
-       return mem->virt_base + (pos << PAGE_SHIFT);
-}
-EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
-
-static void *__dma_alloc_from_coherent(struct dma_coherent_mem *mem,
-               ssize_t size, dma_addr_t *dma_handle)
-{
-       int order = get_order(size);
-       unsigned long flags;
-       int pageno;
-       void *ret;
-
-       spin_lock_irqsave(&mem->spinlock, flags);
-
-       if (unlikely(size > (mem->size << PAGE_SHIFT)))
-               goto err;
-
-       pageno = bitmap_find_free_region(mem->bitmap, mem->size, order);
-       if (unlikely(pageno < 0))
-               goto err;
-
-       /*
-        * Memory was found in the coherent area.
-        */
-       *dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
-       ret = mem->virt_base + (pageno << PAGE_SHIFT);
-       spin_unlock_irqrestore(&mem->spinlock, flags);
-       memset(ret, 0, size);
-       return ret;
-err:
-       spin_unlock_irqrestore(&mem->spinlock, flags);
-       return NULL;
-}
-
-/**
- * dma_alloc_from_dev_coherent() - allocate memory from device coherent pool
- * @dev:       device from which we allocate memory
- * @size:      size of requested memory area
- * @dma_handle:        This will be filled with the correct dma handle
- * @ret:       This pointer will be filled with the virtual address
- *             to allocated area.
- *
- * This function should be only called from per-arch dma_alloc_coherent()
- * to support allocation from per-device coherent memory pools.
- *
- * Returns 0 if dma_alloc_coherent should continue with allocating from
- * generic memory areas, or !0 if dma_alloc_coherent should return @ret.
- */
-int dma_alloc_from_dev_coherent(struct device *dev, ssize_t size,
-               dma_addr_t *dma_handle, void **ret)
-{
-       struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
-
-       if (!mem)
-               return 0;
-
-       *ret = __dma_alloc_from_coherent(mem, size, dma_handle);
-       if (*ret)
-               return 1;
-
-       /*
-        * In the case where the allocation can not be satisfied from the
-        * per-device area, try to fall back to generic memory if the
-        * constraints allow it.
-        */
-       return mem->flags & DMA_MEMORY_EXCLUSIVE;
-}
-EXPORT_SYMBOL(dma_alloc_from_dev_coherent);
-
-void *dma_alloc_from_global_coherent(ssize_t size, dma_addr_t *dma_handle)
-{
-       if (!dma_coherent_default_memory)
-               return NULL;
-
-       return __dma_alloc_from_coherent(dma_coherent_default_memory, size,
-                       dma_handle);
-}
-
-static int __dma_release_from_coherent(struct dma_coherent_mem *mem,
-                                      int order, void *vaddr)
-{
-       if (mem && vaddr >= mem->virt_base && vaddr <
-                  (mem->virt_base + (mem->size << PAGE_SHIFT))) {
-               int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
-               unsigned long flags;
-
-               spin_lock_irqsave(&mem->spinlock, flags);
-               bitmap_release_region(mem->bitmap, page, order);
-               spin_unlock_irqrestore(&mem->spinlock, flags);
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * dma_release_from_dev_coherent() - free memory to device coherent memory pool
- * @dev:       device from which the memory was allocated
- * @order:     the order of pages allocated
- * @vaddr:     virtual address of allocated pages
- *
- * This checks whether the memory was allocated from the per-device
- * coherent memory pool and if so, releases that memory.
- *
- * Returns 1 if we correctly released the memory, or 0 if the caller should
- * proceed with releasing memory from generic pools.
- */
-int dma_release_from_dev_coherent(struct device *dev, int order, void *vaddr)
-{
-       struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
-
-       return __dma_release_from_coherent(mem, order, vaddr);
-}
-EXPORT_SYMBOL(dma_release_from_dev_coherent);
-
-int dma_release_from_global_coherent(int order, void *vaddr)
-{
-       if (!dma_coherent_default_memory)
-               return 0;
-
-       return __dma_release_from_coherent(dma_coherent_default_memory, order,
-                       vaddr);
-}
-
-static int __dma_mmap_from_coherent(struct dma_coherent_mem *mem,
-               struct vm_area_struct *vma, void *vaddr, size_t size, int *ret)
-{
-       if (mem && vaddr >= mem->virt_base && vaddr + size <=
-                  (mem->virt_base + (mem->size << PAGE_SHIFT))) {
-               unsigned long off = vma->vm_pgoff;
-               int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
-               int user_count = vma_pages(vma);
-               int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
-
-               *ret = -ENXIO;
-               if (off < count && user_count <= count - off) {
-                       unsigned long pfn = mem->pfn_base + start + off;
-                       *ret = remap_pfn_range(vma, vma->vm_start, pfn,
-                                              user_count << PAGE_SHIFT,
-                                              vma->vm_page_prot);
-               }
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * dma_mmap_from_dev_coherent() - mmap memory from the device coherent pool
- * @dev:       device from which the memory was allocated
- * @vma:       vm_area for the userspace memory
- * @vaddr:     cpu address returned by dma_alloc_from_dev_coherent
- * @size:      size of the memory buffer allocated
- * @ret:       result from remap_pfn_range()
- *
- * This checks whether the memory was allocated from the per-device
- * coherent memory pool and if so, maps that memory to the provided vma.
- *
- * Returns 1 if @vaddr belongs to the device coherent pool and the caller
- * should return @ret, or 0 if they should proceed with mapping memory from
- * generic areas.
- */
-int dma_mmap_from_dev_coherent(struct device *dev, struct vm_area_struct *vma,
-                          void *vaddr, size_t size, int *ret)
-{
-       struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
-
-       return __dma_mmap_from_coherent(mem, vma, vaddr, size, ret);
-}
-EXPORT_SYMBOL(dma_mmap_from_dev_coherent);
-
-int dma_mmap_from_global_coherent(struct vm_area_struct *vma, void *vaddr,
-                                  size_t size, int *ret)
-{
-       if (!dma_coherent_default_memory)
-               return 0;
-
-       return __dma_mmap_from_coherent(dma_coherent_default_memory, vma,
-                                       vaddr, size, ret);
-}
-
-/*
- * Support for reserved memory regions defined in device tree
- */
-#ifdef CONFIG_OF_RESERVED_MEM
-#include <linux/of.h>
-#include <linux/of_fdt.h>
-#include <linux/of_reserved_mem.h>
-
-static struct reserved_mem *dma_reserved_default_memory __initdata;
-
-static int rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev)
-{
-       struct dma_coherent_mem *mem = rmem->priv;
-       int ret;
-
-       if (!mem) {
-               ret = dma_init_coherent_memory(rmem->base, rmem->base,
-                                              rmem->size,
-                                              DMA_MEMORY_EXCLUSIVE, &mem);
-               if (ret) {
-                       pr_err("Reserved memory: failed to init DMA memory pool at %pa, size %ld MiB\n",
-                               &rmem->base, (unsigned long)rmem->size / SZ_1M);
-                       return ret;
-               }
-       }
-       mem->use_dev_dma_pfn_offset = true;
-       rmem->priv = mem;
-       dma_assign_coherent_memory(dev, mem);
-       return 0;
-}
-
-static void rmem_dma_device_release(struct reserved_mem *rmem,
-                                   struct device *dev)
-{
-       if (dev)
-               dev->dma_mem = NULL;
-}
-
-static const struct reserved_mem_ops rmem_dma_ops = {
-       .device_init    = rmem_dma_device_init,
-       .device_release = rmem_dma_device_release,
-};
-
-static int __init rmem_dma_setup(struct reserved_mem *rmem)
-{
-       unsigned long node = rmem->fdt_node;
-
-       if (of_get_flat_dt_prop(node, "reusable", NULL))
-               return -EINVAL;
-
-#ifdef CONFIG_ARM
-       if (!of_get_flat_dt_prop(node, "no-map", NULL)) {
-               pr_err("Reserved memory: regions without no-map are not yet supported\n");
-               return -EINVAL;
-       }
-
-       if (of_get_flat_dt_prop(node, "linux,dma-default", NULL)) {
-               WARN(dma_reserved_default_memory,
-                    "Reserved memory: region for default DMA coherent area is redefined\n");
-               dma_reserved_default_memory = rmem;
-       }
-#endif
-
-       rmem->ops = &rmem_dma_ops;
-       pr_info("Reserved memory: created DMA memory pool at %pa, size %ld MiB\n",
-               &rmem->base, (unsigned long)rmem->size / SZ_1M);
-       return 0;
-}
-
-static int __init dma_init_reserved_memory(void)
-{
-       const struct reserved_mem_ops *ops;
-       int ret;
-
-       if (!dma_reserved_default_memory)
-               return -ENOMEM;
-
-       ops = dma_reserved_default_memory->ops;
-
-       /*
-        * We rely on rmem_dma_device_init() does not propagate error of
-        * dma_assign_coherent_memory() for "NULL" device.
-        */
-       ret = ops->device_init(dma_reserved_default_memory, NULL);
-
-       if (!ret) {
-               dma_coherent_default_memory = dma_reserved_default_memory->priv;
-               pr_info("DMA: default coherent area is set\n");
-       }
-
-       return ret;
-}
-
-core_initcall(dma_init_reserved_memory);
-
-RESERVEDMEM_OF_DECLARE(dma, "shared-dma-pool", rmem_dma_setup);
-#endif
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
deleted file mode 100644 (file)
index d987dcd..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Contiguous Memory Allocator for DMA mapping framework
- * Copyright (c) 2010-2011 by Samsung Electronics.
- * Written by:
- *     Marek Szyprowski <m.szyprowski@samsung.com>
- *     Michal Nazarewicz <mina86@mina86.com>
- */
-
-#define pr_fmt(fmt) "cma: " fmt
-
-#ifdef CONFIG_CMA_DEBUG
-#ifndef DEBUG
-#  define DEBUG
-#endif
-#endif
-
-#include <asm/page.h>
-#include <asm/dma-contiguous.h>
-
-#include <linux/memblock.h>
-#include <linux/err.h>
-#include <linux/sizes.h>
-#include <linux/dma-contiguous.h>
-#include <linux/cma.h>
-
-#ifdef CONFIG_CMA_SIZE_MBYTES
-#define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES
-#else
-#define CMA_SIZE_MBYTES 0
-#endif
-
-struct cma *dma_contiguous_default_area;
-
-/*
- * Default global CMA area size can be defined in kernel's .config.
- * This is useful mainly for distro maintainers to create a kernel
- * that works correctly for most supported systems.
- * The size can be set in bytes or as a percentage of the total memory
- * in the system.
- *
- * Users, who want to set the size of global CMA area for their system
- * should use cma= kernel parameter.
- */
-static const phys_addr_t size_bytes = (phys_addr_t)CMA_SIZE_MBYTES * SZ_1M;
-static phys_addr_t size_cmdline = -1;
-static phys_addr_t base_cmdline;
-static phys_addr_t limit_cmdline;
-
-static int __init early_cma(char *p)
-{
-       pr_debug("%s(%s)\n", __func__, p);
-       size_cmdline = memparse(p, &p);
-       if (*p != '@')
-               return 0;
-       base_cmdline = memparse(p + 1, &p);
-       if (*p != '-') {
-               limit_cmdline = base_cmdline + size_cmdline;
-               return 0;
-       }
-       limit_cmdline = memparse(p + 1, &p);
-
-       return 0;
-}
-early_param("cma", early_cma);
-
-#ifdef CONFIG_CMA_SIZE_PERCENTAGE
-
-static phys_addr_t __init __maybe_unused cma_early_percent_memory(void)
-{
-       struct memblock_region *reg;
-       unsigned long total_pages = 0;
-
-       /*
-        * We cannot use memblock_phys_mem_size() here, because
-        * memblock_analyze() has not been called yet.
-        */
-       for_each_memblock(memory, reg)
-               total_pages += memblock_region_memory_end_pfn(reg) -
-                              memblock_region_memory_base_pfn(reg);
-
-       return (total_pages * CONFIG_CMA_SIZE_PERCENTAGE / 100) << PAGE_SHIFT;
-}
-
-#else
-
-static inline __maybe_unused phys_addr_t cma_early_percent_memory(void)
-{
-       return 0;
-}
-
-#endif
-
-/**
- * dma_contiguous_reserve() - reserve area(s) for contiguous memory handling
- * @limit: End address of the reserved memory (optional, 0 for any).
- *
- * This function reserves memory from early allocator. It should be
- * called by arch specific code once the early allocator (memblock or bootmem)
- * has been activated and all other subsystems have already allocated/reserved
- * memory.
- */
-void __init dma_contiguous_reserve(phys_addr_t limit)
-{
-       phys_addr_t selected_size = 0;
-       phys_addr_t selected_base = 0;
-       phys_addr_t selected_limit = limit;
-       bool fixed = false;
-
-       pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit);
-
-       if (size_cmdline != -1) {
-               selected_size = size_cmdline;
-               selected_base = base_cmdline;
-               selected_limit = min_not_zero(limit_cmdline, limit);
-               if (base_cmdline + size_cmdline == limit_cmdline)
-                       fixed = true;
-       } else {
-#ifdef CONFIG_CMA_SIZE_SEL_MBYTES
-               selected_size = size_bytes;
-#elif defined(CONFIG_CMA_SIZE_SEL_PERCENTAGE)
-               selected_size = cma_early_percent_memory();
-#elif defined(CONFIG_CMA_SIZE_SEL_MIN)
-               selected_size = min(size_bytes, cma_early_percent_memory());
-#elif defined(CONFIG_CMA_SIZE_SEL_MAX)
-               selected_size = max(size_bytes, cma_early_percent_memory());
-#endif
-       }
-
-       if (selected_size && !dma_contiguous_default_area) {
-               pr_debug("%s: reserving %ld MiB for global area\n", __func__,
-                        (unsigned long)selected_size / SZ_1M);
-
-               dma_contiguous_reserve_area(selected_size, selected_base,
-                                           selected_limit,
-                                           &dma_contiguous_default_area,
-                                           fixed);
-       }
-}
-
-/**
- * dma_contiguous_reserve_area() - reserve custom contiguous area
- * @size: Size of the reserved area (in bytes),
- * @base: Base address of the reserved area optional, use 0 for any
- * @limit: End address of the reserved memory (optional, 0 for any).
- * @res_cma: Pointer to store the created cma region.
- * @fixed: hint about where to place the reserved area
- *
- * This function reserves memory from early allocator. It should be
- * called by arch specific code once the early allocator (memblock or bootmem)
- * has been activated and all other subsystems have already allocated/reserved
- * memory. This function allows to create custom reserved areas for specific
- * devices.
- *
- * If @fixed is true, reserve contiguous area at exactly @base.  If false,
- * reserve in range from @base to @limit.
- */
-int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
-                                      phys_addr_t limit, struct cma **res_cma,
-                                      bool fixed)
-{
-       int ret;
-
-       ret = cma_declare_contiguous(base, size, limit, 0, 0, fixed,
-                                       "reserved", res_cma);
-       if (ret)
-               return ret;
-
-       /* Architecture specific contiguous memory fixup. */
-       dma_contiguous_early_fixup(cma_get_base(*res_cma),
-                               cma_get_size(*res_cma));
-
-       return 0;
-}
-
-/**
- * dma_alloc_from_contiguous() - allocate pages from contiguous area
- * @dev:   Pointer to device for which the allocation is performed.
- * @count: Requested number of pages.
- * @align: Requested alignment of pages (in PAGE_SIZE order).
- * @gfp_mask: GFP flags to use for this allocation.
- *
- * This function allocates memory buffer for specified device. It uses
- * device specific contiguous memory area if available or the default
- * global one. Requires architecture specific dev_get_cma_area() helper
- * function.
- */
-struct page *dma_alloc_from_contiguous(struct device *dev, size_t count,
-                                      unsigned int align, gfp_t gfp_mask)
-{
-       if (align > CONFIG_CMA_ALIGNMENT)
-               align = CONFIG_CMA_ALIGNMENT;
-
-       return cma_alloc(dev_get_cma_area(dev), count, align, gfp_mask);
-}
-
-/**
- * dma_release_from_contiguous() - release allocated pages
- * @dev:   Pointer to device for which the pages were allocated.
- * @pages: Allocated pages.
- * @count: Number of allocated pages.
- *
- * This function releases memory allocated by dma_alloc_from_contiguous().
- * It returns false when provided pages do not belong to contiguous area and
- * true otherwise.
- */
-bool dma_release_from_contiguous(struct device *dev, struct page *pages,
-                                int count)
-{
-       return cma_release(dev_get_cma_area(dev), pages, count);
-}
-
-/*
- * Support for reserved memory regions defined in device tree
- */
-#ifdef CONFIG_OF_RESERVED_MEM
-#include <linux/of.h>
-#include <linux/of_fdt.h>
-#include <linux/of_reserved_mem.h>
-
-#undef pr_fmt
-#define pr_fmt(fmt) fmt
-
-static int rmem_cma_device_init(struct reserved_mem *rmem, struct device *dev)
-{
-       dev_set_cma_area(dev, rmem->priv);
-       return 0;
-}
-
-static void rmem_cma_device_release(struct reserved_mem *rmem,
-                                   struct device *dev)
-{
-       dev_set_cma_area(dev, NULL);
-}
-
-static const struct reserved_mem_ops rmem_cma_ops = {
-       .device_init    = rmem_cma_device_init,
-       .device_release = rmem_cma_device_release,
-};
-
-static int __init rmem_cma_setup(struct reserved_mem *rmem)
-{
-       phys_addr_t align = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);
-       phys_addr_t mask = align - 1;
-       unsigned long node = rmem->fdt_node;
-       struct cma *cma;
-       int err;
-
-       if (!of_get_flat_dt_prop(node, "reusable", NULL) ||
-           of_get_flat_dt_prop(node, "no-map", NULL))
-               return -EINVAL;
-
-       if ((rmem->base & mask) || (rmem->size & mask)) {
-               pr_err("Reserved memory: incorrect alignment of CMA region\n");
-               return -EINVAL;
-       }
-
-       err = cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name, &cma);
-       if (err) {
-               pr_err("Reserved memory: unable to setup CMA region\n");
-               return err;
-       }
-       /* Architecture specific contiguous memory fixup. */
-       dma_contiguous_early_fixup(rmem->base, rmem->size);
-
-       if (of_get_flat_dt_prop(node, "linux,cma-default", NULL))
-               dma_contiguous_set_default(cma);
-
-       rmem->ops = &rmem_cma_ops;
-       rmem->priv = cma;
-
-       pr_info("Reserved memory: created CMA memory pool at %pa, size %ld MiB\n",
-               &rmem->base, (unsigned long)rmem->size / SZ_1M);
-
-       return 0;
-}
-RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup);
-#endif
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
deleted file mode 100644 (file)
index f831a58..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * drivers/base/dma-mapping.c - arch-independent dma-mapping routines
- *
- * Copyright (c) 2006  SUSE Linux Products GmbH
- * Copyright (c) 2006  Tejun Heo <teheo@suse.de>
- */
-
-#include <linux/acpi.h>
-#include <linux/dma-mapping.h>
-#include <linux/export.h>
-#include <linux/gfp.h>
-#include <linux/of_device.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-/*
- * Managed DMA API
- */
-struct dma_devres {
-       size_t          size;
-       void            *vaddr;
-       dma_addr_t      dma_handle;
-       unsigned long   attrs;
-};
-
-static void dmam_release(struct device *dev, void *res)
-{
-       struct dma_devres *this = res;
-
-       dma_free_attrs(dev, this->size, this->vaddr, this->dma_handle,
-                       this->attrs);
-}
-
-static int dmam_match(struct device *dev, void *res, void *match_data)
-{
-       struct dma_devres *this = res, *match = match_data;
-
-       if (this->vaddr == match->vaddr) {
-               WARN_ON(this->size != match->size ||
-                       this->dma_handle != match->dma_handle);
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * dmam_alloc_coherent - Managed dma_alloc_coherent()
- * @dev: Device to allocate coherent memory for
- * @size: Size of allocation
- * @dma_handle: Out argument for allocated DMA handle
- * @gfp: Allocation flags
- *
- * Managed dma_alloc_coherent().  Memory allocated using this function
- * will be automatically released on driver detach.
- *
- * RETURNS:
- * Pointer to allocated memory on success, NULL on failure.
- */
-void *dmam_alloc_coherent(struct device *dev, size_t size,
-                          dma_addr_t *dma_handle, gfp_t gfp)
-{
-       struct dma_devres *dr;
-       void *vaddr;
-
-       dr = devres_alloc(dmam_release, sizeof(*dr), gfp);
-       if (!dr)
-               return NULL;
-
-       vaddr = dma_alloc_coherent(dev, size, dma_handle, gfp);
-       if (!vaddr) {
-               devres_free(dr);
-               return NULL;
-       }
-
-       dr->vaddr = vaddr;
-       dr->dma_handle = *dma_handle;
-       dr->size = size;
-
-       devres_add(dev, dr);
-
-       return vaddr;
-}
-EXPORT_SYMBOL(dmam_alloc_coherent);
-
-/**
- * dmam_free_coherent - Managed dma_free_coherent()
- * @dev: Device to free coherent memory for
- * @size: Size of allocation
- * @vaddr: Virtual address of the memory to free
- * @dma_handle: DMA handle of the memory to free
- *
- * Managed dma_free_coherent().
- */
-void dmam_free_coherent(struct device *dev, size_t size, void *vaddr,
-                       dma_addr_t dma_handle)
-{
-       struct dma_devres match_data = { size, vaddr, dma_handle };
-
-       dma_free_coherent(dev, size, vaddr, dma_handle);
-       WARN_ON(devres_destroy(dev, dmam_release, dmam_match, &match_data));
-}
-EXPORT_SYMBOL(dmam_free_coherent);
-
-/**
- * dmam_alloc_attrs - Managed dma_alloc_attrs()
- * @dev: Device to allocate non_coherent memory for
- * @size: Size of allocation
- * @dma_handle: Out argument for allocated DMA handle
- * @gfp: Allocation flags
- * @attrs: Flags in the DMA_ATTR_* namespace.
- *
- * Managed dma_alloc_attrs().  Memory allocated using this function will be
- * automatically released on driver detach.
- *
- * RETURNS:
- * Pointer to allocated memory on success, NULL on failure.
- */
-void *dmam_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
-               gfp_t gfp, unsigned long attrs)
-{
-       struct dma_devres *dr;
-       void *vaddr;
-
-       dr = devres_alloc(dmam_release, sizeof(*dr), gfp);
-       if (!dr)
-               return NULL;
-
-       vaddr = dma_alloc_attrs(dev, size, dma_handle, gfp, attrs);
-       if (!vaddr) {
-               devres_free(dr);
-               return NULL;
-       }
-
-       dr->vaddr = vaddr;
-       dr->dma_handle = *dma_handle;
-       dr->size = size;
-       dr->attrs = attrs;
-
-       devres_add(dev, dr);
-
-       return vaddr;
-}
-EXPORT_SYMBOL(dmam_alloc_attrs);
-
-#ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT
-
-static void dmam_coherent_decl_release(struct device *dev, void *res)
-{
-       dma_release_declared_memory(dev);
-}
-
-/**
- * dmam_declare_coherent_memory - Managed dma_declare_coherent_memory()
- * @dev: Device to declare coherent memory for
- * @phys_addr: Physical address of coherent memory to be declared
- * @device_addr: Device address of coherent memory to be declared
- * @size: Size of coherent memory to be declared
- * @flags: Flags
- *
- * Managed dma_declare_coherent_memory().
- *
- * RETURNS:
- * 0 on success, -errno on failure.
- */
-int dmam_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
-                                dma_addr_t device_addr, size_t size, int flags)
-{
-       void *res;
-       int rc;
-
-       res = devres_alloc(dmam_coherent_decl_release, 0, GFP_KERNEL);
-       if (!res)
-               return -ENOMEM;
-
-       rc = dma_declare_coherent_memory(dev, phys_addr, device_addr, size,
-                                        flags);
-       if (!rc)
-               devres_add(dev, res);
-       else
-               devres_free(res);
-
-       return rc;
-}
-EXPORT_SYMBOL(dmam_declare_coherent_memory);
-
-/**
- * dmam_release_declared_memory - Managed dma_release_declared_memory().
- * @dev: Device to release declared coherent memory for
- *
- * Managed dmam_release_declared_memory().
- */
-void dmam_release_declared_memory(struct device *dev)
-{
-       WARN_ON(devres_destroy(dev, dmam_coherent_decl_release, NULL, NULL));
-}
-EXPORT_SYMBOL(dmam_release_declared_memory);
-
-#endif
-
-/*
- * Create scatter-list for the already allocated DMA buffer.
- */
-int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
-                void *cpu_addr, dma_addr_t handle, size_t size)
-{
-       struct page *page = virt_to_page(cpu_addr);
-       int ret;
-
-       ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
-       if (unlikely(ret))
-               return ret;
-
-       sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
-       return 0;
-}
-EXPORT_SYMBOL(dma_common_get_sgtable);
-
-/*
- * Create userspace mapping for the DMA-coherent memory.
- */
-int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
-                   void *cpu_addr, dma_addr_t dma_addr, size_t size)
-{
-       int ret = -ENXIO;
-#ifndef CONFIG_ARCH_NO_COHERENT_DMA_MMAP
-       unsigned long user_count = vma_pages(vma);
-       unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
-       unsigned long off = vma->vm_pgoff;
-
-       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
-       if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
-               return ret;
-
-       if (off < count && user_count <= (count - off))
-               ret = remap_pfn_range(vma, vma->vm_start,
-                                     page_to_pfn(virt_to_page(cpu_addr)) + off,
-                                     user_count << PAGE_SHIFT,
-                                     vma->vm_page_prot);
-#endif /* !CONFIG_ARCH_NO_COHERENT_DMA_MMAP */
-
-       return ret;
-}
-EXPORT_SYMBOL(dma_common_mmap);
-
-#ifdef CONFIG_MMU
-static struct vm_struct *__dma_common_pages_remap(struct page **pages,
-                       size_t size, unsigned long vm_flags, pgprot_t prot,
-                       const void *caller)
-{
-       struct vm_struct *area;
-
-       area = get_vm_area_caller(size, vm_flags, caller);
-       if (!area)
-               return NULL;
-
-       if (map_vm_area(area, prot, pages)) {
-               vunmap(area->addr);
-               return NULL;
-       }
-
-       return area;
-}
-
-/*
- * remaps an array of PAGE_SIZE pages into another vm_area
- * Cannot be used in non-sleeping contexts
- */
-void *dma_common_pages_remap(struct page **pages, size_t size,
-                       unsigned long vm_flags, pgprot_t prot,
-                       const void *caller)
-{
-       struct vm_struct *area;
-
-       area = __dma_common_pages_remap(pages, size, vm_flags, prot, caller);
-       if (!area)
-               return NULL;
-
-       area->pages = pages;
-
-       return area->addr;
-}
-
-/*
- * remaps an allocated contiguous region into another vm_area.
- * Cannot be used in non-sleeping contexts
- */
-
-void *dma_common_contiguous_remap(struct page *page, size_t size,
-                       unsigned long vm_flags,
-                       pgprot_t prot, const void *caller)
-{
-       int i;
-       struct page **pages;
-       struct vm_struct *area;
-
-       pages = kmalloc(sizeof(struct page *) << get_order(size), GFP_KERNEL);
-       if (!pages)
-               return NULL;
-
-       for (i = 0; i < (size >> PAGE_SHIFT); i++)
-               pages[i] = nth_page(page, i);
-
-       area = __dma_common_pages_remap(pages, size, vm_flags, prot, caller);
-
-       kfree(pages);
-
-       if (!area)
-               return NULL;
-       return area->addr;
-}
-
-/*
- * unmaps a range previously mapped by dma_common_*_remap
- */
-void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
-{
-       struct vm_struct *area = find_vm_area(cpu_addr);
-
-       if (!area || (area->flags & vm_flags) != vm_flags) {
-               WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
-               return;
-       }
-
-       unmap_kernel_range((unsigned long)cpu_addr, PAGE_ALIGN(size));
-       vunmap(cpu_addr);
-}
-#endif
-
-/*
- * enables DMA API use for a device
- */
-int dma_configure(struct device *dev)
-{
-       if (dev->bus->dma_configure)
-               return dev->bus->dma_configure(dev);
-       return 0;
-}
-
-void dma_deconfigure(struct device *dev)
-{
-       of_dma_deconfigure(dev);
-       acpi_dma_deconfigure(dev);
-}
index b67bf6ac907d8f324494efaf1d441b0ee7955a13..3c5a4cb3eb953174c688c4b965ba09d87925fdb3 100644 (file)
@@ -48,7 +48,7 @@
  *   CMA should not be used by the device drivers directly. It is
  *   only a helper framework for dma-mapping subsystem.
  *
- *   For more information, see kernel-docs in drivers/base/dma-contiguous.c
+ *   For more information, see kernel-docs in kernel/dma/contiguous.c
  */
 
 #ifdef __KERNEL__
index 5a52f07259a2aab4ad5993801a6d15b5dfe5d4a3..fde3d09e8b27cef58d0c273c172bc6079f8b13e5 100644 (file)
@@ -1719,10 +1719,6 @@ source "arch/Kconfig"
 
 endmenu                # General setup
 
-config HAVE_GENERIC_DMA_COHERENT
-       bool
-       default n
-
 config RT_MUTEXES
        bool
 
index d2001624fe7a31b788508e5da97924173bf2e33e..04bc07c2b42a9dfef399caea56a12b072f0ad028 100644 (file)
@@ -41,6 +41,7 @@ obj-y += printk/
 obj-y += irq/
 obj-y += rcu/
 obj-y += livepatch/
+obj-y += dma/
 
 obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o
 obj-$(CONFIG_FREEZER) += freezer.o
diff --git a/kernel/dma/Kconfig b/kernel/dma/Kconfig
new file mode 100644 (file)
index 0000000..9bd5430
--- /dev/null
@@ -0,0 +1,50 @@
+
+config HAS_DMA
+       bool
+       depends on !NO_DMA
+       default y
+
+config NEED_SG_DMA_LENGTH
+       bool
+
+config NEED_DMA_MAP_STATE
+       bool
+
+config ARCH_DMA_ADDR_T_64BIT
+       def_bool 64BIT || PHYS_ADDR_T_64BIT
+
+config HAVE_GENERIC_DMA_COHERENT
+       bool
+
+config ARCH_HAS_SYNC_DMA_FOR_DEVICE
+       bool
+
+config ARCH_HAS_SYNC_DMA_FOR_CPU
+       bool
+       select NEED_DMA_MAP_STATE
+
+config DMA_DIRECT_OPS
+       bool
+       depends on HAS_DMA
+
+config DMA_NONCOHERENT_OPS
+       bool
+       depends on HAS_DMA
+       select DMA_DIRECT_OPS
+
+config DMA_NONCOHERENT_MMAP
+       bool
+       depends on DMA_NONCOHERENT_OPS
+
+config DMA_NONCOHERENT_CACHE_SYNC
+       bool
+       depends on DMA_NONCOHERENT_OPS
+
+config DMA_VIRT_OPS
+       bool
+       depends on HAS_DMA
+
+config SWIOTLB
+       bool
+       select DMA_DIRECT_OPS
+       select NEED_DMA_MAP_STATE
diff --git a/kernel/dma/Makefile b/kernel/dma/Makefile
new file mode 100644 (file)
index 0000000..6de44e4
--- /dev/null
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_HAS_DMA)                  += mapping.o
+obj-$(CONFIG_DMA_CMA)                  += contiguous.o
+obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += coherent.o
+obj-$(CONFIG_DMA_DIRECT_OPS)           += direct.o
+obj-$(CONFIG_DMA_NONCOHERENT_OPS)      += noncoherent.o
+obj-$(CONFIG_DMA_VIRT_OPS)             += virt.o
+obj-$(CONFIG_DMA_API_DEBUG)            += debug.o
+obj-$(CONFIG_SWIOTLB)                  += swiotlb.o
+
diff --git a/kernel/dma/coherent.c b/kernel/dma/coherent.c
new file mode 100644 (file)
index 0000000..597d408
--- /dev/null
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Coherent per-device memory handling.
+ * Borrowed from i386
+ */
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+
+struct dma_coherent_mem {
+       void            *virt_base;
+       dma_addr_t      device_base;
+       unsigned long   pfn_base;
+       int             size;
+       int             flags;
+       unsigned long   *bitmap;
+       spinlock_t      spinlock;
+       bool            use_dev_dma_pfn_offset;
+};
+
+static struct dma_coherent_mem *dma_coherent_default_memory __ro_after_init;
+
+static inline struct dma_coherent_mem *dev_get_coherent_memory(struct device *dev)
+{
+       if (dev && dev->dma_mem)
+               return dev->dma_mem;
+       return NULL;
+}
+
+static inline dma_addr_t dma_get_device_base(struct device *dev,
+                                            struct dma_coherent_mem * mem)
+{
+       if (mem->use_dev_dma_pfn_offset)
+               return (mem->pfn_base - dev->dma_pfn_offset) << PAGE_SHIFT;
+       else
+               return mem->device_base;
+}
+
+static int dma_init_coherent_memory(
+       phys_addr_t phys_addr, dma_addr_t device_addr, size_t size, int flags,
+       struct dma_coherent_mem **mem)
+{
+       struct dma_coherent_mem *dma_mem = NULL;
+       void __iomem *mem_base = NULL;
+       int pages = size >> PAGE_SHIFT;
+       int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
+       int ret;
+
+       if (!size) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       mem_base = memremap(phys_addr, size, MEMREMAP_WC);
+       if (!mem_base) {
+               ret = -EINVAL;
+               goto out;
+       }
+       dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
+       if (!dma_mem) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+       if (!dma_mem->bitmap) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       dma_mem->virt_base = mem_base;
+       dma_mem->device_base = device_addr;
+       dma_mem->pfn_base = PFN_DOWN(phys_addr);
+       dma_mem->size = pages;
+       dma_mem->flags = flags;
+       spin_lock_init(&dma_mem->spinlock);
+
+       *mem = dma_mem;
+       return 0;
+
+out:
+       kfree(dma_mem);
+       if (mem_base)
+               memunmap(mem_base);
+       return ret;
+}
+
+static void dma_release_coherent_memory(struct dma_coherent_mem *mem)
+{
+       if (!mem)
+               return;
+
+       memunmap(mem->virt_base);
+       kfree(mem->bitmap);
+       kfree(mem);
+}
+
+static int dma_assign_coherent_memory(struct device *dev,
+                                     struct dma_coherent_mem *mem)
+{
+       if (!dev)
+               return -ENODEV;
+
+       if (dev->dma_mem)
+               return -EBUSY;
+
+       dev->dma_mem = mem;
+       return 0;
+}
+
+int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
+                               dma_addr_t device_addr, size_t size, int flags)
+{
+       struct dma_coherent_mem *mem;
+       int ret;
+
+       ret = dma_init_coherent_memory(phys_addr, device_addr, size, flags, &mem);
+       if (ret)
+               return ret;
+
+       ret = dma_assign_coherent_memory(dev, mem);
+       if (ret)
+               dma_release_coherent_memory(mem);
+       return ret;
+}
+EXPORT_SYMBOL(dma_declare_coherent_memory);
+
+void dma_release_declared_memory(struct device *dev)
+{
+       struct dma_coherent_mem *mem = dev->dma_mem;
+
+       if (!mem)
+               return;
+       dma_release_coherent_memory(mem);
+       dev->dma_mem = NULL;
+}
+EXPORT_SYMBOL(dma_release_declared_memory);
+
+void *dma_mark_declared_memory_occupied(struct device *dev,
+                                       dma_addr_t device_addr, size_t size)
+{
+       struct dma_coherent_mem *mem = dev->dma_mem;
+       unsigned long flags;
+       int pos, err;
+
+       size += device_addr & ~PAGE_MASK;
+
+       if (!mem)
+               return ERR_PTR(-EINVAL);
+
+       spin_lock_irqsave(&mem->spinlock, flags);
+       pos = PFN_DOWN(device_addr - dma_get_device_base(dev, mem));
+       err = bitmap_allocate_region(mem->bitmap, pos, get_order(size));
+       spin_unlock_irqrestore(&mem->spinlock, flags);
+
+       if (err != 0)
+               return ERR_PTR(err);
+       return mem->virt_base + (pos << PAGE_SHIFT);
+}
+EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
+
+static void *__dma_alloc_from_coherent(struct dma_coherent_mem *mem,
+               ssize_t size, dma_addr_t *dma_handle)
+{
+       int order = get_order(size);
+       unsigned long flags;
+       int pageno;
+       void *ret;
+
+       spin_lock_irqsave(&mem->spinlock, flags);
+
+       if (unlikely(size > (mem->size << PAGE_SHIFT)))
+               goto err;
+
+       pageno = bitmap_find_free_region(mem->bitmap, mem->size, order);
+       if (unlikely(pageno < 0))
+               goto err;
+
+       /*
+        * Memory was found in the coherent area.
+        */
+       *dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
+       ret = mem->virt_base + (pageno << PAGE_SHIFT);
+       spin_unlock_irqrestore(&mem->spinlock, flags);
+       memset(ret, 0, size);
+       return ret;
+err:
+       spin_unlock_irqrestore(&mem->spinlock, flags);
+       return NULL;
+}
+
+/**
+ * dma_alloc_from_dev_coherent() - allocate memory from device coherent pool
+ * @dev:       device from which we allocate memory
+ * @size:      size of requested memory area
+ * @dma_handle:        This will be filled with the correct dma handle
+ * @ret:       This pointer will be filled with the virtual address
+ *             to allocated area.
+ *
+ * This function should be only called from per-arch dma_alloc_coherent()
+ * to support allocation from per-device coherent memory pools.
+ *
+ * Returns 0 if dma_alloc_coherent should continue with allocating from
+ * generic memory areas, or !0 if dma_alloc_coherent should return @ret.
+ */
+int dma_alloc_from_dev_coherent(struct device *dev, ssize_t size,
+               dma_addr_t *dma_handle, void **ret)
+{
+       struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
+
+       if (!mem)
+               return 0;
+
+       *ret = __dma_alloc_from_coherent(mem, size, dma_handle);
+       if (*ret)
+               return 1;
+
+       /*
+        * In the case where the allocation can not be satisfied from the
+        * per-device area, try to fall back to generic memory if the
+        * constraints allow it.
+        */
+       return mem->flags & DMA_MEMORY_EXCLUSIVE;
+}
+EXPORT_SYMBOL(dma_alloc_from_dev_coherent);
+
+void *dma_alloc_from_global_coherent(ssize_t size, dma_addr_t *dma_handle)
+{
+       if (!dma_coherent_default_memory)
+               return NULL;
+
+       return __dma_alloc_from_coherent(dma_coherent_default_memory, size,
+                       dma_handle);
+}
+
+static int __dma_release_from_coherent(struct dma_coherent_mem *mem,
+                                      int order, void *vaddr)
+{
+       if (mem && vaddr >= mem->virt_base && vaddr <
+                  (mem->virt_base + (mem->size << PAGE_SHIFT))) {
+               int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
+               unsigned long flags;
+
+               spin_lock_irqsave(&mem->spinlock, flags);
+               bitmap_release_region(mem->bitmap, page, order);
+               spin_unlock_irqrestore(&mem->spinlock, flags);
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * dma_release_from_dev_coherent() - free memory to device coherent memory pool
+ * @dev:       device from which the memory was allocated
+ * @order:     the order of pages allocated
+ * @vaddr:     virtual address of allocated pages
+ *
+ * This checks whether the memory was allocated from the per-device
+ * coherent memory pool and if so, releases that memory.
+ *
+ * Returns 1 if we correctly released the memory, or 0 if the caller should
+ * proceed with releasing memory from generic pools.
+ */
+int dma_release_from_dev_coherent(struct device *dev, int order, void *vaddr)
+{
+       struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
+
+       return __dma_release_from_coherent(mem, order, vaddr);
+}
+EXPORT_SYMBOL(dma_release_from_dev_coherent);
+
+int dma_release_from_global_coherent(int order, void *vaddr)
+{
+       if (!dma_coherent_default_memory)
+               return 0;
+
+       return __dma_release_from_coherent(dma_coherent_default_memory, order,
+                       vaddr);
+}
+
+static int __dma_mmap_from_coherent(struct dma_coherent_mem *mem,
+               struct vm_area_struct *vma, void *vaddr, size_t size, int *ret)
+{
+       if (mem && vaddr >= mem->virt_base && vaddr + size <=
+                  (mem->virt_base + (mem->size << PAGE_SHIFT))) {
+               unsigned long off = vma->vm_pgoff;
+               int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
+               int user_count = vma_pages(vma);
+               int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+
+               *ret = -ENXIO;
+               if (off < count && user_count <= count - off) {
+                       unsigned long pfn = mem->pfn_base + start + off;
+                       *ret = remap_pfn_range(vma, vma->vm_start, pfn,
+                                              user_count << PAGE_SHIFT,
+                                              vma->vm_page_prot);
+               }
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * dma_mmap_from_dev_coherent() - mmap memory from the device coherent pool
+ * @dev:       device from which the memory was allocated
+ * @vma:       vm_area for the userspace memory
+ * @vaddr:     cpu address returned by dma_alloc_from_dev_coherent
+ * @size:      size of the memory buffer allocated
+ * @ret:       result from remap_pfn_range()
+ *
+ * This checks whether the memory was allocated from the per-device
+ * coherent memory pool and if so, maps that memory to the provided vma.
+ *
+ * Returns 1 if @vaddr belongs to the device coherent pool and the caller
+ * should return @ret, or 0 if they should proceed with mapping memory from
+ * generic areas.
+ */
+int dma_mmap_from_dev_coherent(struct device *dev, struct vm_area_struct *vma,
+                          void *vaddr, size_t size, int *ret)
+{
+       struct dma_coherent_mem *mem = dev_get_coherent_memory(dev);
+
+       return __dma_mmap_from_coherent(mem, vma, vaddr, size, ret);
+}
+EXPORT_SYMBOL(dma_mmap_from_dev_coherent);
+
+int dma_mmap_from_global_coherent(struct vm_area_struct *vma, void *vaddr,
+                                  size_t size, int *ret)
+{
+       if (!dma_coherent_default_memory)
+               return 0;
+
+       return __dma_mmap_from_coherent(dma_coherent_default_memory, vma,
+                                       vaddr, size, ret);
+}
+
+/*
+ * Support for reserved memory regions defined in device tree
+ */
+#ifdef CONFIG_OF_RESERVED_MEM
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_reserved_mem.h>
+
+static struct reserved_mem *dma_reserved_default_memory __initdata;
+
+static int rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev)
+{
+       struct dma_coherent_mem *mem = rmem->priv;
+       int ret;
+
+       if (!mem) {
+               ret = dma_init_coherent_memory(rmem->base, rmem->base,
+                                              rmem->size,
+                                              DMA_MEMORY_EXCLUSIVE, &mem);
+               if (ret) {
+                       pr_err("Reserved memory: failed to init DMA memory pool at %pa, size %ld MiB\n",
+                               &rmem->base, (unsigned long)rmem->size / SZ_1M);
+                       return ret;
+               }
+       }
+       mem->use_dev_dma_pfn_offset = true;
+       rmem->priv = mem;
+       dma_assign_coherent_memory(dev, mem);
+       return 0;
+}
+
+static void rmem_dma_device_release(struct reserved_mem *rmem,
+                                   struct device *dev)
+{
+       if (dev)
+               dev->dma_mem = NULL;
+}
+
+static const struct reserved_mem_ops rmem_dma_ops = {
+       .device_init    = rmem_dma_device_init,
+       .device_release = rmem_dma_device_release,
+};
+
+static int __init rmem_dma_setup(struct reserved_mem *rmem)
+{
+       unsigned long node = rmem->fdt_node;
+
+       if (of_get_flat_dt_prop(node, "reusable", NULL))
+               return -EINVAL;
+
+#ifdef CONFIG_ARM
+       if (!of_get_flat_dt_prop(node, "no-map", NULL)) {
+               pr_err("Reserved memory: regions without no-map are not yet supported\n");
+               return -EINVAL;
+       }
+
+       if (of_get_flat_dt_prop(node, "linux,dma-default", NULL)) {
+               WARN(dma_reserved_default_memory,
+                    "Reserved memory: region for default DMA coherent area is redefined\n");
+               dma_reserved_default_memory = rmem;
+       }
+#endif
+
+       rmem->ops = &rmem_dma_ops;
+       pr_info("Reserved memory: created DMA memory pool at %pa, size %ld MiB\n",
+               &rmem->base, (unsigned long)rmem->size / SZ_1M);
+       return 0;
+}
+
+static int __init dma_init_reserved_memory(void)
+{
+       const struct reserved_mem_ops *ops;
+       int ret;
+
+       if (!dma_reserved_default_memory)
+               return -ENOMEM;
+
+       ops = dma_reserved_default_memory->ops;
+
+       /*
+        * We rely on rmem_dma_device_init() does not propagate error of
+        * dma_assign_coherent_memory() for "NULL" device.
+        */
+       ret = ops->device_init(dma_reserved_default_memory, NULL);
+
+       if (!ret) {
+               dma_coherent_default_memory = dma_reserved_default_memory->priv;
+               pr_info("DMA: default coherent area is set\n");
+       }
+
+       return ret;
+}
+
+core_initcall(dma_init_reserved_memory);
+
+RESERVEDMEM_OF_DECLARE(dma, "shared-dma-pool", rmem_dma_setup);
+#endif
diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
new file mode 100644 (file)
index 0000000..d987dcd
--- /dev/null
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Contiguous Memory Allocator for DMA mapping framework
+ * Copyright (c) 2010-2011 by Samsung Electronics.
+ * Written by:
+ *     Marek Szyprowski <m.szyprowski@samsung.com>
+ *     Michal Nazarewicz <mina86@mina86.com>
+ */
+
+#define pr_fmt(fmt) "cma: " fmt
+
+#ifdef CONFIG_CMA_DEBUG
+#ifndef DEBUG
+#  define DEBUG
+#endif
+#endif
+
+#include <asm/page.h>
+#include <asm/dma-contiguous.h>
+
+#include <linux/memblock.h>
+#include <linux/err.h>
+#include <linux/sizes.h>
+#include <linux/dma-contiguous.h>
+#include <linux/cma.h>
+
+#ifdef CONFIG_CMA_SIZE_MBYTES
+#define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES
+#else
+#define CMA_SIZE_MBYTES 0
+#endif
+
+struct cma *dma_contiguous_default_area;
+
+/*
+ * Default global CMA area size can be defined in kernel's .config.
+ * This is useful mainly for distro maintainers to create a kernel
+ * that works correctly for most supported systems.
+ * The size can be set in bytes or as a percentage of the total memory
+ * in the system.
+ *
+ * Users, who want to set the size of global CMA area for their system
+ * should use cma= kernel parameter.
+ */
+static const phys_addr_t size_bytes = (phys_addr_t)CMA_SIZE_MBYTES * SZ_1M;
+static phys_addr_t size_cmdline = -1;
+static phys_addr_t base_cmdline;
+static phys_addr_t limit_cmdline;
+
+static int __init early_cma(char *p)
+{
+       pr_debug("%s(%s)\n", __func__, p);
+       size_cmdline = memparse(p, &p);
+       if (*p != '@')
+               return 0;
+       base_cmdline = memparse(p + 1, &p);
+       if (*p != '-') {
+               limit_cmdline = base_cmdline + size_cmdline;
+               return 0;
+       }
+       limit_cmdline = memparse(p + 1, &p);
+
+       return 0;
+}
+early_param("cma", early_cma);
+
+#ifdef CONFIG_CMA_SIZE_PERCENTAGE
+
+static phys_addr_t __init __maybe_unused cma_early_percent_memory(void)
+{
+       struct memblock_region *reg;
+       unsigned long total_pages = 0;
+
+       /*
+        * We cannot use memblock_phys_mem_size() here, because
+        * memblock_analyze() has not been called yet.
+        */
+       for_each_memblock(memory, reg)
+               total_pages += memblock_region_memory_end_pfn(reg) -
+                              memblock_region_memory_base_pfn(reg);
+
+       return (total_pages * CONFIG_CMA_SIZE_PERCENTAGE / 100) << PAGE_SHIFT;
+}
+
+#else
+
+static inline __maybe_unused phys_addr_t cma_early_percent_memory(void)
+{
+       return 0;
+}
+
+#endif
+
+/**
+ * dma_contiguous_reserve() - reserve area(s) for contiguous memory handling
+ * @limit: End address of the reserved memory (optional, 0 for any).
+ *
+ * This function reserves memory from early allocator. It should be
+ * called by arch specific code once the early allocator (memblock or bootmem)
+ * has been activated and all other subsystems have already allocated/reserved
+ * memory.
+ */
+void __init dma_contiguous_reserve(phys_addr_t limit)
+{
+       phys_addr_t selected_size = 0;
+       phys_addr_t selected_base = 0;
+       phys_addr_t selected_limit = limit;
+       bool fixed = false;
+
+       pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit);
+
+       if (size_cmdline != -1) {
+               selected_size = size_cmdline;
+               selected_base = base_cmdline;
+               selected_limit = min_not_zero(limit_cmdline, limit);
+               if (base_cmdline + size_cmdline == limit_cmdline)
+                       fixed = true;
+       } else {
+#ifdef CONFIG_CMA_SIZE_SEL_MBYTES
+               selected_size = size_bytes;
+#elif defined(CONFIG_CMA_SIZE_SEL_PERCENTAGE)
+               selected_size = cma_early_percent_memory();
+#elif defined(CONFIG_CMA_SIZE_SEL_MIN)
+               selected_size = min(size_bytes, cma_early_percent_memory());
+#elif defined(CONFIG_CMA_SIZE_SEL_MAX)
+               selected_size = max(size_bytes, cma_early_percent_memory());
+#endif
+       }
+
+       if (selected_size && !dma_contiguous_default_area) {
+               pr_debug("%s: reserving %ld MiB for global area\n", __func__,
+                        (unsigned long)selected_size / SZ_1M);
+
+               dma_contiguous_reserve_area(selected_size, selected_base,
+                                           selected_limit,
+                                           &dma_contiguous_default_area,
+                                           fixed);
+       }
+}
+
+/**
+ * dma_contiguous_reserve_area() - reserve custom contiguous area
+ * @size: Size of the reserved area (in bytes),
+ * @base: Base address of the reserved area optional, use 0 for any
+ * @limit: End address of the reserved memory (optional, 0 for any).
+ * @res_cma: Pointer to store the created cma region.
+ * @fixed: hint about where to place the reserved area
+ *
+ * This function reserves memory from early allocator. It should be
+ * called by arch specific code once the early allocator (memblock or bootmem)
+ * has been activated and all other subsystems have already allocated/reserved
+ * memory. This function allows to create custom reserved areas for specific
+ * devices.
+ *
+ * If @fixed is true, reserve contiguous area at exactly @base.  If false,
+ * reserve in range from @base to @limit.
+ */
+int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
+                                      phys_addr_t limit, struct cma **res_cma,
+                                      bool fixed)
+{
+       int ret;
+
+       ret = cma_declare_contiguous(base, size, limit, 0, 0, fixed,
+                                       "reserved", res_cma);
+       if (ret)
+               return ret;
+
+       /* Architecture specific contiguous memory fixup. */
+       dma_contiguous_early_fixup(cma_get_base(*res_cma),
+                               cma_get_size(*res_cma));
+
+       return 0;
+}
+
+/**
+ * dma_alloc_from_contiguous() - allocate pages from contiguous area
+ * @dev:   Pointer to device for which the allocation is performed.
+ * @count: Requested number of pages.
+ * @align: Requested alignment of pages (in PAGE_SIZE order).
+ * @gfp_mask: GFP flags to use for this allocation.
+ *
+ * This function allocates memory buffer for specified device. It uses
+ * device specific contiguous memory area if available or the default
+ * global one. Requires architecture specific dev_get_cma_area() helper
+ * function.
+ */
+struct page *dma_alloc_from_contiguous(struct device *dev, size_t count,
+                                      unsigned int align, gfp_t gfp_mask)
+{
+       if (align > CONFIG_CMA_ALIGNMENT)
+               align = CONFIG_CMA_ALIGNMENT;
+
+       return cma_alloc(dev_get_cma_area(dev), count, align, gfp_mask);
+}
+
+/**
+ * dma_release_from_contiguous() - release allocated pages
+ * @dev:   Pointer to device for which the pages were allocated.
+ * @pages: Allocated pages.
+ * @count: Number of allocated pages.
+ *
+ * This function releases memory allocated by dma_alloc_from_contiguous().
+ * It returns false when provided pages do not belong to contiguous area and
+ * true otherwise.
+ */
+bool dma_release_from_contiguous(struct device *dev, struct page *pages,
+                                int count)
+{
+       return cma_release(dev_get_cma_area(dev), pages, count);
+}
+
+/*
+ * Support for reserved memory regions defined in device tree
+ */
+#ifdef CONFIG_OF_RESERVED_MEM
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_reserved_mem.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) fmt
+
+static int rmem_cma_device_init(struct reserved_mem *rmem, struct device *dev)
+{
+       dev_set_cma_area(dev, rmem->priv);
+       return 0;
+}
+
+static void rmem_cma_device_release(struct reserved_mem *rmem,
+                                   struct device *dev)
+{
+       dev_set_cma_area(dev, NULL);
+}
+
+static const struct reserved_mem_ops rmem_cma_ops = {
+       .device_init    = rmem_cma_device_init,
+       .device_release = rmem_cma_device_release,
+};
+
+static int __init rmem_cma_setup(struct reserved_mem *rmem)
+{
+       phys_addr_t align = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);
+       phys_addr_t mask = align - 1;
+       unsigned long node = rmem->fdt_node;
+       struct cma *cma;
+       int err;
+
+       if (!of_get_flat_dt_prop(node, "reusable", NULL) ||
+           of_get_flat_dt_prop(node, "no-map", NULL))
+               return -EINVAL;
+
+       if ((rmem->base & mask) || (rmem->size & mask)) {
+               pr_err("Reserved memory: incorrect alignment of CMA region\n");
+               return -EINVAL;
+       }
+
+       err = cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name, &cma);
+       if (err) {
+               pr_err("Reserved memory: unable to setup CMA region\n");
+               return err;
+       }
+       /* Architecture specific contiguous memory fixup. */
+       dma_contiguous_early_fixup(rmem->base, rmem->size);
+
+       if (of_get_flat_dt_prop(node, "linux,cma-default", NULL))
+               dma_contiguous_set_default(cma);
+
+       rmem->ops = &rmem_cma_ops;
+       rmem->priv = cma;
+
+       pr_info("Reserved memory: created CMA memory pool at %pa, size %ld MiB\n",
+               &rmem->base, (unsigned long)rmem->size / SZ_1M);
+
+       return 0;
+}
+RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup);
+#endif
diff --git a/kernel/dma/debug.c b/kernel/dma/debug.c
new file mode 100644 (file)
index 0000000..c007d25
--- /dev/null
@@ -0,0 +1,1773 @@
+/*
+ * Copyright (C) 2008 Advanced Micro Devices, Inc.
+ *
+ * Author: Joerg Roedel <joerg.roedel@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/sched/task_stack.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched/task.h>
+#include <linux/stacktrace.h>
+#include <linux/dma-debug.h>
+#include <linux/spinlock.h>
+#include <linux/vmalloc.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/export.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/ctype.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include <asm/sections.h>
+
+#define HASH_SIZE       1024ULL
+#define HASH_FN_SHIFT   13
+#define HASH_FN_MASK    (HASH_SIZE - 1)
+
+/* allow architectures to override this if absolutely required */
+#ifndef PREALLOC_DMA_DEBUG_ENTRIES
+#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
+#endif
+
+enum {
+       dma_debug_single,
+       dma_debug_page,
+       dma_debug_sg,
+       dma_debug_coherent,
+       dma_debug_resource,
+};
+
+enum map_err_types {
+       MAP_ERR_CHECK_NOT_APPLICABLE,
+       MAP_ERR_NOT_CHECKED,
+       MAP_ERR_CHECKED,
+};
+
+#define DMA_DEBUG_STACKTRACE_ENTRIES 5
+
+/**
+ * struct dma_debug_entry - track a dma_map* or dma_alloc_coherent mapping
+ * @list: node on pre-allocated free_entries list
+ * @dev: 'dev' argument to dma_map_{page|single|sg} or dma_alloc_coherent
+ * @type: single, page, sg, coherent
+ * @pfn: page frame of the start address
+ * @offset: offset of mapping relative to pfn
+ * @size: length of the mapping
+ * @direction: enum dma_data_direction
+ * @sg_call_ents: 'nents' from dma_map_sg
+ * @sg_mapped_ents: 'mapped_ents' from dma_map_sg
+ * @map_err_type: track whether dma_mapping_error() was checked
+ * @stacktrace: support backtraces when a violation is detected
+ */
+struct dma_debug_entry {
+       struct list_head list;
+       struct device    *dev;
+       int              type;
+       unsigned long    pfn;
+       size_t           offset;
+       u64              dev_addr;
+       u64              size;
+       int              direction;
+       int              sg_call_ents;
+       int              sg_mapped_ents;
+       enum map_err_types  map_err_type;
+#ifdef CONFIG_STACKTRACE
+       struct           stack_trace stacktrace;
+       unsigned long    st_entries[DMA_DEBUG_STACKTRACE_ENTRIES];
+#endif
+};
+
+typedef bool (*match_fn)(struct dma_debug_entry *, struct dma_debug_entry *);
+
+struct hash_bucket {
+       struct list_head list;
+       spinlock_t lock;
+} ____cacheline_aligned_in_smp;
+
+/* Hash list to save the allocated dma addresses */
+static struct hash_bucket dma_entry_hash[HASH_SIZE];
+/* List of pre-allocated dma_debug_entry's */
+static LIST_HEAD(free_entries);
+/* Lock for the list above */
+static DEFINE_SPINLOCK(free_entries_lock);
+
+/* Global disable flag - will be set in case of an error */
+static bool global_disable __read_mostly;
+
+/* Early initialization disable flag, set at the end of dma_debug_init */
+static bool dma_debug_initialized __read_mostly;
+
+static inline bool dma_debug_disabled(void)
+{
+       return global_disable || !dma_debug_initialized;
+}
+
+/* Global error count */
+static u32 error_count;
+
+/* Global error show enable*/
+static u32 show_all_errors __read_mostly;
+/* Number of errors to show */
+static u32 show_num_errors = 1;
+
+static u32 num_free_entries;
+static u32 min_free_entries;
+static u32 nr_total_entries;
+
+/* number of preallocated entries requested by kernel cmdline */
+static u32 nr_prealloc_entries = PREALLOC_DMA_DEBUG_ENTRIES;
+
+/* debugfs dentry's for the stuff above */
+static struct dentry *dma_debug_dent        __read_mostly;
+static struct dentry *global_disable_dent   __read_mostly;
+static struct dentry *error_count_dent      __read_mostly;
+static struct dentry *show_all_errors_dent  __read_mostly;
+static struct dentry *show_num_errors_dent  __read_mostly;
+static struct dentry *num_free_entries_dent __read_mostly;
+static struct dentry *min_free_entries_dent __read_mostly;
+static struct dentry *filter_dent           __read_mostly;
+
+/* per-driver filter related state */
+
+#define NAME_MAX_LEN   64
+
+static char                  current_driver_name[NAME_MAX_LEN] __read_mostly;
+static struct device_driver *current_driver                    __read_mostly;
+
+static DEFINE_RWLOCK(driver_name_lock);
+
+static const char *const maperr2str[] = {
+       [MAP_ERR_CHECK_NOT_APPLICABLE] = "dma map error check not applicable",
+       [MAP_ERR_NOT_CHECKED] = "dma map error not checked",
+       [MAP_ERR_CHECKED] = "dma map error checked",
+};
+
+static const char *type2name[5] = { "single", "page",
+                                   "scather-gather", "coherent",
+                                   "resource" };
+
+static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE",
+                                  "DMA_FROM_DEVICE", "DMA_NONE" };
+
+/*
+ * The access to some variables in this macro is racy. We can't use atomic_t
+ * here because all these variables are exported to debugfs. Some of them even
+ * writeable. This is also the reason why a lock won't help much. But anyway,
+ * the races are no big deal. Here is why:
+ *
+ *   error_count: the addition is racy, but the worst thing that can happen is
+ *                that we don't count some errors
+ *   show_num_errors: the subtraction is racy. Also no big deal because in
+ *                    worst case this will result in one warning more in the
+ *                    system log than the user configured. This variable is
+ *                    writeable via debugfs.
+ */
+static inline void dump_entry_trace(struct dma_debug_entry *entry)
+{
+#ifdef CONFIG_STACKTRACE
+       if (entry) {
+               pr_warning("Mapped at:\n");
+               print_stack_trace(&entry->stacktrace, 0);
+       }
+#endif
+}
+
+static bool driver_filter(struct device *dev)
+{
+       struct device_driver *drv;
+       unsigned long flags;
+       bool ret;
+
+       /* driver filter off */
+       if (likely(!current_driver_name[0]))
+               return true;
+
+       /* driver filter on and initialized */
+       if (current_driver && dev && dev->driver == current_driver)
+               return true;
+
+       /* driver filter on, but we can't filter on a NULL device... */
+       if (!dev)
+               return false;
+
+       if (current_driver || !current_driver_name[0])
+               return false;
+
+       /* driver filter on but not yet initialized */
+       drv = dev->driver;
+       if (!drv)
+               return false;
+
+       /* lock to protect against change of current_driver_name */
+       read_lock_irqsave(&driver_name_lock, flags);
+
+       ret = false;
+       if (drv->name &&
+           strncmp(current_driver_name, drv->name, NAME_MAX_LEN - 1) == 0) {
+               current_driver = drv;
+               ret = true;
+       }
+
+       read_unlock_irqrestore(&driver_name_lock, flags);
+
+       return ret;
+}
+
+#define err_printk(dev, entry, format, arg...) do {                    \
+               error_count += 1;                                       \
+               if (driver_filter(dev) &&                               \
+                   (show_all_errors || show_num_errors > 0)) {         \
+                       WARN(1, "%s %s: " format,                       \
+                            dev ? dev_driver_string(dev) : "NULL",     \
+                            dev ? dev_name(dev) : "NULL", ## arg);     \
+                       dump_entry_trace(entry);                        \
+               }                                                       \
+               if (!show_all_errors && show_num_errors > 0)            \
+                       show_num_errors -= 1;                           \
+       } while (0);
+
+/*
+ * Hash related functions
+ *
+ * Every DMA-API request is saved into a struct dma_debug_entry. To
+ * have quick access to these structs they are stored into a hash.
+ */
+static int hash_fn(struct dma_debug_entry *entry)
+{
+       /*
+        * Hash function is based on the dma address.
+        * We use bits 20-27 here as the index into the hash
+        */
+       return (entry->dev_addr >> HASH_FN_SHIFT) & HASH_FN_MASK;
+}
+
+/*
+ * Request exclusive access to a hash bucket for a given dma_debug_entry.
+ */
+static struct hash_bucket *get_hash_bucket(struct dma_debug_entry *entry,
+                                          unsigned long *flags)
+       __acquires(&dma_entry_hash[idx].lock)
+{
+       int idx = hash_fn(entry);
+       unsigned long __flags;
+
+       spin_lock_irqsave(&dma_entry_hash[idx].lock, __flags);
+       *flags = __flags;
+       return &dma_entry_hash[idx];
+}
+
+/*
+ * Give up exclusive access to the hash bucket
+ */
+static void put_hash_bucket(struct hash_bucket *bucket,
+                           unsigned long *flags)
+       __releases(&bucket->lock)
+{
+       unsigned long __flags = *flags;
+
+       spin_unlock_irqrestore(&bucket->lock, __flags);
+}
+
+static bool exact_match(struct dma_debug_entry *a, struct dma_debug_entry *b)
+{
+       return ((a->dev_addr == b->dev_addr) &&
+               (a->dev == b->dev)) ? true : false;
+}
+
+static bool containing_match(struct dma_debug_entry *a,
+                            struct dma_debug_entry *b)
+{
+       if (a->dev != b->dev)
+               return false;
+
+       if ((b->dev_addr <= a->dev_addr) &&
+           ((b->dev_addr + b->size) >= (a->dev_addr + a->size)))
+               return true;
+
+       return false;
+}
+
+/*
+ * Search a given entry in the hash bucket list
+ */
+static struct dma_debug_entry *__hash_bucket_find(struct hash_bucket *bucket,
+                                                 struct dma_debug_entry *ref,
+                                                 match_fn match)
+{
+       struct dma_debug_entry *entry, *ret = NULL;
+       int matches = 0, match_lvl, last_lvl = -1;
+
+       list_for_each_entry(entry, &bucket->list, list) {
+               if (!match(ref, entry))
+                       continue;
+
+               /*
+                * Some drivers map the same physical address multiple
+                * times. Without a hardware IOMMU this results in the
+                * same device addresses being put into the dma-debug
+                * hash multiple times too. This can result in false
+                * positives being reported. Therefore we implement a
+                * best-fit algorithm here which returns the entry from
+                * the hash which fits best to the reference value
+                * instead of the first-fit.
+                */
+               matches += 1;
+               match_lvl = 0;
+               entry->size         == ref->size         ? ++match_lvl : 0;
+               entry->type         == ref->type         ? ++match_lvl : 0;
+               entry->direction    == ref->direction    ? ++match_lvl : 0;
+               entry->sg_call_ents == ref->sg_call_ents ? ++match_lvl : 0;
+
+               if (match_lvl == 4) {
+                       /* perfect-fit - return the result */
+                       return entry;
+               } else if (match_lvl > last_lvl) {
+                       /*
+                        * We found an entry that fits better then the
+                        * previous one or it is the 1st match.
+                        */
+                       last_lvl = match_lvl;
+                       ret      = entry;
+               }
+       }
+
+       /*
+        * If we have multiple matches but no perfect-fit, just return
+        * NULL.
+        */
+       ret = (matches == 1) ? ret : NULL;
+
+       return ret;
+}
+
+static struct dma_debug_entry *bucket_find_exact(struct hash_bucket *bucket,
+                                                struct dma_debug_entry *ref)
+{
+       return __hash_bucket_find(bucket, ref, exact_match);
+}
+
+static struct dma_debug_entry *bucket_find_contain(struct hash_bucket **bucket,
+                                                  struct dma_debug_entry *ref,
+                                                  unsigned long *flags)
+{
+
+       unsigned int max_range = dma_get_max_seg_size(ref->dev);
+       struct dma_debug_entry *entry, index = *ref;
+       unsigned int range = 0;
+
+       while (range <= max_range) {
+               entry = __hash_bucket_find(*bucket, ref, containing_match);
+
+               if (entry)
+                       return entry;
+
+               /*
+                * Nothing found, go back a hash bucket
+                */
+               put_hash_bucket(*bucket, flags);
+               range          += (1 << HASH_FN_SHIFT);
+               index.dev_addr -= (1 << HASH_FN_SHIFT);
+               *bucket = get_hash_bucket(&index, flags);
+       }
+
+       return NULL;
+}
+
+/*
+ * Add an entry to a hash bucket
+ */
+static void hash_bucket_add(struct hash_bucket *bucket,
+                           struct dma_debug_entry *entry)
+{
+       list_add_tail(&entry->list, &bucket->list);
+}
+
+/*
+ * Remove entry from a hash bucket list
+ */
+static void hash_bucket_del(struct dma_debug_entry *entry)
+{
+       list_del(&entry->list);
+}
+
+static unsigned long long phys_addr(struct dma_debug_entry *entry)
+{
+       if (entry->type == dma_debug_resource)
+               return __pfn_to_phys(entry->pfn) + entry->offset;
+
+       return page_to_phys(pfn_to_page(entry->pfn)) + entry->offset;
+}
+
+/*
+ * Dump mapping entries for debugging purposes
+ */
+void debug_dma_dump_mappings(struct device *dev)
+{
+       int idx;
+
+       for (idx = 0; idx < HASH_SIZE; idx++) {
+               struct hash_bucket *bucket = &dma_entry_hash[idx];
+               struct dma_debug_entry *entry;
+               unsigned long flags;
+
+               spin_lock_irqsave(&bucket->lock, flags);
+
+               list_for_each_entry(entry, &bucket->list, list) {
+                       if (!dev || dev == entry->dev) {
+                               dev_info(entry->dev,
+                                        "%s idx %d P=%Lx N=%lx D=%Lx L=%Lx %s %s\n",
+                                        type2name[entry->type], idx,
+                                        phys_addr(entry), entry->pfn,
+                                        entry->dev_addr, entry->size,
+                                        dir2name[entry->direction],
+                                        maperr2str[entry->map_err_type]);
+                       }
+               }
+
+               spin_unlock_irqrestore(&bucket->lock, flags);
+       }
+}
+
+/*
+ * For each mapping (initial cacheline in the case of
+ * dma_alloc_coherent/dma_map_page, initial cacheline in each page of a
+ * scatterlist, or the cacheline specified in dma_map_single) insert
+ * into this tree using the cacheline as the key. At
+ * dma_unmap_{single|sg|page} or dma_free_coherent delete the entry.  If
+ * the entry already exists at insertion time add a tag as a reference
+ * count for the overlapping mappings.  For now, the overlap tracking
+ * just ensures that 'unmaps' balance 'maps' before marking the
+ * cacheline idle, but we should also be flagging overlaps as an API
+ * violation.
+ *
+ * Memory usage is mostly constrained by the maximum number of available
+ * dma-debug entries in that we need a free dma_debug_entry before
+ * inserting into the tree.  In the case of dma_map_page and
+ * dma_alloc_coherent there is only one dma_debug_entry and one
+ * dma_active_cacheline entry to track per event.  dma_map_sg(), on the
+ * other hand, consumes a single dma_debug_entry, but inserts 'nents'
+ * entries into the tree.
+ *
+ * At any time debug_dma_assert_idle() can be called to trigger a
+ * warning if any cachelines in the given page are in the active set.
+ */
+static RADIX_TREE(dma_active_cacheline, GFP_NOWAIT);
+static DEFINE_SPINLOCK(radix_lock);
+#define ACTIVE_CACHELINE_MAX_OVERLAP ((1 << RADIX_TREE_MAX_TAGS) - 1)
+#define CACHELINE_PER_PAGE_SHIFT (PAGE_SHIFT - L1_CACHE_SHIFT)
+#define CACHELINES_PER_PAGE (1 << CACHELINE_PER_PAGE_SHIFT)
+
+static phys_addr_t to_cacheline_number(struct dma_debug_entry *entry)
+{
+       return (entry->pfn << CACHELINE_PER_PAGE_SHIFT) +
+               (entry->offset >> L1_CACHE_SHIFT);
+}
+
+static int active_cacheline_read_overlap(phys_addr_t cln)
+{
+       int overlap = 0, i;
+
+       for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
+               if (radix_tree_tag_get(&dma_active_cacheline, cln, i))
+                       overlap |= 1 << i;
+       return overlap;
+}
+
+static int active_cacheline_set_overlap(phys_addr_t cln, int overlap)
+{
+       int i;
+
+       if (overlap > ACTIVE_CACHELINE_MAX_OVERLAP || overlap < 0)
+               return overlap;
+
+       for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
+               if (overlap & 1 << i)
+                       radix_tree_tag_set(&dma_active_cacheline, cln, i);
+               else
+                       radix_tree_tag_clear(&dma_active_cacheline, cln, i);
+
+       return overlap;
+}
+
+static void active_cacheline_inc_overlap(phys_addr_t cln)
+{
+       int overlap = active_cacheline_read_overlap(cln);
+
+       overlap = active_cacheline_set_overlap(cln, ++overlap);
+
+       /* If we overflowed the overlap counter then we're potentially
+        * leaking dma-mappings.  Otherwise, if maps and unmaps are
+        * balanced then this overflow may cause false negatives in
+        * debug_dma_assert_idle() as the cacheline may be marked idle
+        * prematurely.
+        */
+       WARN_ONCE(overlap > ACTIVE_CACHELINE_MAX_OVERLAP,
+                 "DMA-API: exceeded %d overlapping mappings of cacheline %pa\n",
+                 ACTIVE_CACHELINE_MAX_OVERLAP, &cln);
+}
+
+static int active_cacheline_dec_overlap(phys_addr_t cln)
+{
+       int overlap = active_cacheline_read_overlap(cln);
+
+       return active_cacheline_set_overlap(cln, --overlap);
+}
+
+static int active_cacheline_insert(struct dma_debug_entry *entry)
+{
+       phys_addr_t cln = to_cacheline_number(entry);
+       unsigned long flags;
+       int rc;
+
+       /* If the device is not writing memory then we don't have any
+        * concerns about the cpu consuming stale data.  This mitigates
+        * legitimate usages of overlapping mappings.
+        */
+       if (entry->direction == DMA_TO_DEVICE)
+               return 0;
+
+       spin_lock_irqsave(&radix_lock, flags);
+       rc = radix_tree_insert(&dma_active_cacheline, cln, entry);
+       if (rc == -EEXIST)
+               active_cacheline_inc_overlap(cln);
+       spin_unlock_irqrestore(&radix_lock, flags);
+
+       return rc;
+}
+
+static void active_cacheline_remove(struct dma_debug_entry *entry)
+{
+       phys_addr_t cln = to_cacheline_number(entry);
+       unsigned long flags;
+
+       /* ...mirror the insert case */
+       if (entry->direction == DMA_TO_DEVICE)
+               return;
+
+       spin_lock_irqsave(&radix_lock, flags);
+       /* since we are counting overlaps the final put of the
+        * cacheline will occur when the overlap count is 0.
+        * active_cacheline_dec_overlap() returns -1 in that case
+        */
+       if (active_cacheline_dec_overlap(cln) < 0)
+               radix_tree_delete(&dma_active_cacheline, cln);
+       spin_unlock_irqrestore(&radix_lock, flags);
+}
+
+/**
+ * debug_dma_assert_idle() - assert that a page is not undergoing dma
+ * @page: page to lookup in the dma_active_cacheline tree
+ *
+ * Place a call to this routine in cases where the cpu touching the page
+ * before the dma completes (page is dma_unmapped) will lead to data
+ * corruption.
+ */
+void debug_dma_assert_idle(struct page *page)
+{
+       static struct dma_debug_entry *ents[CACHELINES_PER_PAGE];
+       struct dma_debug_entry *entry = NULL;
+       void **results = (void **) &ents;
+       unsigned int nents, i;
+       unsigned long flags;
+       phys_addr_t cln;
+
+       if (dma_debug_disabled())
+               return;
+
+       if (!page)
+               return;
+
+       cln = (phys_addr_t) page_to_pfn(page) << CACHELINE_PER_PAGE_SHIFT;
+       spin_lock_irqsave(&radix_lock, flags);
+       nents = radix_tree_gang_lookup(&dma_active_cacheline, results, cln,
+                                      CACHELINES_PER_PAGE);
+       for (i = 0; i < nents; i++) {
+               phys_addr_t ent_cln = to_cacheline_number(ents[i]);
+
+               if (ent_cln == cln) {
+                       entry = ents[i];
+                       break;
+               } else if (ent_cln >= cln + CACHELINES_PER_PAGE)
+                       break;
+       }
+       spin_unlock_irqrestore(&radix_lock, flags);
+
+       if (!entry)
+               return;
+
+       cln = to_cacheline_number(entry);
+       err_printk(entry->dev, entry,
+                  "DMA-API: cpu touching an active dma mapped cacheline [cln=%pa]\n",
+                  &cln);
+}
+
+/*
+ * Wrapper function for adding an entry to the hash.
+ * This function takes care of locking itself.
+ */
+static void add_dma_entry(struct dma_debug_entry *entry)
+{
+       struct hash_bucket *bucket;
+       unsigned long flags;
+       int rc;
+
+       bucket = get_hash_bucket(entry, &flags);
+       hash_bucket_add(bucket, entry);
+       put_hash_bucket(bucket, &flags);
+
+       rc = active_cacheline_insert(entry);
+       if (rc == -ENOMEM) {
+               pr_err("DMA-API: cacheline tracking ENOMEM, dma-debug disabled\n");
+               global_disable = true;
+       }
+
+       /* TODO: report -EEXIST errors here as overlapping mappings are
+        * not supported by the DMA API
+        */
+}
+
+static struct dma_debug_entry *__dma_entry_alloc(void)
+{
+       struct dma_debug_entry *entry;
+
+       entry = list_entry(free_entries.next, struct dma_debug_entry, list);
+       list_del(&entry->list);
+       memset(entry, 0, sizeof(*entry));
+
+       num_free_entries -= 1;
+       if (num_free_entries < min_free_entries)
+               min_free_entries = num_free_entries;
+
+       return entry;
+}
+
+/* struct dma_entry allocator
+ *
+ * The next two functions implement the allocator for
+ * struct dma_debug_entries.
+ */
+static struct dma_debug_entry *dma_entry_alloc(void)
+{
+       struct dma_debug_entry *entry;
+       unsigned long flags;
+
+       spin_lock_irqsave(&free_entries_lock, flags);
+
+       if (list_empty(&free_entries)) {
+               global_disable = true;
+               spin_unlock_irqrestore(&free_entries_lock, flags);
+               pr_err("DMA-API: debugging out of memory - disabling\n");
+               return NULL;
+       }
+
+       entry = __dma_entry_alloc();
+
+       spin_unlock_irqrestore(&free_entries_lock, flags);
+
+#ifdef CONFIG_STACKTRACE
+       entry->stacktrace.max_entries = DMA_DEBUG_STACKTRACE_ENTRIES;
+       entry->stacktrace.entries = entry->st_entries;
+       entry->stacktrace.skip = 2;
+       save_stack_trace(&entry->stacktrace);
+#endif
+
+       return entry;
+}
+
+static void dma_entry_free(struct dma_debug_entry *entry)
+{
+       unsigned long flags;
+
+       active_cacheline_remove(entry);
+
+       /*
+        * add to beginning of the list - this way the entries are
+        * more likely cache hot when they are reallocated.
+        */
+       spin_lock_irqsave(&free_entries_lock, flags);
+       list_add(&entry->list, &free_entries);
+       num_free_entries += 1;
+       spin_unlock_irqrestore(&free_entries_lock, flags);
+}
+
+int dma_debug_resize_entries(u32 num_entries)
+{
+       int i, delta, ret = 0;
+       unsigned long flags;
+       struct dma_debug_entry *entry;
+       LIST_HEAD(tmp);
+
+       spin_lock_irqsave(&free_entries_lock, flags);
+
+       if (nr_total_entries < num_entries) {
+               delta = num_entries - nr_total_entries;
+
+               spin_unlock_irqrestore(&free_entries_lock, flags);
+
+               for (i = 0; i < delta; i++) {
+                       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+                       if (!entry)
+                               break;
+
+                       list_add_tail(&entry->list, &tmp);
+               }
+
+               spin_lock_irqsave(&free_entries_lock, flags);
+
+               list_splice(&tmp, &free_entries);
+               nr_total_entries += i;
+               num_free_entries += i;
+       } else {
+               delta = nr_total_entries - num_entries;
+
+               for (i = 0; i < delta && !list_empty(&free_entries); i++) {
+                       entry = __dma_entry_alloc();
+                       kfree(entry);
+               }
+
+               nr_total_entries -= i;
+       }
+
+       if (nr_total_entries != num_entries)
+               ret = 1;
+
+       spin_unlock_irqrestore(&free_entries_lock, flags);
+
+       return ret;
+}
+
+/*
+ * DMA-API debugging init code
+ *
+ * The init code does two things:
+ *   1. Initialize core data structures
+ *   2. Preallocate a given number of dma_debug_entry structs
+ */
+
+static int prealloc_memory(u32 num_entries)
+{
+       struct dma_debug_entry *entry, *next_entry;
+       int i;
+
+       for (i = 0; i < num_entries; ++i) {
+               entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+               if (!entry)
+                       goto out_err;
+
+               list_add_tail(&entry->list, &free_entries);
+       }
+
+       num_free_entries = num_entries;
+       min_free_entries = num_entries;
+
+       pr_info("DMA-API: preallocated %d debug entries\n", num_entries);
+
+       return 0;
+
+out_err:
+
+       list_for_each_entry_safe(entry, next_entry, &free_entries, list) {
+               list_del(&entry->list);
+               kfree(entry);
+       }
+
+       return -ENOMEM;
+}
+
+static ssize_t filter_read(struct file *file, char __user *user_buf,
+                          size_t count, loff_t *ppos)
+{
+       char buf[NAME_MAX_LEN + 1];
+       unsigned long flags;
+       int len;
+
+       if (!current_driver_name[0])
+               return 0;
+
+       /*
+        * We can't copy to userspace directly because current_driver_name can
+        * only be read under the driver_name_lock with irqs disabled. So
+        * create a temporary copy first.
+        */
+       read_lock_irqsave(&driver_name_lock, flags);
+       len = scnprintf(buf, NAME_MAX_LEN + 1, "%s\n", current_driver_name);
+       read_unlock_irqrestore(&driver_name_lock, flags);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t filter_write(struct file *file, const char __user *userbuf,
+                           size_t count, loff_t *ppos)
+{
+       char buf[NAME_MAX_LEN];
+       unsigned long flags;
+       size_t len;
+       int i;
+
+       /*
+        * We can't copy from userspace directly. Access to
+        * current_driver_name is protected with a write_lock with irqs
+        * disabled. Since copy_from_user can fault and may sleep we
+        * need to copy to temporary buffer first
+        */
+       len = min(count, (size_t)(NAME_MAX_LEN - 1));
+       if (copy_from_user(buf, userbuf, len))
+               return -EFAULT;
+
+       buf[len] = 0;
+
+       write_lock_irqsave(&driver_name_lock, flags);
+
+       /*
+        * Now handle the string we got from userspace very carefully.
+        * The rules are:
+        *         - only use the first token we got
+        *         - token delimiter is everything looking like a space
+        *           character (' ', '\n', '\t' ...)
+        *
+        */
+       if (!isalnum(buf[0])) {
+               /*
+                * If the first character userspace gave us is not
+                * alphanumerical then assume the filter should be
+                * switched off.
+                */
+               if (current_driver_name[0])
+                       pr_info("DMA-API: switching off dma-debug driver filter\n");
+               current_driver_name[0] = 0;
+               current_driver = NULL;
+               goto out_unlock;
+       }
+
+       /*
+        * Now parse out the first token and use it as the name for the
+        * driver to filter for.
+        */
+       for (i = 0; i < NAME_MAX_LEN - 1; ++i) {
+               current_driver_name[i] = buf[i];
+               if (isspace(buf[i]) || buf[i] == ' ' || buf[i] == 0)
+                       break;
+       }
+       current_driver_name[i] = 0;
+       current_driver = NULL;
+
+       pr_info("DMA-API: enable driver filter for driver [%s]\n",
+               current_driver_name);
+
+out_unlock:
+       write_unlock_irqrestore(&driver_name_lock, flags);
+
+       return count;
+}
+
+static const struct file_operations filter_fops = {
+       .read  = filter_read,
+       .write = filter_write,
+       .llseek = default_llseek,
+};
+
+static int dma_debug_fs_init(void)
+{
+       dma_debug_dent = debugfs_create_dir("dma-api", NULL);
+       if (!dma_debug_dent) {
+               pr_err("DMA-API: can not create debugfs directory\n");
+               return -ENOMEM;
+       }
+
+       global_disable_dent = debugfs_create_bool("disabled", 0444,
+                       dma_debug_dent,
+                       &global_disable);
+       if (!global_disable_dent)
+               goto out_err;
+
+       error_count_dent = debugfs_create_u32("error_count", 0444,
+                       dma_debug_dent, &error_count);
+       if (!error_count_dent)
+               goto out_err;
+
+       show_all_errors_dent = debugfs_create_u32("all_errors", 0644,
+                       dma_debug_dent,
+                       &show_all_errors);
+       if (!show_all_errors_dent)
+               goto out_err;
+
+       show_num_errors_dent = debugfs_create_u32("num_errors", 0644,
+                       dma_debug_dent,
+                       &show_num_errors);
+       if (!show_num_errors_dent)
+               goto out_err;
+
+       num_free_entries_dent = debugfs_create_u32("num_free_entries", 0444,
+                       dma_debug_dent,
+                       &num_free_entries);
+       if (!num_free_entries_dent)
+               goto out_err;
+
+       min_free_entries_dent = debugfs_create_u32("min_free_entries", 0444,
+                       dma_debug_dent,
+                       &min_free_entries);
+       if (!min_free_entries_dent)
+               goto out_err;
+
+       filter_dent = debugfs_create_file("driver_filter", 0644,
+                                         dma_debug_dent, NULL, &filter_fops);
+       if (!filter_dent)
+               goto out_err;
+
+       return 0;
+
+out_err:
+       debugfs_remove_recursive(dma_debug_dent);
+
+       return -ENOMEM;
+}
+
+static int device_dma_allocations(struct device *dev, struct dma_debug_entry **out_entry)
+{
+       struct dma_debug_entry *entry;
+       unsigned long flags;
+       int count = 0, i;
+
+       for (i = 0; i < HASH_SIZE; ++i) {
+               spin_lock_irqsave(&dma_entry_hash[i].lock, flags);
+               list_for_each_entry(entry, &dma_entry_hash[i].list, list) {
+                       if (entry->dev == dev) {
+                               count += 1;
+                               *out_entry = entry;
+                       }
+               }
+               spin_unlock_irqrestore(&dma_entry_hash[i].lock, flags);
+       }
+
+       return count;
+}
+
+static int dma_debug_device_change(struct notifier_block *nb, unsigned long action, void *data)
+{
+       struct device *dev = data;
+       struct dma_debug_entry *uninitialized_var(entry);
+       int count;
+
+       if (dma_debug_disabled())
+               return 0;
+
+       switch (action) {
+       case BUS_NOTIFY_UNBOUND_DRIVER:
+               count = device_dma_allocations(dev, &entry);
+               if (count == 0)
+                       break;
+               err_printk(dev, entry, "DMA-API: device driver has pending "
+                               "DMA allocations while released from device "
+                               "[count=%d]\n"
+                               "One of leaked entries details: "
+                               "[device address=0x%016llx] [size=%llu bytes] "
+                               "[mapped with %s] [mapped as %s]\n",
+                       count, entry->dev_addr, entry->size,
+                       dir2name[entry->direction], type2name[entry->type]);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+void dma_debug_add_bus(struct bus_type *bus)
+{
+       struct notifier_block *nb;
+
+       if (dma_debug_disabled())
+               return;
+
+       nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL);
+       if (nb == NULL) {
+               pr_err("dma_debug_add_bus: out of memory\n");
+               return;
+       }
+
+       nb->notifier_call = dma_debug_device_change;
+
+       bus_register_notifier(bus, nb);
+}
+
+static int dma_debug_init(void)
+{
+       int i;
+
+       /* Do not use dma_debug_initialized here, since we really want to be
+        * called to set dma_debug_initialized
+        */
+       if (global_disable)
+               return 0;
+
+       for (i = 0; i < HASH_SIZE; ++i) {
+               INIT_LIST_HEAD(&dma_entry_hash[i].list);
+               spin_lock_init(&dma_entry_hash[i].lock);
+       }
+
+       if (dma_debug_fs_init() != 0) {
+               pr_err("DMA-API: error creating debugfs entries - disabling\n");
+               global_disable = true;
+
+               return 0;
+       }
+
+       if (prealloc_memory(nr_prealloc_entries) != 0) {
+               pr_err("DMA-API: debugging out of memory error - disabled\n");
+               global_disable = true;
+
+               return 0;
+       }
+
+       nr_total_entries = num_free_entries;
+
+       dma_debug_initialized = true;
+
+       pr_info("DMA-API: debugging enabled by kernel config\n");
+       return 0;
+}
+core_initcall(dma_debug_init);
+
+static __init int dma_debug_cmdline(char *str)
+{
+       if (!str)
+               return -EINVAL;
+
+       if (strncmp(str, "off", 3) == 0) {
+               pr_info("DMA-API: debugging disabled on kernel command line\n");
+               global_disable = true;
+       }
+
+       return 0;
+}
+
+static __init int dma_debug_entries_cmdline(char *str)
+{
+       if (!str)
+               return -EINVAL;
+       if (!get_option(&str, &nr_prealloc_entries))
+               nr_prealloc_entries = PREALLOC_DMA_DEBUG_ENTRIES;
+       return 0;
+}
+
+__setup("dma_debug=", dma_debug_cmdline);
+__setup("dma_debug_entries=", dma_debug_entries_cmdline);
+
+static void check_unmap(struct dma_debug_entry *ref)
+{
+       struct dma_debug_entry *entry;
+       struct hash_bucket *bucket;
+       unsigned long flags;
+
+       bucket = get_hash_bucket(ref, &flags);
+       entry = bucket_find_exact(bucket, ref);
+
+       if (!entry) {
+               /* must drop lock before calling dma_mapping_error */
+               put_hash_bucket(bucket, &flags);
+
+               if (dma_mapping_error(ref->dev, ref->dev_addr)) {
+                       err_printk(ref->dev, NULL,
+                                  "DMA-API: device driver tries to free an "
+                                  "invalid DMA memory address\n");
+               } else {
+                       err_printk(ref->dev, NULL,
+                                  "DMA-API: device driver tries to free DMA "
+                                  "memory it has not allocated [device "
+                                  "address=0x%016llx] [size=%llu bytes]\n",
+                                  ref->dev_addr, ref->size);
+               }
+               return;
+       }
+
+       if (ref->size != entry->size) {
+               err_printk(ref->dev, entry, "DMA-API: device driver frees "
+                          "DMA memory with different size "
+                          "[device address=0x%016llx] [map size=%llu bytes] "
+                          "[unmap size=%llu bytes]\n",
+                          ref->dev_addr, entry->size, ref->size);
+       }
+
+       if (ref->type != entry->type) {
+               err_printk(ref->dev, entry, "DMA-API: device driver frees "
+                          "DMA memory with wrong function "
+                          "[device address=0x%016llx] [size=%llu bytes] "
+                          "[mapped as %s] [unmapped as %s]\n",
+                          ref->dev_addr, ref->size,
+                          type2name[entry->type], type2name[ref->type]);
+       } else if ((entry->type == dma_debug_coherent) &&
+                  (phys_addr(ref) != phys_addr(entry))) {
+               err_printk(ref->dev, entry, "DMA-API: device driver frees "
+                          "DMA memory with different CPU address "
+                          "[device address=0x%016llx] [size=%llu bytes] "
+                          "[cpu alloc address=0x%016llx] "
+                          "[cpu free address=0x%016llx]",
+                          ref->dev_addr, ref->size,
+                          phys_addr(entry),
+                          phys_addr(ref));
+       }
+
+       if (ref->sg_call_ents && ref->type == dma_debug_sg &&
+           ref->sg_call_ents != entry->sg_call_ents) {
+               err_printk(ref->dev, entry, "DMA-API: device driver frees "
+                          "DMA sg list with different entry count "
+                          "[map count=%d] [unmap count=%d]\n",
+                          entry->sg_call_ents, ref->sg_call_ents);
+       }
+
+       /*
+        * This may be no bug in reality - but most implementations of the
+        * DMA API don't handle this properly, so check for it here
+        */
+       if (ref->direction != entry->direction) {
+               err_printk(ref->dev, entry, "DMA-API: device driver frees "
+                          "DMA memory with different direction "
+                          "[device address=0x%016llx] [size=%llu bytes] "
+                          "[mapped with %s] [unmapped with %s]\n",
+                          ref->dev_addr, ref->size,
+                          dir2name[entry->direction],
+                          dir2name[ref->direction]);
+       }
+
+       /*
+        * Drivers should use dma_mapping_error() to check the returned
+        * addresses of dma_map_single() and dma_map_page().
+        * If not, print this warning message. See Documentation/DMA-API.txt.
+        */
+       if (entry->map_err_type == MAP_ERR_NOT_CHECKED) {
+               err_printk(ref->dev, entry,
+                          "DMA-API: device driver failed to check map error"
+                          "[device address=0x%016llx] [size=%llu bytes] "
+                          "[mapped as %s]",
+                          ref->dev_addr, ref->size,
+                          type2name[entry->type]);
+       }
+
+       hash_bucket_del(entry);
+       dma_entry_free(entry);
+
+       put_hash_bucket(bucket, &flags);
+}
+
+static void check_for_stack(struct device *dev,
+                           struct page *page, size_t offset)
+{
+       void *addr;
+       struct vm_struct *stack_vm_area = task_stack_vm_area(current);
+
+       if (!stack_vm_area) {
+               /* Stack is direct-mapped. */
+               if (PageHighMem(page))
+                       return;
+               addr = page_address(page) + offset;
+               if (object_is_on_stack(addr))
+                       err_printk(dev, NULL, "DMA-API: device driver maps memory from stack [addr=%p]\n", addr);
+       } else {
+               /* Stack is vmalloced. */
+               int i;
+
+               for (i = 0; i < stack_vm_area->nr_pages; i++) {
+                       if (page != stack_vm_area->pages[i])
+                               continue;
+
+                       addr = (u8 *)current->stack + i * PAGE_SIZE + offset;
+                       err_printk(dev, NULL, "DMA-API: device driver maps memory from stack [probable addr=%p]\n", addr);
+                       break;
+               }
+       }
+}
+
+static inline bool overlap(void *addr, unsigned long len, void *start, void *end)
+{
+       unsigned long a1 = (unsigned long)addr;
+       unsigned long b1 = a1 + len;
+       unsigned long a2 = (unsigned long)start;
+       unsigned long b2 = (unsigned long)end;
+
+       return !(b1 <= a2 || a1 >= b2);
+}
+
+static void check_for_illegal_area(struct device *dev, void *addr, unsigned long len)
+{
+       if (overlap(addr, len, _stext, _etext) ||
+           overlap(addr, len, __start_rodata, __end_rodata))
+               err_printk(dev, NULL, "DMA-API: device driver maps memory from kernel text or rodata [addr=%p] [len=%lu]\n", addr, len);
+}
+
+static void check_sync(struct device *dev,
+                      struct dma_debug_entry *ref,
+                      bool to_cpu)
+{
+       struct dma_debug_entry *entry;
+       struct hash_bucket *bucket;
+       unsigned long flags;
+
+       bucket = get_hash_bucket(ref, &flags);
+
+       entry = bucket_find_contain(&bucket, ref, &flags);
+
+       if (!entry) {
+               err_printk(dev, NULL, "DMA-API: device driver tries "
+                               "to sync DMA memory it has not allocated "
+                               "[device address=0x%016llx] [size=%llu bytes]\n",
+                               (unsigned long long)ref->dev_addr, ref->size);
+               goto out;
+       }
+
+       if (ref->size > entry->size) {
+               err_printk(dev, entry, "DMA-API: device driver syncs"
+                               " DMA memory outside allocated range "
+                               "[device address=0x%016llx] "
+                               "[allocation size=%llu bytes] "
+                               "[sync offset+size=%llu]\n",
+                               entry->dev_addr, entry->size,
+                               ref->size);
+       }
+
+       if (entry->direction == DMA_BIDIRECTIONAL)
+               goto out;
+
+       if (ref->direction != entry->direction) {
+               err_printk(dev, entry, "DMA-API: device driver syncs "
+                               "DMA memory with different direction "
+                               "[device address=0x%016llx] [size=%llu bytes] "
+                               "[mapped with %s] [synced with %s]\n",
+                               (unsigned long long)ref->dev_addr, entry->size,
+                               dir2name[entry->direction],
+                               dir2name[ref->direction]);
+       }
+
+       if (to_cpu && !(entry->direction == DMA_FROM_DEVICE) &&
+                     !(ref->direction == DMA_TO_DEVICE))
+               err_printk(dev, entry, "DMA-API: device driver syncs "
+                               "device read-only DMA memory for cpu "
+                               "[device address=0x%016llx] [size=%llu bytes] "
+                               "[mapped with %s] [synced with %s]\n",
+                               (unsigned long long)ref->dev_addr, entry->size,
+                               dir2name[entry->direction],
+                               dir2name[ref->direction]);
+
+       if (!to_cpu && !(entry->direction == DMA_TO_DEVICE) &&
+                      !(ref->direction == DMA_FROM_DEVICE))
+               err_printk(dev, entry, "DMA-API: device driver syncs "
+                               "device write-only DMA memory to device "
+                               "[device address=0x%016llx] [size=%llu bytes] "
+                               "[mapped with %s] [synced with %s]\n",
+                               (unsigned long long)ref->dev_addr, entry->size,
+                               dir2name[entry->direction],
+                               dir2name[ref->direction]);
+
+       if (ref->sg_call_ents && ref->type == dma_debug_sg &&
+           ref->sg_call_ents != entry->sg_call_ents) {
+               err_printk(ref->dev, entry, "DMA-API: device driver syncs "
+                          "DMA sg list with different entry count "
+                          "[map count=%d] [sync count=%d]\n",
+                          entry->sg_call_ents, ref->sg_call_ents);
+       }
+
+out:
+       put_hash_bucket(bucket, &flags);
+}
+
+static void check_sg_segment(struct device *dev, struct scatterlist *sg)
+{
+#ifdef CONFIG_DMA_API_DEBUG_SG
+       unsigned int max_seg = dma_get_max_seg_size(dev);
+       u64 start, end, boundary = dma_get_seg_boundary(dev);
+
+       /*
+        * Either the driver forgot to set dma_parms appropriately, or
+        * whoever generated the list forgot to check them.
+        */
+       if (sg->length > max_seg)
+               err_printk(dev, NULL, "DMA-API: mapping sg segment longer than device claims to support [len=%u] [max=%u]\n",
+                          sg->length, max_seg);
+       /*
+        * In some cases this could potentially be the DMA API
+        * implementation's fault, but it would usually imply that
+        * the scatterlist was built inappropriately to begin with.
+        */
+       start = sg_dma_address(sg);
+       end = start + sg_dma_len(sg) - 1;
+       if ((start ^ end) & ~boundary)
+               err_printk(dev, NULL, "DMA-API: mapping sg segment across boundary [start=0x%016llx] [end=0x%016llx] [boundary=0x%016llx]\n",
+                          start, end, boundary);
+#endif
+}
+
+void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
+                       size_t size, int direction, dma_addr_t dma_addr,
+                       bool map_single)
+{
+       struct dma_debug_entry *entry;
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       if (dma_mapping_error(dev, dma_addr))
+               return;
+
+       entry = dma_entry_alloc();
+       if (!entry)
+               return;
+
+       entry->dev       = dev;
+       entry->type      = dma_debug_page;
+       entry->pfn       = page_to_pfn(page);
+       entry->offset    = offset,
+       entry->dev_addr  = dma_addr;
+       entry->size      = size;
+       entry->direction = direction;
+       entry->map_err_type = MAP_ERR_NOT_CHECKED;
+
+       if (map_single)
+               entry->type = dma_debug_single;
+
+       check_for_stack(dev, page, offset);
+
+       if (!PageHighMem(page)) {
+               void *addr = page_address(page) + offset;
+
+               check_for_illegal_area(dev, addr, size);
+       }
+
+       add_dma_entry(entry);
+}
+EXPORT_SYMBOL(debug_dma_map_page);
+
+void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       struct dma_debug_entry ref;
+       struct dma_debug_entry *entry;
+       struct hash_bucket *bucket;
+       unsigned long flags;
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       ref.dev = dev;
+       ref.dev_addr = dma_addr;
+       bucket = get_hash_bucket(&ref, &flags);
+
+       list_for_each_entry(entry, &bucket->list, list) {
+               if (!exact_match(&ref, entry))
+                       continue;
+
+               /*
+                * The same physical address can be mapped multiple
+                * times. Without a hardware IOMMU this results in the
+                * same device addresses being put into the dma-debug
+                * hash multiple times too. This can result in false
+                * positives being reported. Therefore we implement a
+                * best-fit algorithm here which updates the first entry
+                * from the hash which fits the reference value and is
+                * not currently listed as being checked.
+                */
+               if (entry->map_err_type == MAP_ERR_NOT_CHECKED) {
+                       entry->map_err_type = MAP_ERR_CHECKED;
+                       break;
+               }
+       }
+
+       put_hash_bucket(bucket, &flags);
+}
+EXPORT_SYMBOL(debug_dma_mapping_error);
+
+void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
+                         size_t size, int direction, bool map_single)
+{
+       struct dma_debug_entry ref = {
+               .type           = dma_debug_page,
+               .dev            = dev,
+               .dev_addr       = addr,
+               .size           = size,
+               .direction      = direction,
+       };
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       if (map_single)
+               ref.type = dma_debug_single;
+
+       check_unmap(&ref);
+}
+EXPORT_SYMBOL(debug_dma_unmap_page);
+
+void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
+                     int nents, int mapped_ents, int direction)
+{
+       struct dma_debug_entry *entry;
+       struct scatterlist *s;
+       int i;
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       for_each_sg(sg, s, mapped_ents, i) {
+               entry = dma_entry_alloc();
+               if (!entry)
+                       return;
+
+               entry->type           = dma_debug_sg;
+               entry->dev            = dev;
+               entry->pfn            = page_to_pfn(sg_page(s));
+               entry->offset         = s->offset,
+               entry->size           = sg_dma_len(s);
+               entry->dev_addr       = sg_dma_address(s);
+               entry->direction      = direction;
+               entry->sg_call_ents   = nents;
+               entry->sg_mapped_ents = mapped_ents;
+
+               check_for_stack(dev, sg_page(s), s->offset);
+
+               if (!PageHighMem(sg_page(s))) {
+                       check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s));
+               }
+
+               check_sg_segment(dev, s);
+
+               add_dma_entry(entry);
+       }
+}
+EXPORT_SYMBOL(debug_dma_map_sg);
+
+static int get_nr_mapped_entries(struct device *dev,
+                                struct dma_debug_entry *ref)
+{
+       struct dma_debug_entry *entry;
+       struct hash_bucket *bucket;
+       unsigned long flags;
+       int mapped_ents;
+
+       bucket       = get_hash_bucket(ref, &flags);
+       entry        = bucket_find_exact(bucket, ref);
+       mapped_ents  = 0;
+
+       if (entry)
+               mapped_ents = entry->sg_mapped_ents;
+       put_hash_bucket(bucket, &flags);
+
+       return mapped_ents;
+}
+
+void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
+                       int nelems, int dir)
+{
+       struct scatterlist *s;
+       int mapped_ents = 0, i;
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       for_each_sg(sglist, s, nelems, i) {
+
+               struct dma_debug_entry ref = {
+                       .type           = dma_debug_sg,
+                       .dev            = dev,
+                       .pfn            = page_to_pfn(sg_page(s)),
+                       .offset         = s->offset,
+                       .dev_addr       = sg_dma_address(s),
+                       .size           = sg_dma_len(s),
+                       .direction      = dir,
+                       .sg_call_ents   = nelems,
+               };
+
+               if (mapped_ents && i >= mapped_ents)
+                       break;
+
+               if (!i)
+                       mapped_ents = get_nr_mapped_entries(dev, &ref);
+
+               check_unmap(&ref);
+       }
+}
+EXPORT_SYMBOL(debug_dma_unmap_sg);
+
+void debug_dma_alloc_coherent(struct device *dev, size_t size,
+                             dma_addr_t dma_addr, void *virt)
+{
+       struct dma_debug_entry *entry;
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       if (unlikely(virt == NULL))
+               return;
+
+       /* handle vmalloc and linear addresses */
+       if (!is_vmalloc_addr(virt) && !virt_addr_valid(virt))
+               return;
+
+       entry = dma_entry_alloc();
+       if (!entry)
+               return;
+
+       entry->type      = dma_debug_coherent;
+       entry->dev       = dev;
+       entry->offset    = offset_in_page(virt);
+       entry->size      = size;
+       entry->dev_addr  = dma_addr;
+       entry->direction = DMA_BIDIRECTIONAL;
+
+       if (is_vmalloc_addr(virt))
+               entry->pfn = vmalloc_to_pfn(virt);
+       else
+               entry->pfn = page_to_pfn(virt_to_page(virt));
+
+       add_dma_entry(entry);
+}
+EXPORT_SYMBOL(debug_dma_alloc_coherent);
+
+void debug_dma_free_coherent(struct device *dev, size_t size,
+                        void *virt, dma_addr_t addr)
+{
+       struct dma_debug_entry ref = {
+               .type           = dma_debug_coherent,
+               .dev            = dev,
+               .offset         = offset_in_page(virt),
+               .dev_addr       = addr,
+               .size           = size,
+               .direction      = DMA_BIDIRECTIONAL,
+       };
+
+       /* handle vmalloc and linear addresses */
+       if (!is_vmalloc_addr(virt) && !virt_addr_valid(virt))
+               return;
+
+       if (is_vmalloc_addr(virt))
+               ref.pfn = vmalloc_to_pfn(virt);
+       else
+               ref.pfn = page_to_pfn(virt_to_page(virt));
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       check_unmap(&ref);
+}
+EXPORT_SYMBOL(debug_dma_free_coherent);
+
+void debug_dma_map_resource(struct device *dev, phys_addr_t addr, size_t size,
+                           int direction, dma_addr_t dma_addr)
+{
+       struct dma_debug_entry *entry;
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       entry = dma_entry_alloc();
+       if (!entry)
+               return;
+
+       entry->type             = dma_debug_resource;
+       entry->dev              = dev;
+       entry->pfn              = PHYS_PFN(addr);
+       entry->offset           = offset_in_page(addr);
+       entry->size             = size;
+       entry->dev_addr         = dma_addr;
+       entry->direction        = direction;
+       entry->map_err_type     = MAP_ERR_NOT_CHECKED;
+
+       add_dma_entry(entry);
+}
+EXPORT_SYMBOL(debug_dma_map_resource);
+
+void debug_dma_unmap_resource(struct device *dev, dma_addr_t dma_addr,
+                             size_t size, int direction)
+{
+       struct dma_debug_entry ref = {
+               .type           = dma_debug_resource,
+               .dev            = dev,
+               .dev_addr       = dma_addr,
+               .size           = size,
+               .direction      = direction,
+       };
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       check_unmap(&ref);
+}
+EXPORT_SYMBOL(debug_dma_unmap_resource);
+
+void debug_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+                                  size_t size, int direction)
+{
+       struct dma_debug_entry ref;
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       ref.type         = dma_debug_single;
+       ref.dev          = dev;
+       ref.dev_addr     = dma_handle;
+       ref.size         = size;
+       ref.direction    = direction;
+       ref.sg_call_ents = 0;
+
+       check_sync(dev, &ref, true);
+}
+EXPORT_SYMBOL(debug_dma_sync_single_for_cpu);
+
+void debug_dma_sync_single_for_device(struct device *dev,
+                                     dma_addr_t dma_handle, size_t size,
+                                     int direction)
+{
+       struct dma_debug_entry ref;
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       ref.type         = dma_debug_single;
+       ref.dev          = dev;
+       ref.dev_addr     = dma_handle;
+       ref.size         = size;
+       ref.direction    = direction;
+       ref.sg_call_ents = 0;
+
+       check_sync(dev, &ref, false);
+}
+EXPORT_SYMBOL(debug_dma_sync_single_for_device);
+
+void debug_dma_sync_single_range_for_cpu(struct device *dev,
+                                        dma_addr_t dma_handle,
+                                        unsigned long offset, size_t size,
+                                        int direction)
+{
+       struct dma_debug_entry ref;
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       ref.type         = dma_debug_single;
+       ref.dev          = dev;
+       ref.dev_addr     = dma_handle;
+       ref.size         = offset + size;
+       ref.direction    = direction;
+       ref.sg_call_ents = 0;
+
+       check_sync(dev, &ref, true);
+}
+EXPORT_SYMBOL(debug_dma_sync_single_range_for_cpu);
+
+void debug_dma_sync_single_range_for_device(struct device *dev,
+                                           dma_addr_t dma_handle,
+                                           unsigned long offset,
+                                           size_t size, int direction)
+{
+       struct dma_debug_entry ref;
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       ref.type         = dma_debug_single;
+       ref.dev          = dev;
+       ref.dev_addr     = dma_handle;
+       ref.size         = offset + size;
+       ref.direction    = direction;
+       ref.sg_call_ents = 0;
+
+       check_sync(dev, &ref, false);
+}
+EXPORT_SYMBOL(debug_dma_sync_single_range_for_device);
+
+void debug_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+                              int nelems, int direction)
+{
+       struct scatterlist *s;
+       int mapped_ents = 0, i;
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       for_each_sg(sg, s, nelems, i) {
+
+               struct dma_debug_entry ref = {
+                       .type           = dma_debug_sg,
+                       .dev            = dev,
+                       .pfn            = page_to_pfn(sg_page(s)),
+                       .offset         = s->offset,
+                       .dev_addr       = sg_dma_address(s),
+                       .size           = sg_dma_len(s),
+                       .direction      = direction,
+                       .sg_call_ents   = nelems,
+               };
+
+               if (!i)
+                       mapped_ents = get_nr_mapped_entries(dev, &ref);
+
+               if (i >= mapped_ents)
+                       break;
+
+               check_sync(dev, &ref, true);
+       }
+}
+EXPORT_SYMBOL(debug_dma_sync_sg_for_cpu);
+
+void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+                                 int nelems, int direction)
+{
+       struct scatterlist *s;
+       int mapped_ents = 0, i;
+
+       if (unlikely(dma_debug_disabled()))
+               return;
+
+       for_each_sg(sg, s, nelems, i) {
+
+               struct dma_debug_entry ref = {
+                       .type           = dma_debug_sg,
+                       .dev            = dev,
+                       .pfn            = page_to_pfn(sg_page(s)),
+                       .offset         = s->offset,
+                       .dev_addr       = sg_dma_address(s),
+                       .size           = sg_dma_len(s),
+                       .direction      = direction,
+                       .sg_call_ents   = nelems,
+               };
+               if (!i)
+                       mapped_ents = get_nr_mapped_entries(dev, &ref);
+
+               if (i >= mapped_ents)
+                       break;
+
+               check_sync(dev, &ref, false);
+       }
+}
+EXPORT_SYMBOL(debug_dma_sync_sg_for_device);
+
+static int __init dma_debug_driver_setup(char *str)
+{
+       int i;
+
+       for (i = 0; i < NAME_MAX_LEN - 1; ++i, ++str) {
+               current_driver_name[i] = *str;
+               if (*str == 0)
+                       break;
+       }
+
+       if (current_driver_name[0])
+               pr_info("DMA-API: enable driver filter for driver [%s]\n",
+                       current_driver_name);
+
+
+       return 1;
+}
+__setup("dma_debug_driver=", dma_debug_driver_setup);
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
new file mode 100644 (file)
index 0000000..8be8106
--- /dev/null
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DMA operations that map physical memory directly without using an IOMMU or
+ * flushing caches.
+ */
+#include <linux/export.h>
+#include <linux/mm.h>
+#include <linux/dma-direct.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-contiguous.h>
+#include <linux/pfn.h>
+#include <linux/set_memory.h>
+
+#define DIRECT_MAPPING_ERROR           0
+
+/*
+ * Most architectures use ZONE_DMA for the first 16 Megabytes, but
+ * some use it for entirely different regions:
+ */
+#ifndef ARCH_ZONE_DMA_BITS
+#define ARCH_ZONE_DMA_BITS 24
+#endif
+
+/*
+ * For AMD SEV all DMA must be to unencrypted addresses.
+ */
+static inline bool force_dma_unencrypted(void)
+{
+       return sev_active();
+}
+
+static bool
+check_addr(struct device *dev, dma_addr_t dma_addr, size_t size,
+               const char *caller)
+{
+       if (unlikely(dev && !dma_capable(dev, dma_addr, size))) {
+               if (!dev->dma_mask) {
+                       dev_err(dev,
+                               "%s: call on device without dma_mask\n",
+                               caller);
+                       return false;
+               }
+
+               if (*dev->dma_mask >= DMA_BIT_MASK(32)) {
+                       dev_err(dev,
+                               "%s: overflow %pad+%zu of device mask %llx\n",
+                               caller, &dma_addr, size, *dev->dma_mask);
+               }
+               return false;
+       }
+       return true;
+}
+
+static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
+{
+       dma_addr_t addr = force_dma_unencrypted() ?
+               __phys_to_dma(dev, phys) : phys_to_dma(dev, phys);
+       return addr + size - 1 <= dev->coherent_dma_mask;
+}
+
+void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
+               gfp_t gfp, unsigned long attrs)
+{
+       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       int page_order = get_order(size);
+       struct page *page = NULL;
+       void *ret;
+
+       /* we always manually zero the memory once we are done: */
+       gfp &= ~__GFP_ZERO;
+
+       /* GFP_DMA32 and GFP_DMA are no ops without the corresponding zones: */
+       if (dev->coherent_dma_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS))
+               gfp |= GFP_DMA;
+       if (dev->coherent_dma_mask <= DMA_BIT_MASK(32) && !(gfp & GFP_DMA))
+               gfp |= GFP_DMA32;
+
+again:
+       /* CMA can be used only in the context which permits sleeping */
+       if (gfpflags_allow_blocking(gfp)) {
+               page = dma_alloc_from_contiguous(dev, count, page_order, gfp);
+               if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
+                       dma_release_from_contiguous(dev, page, count);
+                       page = NULL;
+               }
+       }
+       if (!page)
+               page = alloc_pages_node(dev_to_node(dev), gfp, page_order);
+
+       if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
+               __free_pages(page, page_order);
+               page = NULL;
+
+               if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
+                   dev->coherent_dma_mask < DMA_BIT_MASK(64) &&
+                   !(gfp & (GFP_DMA32 | GFP_DMA))) {
+                       gfp |= GFP_DMA32;
+                       goto again;
+               }
+
+               if (IS_ENABLED(CONFIG_ZONE_DMA) &&
+                   dev->coherent_dma_mask < DMA_BIT_MASK(32) &&
+                   !(gfp & GFP_DMA)) {
+                       gfp = (gfp & ~GFP_DMA32) | GFP_DMA;
+                       goto again;
+               }
+       }
+
+       if (!page)
+               return NULL;
+       ret = page_address(page);
+       if (force_dma_unencrypted()) {
+               set_memory_decrypted((unsigned long)ret, 1 << page_order);
+               *dma_handle = __phys_to_dma(dev, page_to_phys(page));
+       } else {
+               *dma_handle = phys_to_dma(dev, page_to_phys(page));
+       }
+       memset(ret, 0, size);
+       return ret;
+}
+
+/*
+ * NOTE: this function must never look at the dma_addr argument, because we want
+ * to be able to use it as a helper for iommu implementations as well.
+ */
+void dma_direct_free(struct device *dev, size_t size, void *cpu_addr,
+               dma_addr_t dma_addr, unsigned long attrs)
+{
+       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       unsigned int page_order = get_order(size);
+
+       if (force_dma_unencrypted())
+               set_memory_encrypted((unsigned long)cpu_addr, 1 << page_order);
+       if (!dma_release_from_contiguous(dev, virt_to_page(cpu_addr), count))
+               free_pages((unsigned long)cpu_addr, page_order);
+}
+
+dma_addr_t dma_direct_map_page(struct device *dev, struct page *page,
+               unsigned long offset, size_t size, enum dma_data_direction dir,
+               unsigned long attrs)
+{
+       dma_addr_t dma_addr = phys_to_dma(dev, page_to_phys(page)) + offset;
+
+       if (!check_addr(dev, dma_addr, size, __func__))
+               return DIRECT_MAPPING_ERROR;
+       return dma_addr;
+}
+
+int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
+               enum dma_data_direction dir, unsigned long attrs)
+{
+       int i;
+       struct scatterlist *sg;
+
+       for_each_sg(sgl, sg, nents, i) {
+               BUG_ON(!sg_page(sg));
+
+               sg_dma_address(sg) = phys_to_dma(dev, sg_phys(sg));
+               if (!check_addr(dev, sg_dma_address(sg), sg->length, __func__))
+                       return 0;
+               sg_dma_len(sg) = sg->length;
+       }
+
+       return nents;
+}
+
+int dma_direct_supported(struct device *dev, u64 mask)
+{
+#ifdef CONFIG_ZONE_DMA
+       if (mask < DMA_BIT_MASK(ARCH_ZONE_DMA_BITS))
+               return 0;
+#else
+       /*
+        * Because 32-bit DMA masks are so common we expect every architecture
+        * to be able to satisfy them - either by not supporting more physical
+        * memory, or by providing a ZONE_DMA32.  If neither is the case, the
+        * architecture needs to use an IOMMU instead of the direct mapping.
+        */
+       if (mask < DMA_BIT_MASK(32))
+               return 0;
+#endif
+       /*
+        * Various PCI/PCIe bridges have broken support for > 32bit DMA even
+        * if the device itself might support it.
+        */
+       if (dev->dma_32bit_limit && mask > DMA_BIT_MASK(32))
+               return 0;
+       return 1;
+}
+
+int dma_direct_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       return dma_addr == DIRECT_MAPPING_ERROR;
+}
+
+const struct dma_map_ops dma_direct_ops = {
+       .alloc                  = dma_direct_alloc,
+       .free                   = dma_direct_free,
+       .map_page               = dma_direct_map_page,
+       .map_sg                 = dma_direct_map_sg,
+       .dma_supported          = dma_direct_supported,
+       .mapping_error          = dma_direct_mapping_error,
+};
+EXPORT_SYMBOL(dma_direct_ops);
diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
new file mode 100644 (file)
index 0000000..d2a92dd
--- /dev/null
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * arch-independent dma-mapping routines
+ *
+ * Copyright (c) 2006  SUSE Linux Products GmbH
+ * Copyright (c) 2006  Tejun Heo <teheo@suse.de>
+ */
+
+#include <linux/acpi.h>
+#include <linux/dma-mapping.h>
+#include <linux/export.h>
+#include <linux/gfp.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+/*
+ * Managed DMA API
+ */
+struct dma_devres {
+       size_t          size;
+       void            *vaddr;
+       dma_addr_t      dma_handle;
+       unsigned long   attrs;
+};
+
+static void dmam_release(struct device *dev, void *res)
+{
+       struct dma_devres *this = res;
+
+       dma_free_attrs(dev, this->size, this->vaddr, this->dma_handle,
+                       this->attrs);
+}
+
+static int dmam_match(struct device *dev, void *res, void *match_data)
+{
+       struct dma_devres *this = res, *match = match_data;
+
+       if (this->vaddr == match->vaddr) {
+               WARN_ON(this->size != match->size ||
+                       this->dma_handle != match->dma_handle);
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * dmam_alloc_coherent - Managed dma_alloc_coherent()
+ * @dev: Device to allocate coherent memory for
+ * @size: Size of allocation
+ * @dma_handle: Out argument for allocated DMA handle
+ * @gfp: Allocation flags
+ *
+ * Managed dma_alloc_coherent().  Memory allocated using this function
+ * will be automatically released on driver detach.
+ *
+ * RETURNS:
+ * Pointer to allocated memory on success, NULL on failure.
+ */
+void *dmam_alloc_coherent(struct device *dev, size_t size,
+                          dma_addr_t *dma_handle, gfp_t gfp)
+{
+       struct dma_devres *dr;
+       void *vaddr;
+
+       dr = devres_alloc(dmam_release, sizeof(*dr), gfp);
+       if (!dr)
+               return NULL;
+
+       vaddr = dma_alloc_coherent(dev, size, dma_handle, gfp);
+       if (!vaddr) {
+               devres_free(dr);
+               return NULL;
+       }
+
+       dr->vaddr = vaddr;
+       dr->dma_handle = *dma_handle;
+       dr->size = size;
+
+       devres_add(dev, dr);
+
+       return vaddr;
+}
+EXPORT_SYMBOL(dmam_alloc_coherent);
+
+/**
+ * dmam_free_coherent - Managed dma_free_coherent()
+ * @dev: Device to free coherent memory for
+ * @size: Size of allocation
+ * @vaddr: Virtual address of the memory to free
+ * @dma_handle: DMA handle of the memory to free
+ *
+ * Managed dma_free_coherent().
+ */
+void dmam_free_coherent(struct device *dev, size_t size, void *vaddr,
+                       dma_addr_t dma_handle)
+{
+       struct dma_devres match_data = { size, vaddr, dma_handle };
+
+       dma_free_coherent(dev, size, vaddr, dma_handle);
+       WARN_ON(devres_destroy(dev, dmam_release, dmam_match, &match_data));
+}
+EXPORT_SYMBOL(dmam_free_coherent);
+
+/**
+ * dmam_alloc_attrs - Managed dma_alloc_attrs()
+ * @dev: Device to allocate non_coherent memory for
+ * @size: Size of allocation
+ * @dma_handle: Out argument for allocated DMA handle
+ * @gfp: Allocation flags
+ * @attrs: Flags in the DMA_ATTR_* namespace.
+ *
+ * Managed dma_alloc_attrs().  Memory allocated using this function will be
+ * automatically released on driver detach.
+ *
+ * RETURNS:
+ * Pointer to allocated memory on success, NULL on failure.
+ */
+void *dmam_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
+               gfp_t gfp, unsigned long attrs)
+{
+       struct dma_devres *dr;
+       void *vaddr;
+
+       dr = devres_alloc(dmam_release, sizeof(*dr), gfp);
+       if (!dr)
+               return NULL;
+
+       vaddr = dma_alloc_attrs(dev, size, dma_handle, gfp, attrs);
+       if (!vaddr) {
+               devres_free(dr);
+               return NULL;
+       }
+
+       dr->vaddr = vaddr;
+       dr->dma_handle = *dma_handle;
+       dr->size = size;
+       dr->attrs = attrs;
+
+       devres_add(dev, dr);
+
+       return vaddr;
+}
+EXPORT_SYMBOL(dmam_alloc_attrs);
+
+#ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT
+
+static void dmam_coherent_decl_release(struct device *dev, void *res)
+{
+       dma_release_declared_memory(dev);
+}
+
+/**
+ * dmam_declare_coherent_memory - Managed dma_declare_coherent_memory()
+ * @dev: Device to declare coherent memory for
+ * @phys_addr: Physical address of coherent memory to be declared
+ * @device_addr: Device address of coherent memory to be declared
+ * @size: Size of coherent memory to be declared
+ * @flags: Flags
+ *
+ * Managed dma_declare_coherent_memory().
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int dmam_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
+                                dma_addr_t device_addr, size_t size, int flags)
+{
+       void *res;
+       int rc;
+
+       res = devres_alloc(dmam_coherent_decl_release, 0, GFP_KERNEL);
+       if (!res)
+               return -ENOMEM;
+
+       rc = dma_declare_coherent_memory(dev, phys_addr, device_addr, size,
+                                        flags);
+       if (!rc)
+               devres_add(dev, res);
+       else
+               devres_free(res);
+
+       return rc;
+}
+EXPORT_SYMBOL(dmam_declare_coherent_memory);
+
+/**
+ * dmam_release_declared_memory - Managed dma_release_declared_memory().
+ * @dev: Device to release declared coherent memory for
+ *
+ * Managed dmam_release_declared_memory().
+ */
+void dmam_release_declared_memory(struct device *dev)
+{
+       WARN_ON(devres_destroy(dev, dmam_coherent_decl_release, NULL, NULL));
+}
+EXPORT_SYMBOL(dmam_release_declared_memory);
+
+#endif
+
+/*
+ * Create scatter-list for the already allocated DMA buffer.
+ */
+int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
+                void *cpu_addr, dma_addr_t handle, size_t size)
+{
+       struct page *page = virt_to_page(cpu_addr);
+       int ret;
+
+       ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
+       if (unlikely(ret))
+               return ret;
+
+       sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
+       return 0;
+}
+EXPORT_SYMBOL(dma_common_get_sgtable);
+
+/*
+ * Create userspace mapping for the DMA-coherent memory.
+ */
+int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
+                   void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+       int ret = -ENXIO;
+#ifndef CONFIG_ARCH_NO_COHERENT_DMA_MMAP
+       unsigned long user_count = vma_pages(vma);
+       unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       unsigned long off = vma->vm_pgoff;
+
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
+               return ret;
+
+       if (off < count && user_count <= (count - off))
+               ret = remap_pfn_range(vma, vma->vm_start,
+                                     page_to_pfn(virt_to_page(cpu_addr)) + off,
+                                     user_count << PAGE_SHIFT,
+                                     vma->vm_page_prot);
+#endif /* !CONFIG_ARCH_NO_COHERENT_DMA_MMAP */
+
+       return ret;
+}
+EXPORT_SYMBOL(dma_common_mmap);
+
+#ifdef CONFIG_MMU
+static struct vm_struct *__dma_common_pages_remap(struct page **pages,
+                       size_t size, unsigned long vm_flags, pgprot_t prot,
+                       const void *caller)
+{
+       struct vm_struct *area;
+
+       area = get_vm_area_caller(size, vm_flags, caller);
+       if (!area)
+               return NULL;
+
+       if (map_vm_area(area, prot, pages)) {
+               vunmap(area->addr);
+               return NULL;
+       }
+
+       return area;
+}
+
+/*
+ * remaps an array of PAGE_SIZE pages into another vm_area
+ * Cannot be used in non-sleeping contexts
+ */
+void *dma_common_pages_remap(struct page **pages, size_t size,
+                       unsigned long vm_flags, pgprot_t prot,
+                       const void *caller)
+{
+       struct vm_struct *area;
+
+       area = __dma_common_pages_remap(pages, size, vm_flags, prot, caller);
+       if (!area)
+               return NULL;
+
+       area->pages = pages;
+
+       return area->addr;
+}
+
+/*
+ * remaps an allocated contiguous region into another vm_area.
+ * Cannot be used in non-sleeping contexts
+ */
+
+void *dma_common_contiguous_remap(struct page *page, size_t size,
+                       unsigned long vm_flags,
+                       pgprot_t prot, const void *caller)
+{
+       int i;
+       struct page **pages;
+       struct vm_struct *area;
+
+       pages = kmalloc(sizeof(struct page *) << get_order(size), GFP_KERNEL);
+       if (!pages)
+               return NULL;
+
+       for (i = 0; i < (size >> PAGE_SHIFT); i++)
+               pages[i] = nth_page(page, i);
+
+       area = __dma_common_pages_remap(pages, size, vm_flags, prot, caller);
+
+       kfree(pages);
+
+       if (!area)
+               return NULL;
+       return area->addr;
+}
+
+/*
+ * unmaps a range previously mapped by dma_common_*_remap
+ */
+void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
+{
+       struct vm_struct *area = find_vm_area(cpu_addr);
+
+       if (!area || (area->flags & vm_flags) != vm_flags) {
+               WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
+               return;
+       }
+
+       unmap_kernel_range((unsigned long)cpu_addr, PAGE_ALIGN(size));
+       vunmap(cpu_addr);
+}
+#endif
+
+/*
+ * enables DMA API use for a device
+ */
+int dma_configure(struct device *dev)
+{
+       if (dev->bus->dma_configure)
+               return dev->bus->dma_configure(dev);
+       return 0;
+}
+
+void dma_deconfigure(struct device *dev)
+{
+       of_dma_deconfigure(dev);
+       acpi_dma_deconfigure(dev);
+}
diff --git a/kernel/dma/noncoherent.c b/kernel/dma/noncoherent.c
new file mode 100644 (file)
index 0000000..79e9a75
--- /dev/null
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Christoph Hellwig.
+ *
+ * DMA operations that map physical memory directly without providing cache
+ * coherence.
+ */
+#include <linux/export.h>
+#include <linux/mm.h>
+#include <linux/dma-direct.h>
+#include <linux/dma-noncoherent.h>
+#include <linux/scatterlist.h>
+
+static void dma_noncoherent_sync_single_for_device(struct device *dev,
+               dma_addr_t addr, size_t size, enum dma_data_direction dir)
+{
+       arch_sync_dma_for_device(dev, dma_to_phys(dev, addr), size, dir);
+}
+
+static void dma_noncoherent_sync_sg_for_device(struct device *dev,
+               struct scatterlist *sgl, int nents, enum dma_data_direction dir)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sgl, sg, nents, i)
+               arch_sync_dma_for_device(dev, sg_phys(sg), sg->length, dir);
+}
+
+static dma_addr_t dma_noncoherent_map_page(struct device *dev, struct page *page,
+               unsigned long offset, size_t size, enum dma_data_direction dir,
+               unsigned long attrs)
+{
+       dma_addr_t addr;
+
+       addr = dma_direct_map_page(dev, page, offset, size, dir, attrs);
+       if (!dma_mapping_error(dev, addr) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
+               arch_sync_dma_for_device(dev, page_to_phys(page) + offset,
+                               size, dir);
+       return addr;
+}
+
+static int dma_noncoherent_map_sg(struct device *dev, struct scatterlist *sgl,
+               int nents, enum dma_data_direction dir, unsigned long attrs)
+{
+       nents = dma_direct_map_sg(dev, sgl, nents, dir, attrs);
+       if (nents > 0 && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
+               dma_noncoherent_sync_sg_for_device(dev, sgl, nents, dir);
+       return nents;
+}
+
+#ifdef CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU
+static void dma_noncoherent_sync_single_for_cpu(struct device *dev,
+               dma_addr_t addr, size_t size, enum dma_data_direction dir)
+{
+       arch_sync_dma_for_cpu(dev, dma_to_phys(dev, addr), size, dir);
+}
+
+static void dma_noncoherent_sync_sg_for_cpu(struct device *dev,
+               struct scatterlist *sgl, int nents, enum dma_data_direction dir)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sgl, sg, nents, i)
+               arch_sync_dma_for_cpu(dev, sg_phys(sg), sg->length, dir);
+}
+
+static void dma_noncoherent_unmap_page(struct device *dev, dma_addr_t addr,
+               size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
+       if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
+               dma_noncoherent_sync_single_for_cpu(dev, addr, size, dir);
+}
+
+static void dma_noncoherent_unmap_sg(struct device *dev, struct scatterlist *sgl,
+               int nents, enum dma_data_direction dir, unsigned long attrs)
+{
+       if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
+               dma_noncoherent_sync_sg_for_cpu(dev, sgl, nents, dir);
+}
+#endif
+
+const struct dma_map_ops dma_noncoherent_ops = {
+       .alloc                  = arch_dma_alloc,
+       .free                   = arch_dma_free,
+       .mmap                   = arch_dma_mmap,
+       .sync_single_for_device = dma_noncoherent_sync_single_for_device,
+       .sync_sg_for_device     = dma_noncoherent_sync_sg_for_device,
+       .map_page               = dma_noncoherent_map_page,
+       .map_sg                 = dma_noncoherent_map_sg,
+#ifdef CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU
+       .sync_single_for_cpu    = dma_noncoherent_sync_single_for_cpu,
+       .sync_sg_for_cpu        = dma_noncoherent_sync_sg_for_cpu,
+       .unmap_page             = dma_noncoherent_unmap_page,
+       .unmap_sg               = dma_noncoherent_unmap_sg,
+#endif
+       .dma_supported          = dma_direct_supported,
+       .mapping_error          = dma_direct_mapping_error,
+       .cache_sync             = arch_dma_cache_sync,
+};
+EXPORT_SYMBOL(dma_noncoherent_ops);
diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
new file mode 100644 (file)
index 0000000..04b68d9
--- /dev/null
@@ -0,0 +1,1087 @@
+/*
+ * Dynamic DMA mapping support.
+ *
+ * This implementation is a fallback for platforms that do not support
+ * I/O TLBs (aka DMA address translation hardware).
+ * Copyright (C) 2000 Asit Mallick <Asit.K.Mallick@intel.com>
+ * Copyright (C) 2000 Goutham Rao <goutham.rao@intel.com>
+ * Copyright (C) 2000, 2003 Hewlett-Packard Co
+ *     David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * 03/05/07 davidm     Switch from PCI-DMA to generic device DMA API.
+ * 00/12/13 davidm     Rename to swiotlb.c and add mark_clean() to avoid
+ *                     unnecessary i-cache flushing.
+ * 04/07/.. ak         Better overflow handling. Assorted fixes.
+ * 05/09/10 linville   Add support for syncing ranges, support syncing for
+ *                     DMA_BIDIRECTIONAL mappings, miscellaneous cleanup.
+ * 08/12/11 beckyb     Add highmem support
+ */
+
+#include <linux/cache.h>
+#include <linux/dma-direct.h>
+#include <linux/mm.h>
+#include <linux/export.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/swiotlb.h>
+#include <linux/pfn.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/highmem.h>
+#include <linux/gfp.h>
+#include <linux/scatterlist.h>
+#include <linux/mem_encrypt.h>
+#include <linux/set_memory.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/iommu-helper.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/swiotlb.h>
+
+#define OFFSET(val,align) ((unsigned long)     \
+                          ( (val) & ( (align) - 1)))
+
+#define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
+
+/*
+ * Minimum IO TLB size to bother booting with.  Systems with mainly
+ * 64bit capable cards will only lightly use the swiotlb.  If we can't
+ * allocate a contiguous 1MB, we're probably in trouble anyway.
+ */
+#define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
+
+enum swiotlb_force swiotlb_force;
+
+/*
+ * Used to do a quick range check in swiotlb_tbl_unmap_single and
+ * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
+ * API.
+ */
+static phys_addr_t io_tlb_start, io_tlb_end;
+
+/*
+ * The number of IO TLB blocks (in groups of 64) between io_tlb_start and
+ * io_tlb_end.  This is command line adjustable via setup_io_tlb_npages.
+ */
+static unsigned long io_tlb_nslabs;
+
+/*
+ * When the IOMMU overflows we return a fallback buffer. This sets the size.
+ */
+static unsigned long io_tlb_overflow = 32*1024;
+
+static phys_addr_t io_tlb_overflow_buffer;
+
+/*
+ * This is a free list describing the number of free entries available from
+ * each index
+ */
+static unsigned int *io_tlb_list;
+static unsigned int io_tlb_index;
+
+/*
+ * Max segment that we can provide which (if pages are contingous) will
+ * not be bounced (unless SWIOTLB_FORCE is set).
+ */
+unsigned int max_segment;
+
+/*
+ * We need to save away the original address corresponding to a mapped entry
+ * for the sync operations.
+ */
+#define INVALID_PHYS_ADDR (~(phys_addr_t)0)
+static phys_addr_t *io_tlb_orig_addr;
+
+/*
+ * Protect the above data structures in the map and unmap calls
+ */
+static DEFINE_SPINLOCK(io_tlb_lock);
+
+static int late_alloc;
+
+static int __init
+setup_io_tlb_npages(char *str)
+{
+       if (isdigit(*str)) {
+               io_tlb_nslabs = simple_strtoul(str, &str, 0);
+               /* avoid tail segment of size < IO_TLB_SEGSIZE */
+               io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
+       }
+       if (*str == ',')
+               ++str;
+       if (!strcmp(str, "force")) {
+               swiotlb_force = SWIOTLB_FORCE;
+       } else if (!strcmp(str, "noforce")) {
+               swiotlb_force = SWIOTLB_NO_FORCE;
+               io_tlb_nslabs = 1;
+       }
+
+       return 0;
+}
+early_param("swiotlb", setup_io_tlb_npages);
+/* make io_tlb_overflow tunable too? */
+
+unsigned long swiotlb_nr_tbl(void)
+{
+       return io_tlb_nslabs;
+}
+EXPORT_SYMBOL_GPL(swiotlb_nr_tbl);
+
+unsigned int swiotlb_max_segment(void)
+{
+       return max_segment;
+}
+EXPORT_SYMBOL_GPL(swiotlb_max_segment);
+
+void swiotlb_set_max_segment(unsigned int val)
+{
+       if (swiotlb_force == SWIOTLB_FORCE)
+               max_segment = 1;
+       else
+               max_segment = rounddown(val, PAGE_SIZE);
+}
+
+/* default to 64MB */
+#define IO_TLB_DEFAULT_SIZE (64UL<<20)
+unsigned long swiotlb_size_or_default(void)
+{
+       unsigned long size;
+
+       size = io_tlb_nslabs << IO_TLB_SHIFT;
+
+       return size ? size : (IO_TLB_DEFAULT_SIZE);
+}
+
+static bool no_iotlb_memory;
+
+void swiotlb_print_info(void)
+{
+       unsigned long bytes = io_tlb_nslabs << IO_TLB_SHIFT;
+       unsigned char *vstart, *vend;
+
+       if (no_iotlb_memory) {
+               pr_warn("software IO TLB: No low mem\n");
+               return;
+       }
+
+       vstart = phys_to_virt(io_tlb_start);
+       vend = phys_to_virt(io_tlb_end);
+
+       printk(KERN_INFO "software IO TLB [mem %#010llx-%#010llx] (%luMB) mapped at [%p-%p]\n",
+              (unsigned long long)io_tlb_start,
+              (unsigned long long)io_tlb_end,
+              bytes >> 20, vstart, vend - 1);
+}
+
+/*
+ * Early SWIOTLB allocation may be too early to allow an architecture to
+ * perform the desired operations.  This function allows the architecture to
+ * call SWIOTLB when the operations are possible.  It needs to be called
+ * before the SWIOTLB memory is used.
+ */
+void __init swiotlb_update_mem_attributes(void)
+{
+       void *vaddr;
+       unsigned long bytes;
+
+       if (no_iotlb_memory || late_alloc)
+               return;
+
+       vaddr = phys_to_virt(io_tlb_start);
+       bytes = PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT);
+       set_memory_decrypted((unsigned long)vaddr, bytes >> PAGE_SHIFT);
+       memset(vaddr, 0, bytes);
+
+       vaddr = phys_to_virt(io_tlb_overflow_buffer);
+       bytes = PAGE_ALIGN(io_tlb_overflow);
+       set_memory_decrypted((unsigned long)vaddr, bytes >> PAGE_SHIFT);
+       memset(vaddr, 0, bytes);
+}
+
+int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
+{
+       void *v_overflow_buffer;
+       unsigned long i, bytes;
+
+       bytes = nslabs << IO_TLB_SHIFT;
+
+       io_tlb_nslabs = nslabs;
+       io_tlb_start = __pa(tlb);
+       io_tlb_end = io_tlb_start + bytes;
+
+       /*
+        * Get the overflow emergency buffer
+        */
+       v_overflow_buffer = memblock_virt_alloc_low_nopanic(
+                                               PAGE_ALIGN(io_tlb_overflow),
+                                               PAGE_SIZE);
+       if (!v_overflow_buffer)
+               return -ENOMEM;
+
+       io_tlb_overflow_buffer = __pa(v_overflow_buffer);
+
+       /*
+        * Allocate and initialize the free list array.  This array is used
+        * to find contiguous free memory regions of size up to IO_TLB_SEGSIZE
+        * between io_tlb_start and io_tlb_end.
+        */
+       io_tlb_list = memblock_virt_alloc(
+                               PAGE_ALIGN(io_tlb_nslabs * sizeof(int)),
+                               PAGE_SIZE);
+       io_tlb_orig_addr = memblock_virt_alloc(
+                               PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t)),
+                               PAGE_SIZE);
+       for (i = 0; i < io_tlb_nslabs; i++) {
+               io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
+               io_tlb_orig_addr[i] = INVALID_PHYS_ADDR;
+       }
+       io_tlb_index = 0;
+
+       if (verbose)
+               swiotlb_print_info();
+
+       swiotlb_set_max_segment(io_tlb_nslabs << IO_TLB_SHIFT);
+       return 0;
+}
+
+/*
+ * Statically reserve bounce buffer space and initialize bounce buffer data
+ * structures for the software IO TLB used to implement the DMA API.
+ */
+void  __init
+swiotlb_init(int verbose)
+{
+       size_t default_size = IO_TLB_DEFAULT_SIZE;
+       unsigned char *vstart;
+       unsigned long bytes;
+
+       if (!io_tlb_nslabs) {
+               io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
+               io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
+       }
+
+       bytes = io_tlb_nslabs << IO_TLB_SHIFT;
+
+       /* Get IO TLB memory from the low pages */
+       vstart = memblock_virt_alloc_low_nopanic(PAGE_ALIGN(bytes), PAGE_SIZE);
+       if (vstart && !swiotlb_init_with_tbl(vstart, io_tlb_nslabs, verbose))
+               return;
+
+       if (io_tlb_start)
+               memblock_free_early(io_tlb_start,
+                                   PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
+       pr_warn("Cannot allocate SWIOTLB buffer");
+       no_iotlb_memory = true;
+}
+
+/*
+ * Systems with larger DMA zones (those that don't support ISA) can
+ * initialize the swiotlb later using the slab allocator if needed.
+ * This should be just like above, but with some error catching.
+ */
+int
+swiotlb_late_init_with_default_size(size_t default_size)
+{
+       unsigned long bytes, req_nslabs = io_tlb_nslabs;
+       unsigned char *vstart = NULL;
+       unsigned int order;
+       int rc = 0;
+
+       if (!io_tlb_nslabs) {
+               io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
+               io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
+       }
+
+       /*
+        * Get IO TLB memory from the low pages
+        */
+       order = get_order(io_tlb_nslabs << IO_TLB_SHIFT);
+       io_tlb_nslabs = SLABS_PER_PAGE << order;
+       bytes = io_tlb_nslabs << IO_TLB_SHIFT;
+
+       while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
+               vstart = (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN,
+                                                 order);
+               if (vstart)
+                       break;
+               order--;
+       }
+
+       if (!vstart) {
+               io_tlb_nslabs = req_nslabs;
+               return -ENOMEM;
+       }
+       if (order != get_order(bytes)) {
+               printk(KERN_WARNING "Warning: only able to allocate %ld MB "
+                      "for software IO TLB\n", (PAGE_SIZE << order) >> 20);
+               io_tlb_nslabs = SLABS_PER_PAGE << order;
+       }
+       rc = swiotlb_late_init_with_tbl(vstart, io_tlb_nslabs);
+       if (rc)
+               free_pages((unsigned long)vstart, order);
+
+       return rc;
+}
+
+int
+swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs)
+{
+       unsigned long i, bytes;
+       unsigned char *v_overflow_buffer;
+
+       bytes = nslabs << IO_TLB_SHIFT;
+
+       io_tlb_nslabs = nslabs;
+       io_tlb_start = virt_to_phys(tlb);
+       io_tlb_end = io_tlb_start + bytes;
+
+       set_memory_decrypted((unsigned long)tlb, bytes >> PAGE_SHIFT);
+       memset(tlb, 0, bytes);
+
+       /*
+        * Get the overflow emergency buffer
+        */
+       v_overflow_buffer = (void *)__get_free_pages(GFP_DMA,
+                                                    get_order(io_tlb_overflow));
+       if (!v_overflow_buffer)
+               goto cleanup2;
+
+       set_memory_decrypted((unsigned long)v_overflow_buffer,
+                       io_tlb_overflow >> PAGE_SHIFT);
+       memset(v_overflow_buffer, 0, io_tlb_overflow);
+       io_tlb_overflow_buffer = virt_to_phys(v_overflow_buffer);
+
+       /*
+        * Allocate and initialize the free list array.  This array is used
+        * to find contiguous free memory regions of size up to IO_TLB_SEGSIZE
+        * between io_tlb_start and io_tlb_end.
+        */
+       io_tlb_list = (unsigned int *)__get_free_pages(GFP_KERNEL,
+                                     get_order(io_tlb_nslabs * sizeof(int)));
+       if (!io_tlb_list)
+               goto cleanup3;
+
+       io_tlb_orig_addr = (phys_addr_t *)
+               __get_free_pages(GFP_KERNEL,
+                                get_order(io_tlb_nslabs *
+                                          sizeof(phys_addr_t)));
+       if (!io_tlb_orig_addr)
+               goto cleanup4;
+
+       for (i = 0; i < io_tlb_nslabs; i++) {
+               io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
+               io_tlb_orig_addr[i] = INVALID_PHYS_ADDR;
+       }
+       io_tlb_index = 0;
+
+       swiotlb_print_info();
+
+       late_alloc = 1;
+
+       swiotlb_set_max_segment(io_tlb_nslabs << IO_TLB_SHIFT);
+
+       return 0;
+
+cleanup4:
+       free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs *
+                                                        sizeof(int)));
+       io_tlb_list = NULL;
+cleanup3:
+       free_pages((unsigned long)v_overflow_buffer,
+                  get_order(io_tlb_overflow));
+       io_tlb_overflow_buffer = 0;
+cleanup2:
+       io_tlb_end = 0;
+       io_tlb_start = 0;
+       io_tlb_nslabs = 0;
+       max_segment = 0;
+       return -ENOMEM;
+}
+
+void __init swiotlb_exit(void)
+{
+       if (!io_tlb_orig_addr)
+               return;
+
+       if (late_alloc) {
+               free_pages((unsigned long)phys_to_virt(io_tlb_overflow_buffer),
+                          get_order(io_tlb_overflow));
+               free_pages((unsigned long)io_tlb_orig_addr,
+                          get_order(io_tlb_nslabs * sizeof(phys_addr_t)));
+               free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs *
+                                                                sizeof(int)));
+               free_pages((unsigned long)phys_to_virt(io_tlb_start),
+                          get_order(io_tlb_nslabs << IO_TLB_SHIFT));
+       } else {
+               memblock_free_late(io_tlb_overflow_buffer,
+                                  PAGE_ALIGN(io_tlb_overflow));
+               memblock_free_late(__pa(io_tlb_orig_addr),
+                                  PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t)));
+               memblock_free_late(__pa(io_tlb_list),
+                                  PAGE_ALIGN(io_tlb_nslabs * sizeof(int)));
+               memblock_free_late(io_tlb_start,
+                                  PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
+       }
+       io_tlb_nslabs = 0;
+       max_segment = 0;
+}
+
+int is_swiotlb_buffer(phys_addr_t paddr)
+{
+       return paddr >= io_tlb_start && paddr < io_tlb_end;
+}
+
+/*
+ * Bounce: copy the swiotlb buffer back to the original dma location
+ */
+static void swiotlb_bounce(phys_addr_t orig_addr, phys_addr_t tlb_addr,
+                          size_t size, enum dma_data_direction dir)
+{
+       unsigned long pfn = PFN_DOWN(orig_addr);
+       unsigned char *vaddr = phys_to_virt(tlb_addr);
+
+       if (PageHighMem(pfn_to_page(pfn))) {
+               /* The buffer does not have a mapping.  Map it in and copy */
+               unsigned int offset = orig_addr & ~PAGE_MASK;
+               char *buffer;
+               unsigned int sz = 0;
+               unsigned long flags;
+
+               while (size) {
+                       sz = min_t(size_t, PAGE_SIZE - offset, size);
+
+                       local_irq_save(flags);
+                       buffer = kmap_atomic(pfn_to_page(pfn));
+                       if (dir == DMA_TO_DEVICE)
+                               memcpy(vaddr, buffer + offset, sz);
+                       else
+                               memcpy(buffer + offset, vaddr, sz);
+                       kunmap_atomic(buffer);
+                       local_irq_restore(flags);
+
+                       size -= sz;
+                       pfn++;
+                       vaddr += sz;
+                       offset = 0;
+               }
+       } else if (dir == DMA_TO_DEVICE) {
+               memcpy(vaddr, phys_to_virt(orig_addr), size);
+       } else {
+               memcpy(phys_to_virt(orig_addr), vaddr, size);
+       }
+}
+
+phys_addr_t swiotlb_tbl_map_single(struct device *hwdev,
+                                  dma_addr_t tbl_dma_addr,
+                                  phys_addr_t orig_addr, size_t size,
+                                  enum dma_data_direction dir,
+                                  unsigned long attrs)
+{
+       unsigned long flags;
+       phys_addr_t tlb_addr;
+       unsigned int nslots, stride, index, wrap;
+       int i;
+       unsigned long mask;
+       unsigned long offset_slots;
+       unsigned long max_slots;
+
+       if (no_iotlb_memory)
+               panic("Can not allocate SWIOTLB buffer earlier and can't now provide you with the DMA bounce buffer");
+
+       if (mem_encrypt_active())
+               pr_warn_once("%s is active and system is using DMA bounce buffers\n",
+                            sme_active() ? "SME" : "SEV");
+
+       mask = dma_get_seg_boundary(hwdev);
+
+       tbl_dma_addr &= mask;
+
+       offset_slots = ALIGN(tbl_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+
+       /*
+        * Carefully handle integer overflow which can occur when mask == ~0UL.
+        */
+       max_slots = mask + 1
+                   ? ALIGN(mask + 1, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT
+                   : 1UL << (BITS_PER_LONG - IO_TLB_SHIFT);
+
+       /*
+        * For mappings greater than or equal to a page, we limit the stride
+        * (and hence alignment) to a page size.
+        */
+       nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+       if (size >= PAGE_SIZE)
+               stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT));
+       else
+               stride = 1;
+
+       BUG_ON(!nslots);
+
+       /*
+        * Find suitable number of IO TLB entries size that will fit this
+        * request and allocate a buffer from that IO TLB pool.
+        */
+       spin_lock_irqsave(&io_tlb_lock, flags);
+       index = ALIGN(io_tlb_index, stride);
+       if (index >= io_tlb_nslabs)
+               index = 0;
+       wrap = index;
+
+       do {
+               while (iommu_is_span_boundary(index, nslots, offset_slots,
+                                             max_slots)) {
+                       index += stride;
+                       if (index >= io_tlb_nslabs)
+                               index = 0;
+                       if (index == wrap)
+                               goto not_found;
+               }
+
+               /*
+                * If we find a slot that indicates we have 'nslots' number of
+                * contiguous buffers, we allocate the buffers from that slot
+                * and mark the entries as '0' indicating unavailable.
+                */
+               if (io_tlb_list[index] >= nslots) {
+                       int count = 0;
+
+                       for (i = index; i < (int) (index + nslots); i++)
+                               io_tlb_list[i] = 0;
+                       for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE - 1) && io_tlb_list[i]; i--)
+                               io_tlb_list[i] = ++count;
+                       tlb_addr = io_tlb_start + (index << IO_TLB_SHIFT);
+
+                       /*
+                        * Update the indices to avoid searching in the next
+                        * round.
+                        */
+                       io_tlb_index = ((index + nslots) < io_tlb_nslabs
+                                       ? (index + nslots) : 0);
+
+                       goto found;
+               }
+               index += stride;
+               if (index >= io_tlb_nslabs)
+                       index = 0;
+       } while (index != wrap);
+
+not_found:
+       spin_unlock_irqrestore(&io_tlb_lock, flags);
+       if (!(attrs & DMA_ATTR_NO_WARN) && printk_ratelimit())
+               dev_warn(hwdev, "swiotlb buffer is full (sz: %zd bytes)\n", size);
+       return SWIOTLB_MAP_ERROR;
+found:
+       spin_unlock_irqrestore(&io_tlb_lock, flags);
+
+       /*
+        * Save away the mapping from the original address to the DMA address.
+        * This is needed when we sync the memory.  Then we sync the buffer if
+        * needed.
+        */
+       for (i = 0; i < nslots; i++)
+               io_tlb_orig_addr[index+i] = orig_addr + (i << IO_TLB_SHIFT);
+       if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
+           (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
+               swiotlb_bounce(orig_addr, tlb_addr, size, DMA_TO_DEVICE);
+
+       return tlb_addr;
+}
+
+/*
+ * Allocates bounce buffer and returns its physical address.
+ */
+static phys_addr_t
+map_single(struct device *hwdev, phys_addr_t phys, size_t size,
+          enum dma_data_direction dir, unsigned long attrs)
+{
+       dma_addr_t start_dma_addr;
+
+       if (swiotlb_force == SWIOTLB_NO_FORCE) {
+               dev_warn_ratelimited(hwdev, "Cannot do DMA to address %pa\n",
+                                    &phys);
+               return SWIOTLB_MAP_ERROR;
+       }
+
+       start_dma_addr = __phys_to_dma(hwdev, io_tlb_start);
+       return swiotlb_tbl_map_single(hwdev, start_dma_addr, phys, size,
+                                     dir, attrs);
+}
+
+/*
+ * tlb_addr is the physical address of the bounce buffer to unmap.
+ */
+void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr,
+                             size_t size, enum dma_data_direction dir,
+                             unsigned long attrs)
+{
+       unsigned long flags;
+       int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+       int index = (tlb_addr - io_tlb_start) >> IO_TLB_SHIFT;
+       phys_addr_t orig_addr = io_tlb_orig_addr[index];
+
+       /*
+        * First, sync the memory before unmapping the entry
+        */
+       if (orig_addr != INVALID_PHYS_ADDR &&
+           !(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
+           ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)))
+               swiotlb_bounce(orig_addr, tlb_addr, size, DMA_FROM_DEVICE);
+
+       /*
+        * Return the buffer to the free list by setting the corresponding
+        * entries to indicate the number of contiguous entries available.
+        * While returning the entries to the free list, we merge the entries
+        * with slots below and above the pool being returned.
+        */
+       spin_lock_irqsave(&io_tlb_lock, flags);
+       {
+               count = ((index + nslots) < ALIGN(index + 1, IO_TLB_SEGSIZE) ?
+                        io_tlb_list[index + nslots] : 0);
+               /*
+                * Step 1: return the slots to the free list, merging the
+                * slots with superceeding slots
+                */
+               for (i = index + nslots - 1; i >= index; i--) {
+                       io_tlb_list[i] = ++count;
+                       io_tlb_orig_addr[i] = INVALID_PHYS_ADDR;
+               }
+               /*
+                * Step 2: merge the returned slots with the preceding slots,
+                * if available (non zero)
+                */
+               for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE -1) && io_tlb_list[i]; i--)
+                       io_tlb_list[i] = ++count;
+       }
+       spin_unlock_irqrestore(&io_tlb_lock, flags);
+}
+
+void swiotlb_tbl_sync_single(struct device *hwdev, phys_addr_t tlb_addr,
+                            size_t size, enum dma_data_direction dir,
+                            enum dma_sync_target target)
+{
+       int index = (tlb_addr - io_tlb_start) >> IO_TLB_SHIFT;
+       phys_addr_t orig_addr = io_tlb_orig_addr[index];
+
+       if (orig_addr == INVALID_PHYS_ADDR)
+               return;
+       orig_addr += (unsigned long)tlb_addr & ((1 << IO_TLB_SHIFT) - 1);
+
+       switch (target) {
+       case SYNC_FOR_CPU:
+               if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL))
+                       swiotlb_bounce(orig_addr, tlb_addr,
+                                      size, DMA_FROM_DEVICE);
+               else
+                       BUG_ON(dir != DMA_TO_DEVICE);
+               break;
+       case SYNC_FOR_DEVICE:
+               if (likely(dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
+                       swiotlb_bounce(orig_addr, tlb_addr,
+                                      size, DMA_TO_DEVICE);
+               else
+                       BUG_ON(dir != DMA_FROM_DEVICE);
+               break;
+       default:
+               BUG();
+       }
+}
+
+static inline bool dma_coherent_ok(struct device *dev, dma_addr_t addr,
+               size_t size)
+{
+       u64 mask = DMA_BIT_MASK(32);
+
+       if (dev && dev->coherent_dma_mask)
+               mask = dev->coherent_dma_mask;
+       return addr + size - 1 <= mask;
+}
+
+static void *
+swiotlb_alloc_buffer(struct device *dev, size_t size, dma_addr_t *dma_handle,
+               unsigned long attrs)
+{
+       phys_addr_t phys_addr;
+
+       if (swiotlb_force == SWIOTLB_NO_FORCE)
+               goto out_warn;
+
+       phys_addr = swiotlb_tbl_map_single(dev,
+                       __phys_to_dma(dev, io_tlb_start),
+                       0, size, DMA_FROM_DEVICE, attrs);
+       if (phys_addr == SWIOTLB_MAP_ERROR)
+               goto out_warn;
+
+       *dma_handle = __phys_to_dma(dev, phys_addr);
+       if (!dma_coherent_ok(dev, *dma_handle, size))
+               goto out_unmap;
+
+       memset(phys_to_virt(phys_addr), 0, size);
+       return phys_to_virt(phys_addr);
+
+out_unmap:
+       dev_warn(dev, "hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n",
+               (unsigned long long)dev->coherent_dma_mask,
+               (unsigned long long)*dma_handle);
+
+       /*
+        * DMA_TO_DEVICE to avoid memcpy in unmap_single.
+        * DMA_ATTR_SKIP_CPU_SYNC is optional.
+        */
+       swiotlb_tbl_unmap_single(dev, phys_addr, size, DMA_TO_DEVICE,
+                       DMA_ATTR_SKIP_CPU_SYNC);
+out_warn:
+       if (!(attrs & DMA_ATTR_NO_WARN) && printk_ratelimit()) {
+               dev_warn(dev,
+                       "swiotlb: coherent allocation failed, size=%zu\n",
+                       size);
+               dump_stack();
+       }
+       return NULL;
+}
+
+static bool swiotlb_free_buffer(struct device *dev, size_t size,
+               dma_addr_t dma_addr)
+{
+       phys_addr_t phys_addr = dma_to_phys(dev, dma_addr);
+
+       WARN_ON_ONCE(irqs_disabled());
+
+       if (!is_swiotlb_buffer(phys_addr))
+               return false;
+
+       /*
+        * DMA_TO_DEVICE to avoid memcpy in swiotlb_tbl_unmap_single.
+        * DMA_ATTR_SKIP_CPU_SYNC is optional.
+        */
+       swiotlb_tbl_unmap_single(dev, phys_addr, size, DMA_TO_DEVICE,
+                                DMA_ATTR_SKIP_CPU_SYNC);
+       return true;
+}
+
+static void
+swiotlb_full(struct device *dev, size_t size, enum dma_data_direction dir,
+            int do_panic)
+{
+       if (swiotlb_force == SWIOTLB_NO_FORCE)
+               return;
+
+       /*
+        * Ran out of IOMMU space for this operation. This is very bad.
+        * Unfortunately the drivers cannot handle this operation properly.
+        * unless they check for dma_mapping_error (most don't)
+        * When the mapping is small enough return a static buffer to limit
+        * the damage, or panic when the transfer is too big.
+        */
+       dev_err_ratelimited(dev, "DMA: Out of SW-IOMMU space for %zu bytes\n",
+                           size);
+
+       if (size <= io_tlb_overflow || !do_panic)
+               return;
+
+       if (dir == DMA_BIDIRECTIONAL)
+               panic("DMA: Random memory could be DMA accessed\n");
+       if (dir == DMA_FROM_DEVICE)
+               panic("DMA: Random memory could be DMA written\n");
+       if (dir == DMA_TO_DEVICE)
+               panic("DMA: Random memory could be DMA read\n");
+}
+
+/*
+ * Map a single buffer of the indicated size for DMA in streaming mode.  The
+ * physical address to use is returned.
+ *
+ * Once the device is given the dma address, the device owns this memory until
+ * either swiotlb_unmap_page or swiotlb_dma_sync_single is performed.
+ */
+dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
+                           unsigned long offset, size_t size,
+                           enum dma_data_direction dir,
+                           unsigned long attrs)
+{
+       phys_addr_t map, phys = page_to_phys(page) + offset;
+       dma_addr_t dev_addr = phys_to_dma(dev, phys);
+
+       BUG_ON(dir == DMA_NONE);
+       /*
+        * If the address happens to be in the device's DMA window,
+        * we can safely return the device addr and not worry about bounce
+        * buffering it.
+        */
+       if (dma_capable(dev, dev_addr, size) && swiotlb_force != SWIOTLB_FORCE)
+               return dev_addr;
+
+       trace_swiotlb_bounced(dev, dev_addr, size, swiotlb_force);
+
+       /* Oh well, have to allocate and map a bounce buffer. */
+       map = map_single(dev, phys, size, dir, attrs);
+       if (map == SWIOTLB_MAP_ERROR) {
+               swiotlb_full(dev, size, dir, 1);
+               return __phys_to_dma(dev, io_tlb_overflow_buffer);
+       }
+
+       dev_addr = __phys_to_dma(dev, map);
+
+       /* Ensure that the address returned is DMA'ble */
+       if (dma_capable(dev, dev_addr, size))
+               return dev_addr;
+
+       attrs |= DMA_ATTR_SKIP_CPU_SYNC;
+       swiotlb_tbl_unmap_single(dev, map, size, dir, attrs);
+
+       return __phys_to_dma(dev, io_tlb_overflow_buffer);
+}
+
+/*
+ * Unmap a single streaming mode DMA translation.  The dma_addr and size must
+ * match what was provided for in a previous swiotlb_map_page call.  All
+ * other usages are undefined.
+ *
+ * After this call, reads by the cpu to the buffer are guaranteed to see
+ * whatever the device wrote there.
+ */
+static void unmap_single(struct device *hwdev, dma_addr_t dev_addr,
+                        size_t size, enum dma_data_direction dir,
+                        unsigned long attrs)
+{
+       phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
+
+       BUG_ON(dir == DMA_NONE);
+
+       if (is_swiotlb_buffer(paddr)) {
+               swiotlb_tbl_unmap_single(hwdev, paddr, size, dir, attrs);
+               return;
+       }
+
+       if (dir != DMA_FROM_DEVICE)
+               return;
+
+       /*
+        * phys_to_virt doesn't work with hihgmem page but we could
+        * call dma_mark_clean() with hihgmem page here. However, we
+        * are fine since dma_mark_clean() is null on POWERPC. We can
+        * make dma_mark_clean() take a physical address if necessary.
+        */
+       dma_mark_clean(phys_to_virt(paddr), size);
+}
+
+void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
+                       size_t size, enum dma_data_direction dir,
+                       unsigned long attrs)
+{
+       unmap_single(hwdev, dev_addr, size, dir, attrs);
+}
+
+/*
+ * Make physical memory consistent for a single streaming mode DMA translation
+ * after a transfer.
+ *
+ * If you perform a swiotlb_map_page() but wish to interrogate the buffer
+ * using the cpu, yet do not wish to teardown the dma mapping, you must
+ * call this function before doing so.  At the next point you give the dma
+ * address back to the card, you must first perform a
+ * swiotlb_dma_sync_for_device, and then the device again owns the buffer
+ */
+static void
+swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
+                   size_t size, enum dma_data_direction dir,
+                   enum dma_sync_target target)
+{
+       phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
+
+       BUG_ON(dir == DMA_NONE);
+
+       if (is_swiotlb_buffer(paddr)) {
+               swiotlb_tbl_sync_single(hwdev, paddr, size, dir, target);
+               return;
+       }
+
+       if (dir != DMA_FROM_DEVICE)
+               return;
+
+       dma_mark_clean(phys_to_virt(paddr), size);
+}
+
+void
+swiotlb_sync_single_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
+                           size_t size, enum dma_data_direction dir)
+{
+       swiotlb_sync_single(hwdev, dev_addr, size, dir, SYNC_FOR_CPU);
+}
+
+void
+swiotlb_sync_single_for_device(struct device *hwdev, dma_addr_t dev_addr,
+                              size_t size, enum dma_data_direction dir)
+{
+       swiotlb_sync_single(hwdev, dev_addr, size, dir, SYNC_FOR_DEVICE);
+}
+
+/*
+ * Map a set of buffers described by scatterlist in streaming mode for DMA.
+ * This is the scatter-gather version of the above swiotlb_map_page
+ * interface.  Here the scatter gather list elements are each tagged with the
+ * appropriate dma address and length.  They are obtained via
+ * sg_dma_{address,length}(SG).
+ *
+ * NOTE: An implementation may be able to use a smaller number of
+ *       DMA address/length pairs than there are SG table elements.
+ *       (for example via virtual mapping capabilities)
+ *       The routine returns the number of addr/length pairs actually
+ *       used, at most nents.
+ *
+ * Device ownership issues as mentioned above for swiotlb_map_page are the
+ * same here.
+ */
+int
+swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
+                    enum dma_data_direction dir, unsigned long attrs)
+{
+       struct scatterlist *sg;
+       int i;
+
+       BUG_ON(dir == DMA_NONE);
+
+       for_each_sg(sgl, sg, nelems, i) {
+               phys_addr_t paddr = sg_phys(sg);
+               dma_addr_t dev_addr = phys_to_dma(hwdev, paddr);
+
+               if (swiotlb_force == SWIOTLB_FORCE ||
+                   !dma_capable(hwdev, dev_addr, sg->length)) {
+                       phys_addr_t map = map_single(hwdev, sg_phys(sg),
+                                                    sg->length, dir, attrs);
+                       if (map == SWIOTLB_MAP_ERROR) {
+                               /* Don't panic here, we expect map_sg users
+                                  to do proper error handling. */
+                               swiotlb_full(hwdev, sg->length, dir, 0);
+                               attrs |= DMA_ATTR_SKIP_CPU_SYNC;
+                               swiotlb_unmap_sg_attrs(hwdev, sgl, i, dir,
+                                                      attrs);
+                               sg_dma_len(sgl) = 0;
+                               return 0;
+                       }
+                       sg->dma_address = __phys_to_dma(hwdev, map);
+               } else
+                       sg->dma_address = dev_addr;
+               sg_dma_len(sg) = sg->length;
+       }
+       return nelems;
+}
+
+/*
+ * Unmap a set of streaming mode DMA translations.  Again, cpu read rules
+ * concerning calls here are the same as for swiotlb_unmap_page() above.
+ */
+void
+swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
+                      int nelems, enum dma_data_direction dir,
+                      unsigned long attrs)
+{
+       struct scatterlist *sg;
+       int i;
+
+       BUG_ON(dir == DMA_NONE);
+
+       for_each_sg(sgl, sg, nelems, i)
+               unmap_single(hwdev, sg->dma_address, sg_dma_len(sg), dir,
+                            attrs);
+}
+
+/*
+ * Make physical memory consistent for a set of streaming mode DMA translations
+ * after a transfer.
+ *
+ * The same as swiotlb_sync_single_* but for a scatter-gather list, same rules
+ * and usage.
+ */
+static void
+swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sgl,
+               int nelems, enum dma_data_direction dir,
+               enum dma_sync_target target)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sgl, sg, nelems, i)
+               swiotlb_sync_single(hwdev, sg->dma_address,
+                                   sg_dma_len(sg), dir, target);
+}
+
+void
+swiotlb_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg,
+                       int nelems, enum dma_data_direction dir)
+{
+       swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_CPU);
+}
+
+void
+swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
+                          int nelems, enum dma_data_direction dir)
+{
+       swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_DEVICE);
+}
+
+int
+swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr)
+{
+       return (dma_addr == __phys_to_dma(hwdev, io_tlb_overflow_buffer));
+}
+
+/*
+ * Return whether the given device DMA address mask can be supported
+ * properly.  For example, if your device can only drive the low 24-bits
+ * during bus mastering, then you would pass 0x00ffffff as the mask to
+ * this function.
+ */
+int
+swiotlb_dma_supported(struct device *hwdev, u64 mask)
+{
+       return __phys_to_dma(hwdev, io_tlb_end - 1) <= mask;
+}
+
+void *swiotlb_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
+               gfp_t gfp, unsigned long attrs)
+{
+       void *vaddr;
+
+       /* temporary workaround: */
+       if (gfp & __GFP_NOWARN)
+               attrs |= DMA_ATTR_NO_WARN;
+
+       /*
+        * Don't print a warning when the first allocation attempt fails.
+        * swiotlb_alloc_coherent() will print a warning when the DMA memory
+        * allocation ultimately failed.
+        */
+       gfp |= __GFP_NOWARN;
+
+       vaddr = dma_direct_alloc(dev, size, dma_handle, gfp, attrs);
+       if (!vaddr)
+               vaddr = swiotlb_alloc_buffer(dev, size, dma_handle, attrs);
+       return vaddr;
+}
+
+void swiotlb_free(struct device *dev, size_t size, void *vaddr,
+               dma_addr_t dma_addr, unsigned long attrs)
+{
+       if (!swiotlb_free_buffer(dev, size, dma_addr))
+               dma_direct_free(dev, size, vaddr, dma_addr, attrs);
+}
+
+const struct dma_map_ops swiotlb_dma_ops = {
+       .mapping_error          = swiotlb_dma_mapping_error,
+       .alloc                  = swiotlb_alloc,
+       .free                   = swiotlb_free,
+       .sync_single_for_cpu    = swiotlb_sync_single_for_cpu,
+       .sync_single_for_device = swiotlb_sync_single_for_device,
+       .sync_sg_for_cpu        = swiotlb_sync_sg_for_cpu,
+       .sync_sg_for_device     = swiotlb_sync_sg_for_device,
+       .map_sg                 = swiotlb_map_sg_attrs,
+       .unmap_sg               = swiotlb_unmap_sg_attrs,
+       .map_page               = swiotlb_map_page,
+       .unmap_page             = swiotlb_unmap_page,
+       .dma_supported          = dma_direct_supported,
+};
diff --git a/kernel/dma/virt.c b/kernel/dma/virt.c
new file mode 100644 (file)
index 0000000..631ddec
--- /dev/null
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DMA operations that map to virtual addresses without flushing memory.
+ */
+#include <linux/export.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+
+static void *dma_virt_alloc(struct device *dev, size_t size,
+                           dma_addr_t *dma_handle, gfp_t gfp,
+                           unsigned long attrs)
+{
+       void *ret;
+
+       ret = (void *)__get_free_pages(gfp, get_order(size));
+       if (ret)
+               *dma_handle = (uintptr_t)ret;
+       return ret;
+}
+
+static void dma_virt_free(struct device *dev, size_t size,
+                         void *cpu_addr, dma_addr_t dma_addr,
+                         unsigned long attrs)
+{
+       free_pages((unsigned long)cpu_addr, get_order(size));
+}
+
+static dma_addr_t dma_virt_map_page(struct device *dev, struct page *page,
+                                   unsigned long offset, size_t size,
+                                   enum dma_data_direction dir,
+                                   unsigned long attrs)
+{
+       return (uintptr_t)(page_address(page) + offset);
+}
+
+static int dma_virt_map_sg(struct device *dev, struct scatterlist *sgl,
+                          int nents, enum dma_data_direction dir,
+                          unsigned long attrs)
+{
+       int i;
+       struct scatterlist *sg;
+
+       for_each_sg(sgl, sg, nents, i) {
+               BUG_ON(!sg_page(sg));
+               sg_dma_address(sg) = (uintptr_t)sg_virt(sg);
+               sg_dma_len(sg) = sg->length;
+       }
+
+       return nents;
+}
+
+const struct dma_map_ops dma_virt_ops = {
+       .alloc                  = dma_virt_alloc,
+       .free                   = dma_virt_free,
+       .map_page               = dma_virt_map_page,
+       .map_sg                 = dma_virt_map_sg,
+};
+EXPORT_SYMBOL(dma_virt_ops);
index 809fdd155739b48470b1c32dc5447b32b86e10dc..803fcbced7293297ea52f2a91ddc9c91d8a99eda 100644 (file)
@@ -420,60 +420,15 @@ config HAS_IOPORT_MAP
        depends on HAS_IOMEM && !NO_IOPORT_MAP
        default y
 
-config HAS_DMA
-       bool
-       depends on !NO_DMA
-       default y
+source "kernel/dma/Kconfig"
 
 config SGL_ALLOC
        bool
        default n
 
-config NEED_SG_DMA_LENGTH
-       bool
-
-config NEED_DMA_MAP_STATE
-       bool
-
-config ARCH_DMA_ADDR_T_64BIT
-       def_bool 64BIT || PHYS_ADDR_T_64BIT
-
 config IOMMU_HELPER
        bool
 
-config ARCH_HAS_SYNC_DMA_FOR_DEVICE
-       bool
-
-config ARCH_HAS_SYNC_DMA_FOR_CPU
-       bool
-       select NEED_DMA_MAP_STATE
-
-config DMA_DIRECT_OPS
-       bool
-       depends on HAS_DMA
-
-config DMA_NONCOHERENT_OPS
-       bool
-       depends on HAS_DMA
-       select DMA_DIRECT_OPS
-
-config DMA_NONCOHERENT_MMAP
-       bool
-       depends on DMA_NONCOHERENT_OPS
-
-config DMA_NONCOHERENT_CACHE_SYNC
-       bool
-       depends on DMA_NONCOHERENT_OPS
-
-config DMA_VIRT_OPS
-       bool
-       depends on HAS_DMA
-
-config SWIOTLB
-       bool
-       select DMA_DIRECT_OPS
-       select NEED_DMA_MAP_STATE
-
 config CHECK_SIGNATURE
        bool
 
index 5e0e160c92425fc25672843f7556dca9c9586729..8153fdab287f5250496504c1d24c34d78b82fc4f 100644 (file)
@@ -29,9 +29,6 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
 lib-$(CONFIG_PRINTK) += dump_stack.o
 lib-$(CONFIG_MMU) += ioremap.o
 lib-$(CONFIG_SMP) += cpumask.o
-obj-$(CONFIG_DMA_DIRECT_OPS) += dma-direct.o
-obj-$(CONFIG_DMA_NONCOHERENT_OPS) += dma-noncoherent.o
-obj-$(CONFIG_DMA_VIRT_OPS) += dma-virt.o
 
 lib-y  += kobject.o klist.o
 obj-y  += lockref.o
@@ -148,7 +145,6 @@ obj-$(CONFIG_SMP) += percpu_counter.o
 obj-$(CONFIG_AUDIT_GENERIC) += audit.o
 obj-$(CONFIG_AUDIT_COMPAT_GENERIC) += compat_audit.o
 
-obj-$(CONFIG_SWIOTLB) += swiotlb.o
 obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
 obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o
 obj-$(CONFIG_NOTIFIER_ERROR_INJECTION) += notifier-error-inject.o
@@ -169,8 +165,6 @@ obj-$(CONFIG_NLATTR) += nlattr.o
 
 obj-$(CONFIG_LRU_CACHE) += lru_cache.o
 
-obj-$(CONFIG_DMA_API_DEBUG) += dma-debug.o
-
 obj-$(CONFIG_GENERIC_CSUM) += checksum.o
 
 obj-$(CONFIG_GENERIC_ATOMIC64) += atomic64.o
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
deleted file mode 100644 (file)
index c007d25..0000000
+++ /dev/null
@@ -1,1773 +0,0 @@
-/*
- * Copyright (C) 2008 Advanced Micro Devices, Inc.
- *
- * Author: Joerg Roedel <joerg.roedel@amd.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#include <linux/sched/task_stack.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-#include <linux/sched/task.h>
-#include <linux/stacktrace.h>
-#include <linux/dma-debug.h>
-#include <linux/spinlock.h>
-#include <linux/vmalloc.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <linux/export.h>
-#include <linux/device.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/ctype.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-
-#include <asm/sections.h>
-
-#define HASH_SIZE       1024ULL
-#define HASH_FN_SHIFT   13
-#define HASH_FN_MASK    (HASH_SIZE - 1)
-
-/* allow architectures to override this if absolutely required */
-#ifndef PREALLOC_DMA_DEBUG_ENTRIES
-#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
-#endif
-
-enum {
-       dma_debug_single,
-       dma_debug_page,
-       dma_debug_sg,
-       dma_debug_coherent,
-       dma_debug_resource,
-};
-
-enum map_err_types {
-       MAP_ERR_CHECK_NOT_APPLICABLE,
-       MAP_ERR_NOT_CHECKED,
-       MAP_ERR_CHECKED,
-};
-
-#define DMA_DEBUG_STACKTRACE_ENTRIES 5
-
-/**
- * struct dma_debug_entry - track a dma_map* or dma_alloc_coherent mapping
- * @list: node on pre-allocated free_entries list
- * @dev: 'dev' argument to dma_map_{page|single|sg} or dma_alloc_coherent
- * @type: single, page, sg, coherent
- * @pfn: page frame of the start address
- * @offset: offset of mapping relative to pfn
- * @size: length of the mapping
- * @direction: enum dma_data_direction
- * @sg_call_ents: 'nents' from dma_map_sg
- * @sg_mapped_ents: 'mapped_ents' from dma_map_sg
- * @map_err_type: track whether dma_mapping_error() was checked
- * @stacktrace: support backtraces when a violation is detected
- */
-struct dma_debug_entry {
-       struct list_head list;
-       struct device    *dev;
-       int              type;
-       unsigned long    pfn;
-       size_t           offset;
-       u64              dev_addr;
-       u64              size;
-       int              direction;
-       int              sg_call_ents;
-       int              sg_mapped_ents;
-       enum map_err_types  map_err_type;
-#ifdef CONFIG_STACKTRACE
-       struct           stack_trace stacktrace;
-       unsigned long    st_entries[DMA_DEBUG_STACKTRACE_ENTRIES];
-#endif
-};
-
-typedef bool (*match_fn)(struct dma_debug_entry *, struct dma_debug_entry *);
-
-struct hash_bucket {
-       struct list_head list;
-       spinlock_t lock;
-} ____cacheline_aligned_in_smp;
-
-/* Hash list to save the allocated dma addresses */
-static struct hash_bucket dma_entry_hash[HASH_SIZE];
-/* List of pre-allocated dma_debug_entry's */
-static LIST_HEAD(free_entries);
-/* Lock for the list above */
-static DEFINE_SPINLOCK(free_entries_lock);
-
-/* Global disable flag - will be set in case of an error */
-static bool global_disable __read_mostly;
-
-/* Early initialization disable flag, set at the end of dma_debug_init */
-static bool dma_debug_initialized __read_mostly;
-
-static inline bool dma_debug_disabled(void)
-{
-       return global_disable || !dma_debug_initialized;
-}
-
-/* Global error count */
-static u32 error_count;
-
-/* Global error show enable*/
-static u32 show_all_errors __read_mostly;
-/* Number of errors to show */
-static u32 show_num_errors = 1;
-
-static u32 num_free_entries;
-static u32 min_free_entries;
-static u32 nr_total_entries;
-
-/* number of preallocated entries requested by kernel cmdline */
-static u32 nr_prealloc_entries = PREALLOC_DMA_DEBUG_ENTRIES;
-
-/* debugfs dentry's for the stuff above */
-static struct dentry *dma_debug_dent        __read_mostly;
-static struct dentry *global_disable_dent   __read_mostly;
-static struct dentry *error_count_dent      __read_mostly;
-static struct dentry *show_all_errors_dent  __read_mostly;
-static struct dentry *show_num_errors_dent  __read_mostly;
-static struct dentry *num_free_entries_dent __read_mostly;
-static struct dentry *min_free_entries_dent __read_mostly;
-static struct dentry *filter_dent           __read_mostly;
-
-/* per-driver filter related state */
-
-#define NAME_MAX_LEN   64
-
-static char                  current_driver_name[NAME_MAX_LEN] __read_mostly;
-static struct device_driver *current_driver                    __read_mostly;
-
-static DEFINE_RWLOCK(driver_name_lock);
-
-static const char *const maperr2str[] = {
-       [MAP_ERR_CHECK_NOT_APPLICABLE] = "dma map error check not applicable",
-       [MAP_ERR_NOT_CHECKED] = "dma map error not checked",
-       [MAP_ERR_CHECKED] = "dma map error checked",
-};
-
-static const char *type2name[5] = { "single", "page",
-                                   "scather-gather", "coherent",
-                                   "resource" };
-
-static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE",
-                                  "DMA_FROM_DEVICE", "DMA_NONE" };
-
-/*
- * The access to some variables in this macro is racy. We can't use atomic_t
- * here because all these variables are exported to debugfs. Some of them even
- * writeable. This is also the reason why a lock won't help much. But anyway,
- * the races are no big deal. Here is why:
- *
- *   error_count: the addition is racy, but the worst thing that can happen is
- *                that we don't count some errors
- *   show_num_errors: the subtraction is racy. Also no big deal because in
- *                    worst case this will result in one warning more in the
- *                    system log than the user configured. This variable is
- *                    writeable via debugfs.
- */
-static inline void dump_entry_trace(struct dma_debug_entry *entry)
-{
-#ifdef CONFIG_STACKTRACE
-       if (entry) {
-               pr_warning("Mapped at:\n");
-               print_stack_trace(&entry->stacktrace, 0);
-       }
-#endif
-}
-
-static bool driver_filter(struct device *dev)
-{
-       struct device_driver *drv;
-       unsigned long flags;
-       bool ret;
-
-       /* driver filter off */
-       if (likely(!current_driver_name[0]))
-               return true;
-
-       /* driver filter on and initialized */
-       if (current_driver && dev && dev->driver == current_driver)
-               return true;
-
-       /* driver filter on, but we can't filter on a NULL device... */
-       if (!dev)
-               return false;
-
-       if (current_driver || !current_driver_name[0])
-               return false;
-
-       /* driver filter on but not yet initialized */
-       drv = dev->driver;
-       if (!drv)
-               return false;
-
-       /* lock to protect against change of current_driver_name */
-       read_lock_irqsave(&driver_name_lock, flags);
-
-       ret = false;
-       if (drv->name &&
-           strncmp(current_driver_name, drv->name, NAME_MAX_LEN - 1) == 0) {
-               current_driver = drv;
-               ret = true;
-       }
-
-       read_unlock_irqrestore(&driver_name_lock, flags);
-
-       return ret;
-}
-
-#define err_printk(dev, entry, format, arg...) do {                    \
-               error_count += 1;                                       \
-               if (driver_filter(dev) &&                               \
-                   (show_all_errors || show_num_errors > 0)) {         \
-                       WARN(1, "%s %s: " format,                       \
-                            dev ? dev_driver_string(dev) : "NULL",     \
-                            dev ? dev_name(dev) : "NULL", ## arg);     \
-                       dump_entry_trace(entry);                        \
-               }                                                       \
-               if (!show_all_errors && show_num_errors > 0)            \
-                       show_num_errors -= 1;                           \
-       } while (0);
-
-/*
- * Hash related functions
- *
- * Every DMA-API request is saved into a struct dma_debug_entry. To
- * have quick access to these structs they are stored into a hash.
- */
-static int hash_fn(struct dma_debug_entry *entry)
-{
-       /*
-        * Hash function is based on the dma address.
-        * We use bits 20-27 here as the index into the hash
-        */
-       return (entry->dev_addr >> HASH_FN_SHIFT) & HASH_FN_MASK;
-}
-
-/*
- * Request exclusive access to a hash bucket for a given dma_debug_entry.
- */
-static struct hash_bucket *get_hash_bucket(struct dma_debug_entry *entry,
-                                          unsigned long *flags)
-       __acquires(&dma_entry_hash[idx].lock)
-{
-       int idx = hash_fn(entry);
-       unsigned long __flags;
-
-       spin_lock_irqsave(&dma_entry_hash[idx].lock, __flags);
-       *flags = __flags;
-       return &dma_entry_hash[idx];
-}
-
-/*
- * Give up exclusive access to the hash bucket
- */
-static void put_hash_bucket(struct hash_bucket *bucket,
-                           unsigned long *flags)
-       __releases(&bucket->lock)
-{
-       unsigned long __flags = *flags;
-
-       spin_unlock_irqrestore(&bucket->lock, __flags);
-}
-
-static bool exact_match(struct dma_debug_entry *a, struct dma_debug_entry *b)
-{
-       return ((a->dev_addr == b->dev_addr) &&
-               (a->dev == b->dev)) ? true : false;
-}
-
-static bool containing_match(struct dma_debug_entry *a,
-                            struct dma_debug_entry *b)
-{
-       if (a->dev != b->dev)
-               return false;
-
-       if ((b->dev_addr <= a->dev_addr) &&
-           ((b->dev_addr + b->size) >= (a->dev_addr + a->size)))
-               return true;
-
-       return false;
-}
-
-/*
- * Search a given entry in the hash bucket list
- */
-static struct dma_debug_entry *__hash_bucket_find(struct hash_bucket *bucket,
-                                                 struct dma_debug_entry *ref,
-                                                 match_fn match)
-{
-       struct dma_debug_entry *entry, *ret = NULL;
-       int matches = 0, match_lvl, last_lvl = -1;
-
-       list_for_each_entry(entry, &bucket->list, list) {
-               if (!match(ref, entry))
-                       continue;
-
-               /*
-                * Some drivers map the same physical address multiple
-                * times. Without a hardware IOMMU this results in the
-                * same device addresses being put into the dma-debug
-                * hash multiple times too. This can result in false
-                * positives being reported. Therefore we implement a
-                * best-fit algorithm here which returns the entry from
-                * the hash which fits best to the reference value
-                * instead of the first-fit.
-                */
-               matches += 1;
-               match_lvl = 0;
-               entry->size         == ref->size         ? ++match_lvl : 0;
-               entry->type         == ref->type         ? ++match_lvl : 0;
-               entry->direction    == ref->direction    ? ++match_lvl : 0;
-               entry->sg_call_ents == ref->sg_call_ents ? ++match_lvl : 0;
-
-               if (match_lvl == 4) {
-                       /* perfect-fit - return the result */
-                       return entry;
-               } else if (match_lvl > last_lvl) {
-                       /*
-                        * We found an entry that fits better then the
-                        * previous one or it is the 1st match.
-                        */
-                       last_lvl = match_lvl;
-                       ret      = entry;
-               }
-       }
-
-       /*
-        * If we have multiple matches but no perfect-fit, just return
-        * NULL.
-        */
-       ret = (matches == 1) ? ret : NULL;
-
-       return ret;
-}
-
-static struct dma_debug_entry *bucket_find_exact(struct hash_bucket *bucket,
-                                                struct dma_debug_entry *ref)
-{
-       return __hash_bucket_find(bucket, ref, exact_match);
-}
-
-static struct dma_debug_entry *bucket_find_contain(struct hash_bucket **bucket,
-                                                  struct dma_debug_entry *ref,
-                                                  unsigned long *flags)
-{
-
-       unsigned int max_range = dma_get_max_seg_size(ref->dev);
-       struct dma_debug_entry *entry, index = *ref;
-       unsigned int range = 0;
-
-       while (range <= max_range) {
-               entry = __hash_bucket_find(*bucket, ref, containing_match);
-
-               if (entry)
-                       return entry;
-
-               /*
-                * Nothing found, go back a hash bucket
-                */
-               put_hash_bucket(*bucket, flags);
-               range          += (1 << HASH_FN_SHIFT);
-               index.dev_addr -= (1 << HASH_FN_SHIFT);
-               *bucket = get_hash_bucket(&index, flags);
-       }
-
-       return NULL;
-}
-
-/*
- * Add an entry to a hash bucket
- */
-static void hash_bucket_add(struct hash_bucket *bucket,
-                           struct dma_debug_entry *entry)
-{
-       list_add_tail(&entry->list, &bucket->list);
-}
-
-/*
- * Remove entry from a hash bucket list
- */
-static void hash_bucket_del(struct dma_debug_entry *entry)
-{
-       list_del(&entry->list);
-}
-
-static unsigned long long phys_addr(struct dma_debug_entry *entry)
-{
-       if (entry->type == dma_debug_resource)
-               return __pfn_to_phys(entry->pfn) + entry->offset;
-
-       return page_to_phys(pfn_to_page(entry->pfn)) + entry->offset;
-}
-
-/*
- * Dump mapping entries for debugging purposes
- */
-void debug_dma_dump_mappings(struct device *dev)
-{
-       int idx;
-
-       for (idx = 0; idx < HASH_SIZE; idx++) {
-               struct hash_bucket *bucket = &dma_entry_hash[idx];
-               struct dma_debug_entry *entry;
-               unsigned long flags;
-
-               spin_lock_irqsave(&bucket->lock, flags);
-
-               list_for_each_entry(entry, &bucket->list, list) {
-                       if (!dev || dev == entry->dev) {
-                               dev_info(entry->dev,
-                                        "%s idx %d P=%Lx N=%lx D=%Lx L=%Lx %s %s\n",
-                                        type2name[entry->type], idx,
-                                        phys_addr(entry), entry->pfn,
-                                        entry->dev_addr, entry->size,
-                                        dir2name[entry->direction],
-                                        maperr2str[entry->map_err_type]);
-                       }
-               }
-
-               spin_unlock_irqrestore(&bucket->lock, flags);
-       }
-}
-
-/*
- * For each mapping (initial cacheline in the case of
- * dma_alloc_coherent/dma_map_page, initial cacheline in each page of a
- * scatterlist, or the cacheline specified in dma_map_single) insert
- * into this tree using the cacheline as the key. At
- * dma_unmap_{single|sg|page} or dma_free_coherent delete the entry.  If
- * the entry already exists at insertion time add a tag as a reference
- * count for the overlapping mappings.  For now, the overlap tracking
- * just ensures that 'unmaps' balance 'maps' before marking the
- * cacheline idle, but we should also be flagging overlaps as an API
- * violation.
- *
- * Memory usage is mostly constrained by the maximum number of available
- * dma-debug entries in that we need a free dma_debug_entry before
- * inserting into the tree.  In the case of dma_map_page and
- * dma_alloc_coherent there is only one dma_debug_entry and one
- * dma_active_cacheline entry to track per event.  dma_map_sg(), on the
- * other hand, consumes a single dma_debug_entry, but inserts 'nents'
- * entries into the tree.
- *
- * At any time debug_dma_assert_idle() can be called to trigger a
- * warning if any cachelines in the given page are in the active set.
- */
-static RADIX_TREE(dma_active_cacheline, GFP_NOWAIT);
-static DEFINE_SPINLOCK(radix_lock);
-#define ACTIVE_CACHELINE_MAX_OVERLAP ((1 << RADIX_TREE_MAX_TAGS) - 1)
-#define CACHELINE_PER_PAGE_SHIFT (PAGE_SHIFT - L1_CACHE_SHIFT)
-#define CACHELINES_PER_PAGE (1 << CACHELINE_PER_PAGE_SHIFT)
-
-static phys_addr_t to_cacheline_number(struct dma_debug_entry *entry)
-{
-       return (entry->pfn << CACHELINE_PER_PAGE_SHIFT) +
-               (entry->offset >> L1_CACHE_SHIFT);
-}
-
-static int active_cacheline_read_overlap(phys_addr_t cln)
-{
-       int overlap = 0, i;
-
-       for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
-               if (radix_tree_tag_get(&dma_active_cacheline, cln, i))
-                       overlap |= 1 << i;
-       return overlap;
-}
-
-static int active_cacheline_set_overlap(phys_addr_t cln, int overlap)
-{
-       int i;
-
-       if (overlap > ACTIVE_CACHELINE_MAX_OVERLAP || overlap < 0)
-               return overlap;
-
-       for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
-               if (overlap & 1 << i)
-                       radix_tree_tag_set(&dma_active_cacheline, cln, i);
-               else
-                       radix_tree_tag_clear(&dma_active_cacheline, cln, i);
-
-       return overlap;
-}
-
-static void active_cacheline_inc_overlap(phys_addr_t cln)
-{
-       int overlap = active_cacheline_read_overlap(cln);
-
-       overlap = active_cacheline_set_overlap(cln, ++overlap);
-
-       /* If we overflowed the overlap counter then we're potentially
-        * leaking dma-mappings.  Otherwise, if maps and unmaps are
-        * balanced then this overflow may cause false negatives in
-        * debug_dma_assert_idle() as the cacheline may be marked idle
-        * prematurely.
-        */
-       WARN_ONCE(overlap > ACTIVE_CACHELINE_MAX_OVERLAP,
-                 "DMA-API: exceeded %d overlapping mappings of cacheline %pa\n",
-                 ACTIVE_CACHELINE_MAX_OVERLAP, &cln);
-}
-
-static int active_cacheline_dec_overlap(phys_addr_t cln)
-{
-       int overlap = active_cacheline_read_overlap(cln);
-
-       return active_cacheline_set_overlap(cln, --overlap);
-}
-
-static int active_cacheline_insert(struct dma_debug_entry *entry)
-{
-       phys_addr_t cln = to_cacheline_number(entry);
-       unsigned long flags;
-       int rc;
-
-       /* If the device is not writing memory then we don't have any
-        * concerns about the cpu consuming stale data.  This mitigates
-        * legitimate usages of overlapping mappings.
-        */
-       if (entry->direction == DMA_TO_DEVICE)
-               return 0;
-
-       spin_lock_irqsave(&radix_lock, flags);
-       rc = radix_tree_insert(&dma_active_cacheline, cln, entry);
-       if (rc == -EEXIST)
-               active_cacheline_inc_overlap(cln);
-       spin_unlock_irqrestore(&radix_lock, flags);
-
-       return rc;
-}
-
-static void active_cacheline_remove(struct dma_debug_entry *entry)
-{
-       phys_addr_t cln = to_cacheline_number(entry);
-       unsigned long flags;
-
-       /* ...mirror the insert case */
-       if (entry->direction == DMA_TO_DEVICE)
-               return;
-
-       spin_lock_irqsave(&radix_lock, flags);
-       /* since we are counting overlaps the final put of the
-        * cacheline will occur when the overlap count is 0.
-        * active_cacheline_dec_overlap() returns -1 in that case
-        */
-       if (active_cacheline_dec_overlap(cln) < 0)
-               radix_tree_delete(&dma_active_cacheline, cln);
-       spin_unlock_irqrestore(&radix_lock, flags);
-}
-
-/**
- * debug_dma_assert_idle() - assert that a page is not undergoing dma
- * @page: page to lookup in the dma_active_cacheline tree
- *
- * Place a call to this routine in cases where the cpu touching the page
- * before the dma completes (page is dma_unmapped) will lead to data
- * corruption.
- */
-void debug_dma_assert_idle(struct page *page)
-{
-       static struct dma_debug_entry *ents[CACHELINES_PER_PAGE];
-       struct dma_debug_entry *entry = NULL;
-       void **results = (void **) &ents;
-       unsigned int nents, i;
-       unsigned long flags;
-       phys_addr_t cln;
-
-       if (dma_debug_disabled())
-               return;
-
-       if (!page)
-               return;
-
-       cln = (phys_addr_t) page_to_pfn(page) << CACHELINE_PER_PAGE_SHIFT;
-       spin_lock_irqsave(&radix_lock, flags);
-       nents = radix_tree_gang_lookup(&dma_active_cacheline, results, cln,
-                                      CACHELINES_PER_PAGE);
-       for (i = 0; i < nents; i++) {
-               phys_addr_t ent_cln = to_cacheline_number(ents[i]);
-
-               if (ent_cln == cln) {
-                       entry = ents[i];
-                       break;
-               } else if (ent_cln >= cln + CACHELINES_PER_PAGE)
-                       break;
-       }
-       spin_unlock_irqrestore(&radix_lock, flags);
-
-       if (!entry)
-               return;
-
-       cln = to_cacheline_number(entry);
-       err_printk(entry->dev, entry,
-                  "DMA-API: cpu touching an active dma mapped cacheline [cln=%pa]\n",
-                  &cln);
-}
-
-/*
- * Wrapper function for adding an entry to the hash.
- * This function takes care of locking itself.
- */
-static void add_dma_entry(struct dma_debug_entry *entry)
-{
-       struct hash_bucket *bucket;
-       unsigned long flags;
-       int rc;
-
-       bucket = get_hash_bucket(entry, &flags);
-       hash_bucket_add(bucket, entry);
-       put_hash_bucket(bucket, &flags);
-
-       rc = active_cacheline_insert(entry);
-       if (rc == -ENOMEM) {
-               pr_err("DMA-API: cacheline tracking ENOMEM, dma-debug disabled\n");
-               global_disable = true;
-       }
-
-       /* TODO: report -EEXIST errors here as overlapping mappings are
-        * not supported by the DMA API
-        */
-}
-
-static struct dma_debug_entry *__dma_entry_alloc(void)
-{
-       struct dma_debug_entry *entry;
-
-       entry = list_entry(free_entries.next, struct dma_debug_entry, list);
-       list_del(&entry->list);
-       memset(entry, 0, sizeof(*entry));
-
-       num_free_entries -= 1;
-       if (num_free_entries < min_free_entries)
-               min_free_entries = num_free_entries;
-
-       return entry;
-}
-
-/* struct dma_entry allocator
- *
- * The next two functions implement the allocator for
- * struct dma_debug_entries.
- */
-static struct dma_debug_entry *dma_entry_alloc(void)
-{
-       struct dma_debug_entry *entry;
-       unsigned long flags;
-
-       spin_lock_irqsave(&free_entries_lock, flags);
-
-       if (list_empty(&free_entries)) {
-               global_disable = true;
-               spin_unlock_irqrestore(&free_entries_lock, flags);
-               pr_err("DMA-API: debugging out of memory - disabling\n");
-               return NULL;
-       }
-
-       entry = __dma_entry_alloc();
-
-       spin_unlock_irqrestore(&free_entries_lock, flags);
-
-#ifdef CONFIG_STACKTRACE
-       entry->stacktrace.max_entries = DMA_DEBUG_STACKTRACE_ENTRIES;
-       entry->stacktrace.entries = entry->st_entries;
-       entry->stacktrace.skip = 2;
-       save_stack_trace(&entry->stacktrace);
-#endif
-
-       return entry;
-}
-
-static void dma_entry_free(struct dma_debug_entry *entry)
-{
-       unsigned long flags;
-
-       active_cacheline_remove(entry);
-
-       /*
-        * add to beginning of the list - this way the entries are
-        * more likely cache hot when they are reallocated.
-        */
-       spin_lock_irqsave(&free_entries_lock, flags);
-       list_add(&entry->list, &free_entries);
-       num_free_entries += 1;
-       spin_unlock_irqrestore(&free_entries_lock, flags);
-}
-
-int dma_debug_resize_entries(u32 num_entries)
-{
-       int i, delta, ret = 0;
-       unsigned long flags;
-       struct dma_debug_entry *entry;
-       LIST_HEAD(tmp);
-
-       spin_lock_irqsave(&free_entries_lock, flags);
-
-       if (nr_total_entries < num_entries) {
-               delta = num_entries - nr_total_entries;
-
-               spin_unlock_irqrestore(&free_entries_lock, flags);
-
-               for (i = 0; i < delta; i++) {
-                       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-                       if (!entry)
-                               break;
-
-                       list_add_tail(&entry->list, &tmp);
-               }
-
-               spin_lock_irqsave(&free_entries_lock, flags);
-
-               list_splice(&tmp, &free_entries);
-               nr_total_entries += i;
-               num_free_entries += i;
-       } else {
-               delta = nr_total_entries - num_entries;
-
-               for (i = 0; i < delta && !list_empty(&free_entries); i++) {
-                       entry = __dma_entry_alloc();
-                       kfree(entry);
-               }
-
-               nr_total_entries -= i;
-       }
-
-       if (nr_total_entries != num_entries)
-               ret = 1;
-
-       spin_unlock_irqrestore(&free_entries_lock, flags);
-
-       return ret;
-}
-
-/*
- * DMA-API debugging init code
- *
- * The init code does two things:
- *   1. Initialize core data structures
- *   2. Preallocate a given number of dma_debug_entry structs
- */
-
-static int prealloc_memory(u32 num_entries)
-{
-       struct dma_debug_entry *entry, *next_entry;
-       int i;
-
-       for (i = 0; i < num_entries; ++i) {
-               entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-               if (!entry)
-                       goto out_err;
-
-               list_add_tail(&entry->list, &free_entries);
-       }
-
-       num_free_entries = num_entries;
-       min_free_entries = num_entries;
-
-       pr_info("DMA-API: preallocated %d debug entries\n", num_entries);
-
-       return 0;
-
-out_err:
-
-       list_for_each_entry_safe(entry, next_entry, &free_entries, list) {
-               list_del(&entry->list);
-               kfree(entry);
-       }
-
-       return -ENOMEM;
-}
-
-static ssize_t filter_read(struct file *file, char __user *user_buf,
-                          size_t count, loff_t *ppos)
-{
-       char buf[NAME_MAX_LEN + 1];
-       unsigned long flags;
-       int len;
-
-       if (!current_driver_name[0])
-               return 0;
-
-       /*
-        * We can't copy to userspace directly because current_driver_name can
-        * only be read under the driver_name_lock with irqs disabled. So
-        * create a temporary copy first.
-        */
-       read_lock_irqsave(&driver_name_lock, flags);
-       len = scnprintf(buf, NAME_MAX_LEN + 1, "%s\n", current_driver_name);
-       read_unlock_irqrestore(&driver_name_lock, flags);
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static ssize_t filter_write(struct file *file, const char __user *userbuf,
-                           size_t count, loff_t *ppos)
-{
-       char buf[NAME_MAX_LEN];
-       unsigned long flags;
-       size_t len;
-       int i;
-
-       /*
-        * We can't copy from userspace directly. Access to
-        * current_driver_name is protected with a write_lock with irqs
-        * disabled. Since copy_from_user can fault and may sleep we
-        * need to copy to temporary buffer first
-        */
-       len = min(count, (size_t)(NAME_MAX_LEN - 1));
-       if (copy_from_user(buf, userbuf, len))
-               return -EFAULT;
-
-       buf[len] = 0;
-
-       write_lock_irqsave(&driver_name_lock, flags);
-
-       /*
-        * Now handle the string we got from userspace very carefully.
-        * The rules are:
-        *         - only use the first token we got
-        *         - token delimiter is everything looking like a space
-        *           character (' ', '\n', '\t' ...)
-        *
-        */
-       if (!isalnum(buf[0])) {
-               /*
-                * If the first character userspace gave us is not
-                * alphanumerical then assume the filter should be
-                * switched off.
-                */
-               if (current_driver_name[0])
-                       pr_info("DMA-API: switching off dma-debug driver filter\n");
-               current_driver_name[0] = 0;
-               current_driver = NULL;
-               goto out_unlock;
-       }
-
-       /*
-        * Now parse out the first token and use it as the name for the
-        * driver to filter for.
-        */
-       for (i = 0; i < NAME_MAX_LEN - 1; ++i) {
-               current_driver_name[i] = buf[i];
-               if (isspace(buf[i]) || buf[i] == ' ' || buf[i] == 0)
-                       break;
-       }
-       current_driver_name[i] = 0;
-       current_driver = NULL;
-
-       pr_info("DMA-API: enable driver filter for driver [%s]\n",
-               current_driver_name);
-
-out_unlock:
-       write_unlock_irqrestore(&driver_name_lock, flags);
-
-       return count;
-}
-
-static const struct file_operations filter_fops = {
-       .read  = filter_read,
-       .write = filter_write,
-       .llseek = default_llseek,
-};
-
-static int dma_debug_fs_init(void)
-{
-       dma_debug_dent = debugfs_create_dir("dma-api", NULL);
-       if (!dma_debug_dent) {
-               pr_err("DMA-API: can not create debugfs directory\n");
-               return -ENOMEM;
-       }
-
-       global_disable_dent = debugfs_create_bool("disabled", 0444,
-                       dma_debug_dent,
-                       &global_disable);
-       if (!global_disable_dent)
-               goto out_err;
-
-       error_count_dent = debugfs_create_u32("error_count", 0444,
-                       dma_debug_dent, &error_count);
-       if (!error_count_dent)
-               goto out_err;
-
-       show_all_errors_dent = debugfs_create_u32("all_errors", 0644,
-                       dma_debug_dent,
-                       &show_all_errors);
-       if (!show_all_errors_dent)
-               goto out_err;
-
-       show_num_errors_dent = debugfs_create_u32("num_errors", 0644,
-                       dma_debug_dent,
-                       &show_num_errors);
-       if (!show_num_errors_dent)
-               goto out_err;
-
-       num_free_entries_dent = debugfs_create_u32("num_free_entries", 0444,
-                       dma_debug_dent,
-                       &num_free_entries);
-       if (!num_free_entries_dent)
-               goto out_err;
-
-       min_free_entries_dent = debugfs_create_u32("min_free_entries", 0444,
-                       dma_debug_dent,
-                       &min_free_entries);
-       if (!min_free_entries_dent)
-               goto out_err;
-
-       filter_dent = debugfs_create_file("driver_filter", 0644,
-                                         dma_debug_dent, NULL, &filter_fops);
-       if (!filter_dent)
-               goto out_err;
-
-       return 0;
-
-out_err:
-       debugfs_remove_recursive(dma_debug_dent);
-
-       return -ENOMEM;
-}
-
-static int device_dma_allocations(struct device *dev, struct dma_debug_entry **out_entry)
-{
-       struct dma_debug_entry *entry;
-       unsigned long flags;
-       int count = 0, i;
-
-       for (i = 0; i < HASH_SIZE; ++i) {
-               spin_lock_irqsave(&dma_entry_hash[i].lock, flags);
-               list_for_each_entry(entry, &dma_entry_hash[i].list, list) {
-                       if (entry->dev == dev) {
-                               count += 1;
-                               *out_entry = entry;
-                       }
-               }
-               spin_unlock_irqrestore(&dma_entry_hash[i].lock, flags);
-       }
-
-       return count;
-}
-
-static int dma_debug_device_change(struct notifier_block *nb, unsigned long action, void *data)
-{
-       struct device *dev = data;
-       struct dma_debug_entry *uninitialized_var(entry);
-       int count;
-
-       if (dma_debug_disabled())
-               return 0;
-
-       switch (action) {
-       case BUS_NOTIFY_UNBOUND_DRIVER:
-               count = device_dma_allocations(dev, &entry);
-               if (count == 0)
-                       break;
-               err_printk(dev, entry, "DMA-API: device driver has pending "
-                               "DMA allocations while released from device "
-                               "[count=%d]\n"
-                               "One of leaked entries details: "
-                               "[device address=0x%016llx] [size=%llu bytes] "
-                               "[mapped with %s] [mapped as %s]\n",
-                       count, entry->dev_addr, entry->size,
-                       dir2name[entry->direction], type2name[entry->type]);
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-void dma_debug_add_bus(struct bus_type *bus)
-{
-       struct notifier_block *nb;
-
-       if (dma_debug_disabled())
-               return;
-
-       nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL);
-       if (nb == NULL) {
-               pr_err("dma_debug_add_bus: out of memory\n");
-               return;
-       }
-
-       nb->notifier_call = dma_debug_device_change;
-
-       bus_register_notifier(bus, nb);
-}
-
-static int dma_debug_init(void)
-{
-       int i;
-
-       /* Do not use dma_debug_initialized here, since we really want to be
-        * called to set dma_debug_initialized
-        */
-       if (global_disable)
-               return 0;
-
-       for (i = 0; i < HASH_SIZE; ++i) {
-               INIT_LIST_HEAD(&dma_entry_hash[i].list);
-               spin_lock_init(&dma_entry_hash[i].lock);
-       }
-
-       if (dma_debug_fs_init() != 0) {
-               pr_err("DMA-API: error creating debugfs entries - disabling\n");
-               global_disable = true;
-
-               return 0;
-       }
-
-       if (prealloc_memory(nr_prealloc_entries) != 0) {
-               pr_err("DMA-API: debugging out of memory error - disabled\n");
-               global_disable = true;
-
-               return 0;
-       }
-
-       nr_total_entries = num_free_entries;
-
-       dma_debug_initialized = true;
-
-       pr_info("DMA-API: debugging enabled by kernel config\n");
-       return 0;
-}
-core_initcall(dma_debug_init);
-
-static __init int dma_debug_cmdline(char *str)
-{
-       if (!str)
-               return -EINVAL;
-
-       if (strncmp(str, "off", 3) == 0) {
-               pr_info("DMA-API: debugging disabled on kernel command line\n");
-               global_disable = true;
-       }
-
-       return 0;
-}
-
-static __init int dma_debug_entries_cmdline(char *str)
-{
-       if (!str)
-               return -EINVAL;
-       if (!get_option(&str, &nr_prealloc_entries))
-               nr_prealloc_entries = PREALLOC_DMA_DEBUG_ENTRIES;
-       return 0;
-}
-
-__setup("dma_debug=", dma_debug_cmdline);
-__setup("dma_debug_entries=", dma_debug_entries_cmdline);
-
-static void check_unmap(struct dma_debug_entry *ref)
-{
-       struct dma_debug_entry *entry;
-       struct hash_bucket *bucket;
-       unsigned long flags;
-
-       bucket = get_hash_bucket(ref, &flags);
-       entry = bucket_find_exact(bucket, ref);
-
-       if (!entry) {
-               /* must drop lock before calling dma_mapping_error */
-               put_hash_bucket(bucket, &flags);
-
-               if (dma_mapping_error(ref->dev, ref->dev_addr)) {
-                       err_printk(ref->dev, NULL,
-                                  "DMA-API: device driver tries to free an "
-                                  "invalid DMA memory address\n");
-               } else {
-                       err_printk(ref->dev, NULL,
-                                  "DMA-API: device driver tries to free DMA "
-                                  "memory it has not allocated [device "
-                                  "address=0x%016llx] [size=%llu bytes]\n",
-                                  ref->dev_addr, ref->size);
-               }
-               return;
-       }
-
-       if (ref->size != entry->size) {
-               err_printk(ref->dev, entry, "DMA-API: device driver frees "
-                          "DMA memory with different size "
-                          "[device address=0x%016llx] [map size=%llu bytes] "
-                          "[unmap size=%llu bytes]\n",
-                          ref->dev_addr, entry->size, ref->size);
-       }
-
-       if (ref->type != entry->type) {
-               err_printk(ref->dev, entry, "DMA-API: device driver frees "
-                          "DMA memory with wrong function "
-                          "[device address=0x%016llx] [size=%llu bytes] "
-                          "[mapped as %s] [unmapped as %s]\n",
-                          ref->dev_addr, ref->size,
-                          type2name[entry->type], type2name[ref->type]);
-       } else if ((entry->type == dma_debug_coherent) &&
-                  (phys_addr(ref) != phys_addr(entry))) {
-               err_printk(ref->dev, entry, "DMA-API: device driver frees "
-                          "DMA memory with different CPU address "
-                          "[device address=0x%016llx] [size=%llu bytes] "
-                          "[cpu alloc address=0x%016llx] "
-                          "[cpu free address=0x%016llx]",
-                          ref->dev_addr, ref->size,
-                          phys_addr(entry),
-                          phys_addr(ref));
-       }
-
-       if (ref->sg_call_ents && ref->type == dma_debug_sg &&
-           ref->sg_call_ents != entry->sg_call_ents) {
-               err_printk(ref->dev, entry, "DMA-API: device driver frees "
-                          "DMA sg list with different entry count "
-                          "[map count=%d] [unmap count=%d]\n",
-                          entry->sg_call_ents, ref->sg_call_ents);
-       }
-
-       /*
-        * This may be no bug in reality - but most implementations of the
-        * DMA API don't handle this properly, so check for it here
-        */
-       if (ref->direction != entry->direction) {
-               err_printk(ref->dev, entry, "DMA-API: device driver frees "
-                          "DMA memory with different direction "
-                          "[device address=0x%016llx] [size=%llu bytes] "
-                          "[mapped with %s] [unmapped with %s]\n",
-                          ref->dev_addr, ref->size,
-                          dir2name[entry->direction],
-                          dir2name[ref->direction]);
-       }
-
-       /*
-        * Drivers should use dma_mapping_error() to check the returned
-        * addresses of dma_map_single() and dma_map_page().
-        * If not, print this warning message. See Documentation/DMA-API.txt.
-        */
-       if (entry->map_err_type == MAP_ERR_NOT_CHECKED) {
-               err_printk(ref->dev, entry,
-                          "DMA-API: device driver failed to check map error"
-                          "[device address=0x%016llx] [size=%llu bytes] "
-                          "[mapped as %s]",
-                          ref->dev_addr, ref->size,
-                          type2name[entry->type]);
-       }
-
-       hash_bucket_del(entry);
-       dma_entry_free(entry);
-
-       put_hash_bucket(bucket, &flags);
-}
-
-static void check_for_stack(struct device *dev,
-                           struct page *page, size_t offset)
-{
-       void *addr;
-       struct vm_struct *stack_vm_area = task_stack_vm_area(current);
-
-       if (!stack_vm_area) {
-               /* Stack is direct-mapped. */
-               if (PageHighMem(page))
-                       return;
-               addr = page_address(page) + offset;
-               if (object_is_on_stack(addr))
-                       err_printk(dev, NULL, "DMA-API: device driver maps memory from stack [addr=%p]\n", addr);
-       } else {
-               /* Stack is vmalloced. */
-               int i;
-
-               for (i = 0; i < stack_vm_area->nr_pages; i++) {
-                       if (page != stack_vm_area->pages[i])
-                               continue;
-
-                       addr = (u8 *)current->stack + i * PAGE_SIZE + offset;
-                       err_printk(dev, NULL, "DMA-API: device driver maps memory from stack [probable addr=%p]\n", addr);
-                       break;
-               }
-       }
-}
-
-static inline bool overlap(void *addr, unsigned long len, void *start, void *end)
-{
-       unsigned long a1 = (unsigned long)addr;
-       unsigned long b1 = a1 + len;
-       unsigned long a2 = (unsigned long)start;
-       unsigned long b2 = (unsigned long)end;
-
-       return !(b1 <= a2 || a1 >= b2);
-}
-
-static void check_for_illegal_area(struct device *dev, void *addr, unsigned long len)
-{
-       if (overlap(addr, len, _stext, _etext) ||
-           overlap(addr, len, __start_rodata, __end_rodata))
-               err_printk(dev, NULL, "DMA-API: device driver maps memory from kernel text or rodata [addr=%p] [len=%lu]\n", addr, len);
-}
-
-static void check_sync(struct device *dev,
-                      struct dma_debug_entry *ref,
-                      bool to_cpu)
-{
-       struct dma_debug_entry *entry;
-       struct hash_bucket *bucket;
-       unsigned long flags;
-
-       bucket = get_hash_bucket(ref, &flags);
-
-       entry = bucket_find_contain(&bucket, ref, &flags);
-
-       if (!entry) {
-               err_printk(dev, NULL, "DMA-API: device driver tries "
-                               "to sync DMA memory it has not allocated "
-                               "[device address=0x%016llx] [size=%llu bytes]\n",
-                               (unsigned long long)ref->dev_addr, ref->size);
-               goto out;
-       }
-
-       if (ref->size > entry->size) {
-               err_printk(dev, entry, "DMA-API: device driver syncs"
-                               " DMA memory outside allocated range "
-                               "[device address=0x%016llx] "
-                               "[allocation size=%llu bytes] "
-                               "[sync offset+size=%llu]\n",
-                               entry->dev_addr, entry->size,
-                               ref->size);
-       }
-
-       if (entry->direction == DMA_BIDIRECTIONAL)
-               goto out;
-
-       if (ref->direction != entry->direction) {
-               err_printk(dev, entry, "DMA-API: device driver syncs "
-                               "DMA memory with different direction "
-                               "[device address=0x%016llx] [size=%llu bytes] "
-                               "[mapped with %s] [synced with %s]\n",
-                               (unsigned long long)ref->dev_addr, entry->size,
-                               dir2name[entry->direction],
-                               dir2name[ref->direction]);
-       }
-
-       if (to_cpu && !(entry->direction == DMA_FROM_DEVICE) &&
-                     !(ref->direction == DMA_TO_DEVICE))
-               err_printk(dev, entry, "DMA-API: device driver syncs "
-                               "device read-only DMA memory for cpu "
-                               "[device address=0x%016llx] [size=%llu bytes] "
-                               "[mapped with %s] [synced with %s]\n",
-                               (unsigned long long)ref->dev_addr, entry->size,
-                               dir2name[entry->direction],
-                               dir2name[ref->direction]);
-
-       if (!to_cpu && !(entry->direction == DMA_TO_DEVICE) &&
-                      !(ref->direction == DMA_FROM_DEVICE))
-               err_printk(dev, entry, "DMA-API: device driver syncs "
-                               "device write-only DMA memory to device "
-                               "[device address=0x%016llx] [size=%llu bytes] "
-                               "[mapped with %s] [synced with %s]\n",
-                               (unsigned long long)ref->dev_addr, entry->size,
-                               dir2name[entry->direction],
-                               dir2name[ref->direction]);
-
-       if (ref->sg_call_ents && ref->type == dma_debug_sg &&
-           ref->sg_call_ents != entry->sg_call_ents) {
-               err_printk(ref->dev, entry, "DMA-API: device driver syncs "
-                          "DMA sg list with different entry count "
-                          "[map count=%d] [sync count=%d]\n",
-                          entry->sg_call_ents, ref->sg_call_ents);
-       }
-
-out:
-       put_hash_bucket(bucket, &flags);
-}
-
-static void check_sg_segment(struct device *dev, struct scatterlist *sg)
-{
-#ifdef CONFIG_DMA_API_DEBUG_SG
-       unsigned int max_seg = dma_get_max_seg_size(dev);
-       u64 start, end, boundary = dma_get_seg_boundary(dev);
-
-       /*
-        * Either the driver forgot to set dma_parms appropriately, or
-        * whoever generated the list forgot to check them.
-        */
-       if (sg->length > max_seg)
-               err_printk(dev, NULL, "DMA-API: mapping sg segment longer than device claims to support [len=%u] [max=%u]\n",
-                          sg->length, max_seg);
-       /*
-        * In some cases this could potentially be the DMA API
-        * implementation's fault, but it would usually imply that
-        * the scatterlist was built inappropriately to begin with.
-        */
-       start = sg_dma_address(sg);
-       end = start + sg_dma_len(sg) - 1;
-       if ((start ^ end) & ~boundary)
-               err_printk(dev, NULL, "DMA-API: mapping sg segment across boundary [start=0x%016llx] [end=0x%016llx] [boundary=0x%016llx]\n",
-                          start, end, boundary);
-#endif
-}
-
-void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
-                       size_t size, int direction, dma_addr_t dma_addr,
-                       bool map_single)
-{
-       struct dma_debug_entry *entry;
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       if (dma_mapping_error(dev, dma_addr))
-               return;
-
-       entry = dma_entry_alloc();
-       if (!entry)
-               return;
-
-       entry->dev       = dev;
-       entry->type      = dma_debug_page;
-       entry->pfn       = page_to_pfn(page);
-       entry->offset    = offset,
-       entry->dev_addr  = dma_addr;
-       entry->size      = size;
-       entry->direction = direction;
-       entry->map_err_type = MAP_ERR_NOT_CHECKED;
-
-       if (map_single)
-               entry->type = dma_debug_single;
-
-       check_for_stack(dev, page, offset);
-
-       if (!PageHighMem(page)) {
-               void *addr = page_address(page) + offset;
-
-               check_for_illegal_area(dev, addr, size);
-       }
-
-       add_dma_entry(entry);
-}
-EXPORT_SYMBOL(debug_dma_map_page);
-
-void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-       struct dma_debug_entry ref;
-       struct dma_debug_entry *entry;
-       struct hash_bucket *bucket;
-       unsigned long flags;
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       ref.dev = dev;
-       ref.dev_addr = dma_addr;
-       bucket = get_hash_bucket(&ref, &flags);
-
-       list_for_each_entry(entry, &bucket->list, list) {
-               if (!exact_match(&ref, entry))
-                       continue;
-
-               /*
-                * The same physical address can be mapped multiple
-                * times. Without a hardware IOMMU this results in the
-                * same device addresses being put into the dma-debug
-                * hash multiple times too. This can result in false
-                * positives being reported. Therefore we implement a
-                * best-fit algorithm here which updates the first entry
-                * from the hash which fits the reference value and is
-                * not currently listed as being checked.
-                */
-               if (entry->map_err_type == MAP_ERR_NOT_CHECKED) {
-                       entry->map_err_type = MAP_ERR_CHECKED;
-                       break;
-               }
-       }
-
-       put_hash_bucket(bucket, &flags);
-}
-EXPORT_SYMBOL(debug_dma_mapping_error);
-
-void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
-                         size_t size, int direction, bool map_single)
-{
-       struct dma_debug_entry ref = {
-               .type           = dma_debug_page,
-               .dev            = dev,
-               .dev_addr       = addr,
-               .size           = size,
-               .direction      = direction,
-       };
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       if (map_single)
-               ref.type = dma_debug_single;
-
-       check_unmap(&ref);
-}
-EXPORT_SYMBOL(debug_dma_unmap_page);
-
-void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
-                     int nents, int mapped_ents, int direction)
-{
-       struct dma_debug_entry *entry;
-       struct scatterlist *s;
-       int i;
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       for_each_sg(sg, s, mapped_ents, i) {
-               entry = dma_entry_alloc();
-               if (!entry)
-                       return;
-
-               entry->type           = dma_debug_sg;
-               entry->dev            = dev;
-               entry->pfn            = page_to_pfn(sg_page(s));
-               entry->offset         = s->offset,
-               entry->size           = sg_dma_len(s);
-               entry->dev_addr       = sg_dma_address(s);
-               entry->direction      = direction;
-               entry->sg_call_ents   = nents;
-               entry->sg_mapped_ents = mapped_ents;
-
-               check_for_stack(dev, sg_page(s), s->offset);
-
-               if (!PageHighMem(sg_page(s))) {
-                       check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s));
-               }
-
-               check_sg_segment(dev, s);
-
-               add_dma_entry(entry);
-       }
-}
-EXPORT_SYMBOL(debug_dma_map_sg);
-
-static int get_nr_mapped_entries(struct device *dev,
-                                struct dma_debug_entry *ref)
-{
-       struct dma_debug_entry *entry;
-       struct hash_bucket *bucket;
-       unsigned long flags;
-       int mapped_ents;
-
-       bucket       = get_hash_bucket(ref, &flags);
-       entry        = bucket_find_exact(bucket, ref);
-       mapped_ents  = 0;
-
-       if (entry)
-               mapped_ents = entry->sg_mapped_ents;
-       put_hash_bucket(bucket, &flags);
-
-       return mapped_ents;
-}
-
-void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
-                       int nelems, int dir)
-{
-       struct scatterlist *s;
-       int mapped_ents = 0, i;
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       for_each_sg(sglist, s, nelems, i) {
-
-               struct dma_debug_entry ref = {
-                       .type           = dma_debug_sg,
-                       .dev            = dev,
-                       .pfn            = page_to_pfn(sg_page(s)),
-                       .offset         = s->offset,
-                       .dev_addr       = sg_dma_address(s),
-                       .size           = sg_dma_len(s),
-                       .direction      = dir,
-                       .sg_call_ents   = nelems,
-               };
-
-               if (mapped_ents && i >= mapped_ents)
-                       break;
-
-               if (!i)
-                       mapped_ents = get_nr_mapped_entries(dev, &ref);
-
-               check_unmap(&ref);
-       }
-}
-EXPORT_SYMBOL(debug_dma_unmap_sg);
-
-void debug_dma_alloc_coherent(struct device *dev, size_t size,
-                             dma_addr_t dma_addr, void *virt)
-{
-       struct dma_debug_entry *entry;
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       if (unlikely(virt == NULL))
-               return;
-
-       /* handle vmalloc and linear addresses */
-       if (!is_vmalloc_addr(virt) && !virt_addr_valid(virt))
-               return;
-
-       entry = dma_entry_alloc();
-       if (!entry)
-               return;
-
-       entry->type      = dma_debug_coherent;
-       entry->dev       = dev;
-       entry->offset    = offset_in_page(virt);
-       entry->size      = size;
-       entry->dev_addr  = dma_addr;
-       entry->direction = DMA_BIDIRECTIONAL;
-
-       if (is_vmalloc_addr(virt))
-               entry->pfn = vmalloc_to_pfn(virt);
-       else
-               entry->pfn = page_to_pfn(virt_to_page(virt));
-
-       add_dma_entry(entry);
-}
-EXPORT_SYMBOL(debug_dma_alloc_coherent);
-
-void debug_dma_free_coherent(struct device *dev, size_t size,
-                        void *virt, dma_addr_t addr)
-{
-       struct dma_debug_entry ref = {
-               .type           = dma_debug_coherent,
-               .dev            = dev,
-               .offset         = offset_in_page(virt),
-               .dev_addr       = addr,
-               .size           = size,
-               .direction      = DMA_BIDIRECTIONAL,
-       };
-
-       /* handle vmalloc and linear addresses */
-       if (!is_vmalloc_addr(virt) && !virt_addr_valid(virt))
-               return;
-
-       if (is_vmalloc_addr(virt))
-               ref.pfn = vmalloc_to_pfn(virt);
-       else
-               ref.pfn = page_to_pfn(virt_to_page(virt));
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       check_unmap(&ref);
-}
-EXPORT_SYMBOL(debug_dma_free_coherent);
-
-void debug_dma_map_resource(struct device *dev, phys_addr_t addr, size_t size,
-                           int direction, dma_addr_t dma_addr)
-{
-       struct dma_debug_entry *entry;
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       entry = dma_entry_alloc();
-       if (!entry)
-               return;
-
-       entry->type             = dma_debug_resource;
-       entry->dev              = dev;
-       entry->pfn              = PHYS_PFN(addr);
-       entry->offset           = offset_in_page(addr);
-       entry->size             = size;
-       entry->dev_addr         = dma_addr;
-       entry->direction        = direction;
-       entry->map_err_type     = MAP_ERR_NOT_CHECKED;
-
-       add_dma_entry(entry);
-}
-EXPORT_SYMBOL(debug_dma_map_resource);
-
-void debug_dma_unmap_resource(struct device *dev, dma_addr_t dma_addr,
-                             size_t size, int direction)
-{
-       struct dma_debug_entry ref = {
-               .type           = dma_debug_resource,
-               .dev            = dev,
-               .dev_addr       = dma_addr,
-               .size           = size,
-               .direction      = direction,
-       };
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       check_unmap(&ref);
-}
-EXPORT_SYMBOL(debug_dma_unmap_resource);
-
-void debug_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-                                  size_t size, int direction)
-{
-       struct dma_debug_entry ref;
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       ref.type         = dma_debug_single;
-       ref.dev          = dev;
-       ref.dev_addr     = dma_handle;
-       ref.size         = size;
-       ref.direction    = direction;
-       ref.sg_call_ents = 0;
-
-       check_sync(dev, &ref, true);
-}
-EXPORT_SYMBOL(debug_dma_sync_single_for_cpu);
-
-void debug_dma_sync_single_for_device(struct device *dev,
-                                     dma_addr_t dma_handle, size_t size,
-                                     int direction)
-{
-       struct dma_debug_entry ref;
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       ref.type         = dma_debug_single;
-       ref.dev          = dev;
-       ref.dev_addr     = dma_handle;
-       ref.size         = size;
-       ref.direction    = direction;
-       ref.sg_call_ents = 0;
-
-       check_sync(dev, &ref, false);
-}
-EXPORT_SYMBOL(debug_dma_sync_single_for_device);
-
-void debug_dma_sync_single_range_for_cpu(struct device *dev,
-                                        dma_addr_t dma_handle,
-                                        unsigned long offset, size_t size,
-                                        int direction)
-{
-       struct dma_debug_entry ref;
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       ref.type         = dma_debug_single;
-       ref.dev          = dev;
-       ref.dev_addr     = dma_handle;
-       ref.size         = offset + size;
-       ref.direction    = direction;
-       ref.sg_call_ents = 0;
-
-       check_sync(dev, &ref, true);
-}
-EXPORT_SYMBOL(debug_dma_sync_single_range_for_cpu);
-
-void debug_dma_sync_single_range_for_device(struct device *dev,
-                                           dma_addr_t dma_handle,
-                                           unsigned long offset,
-                                           size_t size, int direction)
-{
-       struct dma_debug_entry ref;
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       ref.type         = dma_debug_single;
-       ref.dev          = dev;
-       ref.dev_addr     = dma_handle;
-       ref.size         = offset + size;
-       ref.direction    = direction;
-       ref.sg_call_ents = 0;
-
-       check_sync(dev, &ref, false);
-}
-EXPORT_SYMBOL(debug_dma_sync_single_range_for_device);
-
-void debug_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
-                              int nelems, int direction)
-{
-       struct scatterlist *s;
-       int mapped_ents = 0, i;
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       for_each_sg(sg, s, nelems, i) {
-
-               struct dma_debug_entry ref = {
-                       .type           = dma_debug_sg,
-                       .dev            = dev,
-                       .pfn            = page_to_pfn(sg_page(s)),
-                       .offset         = s->offset,
-                       .dev_addr       = sg_dma_address(s),
-                       .size           = sg_dma_len(s),
-                       .direction      = direction,
-                       .sg_call_ents   = nelems,
-               };
-
-               if (!i)
-                       mapped_ents = get_nr_mapped_entries(dev, &ref);
-
-               if (i >= mapped_ents)
-                       break;
-
-               check_sync(dev, &ref, true);
-       }
-}
-EXPORT_SYMBOL(debug_dma_sync_sg_for_cpu);
-
-void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
-                                 int nelems, int direction)
-{
-       struct scatterlist *s;
-       int mapped_ents = 0, i;
-
-       if (unlikely(dma_debug_disabled()))
-               return;
-
-       for_each_sg(sg, s, nelems, i) {
-
-               struct dma_debug_entry ref = {
-                       .type           = dma_debug_sg,
-                       .dev            = dev,
-                       .pfn            = page_to_pfn(sg_page(s)),
-                       .offset         = s->offset,
-                       .dev_addr       = sg_dma_address(s),
-                       .size           = sg_dma_len(s),
-                       .direction      = direction,
-                       .sg_call_ents   = nelems,
-               };
-               if (!i)
-                       mapped_ents = get_nr_mapped_entries(dev, &ref);
-
-               if (i >= mapped_ents)
-                       break;
-
-               check_sync(dev, &ref, false);
-       }
-}
-EXPORT_SYMBOL(debug_dma_sync_sg_for_device);
-
-static int __init dma_debug_driver_setup(char *str)
-{
-       int i;
-
-       for (i = 0; i < NAME_MAX_LEN - 1; ++i, ++str) {
-               current_driver_name[i] = *str;
-               if (*str == 0)
-                       break;
-       }
-
-       if (current_driver_name[0])
-               pr_info("DMA-API: enable driver filter for driver [%s]\n",
-                       current_driver_name);
-
-
-       return 1;
-}
-__setup("dma_debug_driver=", dma_debug_driver_setup);
diff --git a/lib/dma-direct.c b/lib/dma-direct.c
deleted file mode 100644 (file)
index 8be8106..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * DMA operations that map physical memory directly without using an IOMMU or
- * flushing caches.
- */
-#include <linux/export.h>
-#include <linux/mm.h>
-#include <linux/dma-direct.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-contiguous.h>
-#include <linux/pfn.h>
-#include <linux/set_memory.h>
-
-#define DIRECT_MAPPING_ERROR           0
-
-/*
- * Most architectures use ZONE_DMA for the first 16 Megabytes, but
- * some use it for entirely different regions:
- */
-#ifndef ARCH_ZONE_DMA_BITS
-#define ARCH_ZONE_DMA_BITS 24
-#endif
-
-/*
- * For AMD SEV all DMA must be to unencrypted addresses.
- */
-static inline bool force_dma_unencrypted(void)
-{
-       return sev_active();
-}
-
-static bool
-check_addr(struct device *dev, dma_addr_t dma_addr, size_t size,
-               const char *caller)
-{
-       if (unlikely(dev && !dma_capable(dev, dma_addr, size))) {
-               if (!dev->dma_mask) {
-                       dev_err(dev,
-                               "%s: call on device without dma_mask\n",
-                               caller);
-                       return false;
-               }
-
-               if (*dev->dma_mask >= DMA_BIT_MASK(32)) {
-                       dev_err(dev,
-                               "%s: overflow %pad+%zu of device mask %llx\n",
-                               caller, &dma_addr, size, *dev->dma_mask);
-               }
-               return false;
-       }
-       return true;
-}
-
-static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
-{
-       dma_addr_t addr = force_dma_unencrypted() ?
-               __phys_to_dma(dev, phys) : phys_to_dma(dev, phys);
-       return addr + size - 1 <= dev->coherent_dma_mask;
-}
-
-void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
-               gfp_t gfp, unsigned long attrs)
-{
-       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
-       int page_order = get_order(size);
-       struct page *page = NULL;
-       void *ret;
-
-       /* we always manually zero the memory once we are done: */
-       gfp &= ~__GFP_ZERO;
-
-       /* GFP_DMA32 and GFP_DMA are no ops without the corresponding zones: */
-       if (dev->coherent_dma_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS))
-               gfp |= GFP_DMA;
-       if (dev->coherent_dma_mask <= DMA_BIT_MASK(32) && !(gfp & GFP_DMA))
-               gfp |= GFP_DMA32;
-
-again:
-       /* CMA can be used only in the context which permits sleeping */
-       if (gfpflags_allow_blocking(gfp)) {
-               page = dma_alloc_from_contiguous(dev, count, page_order, gfp);
-               if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
-                       dma_release_from_contiguous(dev, page, count);
-                       page = NULL;
-               }
-       }
-       if (!page)
-               page = alloc_pages_node(dev_to_node(dev), gfp, page_order);
-
-       if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
-               __free_pages(page, page_order);
-               page = NULL;
-
-               if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
-                   dev->coherent_dma_mask < DMA_BIT_MASK(64) &&
-                   !(gfp & (GFP_DMA32 | GFP_DMA))) {
-                       gfp |= GFP_DMA32;
-                       goto again;
-               }
-
-               if (IS_ENABLED(CONFIG_ZONE_DMA) &&
-                   dev->coherent_dma_mask < DMA_BIT_MASK(32) &&
-                   !(gfp & GFP_DMA)) {
-                       gfp = (gfp & ~GFP_DMA32) | GFP_DMA;
-                       goto again;
-               }
-       }
-
-       if (!page)
-               return NULL;
-       ret = page_address(page);
-       if (force_dma_unencrypted()) {
-               set_memory_decrypted((unsigned long)ret, 1 << page_order);
-               *dma_handle = __phys_to_dma(dev, page_to_phys(page));
-       } else {
-               *dma_handle = phys_to_dma(dev, page_to_phys(page));
-       }
-       memset(ret, 0, size);
-       return ret;
-}
-
-/*
- * NOTE: this function must never look at the dma_addr argument, because we want
- * to be able to use it as a helper for iommu implementations as well.
- */
-void dma_direct_free(struct device *dev, size_t size, void *cpu_addr,
-               dma_addr_t dma_addr, unsigned long attrs)
-{
-       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
-       unsigned int page_order = get_order(size);
-
-       if (force_dma_unencrypted())
-               set_memory_encrypted((unsigned long)cpu_addr, 1 << page_order);
-       if (!dma_release_from_contiguous(dev, virt_to_page(cpu_addr), count))
-               free_pages((unsigned long)cpu_addr, page_order);
-}
-
-dma_addr_t dma_direct_map_page(struct device *dev, struct page *page,
-               unsigned long offset, size_t size, enum dma_data_direction dir,
-               unsigned long attrs)
-{
-       dma_addr_t dma_addr = phys_to_dma(dev, page_to_phys(page)) + offset;
-
-       if (!check_addr(dev, dma_addr, size, __func__))
-               return DIRECT_MAPPING_ERROR;
-       return dma_addr;
-}
-
-int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
-               enum dma_data_direction dir, unsigned long attrs)
-{
-       int i;
-       struct scatterlist *sg;
-
-       for_each_sg(sgl, sg, nents, i) {
-               BUG_ON(!sg_page(sg));
-
-               sg_dma_address(sg) = phys_to_dma(dev, sg_phys(sg));
-               if (!check_addr(dev, sg_dma_address(sg), sg->length, __func__))
-                       return 0;
-               sg_dma_len(sg) = sg->length;
-       }
-
-       return nents;
-}
-
-int dma_direct_supported(struct device *dev, u64 mask)
-{
-#ifdef CONFIG_ZONE_DMA
-       if (mask < DMA_BIT_MASK(ARCH_ZONE_DMA_BITS))
-               return 0;
-#else
-       /*
-        * Because 32-bit DMA masks are so common we expect every architecture
-        * to be able to satisfy them - either by not supporting more physical
-        * memory, or by providing a ZONE_DMA32.  If neither is the case, the
-        * architecture needs to use an IOMMU instead of the direct mapping.
-        */
-       if (mask < DMA_BIT_MASK(32))
-               return 0;
-#endif
-       /*
-        * Various PCI/PCIe bridges have broken support for > 32bit DMA even
-        * if the device itself might support it.
-        */
-       if (dev->dma_32bit_limit && mask > DMA_BIT_MASK(32))
-               return 0;
-       return 1;
-}
-
-int dma_direct_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-       return dma_addr == DIRECT_MAPPING_ERROR;
-}
-
-const struct dma_map_ops dma_direct_ops = {
-       .alloc                  = dma_direct_alloc,
-       .free                   = dma_direct_free,
-       .map_page               = dma_direct_map_page,
-       .map_sg                 = dma_direct_map_sg,
-       .dma_supported          = dma_direct_supported,
-       .mapping_error          = dma_direct_mapping_error,
-};
-EXPORT_SYMBOL(dma_direct_ops);
diff --git a/lib/dma-noncoherent.c b/lib/dma-noncoherent.c
deleted file mode 100644 (file)
index 79e9a75..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2018 Christoph Hellwig.
- *
- * DMA operations that map physical memory directly without providing cache
- * coherence.
- */
-#include <linux/export.h>
-#include <linux/mm.h>
-#include <linux/dma-direct.h>
-#include <linux/dma-noncoherent.h>
-#include <linux/scatterlist.h>
-
-static void dma_noncoherent_sync_single_for_device(struct device *dev,
-               dma_addr_t addr, size_t size, enum dma_data_direction dir)
-{
-       arch_sync_dma_for_device(dev, dma_to_phys(dev, addr), size, dir);
-}
-
-static void dma_noncoherent_sync_sg_for_device(struct device *dev,
-               struct scatterlist *sgl, int nents, enum dma_data_direction dir)
-{
-       struct scatterlist *sg;
-       int i;
-
-       for_each_sg(sgl, sg, nents, i)
-               arch_sync_dma_for_device(dev, sg_phys(sg), sg->length, dir);
-}
-
-static dma_addr_t dma_noncoherent_map_page(struct device *dev, struct page *page,
-               unsigned long offset, size_t size, enum dma_data_direction dir,
-               unsigned long attrs)
-{
-       dma_addr_t addr;
-
-       addr = dma_direct_map_page(dev, page, offset, size, dir, attrs);
-       if (!dma_mapping_error(dev, addr) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-               arch_sync_dma_for_device(dev, page_to_phys(page) + offset,
-                               size, dir);
-       return addr;
-}
-
-static int dma_noncoherent_map_sg(struct device *dev, struct scatterlist *sgl,
-               int nents, enum dma_data_direction dir, unsigned long attrs)
-{
-       nents = dma_direct_map_sg(dev, sgl, nents, dir, attrs);
-       if (nents > 0 && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-               dma_noncoherent_sync_sg_for_device(dev, sgl, nents, dir);
-       return nents;
-}
-
-#ifdef CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU
-static void dma_noncoherent_sync_single_for_cpu(struct device *dev,
-               dma_addr_t addr, size_t size, enum dma_data_direction dir)
-{
-       arch_sync_dma_for_cpu(dev, dma_to_phys(dev, addr), size, dir);
-}
-
-static void dma_noncoherent_sync_sg_for_cpu(struct device *dev,
-               struct scatterlist *sgl, int nents, enum dma_data_direction dir)
-{
-       struct scatterlist *sg;
-       int i;
-
-       for_each_sg(sgl, sg, nents, i)
-               arch_sync_dma_for_cpu(dev, sg_phys(sg), sg->length, dir);
-}
-
-static void dma_noncoherent_unmap_page(struct device *dev, dma_addr_t addr,
-               size_t size, enum dma_data_direction dir, unsigned long attrs)
-{
-       if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-               dma_noncoherent_sync_single_for_cpu(dev, addr, size, dir);
-}
-
-static void dma_noncoherent_unmap_sg(struct device *dev, struct scatterlist *sgl,
-               int nents, enum dma_data_direction dir, unsigned long attrs)
-{
-       if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-               dma_noncoherent_sync_sg_for_cpu(dev, sgl, nents, dir);
-}
-#endif
-
-const struct dma_map_ops dma_noncoherent_ops = {
-       .alloc                  = arch_dma_alloc,
-       .free                   = arch_dma_free,
-       .mmap                   = arch_dma_mmap,
-       .sync_single_for_device = dma_noncoherent_sync_single_for_device,
-       .sync_sg_for_device     = dma_noncoherent_sync_sg_for_device,
-       .map_page               = dma_noncoherent_map_page,
-       .map_sg                 = dma_noncoherent_map_sg,
-#ifdef CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU
-       .sync_single_for_cpu    = dma_noncoherent_sync_single_for_cpu,
-       .sync_sg_for_cpu        = dma_noncoherent_sync_sg_for_cpu,
-       .unmap_page             = dma_noncoherent_unmap_page,
-       .unmap_sg               = dma_noncoherent_unmap_sg,
-#endif
-       .dma_supported          = dma_direct_supported,
-       .mapping_error          = dma_direct_mapping_error,
-       .cache_sync             = arch_dma_cache_sync,
-};
-EXPORT_SYMBOL(dma_noncoherent_ops);
diff --git a/lib/dma-virt.c b/lib/dma-virt.c
deleted file mode 100644 (file)
index 8e61a02..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- *     lib/dma-virt.c
- *
- * DMA operations that map to virtual addresses without flushing memory.
- */
-#include <linux/export.h>
-#include <linux/mm.h>
-#include <linux/dma-mapping.h>
-#include <linux/scatterlist.h>
-
-static void *dma_virt_alloc(struct device *dev, size_t size,
-                           dma_addr_t *dma_handle, gfp_t gfp,
-                           unsigned long attrs)
-{
-       void *ret;
-
-       ret = (void *)__get_free_pages(gfp, get_order(size));
-       if (ret)
-               *dma_handle = (uintptr_t)ret;
-       return ret;
-}
-
-static void dma_virt_free(struct device *dev, size_t size,
-                         void *cpu_addr, dma_addr_t dma_addr,
-                         unsigned long attrs)
-{
-       free_pages((unsigned long)cpu_addr, get_order(size));
-}
-
-static dma_addr_t dma_virt_map_page(struct device *dev, struct page *page,
-                                   unsigned long offset, size_t size,
-                                   enum dma_data_direction dir,
-                                   unsigned long attrs)
-{
-       return (uintptr_t)(page_address(page) + offset);
-}
-
-static int dma_virt_map_sg(struct device *dev, struct scatterlist *sgl,
-                          int nents, enum dma_data_direction dir,
-                          unsigned long attrs)
-{
-       int i;
-       struct scatterlist *sg;
-
-       for_each_sg(sgl, sg, nents, i) {
-               BUG_ON(!sg_page(sg));
-               sg_dma_address(sg) = (uintptr_t)sg_virt(sg);
-               sg_dma_len(sg) = sg->length;
-       }
-
-       return nents;
-}
-
-const struct dma_map_ops dma_virt_ops = {
-       .alloc                  = dma_virt_alloc,
-       .free                   = dma_virt_free,
-       .map_page               = dma_virt_map_page,
-       .map_sg                 = dma_virt_map_sg,
-};
-EXPORT_SYMBOL(dma_virt_ops);
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
deleted file mode 100644 (file)
index 04b68d9..0000000
+++ /dev/null
@@ -1,1087 +0,0 @@
-/*
- * Dynamic DMA mapping support.
- *
- * This implementation is a fallback for platforms that do not support
- * I/O TLBs (aka DMA address translation hardware).
- * Copyright (C) 2000 Asit Mallick <Asit.K.Mallick@intel.com>
- * Copyright (C) 2000 Goutham Rao <goutham.rao@intel.com>
- * Copyright (C) 2000, 2003 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * 03/05/07 davidm     Switch from PCI-DMA to generic device DMA API.
- * 00/12/13 davidm     Rename to swiotlb.c and add mark_clean() to avoid
- *                     unnecessary i-cache flushing.
- * 04/07/.. ak         Better overflow handling. Assorted fixes.
- * 05/09/10 linville   Add support for syncing ranges, support syncing for
- *                     DMA_BIDIRECTIONAL mappings, miscellaneous cleanup.
- * 08/12/11 beckyb     Add highmem support
- */
-
-#include <linux/cache.h>
-#include <linux/dma-direct.h>
-#include <linux/mm.h>
-#include <linux/export.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/swiotlb.h>
-#include <linux/pfn.h>
-#include <linux/types.h>
-#include <linux/ctype.h>
-#include <linux/highmem.h>
-#include <linux/gfp.h>
-#include <linux/scatterlist.h>
-#include <linux/mem_encrypt.h>
-#include <linux/set_memory.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/iommu-helper.h>
-
-#define CREATE_TRACE_POINTS
-#include <trace/events/swiotlb.h>
-
-#define OFFSET(val,align) ((unsigned long)     \
-                          ( (val) & ( (align) - 1)))
-
-#define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
-
-/*
- * Minimum IO TLB size to bother booting with.  Systems with mainly
- * 64bit capable cards will only lightly use the swiotlb.  If we can't
- * allocate a contiguous 1MB, we're probably in trouble anyway.
- */
-#define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
-
-enum swiotlb_force swiotlb_force;
-
-/*
- * Used to do a quick range check in swiotlb_tbl_unmap_single and
- * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
- * API.
- */
-static phys_addr_t io_tlb_start, io_tlb_end;
-
-/*
- * The number of IO TLB blocks (in groups of 64) between io_tlb_start and
- * io_tlb_end.  This is command line adjustable via setup_io_tlb_npages.
- */
-static unsigned long io_tlb_nslabs;
-
-/*
- * When the IOMMU overflows we return a fallback buffer. This sets the size.
- */
-static unsigned long io_tlb_overflow = 32*1024;
-
-static phys_addr_t io_tlb_overflow_buffer;
-
-/*
- * This is a free list describing the number of free entries available from
- * each index
- */
-static unsigned int *io_tlb_list;
-static unsigned int io_tlb_index;
-
-/*
- * Max segment that we can provide which (if pages are contingous) will
- * not be bounced (unless SWIOTLB_FORCE is set).
- */
-unsigned int max_segment;
-
-/*
- * We need to save away the original address corresponding to a mapped entry
- * for the sync operations.
- */
-#define INVALID_PHYS_ADDR (~(phys_addr_t)0)
-static phys_addr_t *io_tlb_orig_addr;
-
-/*
- * Protect the above data structures in the map and unmap calls
- */
-static DEFINE_SPINLOCK(io_tlb_lock);
-
-static int late_alloc;
-
-static int __init
-setup_io_tlb_npages(char *str)
-{
-       if (isdigit(*str)) {
-               io_tlb_nslabs = simple_strtoul(str, &str, 0);
-               /* avoid tail segment of size < IO_TLB_SEGSIZE */
-               io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
-       }
-       if (*str == ',')
-               ++str;
-       if (!strcmp(str, "force")) {
-               swiotlb_force = SWIOTLB_FORCE;
-       } else if (!strcmp(str, "noforce")) {
-               swiotlb_force = SWIOTLB_NO_FORCE;
-               io_tlb_nslabs = 1;
-       }
-
-       return 0;
-}
-early_param("swiotlb", setup_io_tlb_npages);
-/* make io_tlb_overflow tunable too? */
-
-unsigned long swiotlb_nr_tbl(void)
-{
-       return io_tlb_nslabs;
-}
-EXPORT_SYMBOL_GPL(swiotlb_nr_tbl);
-
-unsigned int swiotlb_max_segment(void)
-{
-       return max_segment;
-}
-EXPORT_SYMBOL_GPL(swiotlb_max_segment);
-
-void swiotlb_set_max_segment(unsigned int val)
-{
-       if (swiotlb_force == SWIOTLB_FORCE)
-               max_segment = 1;
-       else
-               max_segment = rounddown(val, PAGE_SIZE);
-}
-
-/* default to 64MB */
-#define IO_TLB_DEFAULT_SIZE (64UL<<20)
-unsigned long swiotlb_size_or_default(void)
-{
-       unsigned long size;
-
-       size = io_tlb_nslabs << IO_TLB_SHIFT;
-
-       return size ? size : (IO_TLB_DEFAULT_SIZE);
-}
-
-static bool no_iotlb_memory;
-
-void swiotlb_print_info(void)
-{
-       unsigned long bytes = io_tlb_nslabs << IO_TLB_SHIFT;
-       unsigned char *vstart, *vend;
-
-       if (no_iotlb_memory) {
-               pr_warn("software IO TLB: No low mem\n");
-               return;
-       }
-
-       vstart = phys_to_virt(io_tlb_start);
-       vend = phys_to_virt(io_tlb_end);
-
-       printk(KERN_INFO "software IO TLB [mem %#010llx-%#010llx] (%luMB) mapped at [%p-%p]\n",
-              (unsigned long long)io_tlb_start,
-              (unsigned long long)io_tlb_end,
-              bytes >> 20, vstart, vend - 1);
-}
-
-/*
- * Early SWIOTLB allocation may be too early to allow an architecture to
- * perform the desired operations.  This function allows the architecture to
- * call SWIOTLB when the operations are possible.  It needs to be called
- * before the SWIOTLB memory is used.
- */
-void __init swiotlb_update_mem_attributes(void)
-{
-       void *vaddr;
-       unsigned long bytes;
-
-       if (no_iotlb_memory || late_alloc)
-               return;
-
-       vaddr = phys_to_virt(io_tlb_start);
-       bytes = PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT);
-       set_memory_decrypted((unsigned long)vaddr, bytes >> PAGE_SHIFT);
-       memset(vaddr, 0, bytes);
-
-       vaddr = phys_to_virt(io_tlb_overflow_buffer);
-       bytes = PAGE_ALIGN(io_tlb_overflow);
-       set_memory_decrypted((unsigned long)vaddr, bytes >> PAGE_SHIFT);
-       memset(vaddr, 0, bytes);
-}
-
-int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
-{
-       void *v_overflow_buffer;
-       unsigned long i, bytes;
-
-       bytes = nslabs << IO_TLB_SHIFT;
-
-       io_tlb_nslabs = nslabs;
-       io_tlb_start = __pa(tlb);
-       io_tlb_end = io_tlb_start + bytes;
-
-       /*
-        * Get the overflow emergency buffer
-        */
-       v_overflow_buffer = memblock_virt_alloc_low_nopanic(
-                                               PAGE_ALIGN(io_tlb_overflow),
-                                               PAGE_SIZE);
-       if (!v_overflow_buffer)
-               return -ENOMEM;
-
-       io_tlb_overflow_buffer = __pa(v_overflow_buffer);
-
-       /*
-        * Allocate and initialize the free list array.  This array is used
-        * to find contiguous free memory regions of size up to IO_TLB_SEGSIZE
-        * between io_tlb_start and io_tlb_end.
-        */
-       io_tlb_list = memblock_virt_alloc(
-                               PAGE_ALIGN(io_tlb_nslabs * sizeof(int)),
-                               PAGE_SIZE);
-       io_tlb_orig_addr = memblock_virt_alloc(
-                               PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t)),
-                               PAGE_SIZE);
-       for (i = 0; i < io_tlb_nslabs; i++) {
-               io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
-               io_tlb_orig_addr[i] = INVALID_PHYS_ADDR;
-       }
-       io_tlb_index = 0;
-
-       if (verbose)
-               swiotlb_print_info();
-
-       swiotlb_set_max_segment(io_tlb_nslabs << IO_TLB_SHIFT);
-       return 0;
-}
-
-/*
- * Statically reserve bounce buffer space and initialize bounce buffer data
- * structures for the software IO TLB used to implement the DMA API.
- */
-void  __init
-swiotlb_init(int verbose)
-{
-       size_t default_size = IO_TLB_DEFAULT_SIZE;
-       unsigned char *vstart;
-       unsigned long bytes;
-
-       if (!io_tlb_nslabs) {
-               io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
-               io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
-       }
-
-       bytes = io_tlb_nslabs << IO_TLB_SHIFT;
-
-       /* Get IO TLB memory from the low pages */
-       vstart = memblock_virt_alloc_low_nopanic(PAGE_ALIGN(bytes), PAGE_SIZE);
-       if (vstart && !swiotlb_init_with_tbl(vstart, io_tlb_nslabs, verbose))
-               return;
-
-       if (io_tlb_start)
-               memblock_free_early(io_tlb_start,
-                                   PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
-       pr_warn("Cannot allocate SWIOTLB buffer");
-       no_iotlb_memory = true;
-}
-
-/*
- * Systems with larger DMA zones (those that don't support ISA) can
- * initialize the swiotlb later using the slab allocator if needed.
- * This should be just like above, but with some error catching.
- */
-int
-swiotlb_late_init_with_default_size(size_t default_size)
-{
-       unsigned long bytes, req_nslabs = io_tlb_nslabs;
-       unsigned char *vstart = NULL;
-       unsigned int order;
-       int rc = 0;
-
-       if (!io_tlb_nslabs) {
-               io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
-               io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
-       }
-
-       /*
-        * Get IO TLB memory from the low pages
-        */
-       order = get_order(io_tlb_nslabs << IO_TLB_SHIFT);
-       io_tlb_nslabs = SLABS_PER_PAGE << order;
-       bytes = io_tlb_nslabs << IO_TLB_SHIFT;
-
-       while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
-               vstart = (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN,
-                                                 order);
-               if (vstart)
-                       break;
-               order--;
-       }
-
-       if (!vstart) {
-               io_tlb_nslabs = req_nslabs;
-               return -ENOMEM;
-       }
-       if (order != get_order(bytes)) {
-               printk(KERN_WARNING "Warning: only able to allocate %ld MB "
-                      "for software IO TLB\n", (PAGE_SIZE << order) >> 20);
-               io_tlb_nslabs = SLABS_PER_PAGE << order;
-       }
-       rc = swiotlb_late_init_with_tbl(vstart, io_tlb_nslabs);
-       if (rc)
-               free_pages((unsigned long)vstart, order);
-
-       return rc;
-}
-
-int
-swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs)
-{
-       unsigned long i, bytes;
-       unsigned char *v_overflow_buffer;
-
-       bytes = nslabs << IO_TLB_SHIFT;
-
-       io_tlb_nslabs = nslabs;
-       io_tlb_start = virt_to_phys(tlb);
-       io_tlb_end = io_tlb_start + bytes;
-
-       set_memory_decrypted((unsigned long)tlb, bytes >> PAGE_SHIFT);
-       memset(tlb, 0, bytes);
-
-       /*
-        * Get the overflow emergency buffer
-        */
-       v_overflow_buffer = (void *)__get_free_pages(GFP_DMA,
-                                                    get_order(io_tlb_overflow));
-       if (!v_overflow_buffer)
-               goto cleanup2;
-
-       set_memory_decrypted((unsigned long)v_overflow_buffer,
-                       io_tlb_overflow >> PAGE_SHIFT);
-       memset(v_overflow_buffer, 0, io_tlb_overflow);
-       io_tlb_overflow_buffer = virt_to_phys(v_overflow_buffer);
-
-       /*
-        * Allocate and initialize the free list array.  This array is used
-        * to find contiguous free memory regions of size up to IO_TLB_SEGSIZE
-        * between io_tlb_start and io_tlb_end.
-        */
-       io_tlb_list = (unsigned int *)__get_free_pages(GFP_KERNEL,
-                                     get_order(io_tlb_nslabs * sizeof(int)));
-       if (!io_tlb_list)
-               goto cleanup3;
-
-       io_tlb_orig_addr = (phys_addr_t *)
-               __get_free_pages(GFP_KERNEL,
-                                get_order(io_tlb_nslabs *
-                                          sizeof(phys_addr_t)));
-       if (!io_tlb_orig_addr)
-               goto cleanup4;
-
-       for (i = 0; i < io_tlb_nslabs; i++) {
-               io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
-               io_tlb_orig_addr[i] = INVALID_PHYS_ADDR;
-       }
-       io_tlb_index = 0;
-
-       swiotlb_print_info();
-
-       late_alloc = 1;
-
-       swiotlb_set_max_segment(io_tlb_nslabs << IO_TLB_SHIFT);
-
-       return 0;
-
-cleanup4:
-       free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs *
-                                                        sizeof(int)));
-       io_tlb_list = NULL;
-cleanup3:
-       free_pages((unsigned long)v_overflow_buffer,
-                  get_order(io_tlb_overflow));
-       io_tlb_overflow_buffer = 0;
-cleanup2:
-       io_tlb_end = 0;
-       io_tlb_start = 0;
-       io_tlb_nslabs = 0;
-       max_segment = 0;
-       return -ENOMEM;
-}
-
-void __init swiotlb_exit(void)
-{
-       if (!io_tlb_orig_addr)
-               return;
-
-       if (late_alloc) {
-               free_pages((unsigned long)phys_to_virt(io_tlb_overflow_buffer),
-                          get_order(io_tlb_overflow));
-               free_pages((unsigned long)io_tlb_orig_addr,
-                          get_order(io_tlb_nslabs * sizeof(phys_addr_t)));
-               free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs *
-                                                                sizeof(int)));
-               free_pages((unsigned long)phys_to_virt(io_tlb_start),
-                          get_order(io_tlb_nslabs << IO_TLB_SHIFT));
-       } else {
-               memblock_free_late(io_tlb_overflow_buffer,
-                                  PAGE_ALIGN(io_tlb_overflow));
-               memblock_free_late(__pa(io_tlb_orig_addr),
-                                  PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t)));
-               memblock_free_late(__pa(io_tlb_list),
-                                  PAGE_ALIGN(io_tlb_nslabs * sizeof(int)));
-               memblock_free_late(io_tlb_start,
-                                  PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
-       }
-       io_tlb_nslabs = 0;
-       max_segment = 0;
-}
-
-int is_swiotlb_buffer(phys_addr_t paddr)
-{
-       return paddr >= io_tlb_start && paddr < io_tlb_end;
-}
-
-/*
- * Bounce: copy the swiotlb buffer back to the original dma location
- */
-static void swiotlb_bounce(phys_addr_t orig_addr, phys_addr_t tlb_addr,
-                          size_t size, enum dma_data_direction dir)
-{
-       unsigned long pfn = PFN_DOWN(orig_addr);
-       unsigned char *vaddr = phys_to_virt(tlb_addr);
-
-       if (PageHighMem(pfn_to_page(pfn))) {
-               /* The buffer does not have a mapping.  Map it in and copy */
-               unsigned int offset = orig_addr & ~PAGE_MASK;
-               char *buffer;
-               unsigned int sz = 0;
-               unsigned long flags;
-
-               while (size) {
-                       sz = min_t(size_t, PAGE_SIZE - offset, size);
-
-                       local_irq_save(flags);
-                       buffer = kmap_atomic(pfn_to_page(pfn));
-                       if (dir == DMA_TO_DEVICE)
-                               memcpy(vaddr, buffer + offset, sz);
-                       else
-                               memcpy(buffer + offset, vaddr, sz);
-                       kunmap_atomic(buffer);
-                       local_irq_restore(flags);
-
-                       size -= sz;
-                       pfn++;
-                       vaddr += sz;
-                       offset = 0;
-               }
-       } else if (dir == DMA_TO_DEVICE) {
-               memcpy(vaddr, phys_to_virt(orig_addr), size);
-       } else {
-               memcpy(phys_to_virt(orig_addr), vaddr, size);
-       }
-}
-
-phys_addr_t swiotlb_tbl_map_single(struct device *hwdev,
-                                  dma_addr_t tbl_dma_addr,
-                                  phys_addr_t orig_addr, size_t size,
-                                  enum dma_data_direction dir,
-                                  unsigned long attrs)
-{
-       unsigned long flags;
-       phys_addr_t tlb_addr;
-       unsigned int nslots, stride, index, wrap;
-       int i;
-       unsigned long mask;
-       unsigned long offset_slots;
-       unsigned long max_slots;
-
-       if (no_iotlb_memory)
-               panic("Can not allocate SWIOTLB buffer earlier and can't now provide you with the DMA bounce buffer");
-
-       if (mem_encrypt_active())
-               pr_warn_once("%s is active and system is using DMA bounce buffers\n",
-                            sme_active() ? "SME" : "SEV");
-
-       mask = dma_get_seg_boundary(hwdev);
-
-       tbl_dma_addr &= mask;
-
-       offset_slots = ALIGN(tbl_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
-
-       /*
-        * Carefully handle integer overflow which can occur when mask == ~0UL.
-        */
-       max_slots = mask + 1
-                   ? ALIGN(mask + 1, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT
-                   : 1UL << (BITS_PER_LONG - IO_TLB_SHIFT);
-
-       /*
-        * For mappings greater than or equal to a page, we limit the stride
-        * (and hence alignment) to a page size.
-        */
-       nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
-       if (size >= PAGE_SIZE)
-               stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT));
-       else
-               stride = 1;
-
-       BUG_ON(!nslots);
-
-       /*
-        * Find suitable number of IO TLB entries size that will fit this
-        * request and allocate a buffer from that IO TLB pool.
-        */
-       spin_lock_irqsave(&io_tlb_lock, flags);
-       index = ALIGN(io_tlb_index, stride);
-       if (index >= io_tlb_nslabs)
-               index = 0;
-       wrap = index;
-
-       do {
-               while (iommu_is_span_boundary(index, nslots, offset_slots,
-                                             max_slots)) {
-                       index += stride;
-                       if (index >= io_tlb_nslabs)
-                               index = 0;
-                       if (index == wrap)
-                               goto not_found;
-               }
-
-               /*
-                * If we find a slot that indicates we have 'nslots' number of
-                * contiguous buffers, we allocate the buffers from that slot
-                * and mark the entries as '0' indicating unavailable.
-                */
-               if (io_tlb_list[index] >= nslots) {
-                       int count = 0;
-
-                       for (i = index; i < (int) (index + nslots); i++)
-                               io_tlb_list[i] = 0;
-                       for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE - 1) && io_tlb_list[i]; i--)
-                               io_tlb_list[i] = ++count;
-                       tlb_addr = io_tlb_start + (index << IO_TLB_SHIFT);
-
-                       /*
-                        * Update the indices to avoid searching in the next
-                        * round.
-                        */
-                       io_tlb_index = ((index + nslots) < io_tlb_nslabs
-                                       ? (index + nslots) : 0);
-
-                       goto found;
-               }
-               index += stride;
-               if (index >= io_tlb_nslabs)
-                       index = 0;
-       } while (index != wrap);
-
-not_found:
-       spin_unlock_irqrestore(&io_tlb_lock, flags);
-       if (!(attrs & DMA_ATTR_NO_WARN) && printk_ratelimit())
-               dev_warn(hwdev, "swiotlb buffer is full (sz: %zd bytes)\n", size);
-       return SWIOTLB_MAP_ERROR;
-found:
-       spin_unlock_irqrestore(&io_tlb_lock, flags);
-
-       /*
-        * Save away the mapping from the original address to the DMA address.
-        * This is needed when we sync the memory.  Then we sync the buffer if
-        * needed.
-        */
-       for (i = 0; i < nslots; i++)
-               io_tlb_orig_addr[index+i] = orig_addr + (i << IO_TLB_SHIFT);
-       if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
-           (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
-               swiotlb_bounce(orig_addr, tlb_addr, size, DMA_TO_DEVICE);
-
-       return tlb_addr;
-}
-
-/*
- * Allocates bounce buffer and returns its physical address.
- */
-static phys_addr_t
-map_single(struct device *hwdev, phys_addr_t phys, size_t size,
-          enum dma_data_direction dir, unsigned long attrs)
-{
-       dma_addr_t start_dma_addr;
-
-       if (swiotlb_force == SWIOTLB_NO_FORCE) {
-               dev_warn_ratelimited(hwdev, "Cannot do DMA to address %pa\n",
-                                    &phys);
-               return SWIOTLB_MAP_ERROR;
-       }
-
-       start_dma_addr = __phys_to_dma(hwdev, io_tlb_start);
-       return swiotlb_tbl_map_single(hwdev, start_dma_addr, phys, size,
-                                     dir, attrs);
-}
-
-/*
- * tlb_addr is the physical address of the bounce buffer to unmap.
- */
-void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr,
-                             size_t size, enum dma_data_direction dir,
-                             unsigned long attrs)
-{
-       unsigned long flags;
-       int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
-       int index = (tlb_addr - io_tlb_start) >> IO_TLB_SHIFT;
-       phys_addr_t orig_addr = io_tlb_orig_addr[index];
-
-       /*
-        * First, sync the memory before unmapping the entry
-        */
-       if (orig_addr != INVALID_PHYS_ADDR &&
-           !(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
-           ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)))
-               swiotlb_bounce(orig_addr, tlb_addr, size, DMA_FROM_DEVICE);
-
-       /*
-        * Return the buffer to the free list by setting the corresponding
-        * entries to indicate the number of contiguous entries available.
-        * While returning the entries to the free list, we merge the entries
-        * with slots below and above the pool being returned.
-        */
-       spin_lock_irqsave(&io_tlb_lock, flags);
-       {
-               count = ((index + nslots) < ALIGN(index + 1, IO_TLB_SEGSIZE) ?
-                        io_tlb_list[index + nslots] : 0);
-               /*
-                * Step 1: return the slots to the free list, merging the
-                * slots with superceeding slots
-                */
-               for (i = index + nslots - 1; i >= index; i--) {
-                       io_tlb_list[i] = ++count;
-                       io_tlb_orig_addr[i] = INVALID_PHYS_ADDR;
-               }
-               /*
-                * Step 2: merge the returned slots with the preceding slots,
-                * if available (non zero)
-                */
-               for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE -1) && io_tlb_list[i]; i--)
-                       io_tlb_list[i] = ++count;
-       }
-       spin_unlock_irqrestore(&io_tlb_lock, flags);
-}
-
-void swiotlb_tbl_sync_single(struct device *hwdev, phys_addr_t tlb_addr,
-                            size_t size, enum dma_data_direction dir,
-                            enum dma_sync_target target)
-{
-       int index = (tlb_addr - io_tlb_start) >> IO_TLB_SHIFT;
-       phys_addr_t orig_addr = io_tlb_orig_addr[index];
-
-       if (orig_addr == INVALID_PHYS_ADDR)
-               return;
-       orig_addr += (unsigned long)tlb_addr & ((1 << IO_TLB_SHIFT) - 1);
-
-       switch (target) {
-       case SYNC_FOR_CPU:
-               if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL))
-                       swiotlb_bounce(orig_addr, tlb_addr,
-                                      size, DMA_FROM_DEVICE);
-               else
-                       BUG_ON(dir != DMA_TO_DEVICE);
-               break;
-       case SYNC_FOR_DEVICE:
-               if (likely(dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
-                       swiotlb_bounce(orig_addr, tlb_addr,
-                                      size, DMA_TO_DEVICE);
-               else
-                       BUG_ON(dir != DMA_FROM_DEVICE);
-               break;
-       default:
-               BUG();
-       }
-}
-
-static inline bool dma_coherent_ok(struct device *dev, dma_addr_t addr,
-               size_t size)
-{
-       u64 mask = DMA_BIT_MASK(32);
-
-       if (dev && dev->coherent_dma_mask)
-               mask = dev->coherent_dma_mask;
-       return addr + size - 1 <= mask;
-}
-
-static void *
-swiotlb_alloc_buffer(struct device *dev, size_t size, dma_addr_t *dma_handle,
-               unsigned long attrs)
-{
-       phys_addr_t phys_addr;
-
-       if (swiotlb_force == SWIOTLB_NO_FORCE)
-               goto out_warn;
-
-       phys_addr = swiotlb_tbl_map_single(dev,
-                       __phys_to_dma(dev, io_tlb_start),
-                       0, size, DMA_FROM_DEVICE, attrs);
-       if (phys_addr == SWIOTLB_MAP_ERROR)
-               goto out_warn;
-
-       *dma_handle = __phys_to_dma(dev, phys_addr);
-       if (!dma_coherent_ok(dev, *dma_handle, size))
-               goto out_unmap;
-
-       memset(phys_to_virt(phys_addr), 0, size);
-       return phys_to_virt(phys_addr);
-
-out_unmap:
-       dev_warn(dev, "hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n",
-               (unsigned long long)dev->coherent_dma_mask,
-               (unsigned long long)*dma_handle);
-
-       /*
-        * DMA_TO_DEVICE to avoid memcpy in unmap_single.
-        * DMA_ATTR_SKIP_CPU_SYNC is optional.
-        */
-       swiotlb_tbl_unmap_single(dev, phys_addr, size, DMA_TO_DEVICE,
-                       DMA_ATTR_SKIP_CPU_SYNC);
-out_warn:
-       if (!(attrs & DMA_ATTR_NO_WARN) && printk_ratelimit()) {
-               dev_warn(dev,
-                       "swiotlb: coherent allocation failed, size=%zu\n",
-                       size);
-               dump_stack();
-       }
-       return NULL;
-}
-
-static bool swiotlb_free_buffer(struct device *dev, size_t size,
-               dma_addr_t dma_addr)
-{
-       phys_addr_t phys_addr = dma_to_phys(dev, dma_addr);
-
-       WARN_ON_ONCE(irqs_disabled());
-
-       if (!is_swiotlb_buffer(phys_addr))
-               return false;
-
-       /*
-        * DMA_TO_DEVICE to avoid memcpy in swiotlb_tbl_unmap_single.
-        * DMA_ATTR_SKIP_CPU_SYNC is optional.
-        */
-       swiotlb_tbl_unmap_single(dev, phys_addr, size, DMA_TO_DEVICE,
-                                DMA_ATTR_SKIP_CPU_SYNC);
-       return true;
-}
-
-static void
-swiotlb_full(struct device *dev, size_t size, enum dma_data_direction dir,
-            int do_panic)
-{
-       if (swiotlb_force == SWIOTLB_NO_FORCE)
-               return;
-
-       /*
-        * Ran out of IOMMU space for this operation. This is very bad.
-        * Unfortunately the drivers cannot handle this operation properly.
-        * unless they check for dma_mapping_error (most don't)
-        * When the mapping is small enough return a static buffer to limit
-        * the damage, or panic when the transfer is too big.
-        */
-       dev_err_ratelimited(dev, "DMA: Out of SW-IOMMU space for %zu bytes\n",
-                           size);
-
-       if (size <= io_tlb_overflow || !do_panic)
-               return;
-
-       if (dir == DMA_BIDIRECTIONAL)
-               panic("DMA: Random memory could be DMA accessed\n");
-       if (dir == DMA_FROM_DEVICE)
-               panic("DMA: Random memory could be DMA written\n");
-       if (dir == DMA_TO_DEVICE)
-               panic("DMA: Random memory could be DMA read\n");
-}
-
-/*
- * Map a single buffer of the indicated size for DMA in streaming mode.  The
- * physical address to use is returned.
- *
- * Once the device is given the dma address, the device owns this memory until
- * either swiotlb_unmap_page or swiotlb_dma_sync_single is performed.
- */
-dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
-                           unsigned long offset, size_t size,
-                           enum dma_data_direction dir,
-                           unsigned long attrs)
-{
-       phys_addr_t map, phys = page_to_phys(page) + offset;
-       dma_addr_t dev_addr = phys_to_dma(dev, phys);
-
-       BUG_ON(dir == DMA_NONE);
-       /*
-        * If the address happens to be in the device's DMA window,
-        * we can safely return the device addr and not worry about bounce
-        * buffering it.
-        */
-       if (dma_capable(dev, dev_addr, size) && swiotlb_force != SWIOTLB_FORCE)
-               return dev_addr;
-
-       trace_swiotlb_bounced(dev, dev_addr, size, swiotlb_force);
-
-       /* Oh well, have to allocate and map a bounce buffer. */
-       map = map_single(dev, phys, size, dir, attrs);
-       if (map == SWIOTLB_MAP_ERROR) {
-               swiotlb_full(dev, size, dir, 1);
-               return __phys_to_dma(dev, io_tlb_overflow_buffer);
-       }
-
-       dev_addr = __phys_to_dma(dev, map);
-
-       /* Ensure that the address returned is DMA'ble */
-       if (dma_capable(dev, dev_addr, size))
-               return dev_addr;
-
-       attrs |= DMA_ATTR_SKIP_CPU_SYNC;
-       swiotlb_tbl_unmap_single(dev, map, size, dir, attrs);
-
-       return __phys_to_dma(dev, io_tlb_overflow_buffer);
-}
-
-/*
- * Unmap a single streaming mode DMA translation.  The dma_addr and size must
- * match what was provided for in a previous swiotlb_map_page call.  All
- * other usages are undefined.
- *
- * After this call, reads by the cpu to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-static void unmap_single(struct device *hwdev, dma_addr_t dev_addr,
-                        size_t size, enum dma_data_direction dir,
-                        unsigned long attrs)
-{
-       phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
-
-       BUG_ON(dir == DMA_NONE);
-
-       if (is_swiotlb_buffer(paddr)) {
-               swiotlb_tbl_unmap_single(hwdev, paddr, size, dir, attrs);
-               return;
-       }
-
-       if (dir != DMA_FROM_DEVICE)
-               return;
-
-       /*
-        * phys_to_virt doesn't work with hihgmem page but we could
-        * call dma_mark_clean() with hihgmem page here. However, we
-        * are fine since dma_mark_clean() is null on POWERPC. We can
-        * make dma_mark_clean() take a physical address if necessary.
-        */
-       dma_mark_clean(phys_to_virt(paddr), size);
-}
-
-void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
-                       size_t size, enum dma_data_direction dir,
-                       unsigned long attrs)
-{
-       unmap_single(hwdev, dev_addr, size, dir, attrs);
-}
-
-/*
- * Make physical memory consistent for a single streaming mode DMA translation
- * after a transfer.
- *
- * If you perform a swiotlb_map_page() but wish to interrogate the buffer
- * using the cpu, yet do not wish to teardown the dma mapping, you must
- * call this function before doing so.  At the next point you give the dma
- * address back to the card, you must first perform a
- * swiotlb_dma_sync_for_device, and then the device again owns the buffer
- */
-static void
-swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
-                   size_t size, enum dma_data_direction dir,
-                   enum dma_sync_target target)
-{
-       phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
-
-       BUG_ON(dir == DMA_NONE);
-
-       if (is_swiotlb_buffer(paddr)) {
-               swiotlb_tbl_sync_single(hwdev, paddr, size, dir, target);
-               return;
-       }
-
-       if (dir != DMA_FROM_DEVICE)
-               return;
-
-       dma_mark_clean(phys_to_virt(paddr), size);
-}
-
-void
-swiotlb_sync_single_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
-                           size_t size, enum dma_data_direction dir)
-{
-       swiotlb_sync_single(hwdev, dev_addr, size, dir, SYNC_FOR_CPU);
-}
-
-void
-swiotlb_sync_single_for_device(struct device *hwdev, dma_addr_t dev_addr,
-                              size_t size, enum dma_data_direction dir)
-{
-       swiotlb_sync_single(hwdev, dev_addr, size, dir, SYNC_FOR_DEVICE);
-}
-
-/*
- * Map a set of buffers described by scatterlist in streaming mode for DMA.
- * This is the scatter-gather version of the above swiotlb_map_page
- * interface.  Here the scatter gather list elements are each tagged with the
- * appropriate dma address and length.  They are obtained via
- * sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of
- *       DMA address/length pairs than there are SG table elements.
- *       (for example via virtual mapping capabilities)
- *       The routine returns the number of addr/length pairs actually
- *       used, at most nents.
- *
- * Device ownership issues as mentioned above for swiotlb_map_page are the
- * same here.
- */
-int
-swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
-                    enum dma_data_direction dir, unsigned long attrs)
-{
-       struct scatterlist *sg;
-       int i;
-
-       BUG_ON(dir == DMA_NONE);
-
-       for_each_sg(sgl, sg, nelems, i) {
-               phys_addr_t paddr = sg_phys(sg);
-               dma_addr_t dev_addr = phys_to_dma(hwdev, paddr);
-
-               if (swiotlb_force == SWIOTLB_FORCE ||
-                   !dma_capable(hwdev, dev_addr, sg->length)) {
-                       phys_addr_t map = map_single(hwdev, sg_phys(sg),
-                                                    sg->length, dir, attrs);
-                       if (map == SWIOTLB_MAP_ERROR) {
-                               /* Don't panic here, we expect map_sg users
-                                  to do proper error handling. */
-                               swiotlb_full(hwdev, sg->length, dir, 0);
-                               attrs |= DMA_ATTR_SKIP_CPU_SYNC;
-                               swiotlb_unmap_sg_attrs(hwdev, sgl, i, dir,
-                                                      attrs);
-                               sg_dma_len(sgl) = 0;
-                               return 0;
-                       }
-                       sg->dma_address = __phys_to_dma(hwdev, map);
-               } else
-                       sg->dma_address = dev_addr;
-               sg_dma_len(sg) = sg->length;
-       }
-       return nelems;
-}
-
-/*
- * Unmap a set of streaming mode DMA translations.  Again, cpu read rules
- * concerning calls here are the same as for swiotlb_unmap_page() above.
- */
-void
-swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
-                      int nelems, enum dma_data_direction dir,
-                      unsigned long attrs)
-{
-       struct scatterlist *sg;
-       int i;
-
-       BUG_ON(dir == DMA_NONE);
-
-       for_each_sg(sgl, sg, nelems, i)
-               unmap_single(hwdev, sg->dma_address, sg_dma_len(sg), dir,
-                            attrs);
-}
-
-/*
- * Make physical memory consistent for a set of streaming mode DMA translations
- * after a transfer.
- *
- * The same as swiotlb_sync_single_* but for a scatter-gather list, same rules
- * and usage.
- */
-static void
-swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sgl,
-               int nelems, enum dma_data_direction dir,
-               enum dma_sync_target target)
-{
-       struct scatterlist *sg;
-       int i;
-
-       for_each_sg(sgl, sg, nelems, i)
-               swiotlb_sync_single(hwdev, sg->dma_address,
-                                   sg_dma_len(sg), dir, target);
-}
-
-void
-swiotlb_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg,
-                       int nelems, enum dma_data_direction dir)
-{
-       swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_CPU);
-}
-
-void
-swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
-                          int nelems, enum dma_data_direction dir)
-{
-       swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_DEVICE);
-}
-
-int
-swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr)
-{
-       return (dma_addr == __phys_to_dma(hwdev, io_tlb_overflow_buffer));
-}
-
-/*
- * Return whether the given device DMA address mask can be supported
- * properly.  For example, if your device can only drive the low 24-bits
- * during bus mastering, then you would pass 0x00ffffff as the mask to
- * this function.
- */
-int
-swiotlb_dma_supported(struct device *hwdev, u64 mask)
-{
-       return __phys_to_dma(hwdev, io_tlb_end - 1) <= mask;
-}
-
-void *swiotlb_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
-               gfp_t gfp, unsigned long attrs)
-{
-       void *vaddr;
-
-       /* temporary workaround: */
-       if (gfp & __GFP_NOWARN)
-               attrs |= DMA_ATTR_NO_WARN;
-
-       /*
-        * Don't print a warning when the first allocation attempt fails.
-        * swiotlb_alloc_coherent() will print a warning when the DMA memory
-        * allocation ultimately failed.
-        */
-       gfp |= __GFP_NOWARN;
-
-       vaddr = dma_direct_alloc(dev, size, dma_handle, gfp, attrs);
-       if (!vaddr)
-               vaddr = swiotlb_alloc_buffer(dev, size, dma_handle, attrs);
-       return vaddr;
-}
-
-void swiotlb_free(struct device *dev, size_t size, void *vaddr,
-               dma_addr_t dma_addr, unsigned long attrs)
-{
-       if (!swiotlb_free_buffer(dev, size, dma_addr))
-               dma_direct_free(dev, size, vaddr, dma_addr, attrs);
-}
-
-const struct dma_map_ops swiotlb_dma_ops = {
-       .mapping_error          = swiotlb_dma_mapping_error,
-       .alloc                  = swiotlb_alloc,
-       .free                   = swiotlb_free,
-       .sync_single_for_cpu    = swiotlb_sync_single_for_cpu,
-       .sync_single_for_device = swiotlb_sync_single_for_device,
-       .sync_sg_for_cpu        = swiotlb_sync_sg_for_cpu,
-       .sync_sg_for_device     = swiotlb_sync_sg_for_device,
-       .map_sg                 = swiotlb_map_sg_attrs,
-       .unmap_sg               = swiotlb_unmap_sg_attrs,
-       .map_page               = swiotlb_map_page,
-       .unmap_page             = swiotlb_unmap_page,
-       .dma_supported          = dma_direct_supported,
-};