Commit 671df189 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'dma-mapping-5.4' of git://git.infradead.org/users/hch/dma-mapping

Pull dma-mapping updates from Christoph Hellwig:

 - add dma-mapping and block layer helpers to take care of IOMMU merging
   for mmc plus subsequent fixups (Yoshihiro Shimoda)

 - rework handling of the pgprot bits for remapping (me)

 - take care of the dma direct infrastructure for swiotlb-xen (me)

 - improve the dma noncoherent remapping infrastructure (me)

 - better defaults for ->mmap, ->get_sgtable and ->get_required_mask
   (me)

 - cleanup mmaping of coherent DMA allocations (me)

 - various misc cleanups (Andy Shevchenko, me)

* tag 'dma-mapping-5.4' of git://git.infradead.org/users/hch/dma-mapping: (41 commits)
  mmc: renesas_sdhi_internal_dmac: Add MMC_CAP2_MERGE_CAPABLE
  mmc: queue: Fix bigger segments usage
  arm64: use asm-generic/dma-mapping.h
  swiotlb-xen: merge xen_unmap_single into xen_swiotlb_unmap_page
  swiotlb-xen: simplify cache maintainance
  swiotlb-xen: use the same foreign page check everywhere
  swiotlb-xen: remove xen_swiotlb_dma_mmap and xen_swiotlb_dma_get_sgtable
  xen: remove the exports for xen_{create,destroy}_contiguous_region
  xen/arm: remove xen_dma_ops
  xen/arm: simplify dma_cache_maint
  xen/arm: use dev_is_dma_coherent
  xen/arm: consolidate page-coherent.h
  xen/arm: use dma-noncoherent.h calls for xen-swiotlb cache maintainance
  arm: remove wrappers for the generic dma remap helpers
  dma-mapping: introduce a dma_common_find_pages helper
  dma-mapping: always use VM_DMA_COHERENT for generic DMA remap
  vmalloc: lift the arm flag for coherent mappings to common code
  dma-mapping: provide a better default ->get_required_mask
  dma-mapping: remove the dma_declare_coherent_memory export
  remoteproc: don't allow modular build
  ...
parents c9fe5630 c7d9eccb
...@@ -204,6 +204,14 @@ Returns the maximum size of a mapping for the device. The size parameter ...@@ -204,6 +204,14 @@ Returns the maximum size of a mapping for the device. The size parameter
of the mapping functions like dma_map_single(), dma_map_page() and of the mapping functions like dma_map_single(), dma_map_page() and
others should not be larger than the returned value. others should not be larger than the returned value.
::
unsigned long
dma_get_merge_boundary(struct device *dev);
Returns the DMA merge boundary. If the device cannot merge any the DMA address
segments, the function returns 0.
Part Id - Streaming DMA mappings Part Id - Streaming DMA mappings
-------------------------------- --------------------------------
...@@ -595,17 +603,6 @@ For reasons of efficiency, most platforms choose to track the declared ...@@ -595,17 +603,6 @@ For reasons of efficiency, most platforms choose to track the declared
region only at the granularity of a page. For smaller allocations, region only at the granularity of a page. For smaller allocations,
you should use the dma_pool() API. you should use the dma_pool() API.
::
void
dma_release_declared_memory(struct device *dev)
Remove the memory region previously declared from the system. This
API performs *no* in-use checking for this region and will return
unconditionally having removed all the required structures. It is the
driver's job to ensure that no parts of this memory region are
currently in use.
Part III - Debug drivers use of the DMA-API Part III - Debug drivers use of the DMA-API
------------------------------------------- -------------------------------------------
......
...@@ -230,7 +230,7 @@ IOMMU (input/output memory management unit) ...@@ -230,7 +230,7 @@ IOMMU (input/output memory management unit)
=========================================== ===========================================
Multiple x86-64 PCI-DMA mapping implementations exist, for example: Multiple x86-64 PCI-DMA mapping implementations exist, for example:
1. <lib/dma-direct.c>: use no hardware/software IOMMU at all 1. <kernel/dma/direct.c>: use no hardware/software IOMMU at all
(e.g. because you have < 3 GB memory). (e.g. because you have < 3 GB memory).
Kernel boot message: "PCI-DMA: Disabling IOMMU" Kernel boot message: "PCI-DMA: Disabling IOMMU"
......
...@@ -793,9 +793,6 @@ config COMPAT_32BIT_TIME ...@@ -793,9 +793,6 @@ config COMPAT_32BIT_TIME
This is relevant on all 32-bit architectures, and 64-bit architectures This is relevant on all 32-bit architectures, and 64-bit architectures
as part of compat syscall handling. as part of compat syscall handling.
config ARCH_NO_COHERENT_DMA_MMAP
bool
config ARCH_NO_PREEMPT config ARCH_NO_PREEMPT
bool bool
......
...@@ -955,5 +955,7 @@ const struct dma_map_ops alpha_pci_ops = { ...@@ -955,5 +955,7 @@ const struct dma_map_ops alpha_pci_ops = {
.map_sg = alpha_pci_map_sg, .map_sg = alpha_pci_map_sg,
.unmap_sg = alpha_pci_unmap_sg, .unmap_sg = alpha_pci_unmap_sg,
.dma_supported = alpha_pci_supported, .dma_supported = alpha_pci_supported,
.mmap = dma_common_mmap,
.get_sgtable = dma_common_get_sgtable,
}; };
EXPORT_SYMBOL(alpha_pci_ops); EXPORT_SYMBOL(alpha_pci_ops);
...@@ -104,9 +104,3 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, ...@@ -104,9 +104,3 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
dev_info(dev, "use %scoherent DMA ops\n", dev_info(dev, "use %scoherent DMA ops\n",
dev->dma_coherent ? "" : "non"); dev->dma_coherent ? "" : "non");
} }
static int __init atomic_pool_init(void)
{
return dma_atomic_pool_init(GFP_KERNEL, pgprot_noncached(PAGE_KERNEL));
}
postcore_initcall(atomic_pool_init);
...@@ -8,7 +8,7 @@ config ARM ...@@ -8,7 +8,7 @@ config ARM
select ARCH_HAS_DEBUG_VIRTUAL if MMU select ARCH_HAS_DEBUG_VIRTUAL if MMU
select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_DMA_COHERENT_TO_PFN if SWIOTLB select ARCH_HAS_DMA_COHERENT_TO_PFN if SWIOTLB
select ARCH_HAS_DMA_MMAP_PGPROT if SWIOTLB select ARCH_HAS_DMA_WRITE_COMBINE if !ARM_DMA_MEM_BUFFERABLE
select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_FORTIFY_SOURCE
select ARCH_HAS_KEEPINITRD select ARCH_HAS_KEEPINITRD
......
...@@ -14,9 +14,6 @@ struct dev_archdata { ...@@ -14,9 +14,6 @@ struct dev_archdata {
#endif #endif
#ifdef CONFIG_ARM_DMA_USE_IOMMU #ifdef CONFIG_ARM_DMA_USE_IOMMU
struct dma_iommu_mapping *mapping; struct dma_iommu_mapping *mapping;
#endif
#ifdef CONFIG_XEN
const struct dma_map_ops *dev_dma_ops;
#endif #endif
unsigned int dma_coherent:1; unsigned int dma_coherent:1;
unsigned int dma_ops_setup:1; unsigned int dma_ops_setup:1;
......
...@@ -91,12 +91,6 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr) ...@@ -91,12 +91,6 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
} }
#endif #endif
/* do not use this function in a driver */
static inline bool is_device_dma_coherent(struct device *dev)
{
return dev->archdata.dma_coherent;
}
/** /**
* arm_dma_alloc - allocate consistent memory for DMA * arm_dma_alloc - allocate consistent memory for DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
......
...@@ -62,7 +62,6 @@ typedef pte_t *pte_addr_t; ...@@ -62,7 +62,6 @@ typedef pte_t *pte_addr_t;
*/ */
#define pgprot_noncached(prot) (prot) #define pgprot_noncached(prot) (prot)
#define pgprot_writecombine(prot) (prot) #define pgprot_writecombine(prot) (prot)
#define pgprot_dmacoherent(prot) (prot)
#define pgprot_device(prot) (prot) #define pgprot_device(prot) (prot)
......
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_ARM_XEN_PAGE_COHERENT_H
#define _ASM_ARM_XEN_PAGE_COHERENT_H
#include <linux/dma-mapping.h>
#include <asm/page.h>
#include <xen/arm/page-coherent.h> #include <xen/arm/page-coherent.h>
static inline const struct dma_map_ops *xen_get_dma_ops(struct device *dev)
{
if (dev && dev->archdata.dev_dma_ops)
return dev->archdata.dev_dma_ops;
return get_arch_dma_ops(NULL);
}
static inline void *xen_alloc_coherent_pages(struct device *hwdev, size_t size,
dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs)
{
return xen_get_dma_ops(hwdev)->alloc(hwdev, size, dma_handle, flags, attrs);
}
static inline void xen_free_coherent_pages(struct device *hwdev, size_t size,
void *cpu_addr, dma_addr_t dma_handle, unsigned long attrs)
{
xen_get_dma_ops(hwdev)->free(hwdev, size, cpu_addr, dma_handle, attrs);
}
static inline void xen_dma_map_page(struct device *hwdev, struct page *page,
dma_addr_t dev_addr, unsigned long offset, size_t size,
enum dma_data_direction dir, unsigned long attrs)
{
unsigned long page_pfn = page_to_xen_pfn(page);
unsigned long dev_pfn = XEN_PFN_DOWN(dev_addr);
unsigned long compound_pages =
(1<<compound_order(page)) * XEN_PFN_PER_PAGE;
bool local = (page_pfn <= dev_pfn) &&
(dev_pfn - page_pfn < compound_pages);
/*
* Dom0 is mapped 1:1, while the Linux page can span across
* multiple Xen pages, it's not possible for it to contain a
* mix of local and foreign Xen pages. So if the first xen_pfn
* == mfn the page is local otherwise it's a foreign page
* grant-mapped in dom0. If the page is local we can safely
* call the native dma_ops function, otherwise we call the xen
* specific function.
*/
if (local)
xen_get_dma_ops(hwdev)->map_page(hwdev, page, offset, size, dir, attrs);
else
__xen_dma_map_page(hwdev, page, dev_addr, offset, size, dir, attrs);
}
static inline void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
size_t size, enum dma_data_direction dir, unsigned long attrs)
{
unsigned long pfn = PFN_DOWN(handle);
/*
* Dom0 is mapped 1:1, while the Linux page can be spanned accross
* multiple Xen page, it's not possible to have a mix of local and
* foreign Xen page. Dom0 is mapped 1:1, so calling pfn_valid on a
* foreign mfn will always return false. If the page is local we can
* safely call the native dma_ops function, otherwise we call the xen
* specific function.
*/
if (pfn_valid(pfn)) {
if (xen_get_dma_ops(hwdev)->unmap_page)
xen_get_dma_ops(hwdev)->unmap_page(hwdev, handle, size, dir, attrs);
} else
__xen_dma_unmap_page(hwdev, handle, size, dir, attrs);
}
static inline void xen_dma_sync_single_for_cpu(struct device *hwdev,
dma_addr_t handle, size_t size, enum dma_data_direction dir)
{
unsigned long pfn = PFN_DOWN(handle);
if (pfn_valid(pfn)) {
if (xen_get_dma_ops(hwdev)->sync_single_for_cpu)
xen_get_dma_ops(hwdev)->sync_single_for_cpu(hwdev, handle, size, dir);
} else
__xen_dma_sync_single_for_cpu(hwdev, handle, size, dir);
}
static inline void xen_dma_sync_single_for_device(struct device *hwdev,
dma_addr_t handle, size_t size, enum dma_data_direction dir)
{
unsigned long pfn = PFN_DOWN(handle);
if (pfn_valid(pfn)) {
if (xen_get_dma_ops(hwdev)->sync_single_for_device)
xen_get_dma_ops(hwdev)->sync_single_for_device(hwdev, handle, size, dir);
} else
__xen_dma_sync_single_for_device(hwdev, handle, size, dir);
}
#endif /* _ASM_ARM_XEN_PAGE_COHERENT_H */
...@@ -68,8 +68,9 @@ static int arm_nommu_dma_mmap(struct device *dev, struct vm_area_struct *vma, ...@@ -68,8 +68,9 @@ static int arm_nommu_dma_mmap(struct device *dev, struct vm_area_struct *vma,
if (dma_mmap_from_global_coherent(vma, cpu_addr, size, &ret)) if (dma_mmap_from_global_coherent(vma, cpu_addr, size, &ret))
return ret; return ret;
if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size, attrs); return ret;
return -ENXIO;
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/dma-direct.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dma-noncoherent.h> #include <linux/dma-noncoherent.h>
#include <linux/dma-contiguous.h> #include <linux/dma-contiguous.h>
...@@ -35,6 +36,7 @@ ...@@ -35,6 +36,7 @@
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/system_info.h> #include <asm/system_info.h>
#include <asm/dma-contiguous.h> #include <asm/dma-contiguous.h>
#include <xen/swiotlb-xen.h>
#include "dma.h" #include "dma.h"
#include "mm.h" #include "mm.h"
...@@ -192,6 +194,7 @@ const struct dma_map_ops arm_dma_ops = { ...@@ -192,6 +194,7 @@ const struct dma_map_ops arm_dma_ops = {
.sync_sg_for_cpu = arm_dma_sync_sg_for_cpu, .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
.sync_sg_for_device = arm_dma_sync_sg_for_device, .sync_sg_for_device = arm_dma_sync_sg_for_device,
.dma_supported = arm_dma_supported, .dma_supported = arm_dma_supported,
.get_required_mask = dma_direct_get_required_mask,
}; };
EXPORT_SYMBOL(arm_dma_ops); EXPORT_SYMBOL(arm_dma_ops);
...@@ -212,6 +215,7 @@ const struct dma_map_ops arm_coherent_dma_ops = { ...@@ -212,6 +215,7 @@ const struct dma_map_ops arm_coherent_dma_ops = {
.map_sg = arm_dma_map_sg, .map_sg = arm_dma_map_sg,
.map_resource = dma_direct_map_resource, .map_resource = dma_direct_map_resource,
.dma_supported = arm_dma_supported, .dma_supported = arm_dma_supported,
.get_required_mask = dma_direct_get_required_mask,
}; };
EXPORT_SYMBOL(arm_coherent_dma_ops); EXPORT_SYMBOL(arm_coherent_dma_ops);
...@@ -336,25 +340,6 @@ static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp, ...@@ -336,25 +340,6 @@ static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
pgprot_t prot, struct page **ret_page, pgprot_t prot, struct page **ret_page,
const void *caller, bool want_vaddr); const void *caller, bool want_vaddr);
static void *
__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
const void *caller)
{
/*
* DMA allocation can be mapped to user space, so lets
* set VM_USERMAP flags too.
*/
return dma_common_contiguous_remap(page, size,
VM_ARM_DMA_CONSISTENT | VM_USERMAP,
prot, caller);
}
static void __dma_free_remap(void *cpu_addr, size_t size)
{
dma_common_free_remap(cpu_addr, size,
VM_ARM_DMA_CONSISTENT | VM_USERMAP);
}
#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K #define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
static struct gen_pool *atomic_pool __ro_after_init; static struct gen_pool *atomic_pool __ro_after_init;
...@@ -510,7 +495,7 @@ static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp, ...@@ -510,7 +495,7 @@ static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
if (!want_vaddr) if (!want_vaddr)
goto out; goto out;
ptr = __dma_alloc_remap(page, size, gfp, prot, caller); ptr = dma_common_contiguous_remap(page, size, prot, caller);
if (!ptr) { if (!ptr) {
__dma_free_buffer(page, size); __dma_free_buffer(page, size);
return NULL; return NULL;
...@@ -577,7 +562,7 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size, ...@@ -577,7 +562,7 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size,
goto out; goto out;
if (PageHighMem(page)) { if (PageHighMem(page)) {
ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, caller); ptr = dma_common_contiguous_remap(page, size, prot, caller);
if (!ptr) { if (!ptr) {
dma_release_from_contiguous(dev, page, count); dma_release_from_contiguous(dev, page, count);
return NULL; return NULL;
...@@ -597,7 +582,7 @@ static void __free_from_contiguous(struct device *dev, struct page *page, ...@@ -597,7 +582,7 @@ static void __free_from_contiguous(struct device *dev, struct page *page,
{ {
if (want_vaddr) { if (want_vaddr) {
if (PageHighMem(page)) if (PageHighMem(page))
__dma_free_remap(cpu_addr, size); dma_common_free_remap(cpu_addr, size);
else else
__dma_remap(page, size, PAGE_KERNEL); __dma_remap(page, size, PAGE_KERNEL);
} }
...@@ -689,7 +674,7 @@ static void *remap_allocator_alloc(struct arm_dma_alloc_args *args, ...@@ -689,7 +674,7 @@ static void *remap_allocator_alloc(struct arm_dma_alloc_args *args,
static void remap_allocator_free(struct arm_dma_free_args *args) static void remap_allocator_free(struct arm_dma_free_args *args)
{ {
if (args->want_vaddr) if (args->want_vaddr)
__dma_free_remap(args->cpu_addr, args->size); dma_common_free_remap(args->cpu_addr, args->size);
__dma_free_buffer(args->page, args->size); __dma_free_buffer(args->page, args->size);
} }
...@@ -877,17 +862,6 @@ static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_add ...@@ -877,17 +862,6 @@ static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_add
__arm_dma_free(dev, size, cpu_addr, handle, attrs, true); __arm_dma_free(dev, size, cpu_addr, handle, attrs, true);
} }
/*
* The whole dma_get_sgtable() idea is fundamentally unsafe - it seems
* that the intention is to allow exporting memory allocated via the
* coherent DMA APIs through the dma_buf API, which only accepts a
* scattertable. This presents a couple of problems:
* 1. Not all memory allocated via the coherent DMA APIs is backed by
* a struct page
* 2. Passing coherent DMA memory into the streaming APIs is not allowed
* as we will try to flush the memory through a different alias to that
* actually being used (and the flushes are redundant.)
*/
int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt, int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
void *cpu_addr, dma_addr_t handle, size_t size, void *cpu_addr, dma_addr_t handle, size_t size,
unsigned long attrs) unsigned long attrs)
...@@ -1132,10 +1106,6 @@ static const struct dma_map_ops *arm_get_dma_map_ops(bool coherent) ...@@ -1132,10 +1106,6 @@ static const struct dma_map_ops *arm_get_dma_map_ops(bool coherent)
* 32-bit DMA. * 32-bit DMA.
* Use the generic dma-direct / swiotlb ops code in that case, as that * Use the generic dma-direct / swiotlb ops code in that case, as that
* handles bounce buffering for us. * handles bounce buffering for us.
*
* Note: this checks CONFIG_ARM_LPAE instead of CONFIG_SWIOTLB as the
* latter is also selected by the Xen code, but that code for now relies
* on non-NULL dev_dma_ops. To be cleaned up later.
*/ */
if (IS_ENABLED(CONFIG_ARM_LPAE)) if (IS_ENABLED(CONFIG_ARM_LPAE))
return NULL; return NULL;
...@@ -1372,17 +1342,6 @@ static int __iommu_free_buffer(struct device *dev, struct page **pages, ...@@ -1372,17 +1342,6 @@ static int __iommu_free_buffer(struct device *dev, struct page **pages,
return 0; return 0;
} }
/*
* Create a CPU mapping for a specified pages
*/
static void *
__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot,
const void *caller)
{
return dma_common_pages_remap(pages, size,
VM_ARM_DMA_CONSISTENT | VM_USERMAP, prot, caller);
}
/* /*
* Create a mapping in device IO address space for specified pages * Create a mapping in device IO address space for specified pages
*/ */
...@@ -1455,18 +1414,13 @@ static struct page **__atomic_get_pages(void *addr) ...@@ -1455,18 +1414,13 @@ static struct page **__atomic_get_pages(void *addr)
static struct page **__iommu_get_pages(void *cpu_addr, unsigned long attrs) static struct page **__iommu_get_pages(void *cpu_addr, unsigned long attrs)
{ {
struct vm_struct *area;
if (__in_atomic_pool(cpu_addr, PAGE_SIZE)) if (__in_atomic_pool(cpu_addr, PAGE_SIZE))
return __atomic_get_pages(cpu_addr); return __atomic_get_pages(cpu_addr);
if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) if (attrs & DMA_ATTR_NO_KERNEL_MAPPING)
return cpu_addr; return cpu_addr;
area = find_vm_area(cpu_addr); return dma_common_find_pages(cpu_addr);
if (area && (area->flags & VM_ARM_DMA_CONSISTENT))
return area->pages;
return NULL;
} }
static void *__iommu_alloc_simple(struct device *dev, size_t size, gfp_t gfp, static void *__iommu_alloc_simple(struct device *dev, size_t size, gfp_t gfp,
...@@ -1539,7 +1493,7 @@ static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size, ...@@ -1539,7 +1493,7 @@ static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size,
if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) if (attrs & DMA_ATTR_NO_KERNEL_MAPPING)
return pages; return pages;
addr = __iommu_alloc_remap(pages, size, gfp, prot, addr = dma_common_pages_remap(pages, size, prot,
__builtin_return_address(0)); __builtin_return_address(0));
if (!addr) if (!addr)
goto err_mapping; goto err_mapping;
...@@ -1622,10 +1576,8 @@ void __arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, ...@@ -1622,10 +1576,8 @@ void __arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
return; return;
} }
if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0) { if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0)
dma_common_free_remap(cpu_addr, size, dma_common_free_remap(cpu_addr, size);
VM_ARM_DMA_CONSISTENT | VM_USERMAP);
}
__iommu_remove_mapping(dev, handle, size); __iommu_remove_mapping(dev, handle, size);
__iommu_free_buffer(dev, pages, size, attrs); __iommu_free_buffer(dev, pages, size, attrs);
...@@ -2363,10 +2315,8 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, ...@@ -2363,10 +2315,8 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
set_dma_ops(dev, dma_ops); set_dma_ops(dev, dma_ops);
#ifdef CONFIG_XEN #ifdef CONFIG_XEN
if (xen_initial_domain()) { if (xen_initial_domain())
dev->archdata.dev_dma_ops = dev->dma_ops; dev->dma_ops = &xen_swiotlb_dma_ops;
dev->dma_ops = xen_dma_ops;
}
#endif #endif
dev->archdata.dma_ops_setup = true; dev->archdata.dma_ops_setup = true;
} }
...@@ -2402,12 +2352,6 @@ long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr, ...@@ -2402,12 +2352,6 @@ long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
return dma_to_pfn(dev, dma_addr); return dma_to_pfn(dev, dma_addr);
} }
pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
unsigned long attrs)
{
return __get_dma_pgprot(attrs, prot);
}
void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
gfp_t gfp, unsigned long attrs) gfp_t gfp, unsigned long attrs)
{ {
......
...@@ -70,9 +70,6 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page ...@@ -70,9 +70,6 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page
#define VM_ARM_MTYPE(mt) ((mt) << 20) #define VM_ARM_MTYPE(mt) ((mt) << 20)
#define VM_ARM_MTYPE_MASK (0x1f << 20) #define VM_ARM_MTYPE_MASK (0x1f << 20)
/* consistent regions used by dma_alloc_attrs() */
#define VM_ARM_DMA_CONSISTENT 0x20000000
struct static_vm { struct static_vm {
struct vm_struct vm; struct vm_struct vm;
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/dma-mapping.h> #include <linux/dma-noncoherent.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/export.h> #include <linux/export.h>
...@@ -35,105 +35,56 @@ unsigned long xen_get_swiotlb_free_pages(unsigned int order) ...@@ -35,105 +35,56 @@ unsigned long xen_get_swiotlb_free_pages(unsigned int order)
return __get_free_pages(flags, order); return __get_free_pages(flags, order);
} }
enum dma_cache_op {
DMA_UNMAP,
DMA_MAP,
};
static bool hypercall_cflush = false; static bool hypercall_cflush = false;
/* functions called by SWIOTLB */ /* buffers in highmem or foreign pages cannot cross page boundaries */
static void dma_cache_maint(dma_addr_t handle, size_t size, u32 op)
static void dma_cache_maint(dma_addr_t handle, unsigned long offset,
size_t size, enum dma_data_direction dir, enum dma_cache_op op)
{ {
struct gnttab_cache_flush cflush; struct gnttab_cache_flush cflush;
unsigned long xen_pfn;
size_t left = size;
xen_pfn = (handle >> XEN_PAGE_SHIFT) + offset / XEN_PAGE_SIZE; cflush.a.dev_bus_addr = handle & XEN_PAGE_MASK;
offset %= XEN_PAGE_SIZE; cflush.offset = xen_offset_in_page(handle);
cflush.op = op;
do { do {
size_t len = left; if (size + cflush.offset > XEN_PAGE_SIZE)
cflush.length = XEN_PAGE_SIZE - cflush.offset;
/* buffers in highmem or foreign pages cannot cross page else
* boundaries */ cflush.length = size;
if (len + offset > XEN_PAGE_SIZE)
len = XEN_PAGE_SIZE - offset;
cflush.op = 0;
cflush.a.dev_bus_addr = xen_pfn << XEN_PAGE_SHIFT;
cflush.offset = offset;
cflush.length = len;
if (op == DMA_UNMAP && dir != DMA_TO_DEVICE)
cflush.op = GNTTAB_CACHE_INVAL;
if (op == DMA_MAP) {
if (dir == DMA_FROM_DEVICE)
cflush.op = GNTTAB_CACHE_INVAL;
else
cflush.op = GNTTAB_CACHE_CLEAN;
}
if (cflush.op)
HYPERVISOR_grant_table_op(GNTTABOP_cache_flush, &cflush, 1);
offset = 0; HYPERVISOR_grant_table_op(GNTTABOP_cache_flush, &cflush, 1);
xen_pfn++;
left -= len;
} while (left);
}
static void __xen_dma_page_dev_to_cpu(struct device *hwdev, dma_addr_t handle, cflush.offset = 0;
size_t size, enum dma_data_direction dir) cflush.a.dev_bus_addr += cflush.length;
{ size -= cflush.length;
dma_cache_maint(handle & PAGE_MASK, handle & ~PAGE_MASK, size, dir, DMA_UNMAP); } while (size);
} }
static void __xen_dma_page_cpu_to_dev(struct device *hwdev, dma_addr_t handle, /*
size_t size, enum dma_data_direction dir) * Dom0 is mapped 1:1, and while the Linux page can span across multiple Xen
* pages, it is not possible for it to contain a mix of local and foreign Xen
* pages. Calling pfn_valid on a foreign mfn will always return false, so if
* pfn_valid returns true the pages is local and we can use the native
* dma-direct functions, otherwise we call the Xen specific version.
*/
void xen_dma_sync_for_cpu(struct device *dev, dma_addr_t handle,
phys_addr_t paddr, size_t size, enum dma_data_direction dir)
{ {
dma_cache_maint(handle & PAGE_MASK, handle & ~PAGE_MASK, size, dir, DMA_MAP); if (pfn_valid(PFN_DOWN(handle)))
arch_sync_dma_for_cpu(dev, paddr, size, dir);
else if (dir != DMA_TO_DEVICE)
dma_cache_maint(handle, size, GNTTAB_CACHE_INVAL);
} }
void __xen_dma_map_page(struct device *hwdev, struct page *page, void xen_dma_sync_for_device(struct device *dev, dma_addr_t handle,
dma_addr_t dev_addr, unsigned long offset, size_t size, phys_addr_t paddr, size_t size, enum dma_data_direction dir)
enum dma_data_direction dir, unsigned long attrs)
{ {
if (is_device_dma_coherent(hwdev)) if (pfn_valid(PFN_DOWN(handle)))
return; arch_sync_dma_for_device(dev, paddr, size, dir);
if (attrs & DMA_ATTR_SKIP_CPU_SYNC) else if (dir == DMA_FROM_DEVICE)
return; dma_cache_maint(handle, size, GNTTAB_CACHE_INVAL);
else
__xen_dma_page_cpu_to_dev(hwdev, dev_addr, size, dir); dma_cache_maint(handle, size, GNTTAB_CACHE_CLEAN);
}
void __xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
size_t size, enum dma_data_direction dir,
unsigned long attrs)
{
if (is_device_dma_coherent(hwdev))
return;
if (attrs & DMA_ATTR_SKIP_CPU_SYNC)
return;
__xen_dma_page_dev_to_cpu(hwdev, handle, size, dir);
}
void __xen_dma_sync_single_for_cpu(struct device *hwdev,
dma_addr_t handle, size_t size, enum dma_data_direction dir)
{
if (is_device_dma_coherent(hwdev))
return;
__xen_dma_page_dev_to_cpu(hwdev, handle, size, dir);
}
void __xen_dma_sync_single_for_device(struct device *hwdev,
dma_addr_t handle, size_t size, enum dma_data_direction dir)
{
if (is_device_dma_coherent(hwdev))
return;
__xen_dma_page_cpu_to_dev(hwdev, handle, size, dir);
} }
bool xen_arch_need_swiotlb(struct device *dev, bool xen_arch_need_swiotlb(struct device *dev,
...@@ -159,7 +110,7 @@ bool xen_arch_need_swiotlb(struct device *dev, ...@@ -159,7 +110,7 @@ bool xen_arch_need_swiotlb(struct device *dev,
* memory and we are not able to flush the cache. * memory and we are not able to flush the cache.
*/ */
return (!hypercall_cflush && (xen_pfn != bfn) && return (!hypercall_cflush && (xen_pfn != bfn) &&
!is_device_dma_coherent(dev)); !dev_is_dma_coherent(dev));
} }
int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order, int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
...@@ -173,16 +124,11 @@ int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order, ...@@ -173,16 +124,11 @@ int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
*dma_handle = pstart; *dma_handle = pstart;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(xen_create_contiguous_region);
void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order) void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order)
{ {
return; return;
} }
EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region);
const struct dma_map_ops *xen_dma_ops;
EXPORT_SYMBOL(xen_dma_ops);
int __init xen_mm_init(void) int __init xen_mm_init(void)
{ {
...@@ -190,7 +136,6 @@ int __init xen_mm_init(void) ...@@ -190,7 +136,6 @@ int __init xen_mm_init(void)
if (!xen_initial_domain()) if (!xen_initial_domain())
return 0; return 0;
xen_swiotlb_init(1, false); xen_swiotlb_init(1, false);
xen_dma_ops = &xen_swiotlb_dma_ops;
cflush.op = 0; cflush.op = 0;
cflush.a.dev_bus_addr = 0; cflush.a.dev_bus_addr = 0;
......
...@@ -13,7 +13,6 @@ config ARM64 ...@@ -13,7 +13,6 @@ config ARM64
select ARCH_HAS_DEBUG_VIRTUAL select ARCH_HAS_DEBUG_VIRTUAL
select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_DMA_COHERENT_TO_PFN select ARCH_HAS_DMA_COHERENT_TO_PFN
select ARCH_HAS_DMA_MMAP_PGPROT
select ARCH_HAS_DMA_PREP_COHERENT select ARCH_HAS_DMA_PREP_COHERENT
select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_ELF_RANDOMIZE
......
...@@ -4,6 +4,7 @@ generic-y += delay.h ...@@ -4,6 +4,7 @@ generic-y += delay.h
generic-y += div64.h generic-y += div64.h
generic-y += dma.h generic-y += dma.h
generic-y += dma-contiguous.h generic-y += dma-contiguous.h
generic-y += dma-mapping.h
generic-y += early_ioremap.h generic-y += early_ioremap.h
generic-y += emergency-restart.h generic-y += emergency-restart.h
generic-y += hw_irq.h generic-y += hw_irq.h
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 ARM Ltd.
*/
#ifndef __ASM_DMA_MAPPING_H
#define __ASM_DMA_MAPPING_H
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <xen/xen.h>
#include <asm/xen/hypervisor.h>
static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus)
{
return NULL;
}
/*
* Do not use this function in a driver, it is only provided for
* arch/arm/mm/xen.c, which is used by arm64 as well.
*/
static inline bool is_device_dma_coherent(struct device *dev)
{
return dev->dma_coherent;
}
#endif /* __ASM_DMA_MAPPING_H */
...@@ -437,6 +437,18 @@ static inline pmd_t pmd_mkdevmap(pmd_t pmd) ...@@ -437,6 +437,18 @@ static inline pmd_t pmd_mkdevmap(pmd_t pmd)
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN) __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
#define pgprot_device(prot) \ #define pgprot_device(prot) \
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN) __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN)
/*
* DMA allocations for non-coherent devices use what the Arm architecture calls
* "Normal non-cacheable" memory, which permits speculation, unaligned accesses
* and merging of writes. This is different from "Device-nGnR[nE]" memory which
* is intended for MMIO and thus forbids speculation, preserves access size,
* requires strict alignment and can also force write responses to come from the
* endpoint.
*/
#define pgprot_dmacoherent(prot) \
__pgprot_modify(prot, PTE_ATTRINDX_MASK, \
PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
#define __HAVE_PHYS_MEM_ACCESS_PROT #define __HAVE_PHYS_MEM_ACCESS_PROT
struct file; struct file;
extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
......
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_ARM64_XEN_PAGE_COHERENT_H
#define _ASM_ARM64_XEN_PAGE_COHERENT_H
#include <linux/dma-mapping.h>
#include <asm/page.h>
#include <xen/arm/page-coherent.h> #include <xen/arm/page-coherent.h>
static inline void *xen_alloc_coherent_pages(struct device *hwdev, size_t size,
dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs)
{
return dma_direct_alloc(hwdev, size, dma_handle, flags, attrs);
}
static inline void xen_free_coherent_pages(struct device *hwdev, size_t size,
void *cpu_addr, dma_addr_t dma_handle, unsigned long attrs)
{
dma_direct_free(hwdev, size, cpu_addr, dma_handle, attrs);
}
static inline void xen_dma_sync_single_for_cpu(struct device *hwdev,
dma_addr_t handle, size_t size, enum dma_data_direction dir)
{
unsigned long pfn = PFN_DOWN(handle);
if (pfn_valid(pfn))
dma_direct_sync_single_for_cpu(hwdev, handle, size, dir);
else
__xen_dma_sync_single_for_cpu(hwdev, handle, size, dir);
}
static inline void xen_dma_sync_single_for_device(struct device *hwdev,
dma_addr_t handle, size_t size, enum dma_data_direction dir)
{
unsigned long pfn = PFN_DOWN(handle);
if (pfn_valid(pfn))
dma_direct_sync_single_for_device(hwdev, handle, size, dir);
else
__xen_dma_sync_single_for_device(hwdev, handle, size, dir);
}
static inline void xen_dma_map_page(struct device *hwdev, struct page *page,
dma_addr_t dev_addr, unsigned long offset, size_t size,
enum dma_data_direction dir, unsigned long attrs)
{
unsigned long page_pfn = page_to_xen_pfn(page);
unsigned long dev_pfn = XEN_PFN_DOWN(dev_addr);
unsigned long compound_pages =
(1<<compound_order(page)) * XEN_PFN_PER_PAGE;
bool local = (page_pfn <= dev_pfn) &&
(dev_pfn - page_pfn < compound_pages);
if (local)
dma_direct_map_page(hwdev, page, offset, size, dir, attrs);
else
__xen_dma_map_page(hwdev, page, dev_addr, offset, size, dir, attrs);
}
static inline void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
size_t size, enum dma_data_direction dir, unsigned long attrs)
{
unsigned long pfn = PFN_DOWN(handle);
/*
* Dom0 is mapped 1:1, while the Linux page can be spanned accross
* multiple Xen page, it's not possible to have a mix of local and
* foreign Xen page. Dom0 is mapped 1:1, so calling pfn_valid on a
* foreign mfn will always return false. If the page is local we can
* safely call the native dma_ops function, otherwise we call the xen
* specific function.
*/
if (pfn_valid(pfn))
dma_direct_unmap_page(hwdev, handle, size, dir, attrs);
else
__xen_dma_unmap_page(hwdev, handle, size, dir, attrs);
}
#endif /* _ASM_ARM64_XEN_PAGE_COHERENT_H */
...@@ -8,15 +8,11 @@ ...@@ -8,15 +8,11 @@
#include <linux/cache.h> #include <linux/cache.h>
#include <linux/dma-noncoherent.h> #include <linux/dma-noncoherent.h>
#include <linux/dma-iommu.h> #include <linux/dma-iommu.h>
#include <xen/xen.h>
#include <xen/swiotlb-xen.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
unsigned long attrs)
{
return pgprot_writecombine(prot);
}
void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr, void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
size_t size, enum dma_data_direction dir) size_t size, enum dma_data_direction dir)
{ {
...@@ -34,12 +30,6 @@ void arch_dma_prep_coherent(struct page *page, size_t size) ...@@ -34,12 +30,6 @@ void arch_dma_prep_coherent(struct page *page, size_t size)
__dma_flush_area(page_address(page), size); __dma_flush_area(page_address(page), size);
} }
static int __init arm64_dma_init(void)
{
return dma_atomic_pool_init(GFP_DMA32, __pgprot(PROT_NORMAL_NC));
}
arch_initcall(arm64_dma_init);
#ifdef CONFIG_IOMMU_DMA #ifdef CONFIG_IOMMU_DMA
void arch_teardown_dma_ops(struct device *dev) void arch_teardown_dma_ops(struct device *dev)
{ {
...@@ -64,6 +54,6 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, ...@@ -64,6 +54,6 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
#ifdef CONFIG_XEN #ifdef CONFIG_XEN
if (xen_initial_domain()) if (xen_initial_domain())
dev->dma_ops = xen_dma_ops; dev->dma_ops = &xen_swiotlb_dma_ops;
#endif #endif
} }
...@@ -20,7 +20,6 @@ config C6X ...@@ -20,7 +20,6 @@ config C6X
select OF_EARLY_FLATTREE select OF_EARLY_FLATTREE
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select MODULES_USE_ELF_RELA select MODULES_USE_ELF_RELA
select ARCH_NO_COHERENT_DMA_MMAP
select MMU_GATHER_NO_RANGE if MMU select MMU_GATHER_NO_RANGE if MMU
config MMU config MMU
......
...@@ -14,12 +14,6 @@ ...@@ -14,12 +14,6 @@
#include <linux/version.h> #include <linux/version.h>
#include <asm/cache.h> #include <asm/cache.h>
static int __init atomic_pool_init(void)
{
return dma_atomic_pool_init(GFP_KERNEL, pgprot_noncached(PAGE_KERNEL));
}
postcore_initcall(atomic_pool_init);
void arch_dma_prep_coherent(struct page *page, size_t size) void arch_dma_prep_coherent(struct page *page, size_t size)
{ {
if (PageHighMem(page)) { if (PageHighMem(page)) {
......
...@@ -2069,6 +2069,8 @@ static const struct dma_map_ops sba_dma_ops = { ...@@ -2069,6 +2069,8 @@ static const struct dma_map_ops sba_dma_ops = {
.map_sg = sba_map_sg_attrs, .map_sg = sba_map_sg_attrs,
.unmap_sg = sba_unmap_sg_attrs, .unmap_sg = sba_unmap_sg_attrs,
.dma_supported = sba_dma_supported, .dma_supported = sba_dma_supported,
.mmap = dma_common_mmap,
.get_sgtable = dma_common_get_sgtable,
}; };
static int __init static int __init
......
...@@ -259,7 +259,7 @@ __initcall(register_memory); ...@@ -259,7 +259,7 @@ __initcall(register_memory);
* This function checks if the reserved crashkernel is allowed on the specific * This function checks if the reserved crashkernel is allowed on the specific
* IA64 machine flavour. Machines without an IO TLB use swiotlb and require * IA64 machine flavour. Machines without an IO TLB use swiotlb and require
* some memory below 4 GB (i.e. in 32 bit area), see the implementation of * some memory below 4 GB (i.e. in 32 bit area), see the implementation of
* lib/swiotlb.c. The hpzx1 architecture has an IO TLB but cannot use that * kernel/dma/swiotlb.c. The hpzx1 architecture has an IO TLB but cannot use that
* in kdump case. See the comment in sba_init() in sba_iommu.c. * in kdump case. See the comment in sba_init() in sba_iommu.c.
* *
* So, the only machvec that really supports loading the kdump kernel * So, the only machvec that really supports loading the kdump kernel
......
...@@ -4,11 +4,9 @@ config M68K ...@@ -4,11 +4,9 @@ config M68K
default y default y
select ARCH_32BIT_OFF_T select ARCH_32BIT_OFF_T
select ARCH_HAS_BINFMT_FLAT select ARCH_HAS_BINFMT_FLAT
select ARCH_HAS_DMA_MMAP_PGPROT if MMU && !COLDFIRE
select ARCH_HAS_DMA_PREP_COHERENT if HAS_DMA && MMU && !COLDFIRE select ARCH_HAS_DMA_PREP_COHERENT if HAS_DMA && MMU && !COLDFIRE
select ARCH_HAS_SYNC_DMA_FOR_DEVICE if HAS_DMA select ARCH_HAS_SYNC_DMA_FOR_DEVICE if HAS_DMA
select ARCH_MIGHT_HAVE_PC_PARPORT if ISA select ARCH_MIGHT_HAVE_PC_PARPORT if ISA
select ARCH_NO_COHERENT_DMA_MMAP if !MMU
select ARCH_NO_PREEMPT if !COLDFIRE select ARCH_NO_PREEMPT if !COLDFIRE
select BINFMT_FLAT_ARGVP_ENVP_ON_STACK select BINFMT_FLAT_ARGVP_ENVP_ON_STACK
select DMA_DIRECT_REMAP if HAS_DMA && MMU && !COLDFIRE select DMA_DIRECT_REMAP if HAS_DMA && MMU && !COLDFIRE
......
...@@ -169,6 +169,9 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, ...@@ -169,6 +169,9 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
? (__pgprot((pgprot_val(prot) & _CACHEMASK040) | _PAGE_NOCACHE_S)) \ ? (__pgprot((pgprot_val(prot) & _CACHEMASK040) | _PAGE_NOCACHE_S)) \
: (prot))) : (prot)))
pgprot_t pgprot_dmacoherent(pgprot_t prot);
#define pgprot_dmacoherent(prot) pgprot_dmacoherent(prot)
#endif /* CONFIG_COLDFIRE */ #endif /* CONFIG_COLDFIRE */
#include <asm-generic/pgtable.h> #include <asm-generic/pgtable.h>
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */
......
...@@ -23,8 +23,7 @@ void arch_dma_prep_coherent(struct page *page, size_t size) ...@@ -23,8 +23,7 @@ void arch_dma_prep_coherent(struct page *page, size_t size)
cache_push(page_to_phys(page), size); cache_push(page_to_phys(page), size);
} }
pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot, pgprot_t pgprot_dmacoherent(pgprot_t prot)
unsigned long attrs)
{ {
if (CPU_IS_040_OR_060) { if (CPU_IS_040_OR_060) {
pgprot_val(prot) &= ~_PAGE_CACHE040; pgprot_val(prot) &= ~_PAGE_CACHE040;
......
...@@ -9,7 +9,6 @@ config MICROBLAZE ...@@ -9,7 +9,6 @@ config MICROBLAZE
select ARCH_HAS_SYNC_DMA_FOR_CPU select ARCH_HAS_SYNC_DMA_FOR_CPU
select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_HAS_SYNC_DMA_FOR_DEVICE
select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_PARPORT
select ARCH_NO_COHERENT_DMA_MMAP if !MMU
select ARCH_WANT_IPC_PARSE_VERSION select ARCH_WANT_IPC_PARSE_VERSION
select BUILDTIME_EXTABLE_SORT select BUILDTIME_EXTABLE_SORT
select TIMER_OF select TIMER_OF
......
...@@ -1119,7 +1119,14 @@ config DMA_PERDEV_COHERENT ...@@ -1119,7 +1119,14 @@ config DMA_PERDEV_COHERENT
config DMA_NONCOHERENT config DMA_NONCOHERENT
bool bool
select ARCH_HAS_DMA_MMAP_PGPROT #
# MIPS allows mixing "slightly different" Cacheability and Coherency
# Attribute bits. It is believed that the uncached access through
# KSEG1 and the implementation specific "uncached accelerated" used
# by pgprot_writcombine can be mixed, and the latter sometimes provides
# significant advantages.
#
select ARCH_HAS_DMA_WRITE_COMBINE
select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_HAS_SYNC_DMA_FOR_DEVICE
select ARCH_HAS_UNCACHED_SEGMENT select ARCH_HAS_UNCACHED_SEGMENT
select NEED_DMA_MAP_STATE select NEED_DMA_MAP_STATE
......
...@@ -682,5 +682,7 @@ const struct dma_map_ops jazz_dma_ops = { ...@@ -682,5 +682,7 @@ const struct dma_map_ops jazz_dma_ops = {
.sync_sg_for_device = jazz_dma_sync_sg_for_device, .sync_sg_for_device = jazz_dma_sync_sg_for_device,
.dma_supported = dma_direct_supported, .dma_supported = dma_direct_supported,
.cache_sync = arch_dma_cache_sync, .cache_sync = arch_dma_cache_sync,
.mmap = dma_common_mmap,
.get_sgtable = dma_common_get_sgtable,
}; };
EXPORT_SYMBOL(jazz_dma_ops); EXPORT_SYMBOL(jazz_dma_ops);
...@@ -65,14 +65,6 @@ long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr, ...@@ -65,14 +65,6 @@ long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
return page_to_pfn(virt_to_page(cached_kernel_address(cpu_addr))); return page_to_pfn(virt_to_page(cached_kernel_address(cpu_addr)));
} }
pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
unsigned long attrs)
{
if (attrs & DMA_ATTR_WRITE_COMBINE)
return pgprot_writecombine(prot);
return pgprot_noncached(prot);
}
static inline void dma_sync_virt(void *addr, size_t size, static inline void dma_sync_virt(void *addr, size_t size,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
......
...@@ -80,9 +80,3 @@ void arch_dma_prep_coherent(struct page *page, size_t size) ...@@ -80,9 +80,3 @@ void arch_dma_prep_coherent(struct page *page, size_t size)
{ {
cache_op(page_to_phys(page), size, cpu_dma_wbinval_range); cache_op(page_to_phys(page), size, cpu_dma_wbinval_range);
} }
static int __init atomic_pool_init(void)
{
return dma_atomic_pool_init(GFP_KERNEL, pgprot_noncached(PAGE_KERNEL));
}
postcore_initcall(atomic_pool_init);
...@@ -52,7 +52,6 @@ config PARISC ...@@ -52,7 +52,6 @@ config PARISC
select GENERIC_SCHED_CLOCK select GENERIC_SCHED_CLOCK
select HAVE_UNSTABLE_SCHED_CLOCK if SMP select HAVE_UNSTABLE_SCHED_CLOCK if SMP
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select ARCH_NO_COHERENT_DMA_MMAP
select CPU_NO_EFFICIENT_FFS select CPU_NO_EFFICIENT_FFS
select NEED_DMA_MAP_STATE select NEED_DMA_MAP_STATE
select NEED_SG_DMA_LENGTH select NEED_SG_DMA_LENGTH
......
...@@ -208,4 +208,6 @@ const struct dma_map_ops dma_iommu_ops = { ...@@ -208,4 +208,6 @@ const struct dma_map_ops dma_iommu_ops = {
.sync_single_for_device = dma_iommu_sync_for_device, .sync_single_for_device = dma_iommu_sync_for_device,
.sync_sg_for_cpu = dma_iommu_sync_sg_for_cpu, .sync_sg_for_cpu = dma_iommu_sync_sg_for_cpu,
.sync_sg_for_device = dma_iommu_sync_sg_for_device, .sync_sg_for_device = dma_iommu_sync_sg_for_device,
.mmap = dma_common_mmap,
.get_sgtable = dma_common_get_sgtable,
}; };
...@@ -686,20 +686,16 @@ static int ps3_dma_supported(struct device *_dev, u64 mask) ...@@ -686,20 +686,16 @@ static int ps3_dma_supported(struct device *_dev, u64 mask)
return mask >= DMA_BIT_MASK(32); return mask >= DMA_BIT_MASK(32);
} }
static u64 ps3_dma_get_required_mask(struct device *_dev)
{
return DMA_BIT_MASK(32);
}
static const struct dma_map_ops ps3_sb_dma_ops = { static const struct dma_map_ops ps3_sb_dma_ops = {
.alloc = ps3_alloc_coherent, .alloc = ps3_alloc_coherent,
.free = ps3_free_coherent, .free = ps3_free_coherent,
.map_sg = ps3_sb_map_sg, .map_sg = ps3_sb_map_sg,
.unmap_sg = ps3_sb_unmap_sg, .unmap_sg = ps3_sb_unmap_sg,
.dma_supported = ps3_dma_supported, .dma_supported = ps3_dma_supported,
.get_required_mask = ps3_dma_get_required_mask,
.map_page = ps3_sb_map_page, .map_page = ps3_sb_map_page,
.unmap_page = ps3_unmap_page, .unmap_page = ps3_unmap_page,
.mmap = dma_common_mmap,
.get_sgtable = dma_common_get_sgtable,
}; };
static const struct dma_map_ops ps3_ioc0_dma_ops = { static const struct dma_map_ops ps3_ioc0_dma_ops = {
...@@ -708,9 +704,10 @@ static const struct dma_map_ops ps3_ioc0_dma_ops = { ...@@ -708,9 +704,10 @@ static const struct dma_map_ops ps3_ioc0_dma_ops = {
.map_sg = ps3_ioc0_map_sg, .map_sg = ps3_ioc0_map_sg,
.unmap_sg = ps3_ioc0_unmap_sg, .unmap_sg = ps3_ioc0_unmap_sg,
.dma_supported = ps3_dma_supported, .dma_supported = ps3_dma_supported,
.get_required_mask = ps3_dma_get_required_mask,
.map_page = ps3_ioc0_map_page, .map_page = ps3_ioc0_map_page,
.unmap_page = ps3_unmap_page, .unmap_page = ps3_unmap_page,
.mmap = dma_common_mmap,
.get_sgtable = dma_common_get_sgtable,
}; };
/** /**
......
...@@ -605,6 +605,8 @@ static const struct dma_map_ops vio_dma_mapping_ops = { ...@@ -605,6 +605,8 @@ static const struct dma_map_ops vio_dma_mapping_ops = {
.unmap_page = vio_dma_iommu_unmap_page, .unmap_page = vio_dma_iommu_unmap_page,
.dma_supported = dma_iommu_dma_supported, .dma_supported = dma_iommu_dma_supported,
.get_required_mask = dma_iommu_get_required_mask, .get_required_mask = dma_iommu_get_required_mask,
.mmap = dma_common_mmap,
.get_sgtable = dma_common_get_sgtable,
}; };
/** /**
......
...@@ -668,6 +668,8 @@ const struct dma_map_ops s390_pci_dma_ops = { ...@@ -668,6 +668,8 @@ const struct dma_map_ops s390_pci_dma_ops = {
.unmap_sg = s390_dma_unmap_sg, .unmap_sg = s390_dma_unmap_sg,
.map_page = s390_dma_map_pages, .map_page = s390_dma_map_pages,
.unmap_page = s390_dma_unmap_pages, .unmap_page = s390_dma_unmap_pages,
.mmap = dma_common_mmap,
.get_sgtable = dma_common_get_sgtable,
/* dma_supported is unconditionally true without a callback */ /* dma_supported is unconditionally true without a callback */
}; };
EXPORT_SYMBOL_GPL(s390_pci_dma_ops); EXPORT_SYMBOL_GPL(s390_pci_dma_ops);
......
...@@ -5,7 +5,6 @@ config SUPERH ...@@ -5,7 +5,6 @@ config SUPERH
select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_PTE_SPECIAL
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_PARPORT
select ARCH_NO_COHERENT_DMA_MMAP if !MMU
select HAVE_PATA_PLATFORM select HAVE_PATA_PLATFORM
select CLKDEV_LOOKUP select CLKDEV_LOOKUP
select DMA_DECLARE_COHERENT select DMA_DECLARE_COHERENT
......
...@@ -198,8 +198,6 @@ static inline pte_t pte_mkspecial(pte_t pte) { return pte; } ...@@ -198,8 +198,6 @@ static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
__pgprot(pgprot_val(prot) & ~PTE_CACHEABLE) __pgprot(pgprot_val(prot) & ~PTE_CACHEABLE)
#define pgprot_writecombine(prot) \ #define pgprot_writecombine(prot) \
__pgprot(pgprot_val(prot) & ~PTE_CACHEABLE) __pgprot(pgprot_val(prot) & ~PTE_CACHEABLE)
#define pgprot_dmacoherent(prot) \
__pgprot(pgprot_val(prot) & ~PTE_CACHEABLE)
#define pmd_none(pmd) (!pmd_val(pmd)) #define pmd_none(pmd) (!pmd_val(pmd))
#define pmd_present(pmd) (pmd_val(pmd) & PMD_PRESENT) #define pmd_present(pmd) (pmd_val(pmd) & PMD_PRESENT)
......
...@@ -21,18 +21,4 @@ static inline void xen_free_coherent_pages(struct device *hwdev, size_t size, ...@@ -21,18 +21,4 @@ static inline void xen_free_coherent_pages(struct device *hwdev, size_t size,
free_pages((unsigned long) cpu_addr, get_order(size)); free_pages((unsigned long) cpu_addr, get_order(size));
} }
static inline void xen_dma_map_page(struct device *hwdev, struct page *page,
dma_addr_t dev_addr, unsigned long offset, size_t size,
enum dma_data_direction dir, unsigned long attrs) { }
static inline void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
size_t size, enum dma_data_direction dir,
unsigned long attrs) { }
static inline void xen_dma_sync_single_for_cpu(struct device *hwdev,
dma_addr_t handle, size_t size, enum dma_data_direction dir) { }
static inline void xen_dma_sync_single_for_device(struct device *hwdev,
dma_addr_t handle, size_t size, enum dma_data_direction dir) { }
#endif /* _ASM_X86_XEN_PAGE_COHERENT_H */ #endif /* _ASM_X86_XEN_PAGE_COHERENT_H */
...@@ -677,7 +677,10 @@ static const struct dma_map_ops gart_dma_ops = { ...@@ -677,7 +677,10 @@ static const struct dma_map_ops gart_dma_ops = {
.unmap_page = gart_unmap_page, .unmap_page = gart_unmap_page,
.alloc = gart_alloc_coherent, .alloc = gart_alloc_coherent,
.free = gart_free_coherent, .free = gart_free_coherent,
.mmap = dma_common_mmap,
.get_sgtable = dma_common_get_sgtable,
.dma_supported = dma_direct_supported, .dma_supported = dma_direct_supported,
.get_required_mask = dma_direct_get_required_mask,
}; };
static void gart_iommu_shutdown(void) static void gart_iommu_shutdown(void)
......
...@@ -468,6 +468,8 @@ static const struct dma_map_ops calgary_dma_ops = { ...@@ -468,6 +468,8 @@ static const struct dma_map_ops calgary_dma_ops = {
.map_page = calgary_map_page, .map_page = calgary_map_page,
.unmap_page = calgary_unmap_page, .unmap_page = calgary_unmap_page,
.dma_supported = dma_direct_supported, .dma_supported = dma_direct_supported,
.mmap = dma_common_mmap,
.get_sgtable = dma_common_get_sgtable,
}; };
static inline void __iomem * busno_to_bbar(unsigned char num) static inline void __iomem * busno_to_bbar(unsigned char num)
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* Glue code to lib/swiotlb.c */
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/cache.h> #include <linux/cache.h>
......
...@@ -486,7 +486,7 @@ static int __init reserve_crashkernel_low(void) ...@@ -486,7 +486,7 @@ static int __init reserve_crashkernel_low(void)
ret = parse_crashkernel_low(boot_command_line, total_low_mem, &low_size, &base); ret = parse_crashkernel_low(boot_command_line, total_low_mem, &low_size, &base);
if (ret) { if (ret) {
/* /*
* two parts from lib/swiotlb.c: * two parts from kernel/dma/swiotlb.c:
* -swiotlb size: user-specified with swiotlb= or default. * -swiotlb size: user-specified with swiotlb= or default.
* *
* -swiotlb overflow buffer: now hardcoded to 32k. We round it * -swiotlb overflow buffer: now hardcoded to 32k. We round it
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* arch/x86/pci/sta2x11-fixup.c * DMA translation between STA2x11 AMBA memory mapping and the x86 memory mapping
* glue code for lib/swiotlb.c and DMA translation between STA2x11
* AMBA memory mapping and the X86 memory mapping
* *
* ST Microelectronics ConneXt (STA2X11/STA2X10) * ST Microelectronics ConneXt (STA2X11/STA2X10)
* *
......
...@@ -2625,7 +2625,6 @@ int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order, ...@@ -2625,7 +2625,6 @@ int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
*dma_handle = virt_to_machine(vstart).maddr; *dma_handle = virt_to_machine(vstart).maddr;
return success ? 0 : -ENOMEM; return success ? 0 : -ENOMEM;
} }
EXPORT_SYMBOL_GPL(xen_create_contiguous_region);
void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order) void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order)
{ {
...@@ -2660,7 +2659,6 @@ void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order) ...@@ -2660,7 +2659,6 @@ void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order)
spin_unlock_irqrestore(&xen_reservation_lock, flags); spin_unlock_irqrestore(&xen_reservation_lock, flags);
} }
EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region);
static noinline void xen_flush_tlb_all(void) static noinline void xen_flush_tlb_all(void)
{ {
......
...@@ -5,7 +5,6 @@ config XTENSA ...@@ -5,7 +5,6 @@ config XTENSA
select ARCH_HAS_BINFMT_FLAT if !MMU select ARCH_HAS_BINFMT_FLAT if !MMU
select ARCH_HAS_SYNC_DMA_FOR_CPU select ARCH_HAS_SYNC_DMA_FOR_CPU
select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_HAS_SYNC_DMA_FOR_DEVICE
select ARCH_NO_COHERENT_DMA_MMAP if !MMU
select ARCH_USE_QUEUED_RWLOCKS select ARCH_USE_QUEUED_RWLOCKS
select ARCH_USE_QUEUED_SPINLOCKS select ARCH_USE_QUEUED_SPINLOCKS
select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_FRAME_POINTERS
......
...@@ -167,7 +167,7 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, ...@@ -167,7 +167,7 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
if (PageHighMem(page)) { if (PageHighMem(page)) {
void *p; void *p;
p = dma_common_contiguous_remap(page, size, VM_MAP, p = dma_common_contiguous_remap(page, size,
pgprot_noncached(PAGE_KERNEL), pgprot_noncached(PAGE_KERNEL),
__builtin_return_address(0)); __builtin_return_address(0));
if (!p) { if (!p) {
...@@ -192,7 +192,7 @@ void arch_dma_free(struct device *dev, size_t size, void *vaddr, ...@@ -192,7 +192,7 @@ void arch_dma_free(struct device *dev, size_t size, void *vaddr,
page = virt_to_page(platform_vaddr_to_cached(vaddr)); page = virt_to_page(platform_vaddr_to_cached(vaddr));
} else { } else {
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
dma_common_free_remap(vaddr, size, VM_MAP); dma_common_free_remap(vaddr, size);
#endif #endif
page = pfn_to_page(PHYS_PFN(dma_to_phys(dev, dma_handle))); page = pfn_to_page(PHYS_PFN(dma_to_phys(dev, dma_handle)));
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/lcm.h> #include <linux/lcm.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/dma-mapping.h>
#include "blk.h" #include "blk.h"
#include "blk-wbt.h" #include "blk-wbt.h"
...@@ -848,6 +849,28 @@ void blk_queue_required_elevator_features(struct request_queue *q, ...@@ -848,6 +849,28 @@ void blk_queue_required_elevator_features(struct request_queue *q,
} }
EXPORT_SYMBOL_GPL(blk_queue_required_elevator_features); EXPORT_SYMBOL_GPL(blk_queue_required_elevator_features);
/**
* blk_queue_can_use_dma_map_merging - configure queue for merging segments.
* @q: the request queue for the device
* @dev: the device pointer for dma
*
* Tell the block layer about merging the segments by dma map of @q.
*/
bool blk_queue_can_use_dma_map_merging(struct request_queue *q,
struct device *dev)
{
unsigned long boundary = dma_get_merge_boundary(dev);
if (!boundary)
return false;
/* No need to update max_segment_size. see blk_queue_virt_boundary() */
blk_queue_virt_boundary(q, boundary);
return true;
}
EXPORT_SYMBOL_GPL(blk_queue_can_use_dma_map_merging);
static int __init blk_settings_init(void) static int __init blk_settings_init(void)
{ {
blk_max_low_pfn = max_low_pfn - 1; blk_max_low_pfn = max_low_pfn - 1;
......
...@@ -4609,11 +4609,10 @@ static int dispc_errata_i734_wa_init(struct dispc_device *dispc) ...@@ -4609,11 +4609,10 @@ static int dispc_errata_i734_wa_init(struct dispc_device *dispc)
i734_buf.size = i734.ovli.width * i734.ovli.height * i734_buf.size = i734.ovli.width * i734.ovli.height *
color_mode_to_bpp(i734.ovli.fourcc) / 8; color_mode_to_bpp(i734.ovli.fourcc) / 8;
i734_buf.vaddr = dma_alloc_writecombine(&dispc->pdev->dev, i734_buf.vaddr = dma_alloc_wc(&dispc->pdev->dev, i734_buf.size,
i734_buf.size, &i734_buf.paddr, &i734_buf.paddr, GFP_KERNEL);
GFP_KERNEL);
if (!i734_buf.vaddr) { if (!i734_buf.vaddr) {
dev_err(&dispc->pdev->dev, "%s: dma_alloc_writecombine failed\n", dev_err(&dispc->pdev->dev, "%s: dma_alloc_wc failed\n",
__func__); __func__);
return -ENOMEM; return -ENOMEM;
} }
...@@ -4626,8 +4625,8 @@ static void dispc_errata_i734_wa_fini(struct dispc_device *dispc) ...@@ -4626,8 +4625,8 @@ static void dispc_errata_i734_wa_fini(struct dispc_device *dispc)
if (!dispc->feat->has_gamma_i734_bug) if (!dispc->feat->has_gamma_i734_bug)
return; return;
dma_free_writecombine(&dispc->pdev->dev, i734_buf.size, i734_buf.vaddr, dma_free_wc(&dispc->pdev->dev, i734_buf.size, i734_buf.vaddr,
i734_buf.paddr); i734_buf.paddr);
} }
static void dispc_errata_i734_wa(struct dispc_device *dispc) static void dispc_errata_i734_wa(struct dispc_device *dispc)
......
...@@ -2754,6 +2754,8 @@ static const struct dma_map_ops amd_iommu_dma_ops = { ...@@ -2754,6 +2754,8 @@ static const struct dma_map_ops amd_iommu_dma_ops = {
.map_sg = map_sg, .map_sg = map_sg,
.unmap_sg = unmap_sg, .unmap_sg = unmap_sg,
.dma_supported = amd_iommu_dma_supported, .dma_supported = amd_iommu_dma_supported,
.mmap = dma_common_mmap,
.get_sgtable = dma_common_get_sgtable,
}; };
static int init_reserved_iova_ranges(void) static int init_reserved_iova_ranges(void)
......
...@@ -548,15 +548,6 @@ static struct page **__iommu_dma_alloc_pages(struct device *dev, ...@@ -548,15 +548,6 @@ static struct page **__iommu_dma_alloc_pages(struct device *dev,
return pages; return pages;
} }
static struct page **__iommu_dma_get_pages(void *cpu_addr)
{
struct vm_struct *area = find_vm_area(cpu_addr);
if (!area || !area->pages)
return NULL;
return area->pages;
}
/** /**
* iommu_dma_alloc_remap - Allocate and map a buffer contiguous in IOVA space * iommu_dma_alloc_remap - Allocate and map a buffer contiguous in IOVA space
* @dev: Device to allocate memory for. Must be a real device * @dev: Device to allocate memory for. Must be a real device
...@@ -624,7 +615,7 @@ static void *iommu_dma_alloc_remap(struct device *dev, size_t size, ...@@ -624,7 +615,7 @@ static void *iommu_dma_alloc_remap(struct device *dev, size_t size,
< size) < size)
goto out_free_sg; goto out_free_sg;
vaddr = dma_common_pages_remap(pages, size, VM_USERMAP, prot, vaddr = dma_common_pages_remap(pages, size, prot,
__builtin_return_address(0)); __builtin_return_address(0));
if (!vaddr) if (!vaddr)
goto out_unmap; goto out_unmap;
...@@ -945,10 +936,10 @@ static void __iommu_dma_free(struct device *dev, size_t size, void *cpu_addr) ...@@ -945,10 +936,10 @@ static void __iommu_dma_free(struct device *dev, size_t size, void *cpu_addr)
* If it the address is remapped, then it's either non-coherent * If it the address is remapped, then it's either non-coherent
* or highmem CMA, or an iommu_dma_alloc_remap() construction. * or highmem CMA, or an iommu_dma_alloc_remap() construction.
*/ */
pages = __iommu_dma_get_pages(cpu_addr); pages = dma_common_find_pages(cpu_addr);
if (!pages) if (!pages)
page = vmalloc_to_page(cpu_addr); page = vmalloc_to_page(cpu_addr);
dma_common_free_remap(cpu_addr, alloc_size, VM_USERMAP); dma_common_free_remap(cpu_addr, alloc_size);
} else { } else {
/* Lowmem means a coherent atomic or CMA allocation */ /* Lowmem means a coherent atomic or CMA allocation */
page = virt_to_page(cpu_addr); page = virt_to_page(cpu_addr);
...@@ -986,7 +977,7 @@ static void *iommu_dma_alloc_pages(struct device *dev, size_t size, ...@@ -986,7 +977,7 @@ static void *iommu_dma_alloc_pages(struct device *dev, size_t size,
pgprot_t prot = dma_pgprot(dev, PAGE_KERNEL, attrs); pgprot_t prot = dma_pgprot(dev, PAGE_KERNEL, attrs);
cpu_addr = dma_common_contiguous_remap(page, alloc_size, cpu_addr = dma_common_contiguous_remap(page, alloc_size,
VM_USERMAP, prot, __builtin_return_address(0)); prot, __builtin_return_address(0));
if (!cpu_addr) if (!cpu_addr)
goto out_free_pages; goto out_free_pages;
...@@ -1052,7 +1043,7 @@ static int iommu_dma_mmap(struct device *dev, struct vm_area_struct *vma, ...@@ -1052,7 +1043,7 @@ static int iommu_dma_mmap(struct device *dev, struct vm_area_struct *vma,
return -ENXIO; return -ENXIO;
if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr)) { if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr)) {
struct page **pages = __iommu_dma_get_pages(cpu_addr); struct page **pages = dma_common_find_pages(cpu_addr);
if (pages) if (pages)
return __iommu_dma_mmap(pages, size, vma); return __iommu_dma_mmap(pages, size, vma);
...@@ -1074,7 +1065,7 @@ static int iommu_dma_get_sgtable(struct device *dev, struct sg_table *sgt, ...@@ -1074,7 +1065,7 @@ static int iommu_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
int ret; int ret;
if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr)) { if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr)) {
struct page **pages = __iommu_dma_get_pages(cpu_addr); struct page **pages = dma_common_find_pages(cpu_addr);
if (pages) { if (pages) {
return sg_alloc_table_from_pages(sgt, pages, return sg_alloc_table_from_pages(sgt, pages,
...@@ -1093,6 +1084,13 @@ static int iommu_dma_get_sgtable(struct device *dev, struct sg_table *sgt, ...@@ -1093,6 +1084,13 @@ static int iommu_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
return ret; return ret;
} }
static unsigned long iommu_dma_get_merge_boundary(struct device *dev)
{
struct iommu_domain *domain = iommu_get_dma_domain(dev);
return (1UL << __ffs(domain->pgsize_bitmap)) - 1;
}
static const struct dma_map_ops iommu_dma_ops = { static const struct dma_map_ops iommu_dma_ops = {
.alloc = iommu_dma_alloc, .alloc = iommu_dma_alloc,
.free = iommu_dma_free, .free = iommu_dma_free,
...@@ -1108,6 +1106,7 @@ static const struct dma_map_ops iommu_dma_ops = { ...@@ -1108,6 +1106,7 @@ static const struct dma_map_ops iommu_dma_ops = {
.sync_sg_for_device = iommu_dma_sync_sg_for_device, .sync_sg_for_device = iommu_dma_sync_sg_for_device,
.map_resource = iommu_dma_map_resource, .map_resource = iommu_dma_map_resource,
.unmap_resource = iommu_dma_unmap_resource, .unmap_resource = iommu_dma_unmap_resource,
.get_merge_boundary = iommu_dma_get_merge_boundary,
}; };
/* /*
......
...@@ -3785,6 +3785,8 @@ static const struct dma_map_ops intel_dma_ops = { ...@@ -3785,6 +3785,8 @@ static const struct dma_map_ops intel_dma_ops = {
.map_resource = intel_map_resource, .map_resource = intel_map_resource,
.unmap_resource = intel_unmap_resource, .unmap_resource = intel_unmap_resource,
.dma_supported = dma_direct_supported, .dma_supported = dma_direct_supported,
.mmap = dma_common_mmap,
.get_sgtable = dma_common_get_sgtable,
}; };
static void static void
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include "card.h" #include "card.h"
#include "host.h" #include "host.h"
#define MMC_DMA_MAP_MERGE_SEGMENTS 512
static inline bool mmc_cqe_dcmd_busy(struct mmc_queue *mq) static inline bool mmc_cqe_dcmd_busy(struct mmc_queue *mq)
{ {
/* Allow only 1 DCMD at a time */ /* Allow only 1 DCMD at a time */
...@@ -193,6 +195,12 @@ static void mmc_queue_setup_discard(struct request_queue *q, ...@@ -193,6 +195,12 @@ static void mmc_queue_setup_discard(struct request_queue *q,
blk_queue_flag_set(QUEUE_FLAG_SECERASE, q); blk_queue_flag_set(QUEUE_FLAG_SECERASE, q);
} }
static unsigned int mmc_get_max_segments(struct mmc_host *host)
{
return host->can_dma_map_merge ? MMC_DMA_MAP_MERGE_SEGMENTS :
host->max_segs;
}
/** /**
* mmc_init_request() - initialize the MMC-specific per-request data * mmc_init_request() - initialize the MMC-specific per-request data
* @q: the request queue * @q: the request queue
...@@ -206,7 +214,7 @@ static int __mmc_init_request(struct mmc_queue *mq, struct request *req, ...@@ -206,7 +214,7 @@ static int __mmc_init_request(struct mmc_queue *mq, struct request *req,
struct mmc_card *card = mq->card; struct mmc_card *card = mq->card;
struct mmc_host *host = card->host; struct mmc_host *host = card->host;
mq_rq->sg = mmc_alloc_sg(host->max_segs, gfp); mq_rq->sg = mmc_alloc_sg(mmc_get_max_segments(host), gfp);
if (!mq_rq->sg) if (!mq_rq->sg)
return -ENOMEM; return -ENOMEM;
...@@ -362,13 +370,23 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card) ...@@ -362,13 +370,23 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)
blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_HIGH); blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_HIGH);
blk_queue_max_hw_sectors(mq->queue, blk_queue_max_hw_sectors(mq->queue,
min(host->max_blk_count, host->max_req_size / 512)); min(host->max_blk_count, host->max_req_size / 512));
blk_queue_max_segments(mq->queue, host->max_segs); if (host->can_dma_map_merge)
WARN(!blk_queue_can_use_dma_map_merging(mq->queue,
mmc_dev(host)),
"merging was advertised but not possible");
blk_queue_max_segments(mq->queue, mmc_get_max_segments(host));
if (mmc_card_mmc(card)) if (mmc_card_mmc(card))
block_size = card->ext_csd.data_sector_size; block_size = card->ext_csd.data_sector_size;
blk_queue_logical_block_size(mq->queue, block_size); blk_queue_logical_block_size(mq->queue, block_size);
blk_queue_max_segment_size(mq->queue, /*
* After blk_queue_can_use_dma_map_merging() was called with succeed,
* since it calls blk_queue_virt_boundary(), the mmc should not call
* both blk_queue_max_segment_size().
*/
if (!host->can_dma_map_merge)
blk_queue_max_segment_size(mq->queue,
round_down(host->max_seg_size, block_size)); round_down(host->max_seg_size, block_size));
dma_set_max_seg_size(mmc_dev(host), queue_max_segment_size(mq->queue)); dma_set_max_seg_size(mmc_dev(host), queue_max_segment_size(mq->queue));
...@@ -381,6 +399,11 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card) ...@@ -381,6 +399,11 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)
init_waitqueue_head(&mq->wait); init_waitqueue_head(&mq->wait);
} }
static inline bool mmc_merge_capable(struct mmc_host *host)
{
return host->caps2 & MMC_CAP2_MERGE_CAPABLE;
}
/* Set queue depth to get a reasonable value for q->nr_requests */ /* Set queue depth to get a reasonable value for q->nr_requests */
#define MMC_QUEUE_DEPTH 64 #define MMC_QUEUE_DEPTH 64
...@@ -418,6 +441,18 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card) ...@@ -418,6 +441,18 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card)
mq->tag_set.cmd_size = sizeof(struct mmc_queue_req); mq->tag_set.cmd_size = sizeof(struct mmc_queue_req);
mq->tag_set.driver_data = mq; mq->tag_set.driver_data = mq;
/*
* Since blk_mq_alloc_tag_set() calls .init_request() of mmc_mq_ops,
* the host->can_dma_map_merge should be set before to get max_segs
* from mmc_get_max_segments().
*/
if (mmc_merge_capable(host) &&
host->max_segs < MMC_DMA_MAP_MERGE_SEGMENTS &&
dma_get_merge_boundary(mmc_dev(host)))
host->can_dma_map_merge = 1;
else
host->can_dma_map_merge = 0;
ret = blk_mq_alloc_tag_set(&mq->tag_set); ret = blk_mq_alloc_tag_set(&mq->tag_set);
if (ret) if (ret)
return ret; return ret;
......
...@@ -106,7 +106,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { ...@@ -106,7 +106,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
MMC_CAP_CMD23, MMC_CAP_CMD23,
.capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE,
.bus_shift = 2, .bus_shift = 2,
.scc_offset = 0x1000, .scc_offset = 0x1000,
.taps = rcar_gen3_scc_taps, .taps = rcar_gen3_scc_taps,
......
...@@ -1024,6 +1024,7 @@ static const struct dma_map_ops ccio_ops = { ...@@ -1024,6 +1024,7 @@ static const struct dma_map_ops ccio_ops = {
.unmap_page = ccio_unmap_page, .unmap_page = ccio_unmap_page,
.map_sg = ccio_map_sg, .map_sg = ccio_map_sg,
.unmap_sg = ccio_unmap_sg, .unmap_sg = ccio_unmap_sg,
.get_sgtable = dma_common_get_sgtable,
}; };
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
......
...@@ -1084,6 +1084,7 @@ static const struct dma_map_ops sba_ops = { ...@@ -1084,6 +1084,7 @@ static const struct dma_map_ops sba_ops = {
.unmap_page = sba_unmap_page, .unmap_page = sba_unmap_page,
.map_sg = sba_map_sg, .map_sg = sba_map_sg,
.unmap_sg = sba_unmap_sg, .unmap_sg = sba_unmap_sg,
.get_sgtable = dma_common_get_sgtable,
}; };
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
menu "Remoteproc drivers" menu "Remoteproc drivers"
config REMOTEPROC config REMOTEPROC
tristate "Support for Remote Processor subsystem" bool "Support for Remote Processor subsystem"
depends on HAS_DMA depends on HAS_DMA
select CRC32 select CRC32
select FW_LOADER select FW_LOADER
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/dma-direct.h> #include <linux/dma-direct.h>
#include <linux/dma-noncoherent.h>
#include <linux/export.h> #include <linux/export.h>
#include <xen/swiotlb-xen.h> #include <xen/swiotlb-xen.h>
#include <xen/page.h> #include <xen/page.h>
...@@ -391,6 +392,7 @@ static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, ...@@ -391,6 +392,7 @@ static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
if (map == (phys_addr_t)DMA_MAPPING_ERROR) if (map == (phys_addr_t)DMA_MAPPING_ERROR)
return DMA_MAPPING_ERROR; return DMA_MAPPING_ERROR;
phys = map;
dev_addr = xen_phys_to_bus(map); dev_addr = xen_phys_to_bus(map);
/* /*
...@@ -402,14 +404,9 @@ static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, ...@@ -402,14 +404,9 @@ static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
return DMA_MAPPING_ERROR; return DMA_MAPPING_ERROR;
} }
page = pfn_to_page(map >> PAGE_SHIFT);
offset = map & ~PAGE_MASK;
done: done:
/* if (!dev_is_dma_coherent(dev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
* we are not interested in the dma_addr returned by xen_dma_map_page, xen_dma_sync_for_device(dev, dev_addr, phys, size, dir);
* only in the potential cache flushes executed by the function.
*/
xen_dma_map_page(dev, page, dev_addr, offset, size, dir, attrs);
return dev_addr; return dev_addr;
} }
...@@ -421,35 +418,29 @@ static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, ...@@ -421,35 +418,29 @@ static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
* After this call, reads by the cpu to the buffer are guaranteed to see * After this call, reads by the cpu to the buffer are guaranteed to see
* whatever the device wrote there. * whatever the device wrote there.
*/ */
static void xen_unmap_single(struct device *hwdev, dma_addr_t dev_addr, static void xen_swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
size_t size, enum dma_data_direction dir, size_t size, enum dma_data_direction dir, unsigned long attrs)
unsigned long attrs)
{ {
phys_addr_t paddr = xen_bus_to_phys(dev_addr); phys_addr_t paddr = xen_bus_to_phys(dev_addr);
BUG_ON(dir == DMA_NONE); BUG_ON(dir == DMA_NONE);
xen_dma_unmap_page(hwdev, dev_addr, size, dir, attrs); if (!dev_is_dma_coherent(hwdev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
xen_dma_sync_for_cpu(hwdev, dev_addr, paddr, size, dir);
/* NOTE: We use dev_addr here, not paddr! */ /* NOTE: We use dev_addr here, not paddr! */
if (is_xen_swiotlb_buffer(dev_addr)) if (is_xen_swiotlb_buffer(dev_addr))
swiotlb_tbl_unmap_single(hwdev, paddr, size, size, dir, attrs); swiotlb_tbl_unmap_single(hwdev, paddr, size, size, dir, attrs);
} }
static void xen_swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
size_t size, enum dma_data_direction dir,
unsigned long attrs)
{
xen_unmap_single(hwdev, dev_addr, size, dir, attrs);
}
static void static void
xen_swiotlb_sync_single_for_cpu(struct device *dev, dma_addr_t dma_addr, xen_swiotlb_sync_single_for_cpu(struct device *dev, dma_addr_t dma_addr,
size_t size, enum dma_data_direction dir) size_t size, enum dma_data_direction dir)
{ {
phys_addr_t paddr = xen_bus_to_phys(dma_addr); phys_addr_t paddr = xen_bus_to_phys(dma_addr);
xen_dma_sync_single_for_cpu(dev, dma_addr, size, dir); if (!dev_is_dma_coherent(dev))
xen_dma_sync_for_cpu(dev, dma_addr, paddr, size, dir);
if (is_xen_swiotlb_buffer(dma_addr)) if (is_xen_swiotlb_buffer(dma_addr))
swiotlb_tbl_sync_single(dev, paddr, size, dir, SYNC_FOR_CPU); swiotlb_tbl_sync_single(dev, paddr, size, dir, SYNC_FOR_CPU);
...@@ -464,7 +455,8 @@ xen_swiotlb_sync_single_for_device(struct device *dev, dma_addr_t dma_addr, ...@@ -464,7 +455,8 @@ xen_swiotlb_sync_single_for_device(struct device *dev, dma_addr_t dma_addr,
if (is_xen_swiotlb_buffer(dma_addr)) if (is_xen_swiotlb_buffer(dma_addr))
swiotlb_tbl_sync_single(dev, paddr, size, dir, SYNC_FOR_DEVICE); swiotlb_tbl_sync_single(dev, paddr, size, dir, SYNC_FOR_DEVICE);
xen_dma_sync_single_for_device(dev, dma_addr, size, dir); if (!dev_is_dma_coherent(dev))
xen_dma_sync_for_device(dev, dma_addr, paddr, size, dir);
} }
/* /*
...@@ -481,7 +473,8 @@ xen_swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems, ...@@ -481,7 +473,8 @@ xen_swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
BUG_ON(dir == DMA_NONE); BUG_ON(dir == DMA_NONE);
for_each_sg(sgl, sg, nelems, i) for_each_sg(sgl, sg, nelems, i)
xen_unmap_single(hwdev, sg->dma_address, sg_dma_len(sg), dir, attrs); xen_swiotlb_unmap_page(hwdev, sg->dma_address, sg_dma_len(sg),
dir, attrs);
} }
...@@ -547,51 +540,6 @@ xen_swiotlb_dma_supported(struct device *hwdev, u64 mask) ...@@ -547,51 +540,6 @@ xen_swiotlb_dma_supported(struct device *hwdev, u64 mask)
return xen_virt_to_bus(xen_io_tlb_end - 1) <= mask; return xen_virt_to_bus(xen_io_tlb_end - 1) <= mask;
} }
/*
* Create userspace mapping for the DMA-coherent memory.
* This function should be called with the pages from the current domain only,
* passing pages mapped from other domains would lead to memory corruption.
*/
static int
xen_swiotlb_dma_mmap(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size,
unsigned long attrs)
{
#ifdef CONFIG_ARM
if (xen_get_dma_ops(dev)->mmap)
return xen_get_dma_ops(dev)->mmap(dev, vma, cpu_addr,
dma_addr, size, attrs);
#endif
return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
}
/*
* This function should be called with the pages from the current domain only,
* passing pages mapped from other domains would lead to memory corruption.
*/
static int
xen_swiotlb_get_sgtable(struct device *dev, struct sg_table *sgt,
void *cpu_addr, dma_addr_t handle, size_t size,
unsigned long attrs)
{
#ifdef CONFIG_ARM
if (xen_get_dma_ops(dev)->get_sgtable) {
#if 0
/*
* This check verifies that the page belongs to the current domain and
* is not one mapped from another domain.
* This check is for debug only, and should not go to production build
*/
unsigned long bfn = PHYS_PFN(dma_to_phys(dev, handle));
BUG_ON (!page_is_ram(bfn));
#endif
return xen_get_dma_ops(dev)->get_sgtable(dev, sgt, cpu_addr,
handle, size, attrs);
}
#endif
return dma_common_get_sgtable(dev, sgt, cpu_addr, handle, size, attrs);
}
const struct dma_map_ops xen_swiotlb_dma_ops = { const struct dma_map_ops xen_swiotlb_dma_ops = {
.alloc = xen_swiotlb_alloc_coherent, .alloc = xen_swiotlb_alloc_coherent,
.free = xen_swiotlb_free_coherent, .free = xen_swiotlb_free_coherent,
...@@ -604,6 +552,6 @@ const struct dma_map_ops xen_swiotlb_dma_ops = { ...@@ -604,6 +552,6 @@ const struct dma_map_ops xen_swiotlb_dma_ops = {
.map_page = xen_swiotlb_map_page, .map_page = xen_swiotlb_map_page,
.unmap_page = xen_swiotlb_unmap_page, .unmap_page = xen_swiotlb_unmap_page,
.dma_supported = xen_swiotlb_dma_supported, .dma_supported = xen_swiotlb_dma_supported,
.mmap = xen_swiotlb_dma_mmap, .mmap = dma_common_mmap,
.get_sgtable = xen_swiotlb_get_sgtable, .get_sgtable = dma_common_get_sgtable,
}; };
...@@ -1110,6 +1110,8 @@ extern void blk_queue_rq_timeout(struct request_queue *, unsigned int); ...@@ -1110,6 +1110,8 @@ extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
extern void blk_queue_write_cache(struct request_queue *q, bool enabled, bool fua); extern void blk_queue_write_cache(struct request_queue *q, bool enabled, bool fua);
extern void blk_queue_required_elevator_features(struct request_queue *q, extern void blk_queue_required_elevator_features(struct request_queue *q,
unsigned int features); unsigned int features);
extern bool blk_queue_can_use_dma_map_merging(struct request_queue *q,
struct device *dev);
/* /*
* Number of physical segments as sent to the device. * Number of physical segments as sent to the device.
......
...@@ -131,6 +131,7 @@ struct dma_map_ops { ...@@ -131,6 +131,7 @@ struct dma_map_ops {
int (*dma_supported)(struct device *dev, u64 mask); int (*dma_supported)(struct device *dev, u64 mask);
u64 (*get_required_mask)(struct device *dev); u64 (*get_required_mask)(struct device *dev);
size_t (*max_mapping_size)(struct device *dev); size_t (*max_mapping_size)(struct device *dev);
unsigned long (*get_merge_boundary)(struct device *dev);
}; };
#define DMA_MAPPING_ERROR (~(dma_addr_t)0) #define DMA_MAPPING_ERROR (~(dma_addr_t)0)
...@@ -457,11 +458,13 @@ int dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, ...@@ -457,11 +458,13 @@ int dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt,
int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size, void *cpu_addr, dma_addr_t dma_addr, size_t size,
unsigned long attrs); unsigned long attrs);
bool dma_can_mmap(struct device *dev);
int dma_supported(struct device *dev, u64 mask); int dma_supported(struct device *dev, u64 mask);
int dma_set_mask(struct device *dev, u64 mask); int dma_set_mask(struct device *dev, u64 mask);
int dma_set_coherent_mask(struct device *dev, u64 mask); int dma_set_coherent_mask(struct device *dev, u64 mask);
u64 dma_get_required_mask(struct device *dev); u64 dma_get_required_mask(struct device *dev);
size_t dma_max_mapping_size(struct device *dev); size_t dma_max_mapping_size(struct device *dev);
unsigned long dma_get_merge_boundary(struct device *dev);
#else /* CONFIG_HAS_DMA */ #else /* CONFIG_HAS_DMA */
static inline dma_addr_t dma_map_page_attrs(struct device *dev, static inline dma_addr_t dma_map_page_attrs(struct device *dev,
struct page *page, size_t offset, size_t size, struct page *page, size_t offset, size_t size,
...@@ -547,6 +550,10 @@ static inline int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, ...@@ -547,6 +550,10 @@ static inline int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
{ {
return -ENXIO; return -ENXIO;
} }
static inline bool dma_can_mmap(struct device *dev)
{
return false;
}
static inline int dma_supported(struct device *dev, u64 mask) static inline int dma_supported(struct device *dev, u64 mask)
{ {
return 0; return 0;
...@@ -567,6 +574,10 @@ static inline size_t dma_max_mapping_size(struct device *dev) ...@@ -567,6 +574,10 @@ static inline size_t dma_max_mapping_size(struct device *dev)
{ {
return 0; return 0;
} }
static inline unsigned long dma_get_merge_boundary(struct device *dev)
{
return 0;
}
#endif /* CONFIG_HAS_DMA */ #endif /* CONFIG_HAS_DMA */
static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr, static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
...@@ -610,16 +621,14 @@ extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, ...@@ -610,16 +621,14 @@ extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size, void *cpu_addr, dma_addr_t dma_addr, size_t size,
unsigned long attrs); unsigned long attrs);
struct page **dma_common_find_pages(void *cpu_addr);
void *dma_common_contiguous_remap(struct page *page, size_t size, void *dma_common_contiguous_remap(struct page *page, size_t size,
unsigned long vm_flags,
pgprot_t prot, const void *caller); pgprot_t prot, const void *caller);
void *dma_common_pages_remap(struct page **pages, size_t size, void *dma_common_pages_remap(struct page **pages, size_t size,
unsigned long vm_flags, pgprot_t prot, pgprot_t prot, const void *caller);
const void *caller); void dma_common_free_remap(void *cpu_addr, size_t size);
void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags);
int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot);
bool dma_in_atomic_pool(void *start, size_t size); bool dma_in_atomic_pool(void *start, size_t size);
void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags); void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags);
bool dma_free_from_pool(void *start, size_t size); bool dma_free_from_pool(void *start, size_t size);
...@@ -749,7 +758,6 @@ static inline int dma_get_cache_alignment(void) ...@@ -749,7 +758,6 @@ static inline int dma_get_cache_alignment(void)
#ifdef CONFIG_DMA_DECLARE_COHERENT #ifdef CONFIG_DMA_DECLARE_COHERENT
int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
dma_addr_t device_addr, size_t size); dma_addr_t device_addr, size_t size);
void dma_release_declared_memory(struct device *dev);
#else #else
static inline int static inline int
dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
...@@ -757,11 +765,6 @@ dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, ...@@ -757,11 +765,6 @@ dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
{ {
return -ENOSYS; return -ENOSYS;
} }
static inline void
dma_release_declared_memory(struct device *dev)
{
}
#endif /* CONFIG_DMA_DECLARE_COHERENT */ #endif /* CONFIG_DMA_DECLARE_COHERENT */
static inline void *dmam_alloc_coherent(struct device *dev, size_t size, static inline void *dmam_alloc_coherent(struct device *dev, size_t size,
...@@ -781,9 +784,6 @@ static inline void *dma_alloc_wc(struct device *dev, size_t size, ...@@ -781,9 +784,6 @@ static inline void *dma_alloc_wc(struct device *dev, size_t size,
return dma_alloc_attrs(dev, size, dma_addr, gfp, attrs); return dma_alloc_attrs(dev, size, dma_addr, gfp, attrs);
} }
#ifndef dma_alloc_writecombine
#define dma_alloc_writecombine dma_alloc_wc
#endif
static inline void dma_free_wc(struct device *dev, size_t size, static inline void dma_free_wc(struct device *dev, size_t size,
void *cpu_addr, dma_addr_t dma_addr) void *cpu_addr, dma_addr_t dma_addr)
...@@ -791,9 +791,6 @@ static inline void dma_free_wc(struct device *dev, size_t size, ...@@ -791,9 +791,6 @@ static inline void dma_free_wc(struct device *dev, size_t size,
return dma_free_attrs(dev, size, cpu_addr, dma_addr, return dma_free_attrs(dev, size, cpu_addr, dma_addr,
DMA_ATTR_WRITE_COMBINE); DMA_ATTR_WRITE_COMBINE);
} }
#ifndef dma_free_writecombine
#define dma_free_writecombine dma_free_wc
#endif
static inline int dma_mmap_wc(struct device *dev, static inline int dma_mmap_wc(struct device *dev,
struct vm_area_struct *vma, struct vm_area_struct *vma,
...@@ -803,9 +800,6 @@ static inline int dma_mmap_wc(struct device *dev, ...@@ -803,9 +800,6 @@ static inline int dma_mmap_wc(struct device *dev,
return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size,
DMA_ATTR_WRITE_COMBINE); DMA_ATTR_WRITE_COMBINE);
} }
#ifndef dma_mmap_writecombine
#define dma_mmap_writecombine dma_mmap_wc
#endif
#ifdef CONFIG_NEED_DMA_MAP_STATE #ifdef CONFIG_NEED_DMA_MAP_STATE
#define DEFINE_DMA_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME #define DEFINE_DMA_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#define _LINUX_DMA_NONCOHERENT_H 1 #define _LINUX_DMA_NONCOHERENT_H 1
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <asm/pgtable.h>
#ifdef CONFIG_ARCH_HAS_DMA_COHERENCE_H #ifdef CONFIG_ARCH_HAS_DMA_COHERENCE_H
#include <asm/dma-coherence.h> #include <asm/dma-coherence.h>
...@@ -42,10 +43,18 @@ void arch_dma_free(struct device *dev, size_t size, void *cpu_addr, ...@@ -42,10 +43,18 @@ void arch_dma_free(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t dma_addr, unsigned long attrs); dma_addr_t dma_addr, unsigned long attrs);
long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr, long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
dma_addr_t dma_addr); dma_addr_t dma_addr);
pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
unsigned long attrs);
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
/*
* Page protection so that devices that can't snoop CPU caches can use the
* memory coherently. We default to pgprot_noncached which is usually used
* for ioremap as a safe bet, but architectures can override this with less
* strict semantics if possible.
*/
#ifndef pgprot_dmacoherent
#define pgprot_dmacoherent(prot) pgprot_noncached(prot)
#endif
pgprot_t dma_pgprot(struct device *dev, pgprot_t prot, unsigned long attrs); pgprot_t dma_pgprot(struct device *dev, pgprot_t prot, unsigned long attrs);
#else #else
static inline pgprot_t dma_pgprot(struct device *dev, pgprot_t prot, static inline pgprot_t dma_pgprot(struct device *dev, pgprot_t prot,
......
...@@ -368,6 +368,7 @@ struct mmc_host { ...@@ -368,6 +368,7 @@ struct mmc_host {
#define MMC_CAP2_CQE (1 << 23) /* Has eMMC command queue engine */ #define MMC_CAP2_CQE (1 << 23) /* Has eMMC command queue engine */
#define MMC_CAP2_CQE_DCMD (1 << 24) /* CQE can issue a direct command */ #define MMC_CAP2_CQE_DCMD (1 << 24) /* CQE can issue a direct command */
#define MMC_CAP2_AVOID_3_3V (1 << 25) /* Host must negotiate down from 3.3V */ #define MMC_CAP2_AVOID_3_3V (1 << 25) /* Host must negotiate down from 3.3V */
#define MMC_CAP2_MERGE_CAPABLE (1 << 26) /* Host can merge a segment over the segment size */
int fixed_drv_type; /* fixed driver type for non-removable media */ int fixed_drv_type; /* fixed driver type for non-removable media */
...@@ -397,6 +398,7 @@ struct mmc_host { ...@@ -397,6 +398,7 @@ struct mmc_host {
unsigned int retune_paused:1; /* re-tuning is temporarily disabled */ unsigned int retune_paused:1; /* re-tuning is temporarily disabled */
unsigned int use_blk_mq:1; /* use blk-mq */ unsigned int use_blk_mq:1; /* use blk-mq */
unsigned int retune_crc_disable:1; /* don't trigger retune upon crc */ unsigned int retune_crc_disable:1; /* don't trigger retune upon crc */
unsigned int can_dma_map_merge:1; /* merging can be used */
int rescan_disable; /* disable card detection */ int rescan_disable; /* disable card detection */
int rescan_entered; /* used with nonremovable devices */ int rescan_entered; /* used with nonremovable devices */
......
...@@ -18,6 +18,7 @@ struct notifier_block; /* in notifier.h */ ...@@ -18,6 +18,7 @@ struct notifier_block; /* in notifier.h */
#define VM_ALLOC 0x00000002 /* vmalloc() */ #define VM_ALLOC 0x00000002 /* vmalloc() */
#define VM_MAP 0x00000004 /* vmap()ed pages */ #define VM_MAP 0x00000004 /* vmap()ed pages */
#define VM_USERMAP 0x00000008 /* suitable for remap_vmalloc_range */ #define VM_USERMAP 0x00000008 /* suitable for remap_vmalloc_range */
#define VM_DMA_COHERENT 0x00000010 /* dma_alloc_coherent */
#define VM_UNINITIALIZED 0x00000020 /* vm_struct is not fully initialized */ #define VM_UNINITIALIZED 0x00000020 /* vm_struct is not fully initialized */
#define VM_NO_GUARD 0x00000040 /* don't add guard page */ #define VM_NO_GUARD 0x00000040 /* don't add guard page */
#define VM_KASAN 0x00000080 /* has allocated kasan shadow memory */ #define VM_KASAN 0x00000080 /* has allocated kasan shadow memory */
...@@ -26,6 +27,7 @@ struct notifier_block; /* in notifier.h */ ...@@ -26,6 +27,7 @@ struct notifier_block; /* in notifier.h */
* vfree_atomic(). * vfree_atomic().
*/ */
#define VM_FLUSH_RESET_PERMS 0x00000100 /* Reset direct map and flush TLB on unmap */ #define VM_FLUSH_RESET_PERMS 0x00000100 /* Reset direct map and flush TLB on unmap */
/* bits [20..32] reserved for arch specific ioremap internals */ /* bits [20..32] reserved for arch specific ioremap internals */
/* /*
......
...@@ -19,8 +19,6 @@ static inline enum paravirt_lazy_mode paravirt_get_lazy_mode(void) ...@@ -19,8 +19,6 @@ static inline enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
return PARAVIRT_LAZY_NONE; return PARAVIRT_LAZY_NONE;
} }
extern const struct dma_map_ops *xen_dma_ops;
#ifdef CONFIG_XEN #ifdef CONFIG_XEN
void __init xen_early_init(void); void __init xen_early_init(void);
#else #else
......
...@@ -2,15 +2,19 @@ ...@@ -2,15 +2,19 @@
#ifndef _XEN_ARM_PAGE_COHERENT_H #ifndef _XEN_ARM_PAGE_COHERENT_H
#define _XEN_ARM_PAGE_COHERENT_H #define _XEN_ARM_PAGE_COHERENT_H
void __xen_dma_map_page(struct device *hwdev, struct page *page, #include <linux/dma-mapping.h>
dma_addr_t dev_addr, unsigned long offset, size_t size, #include <asm/page.h>
enum dma_data_direction dir, unsigned long attrs);
void __xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle, static inline void *xen_alloc_coherent_pages(struct device *hwdev, size_t size,
size_t size, enum dma_data_direction dir, dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs)
unsigned long attrs); {
void __xen_dma_sync_single_for_cpu(struct device *hwdev, return dma_direct_alloc(hwdev, size, dma_handle, flags, attrs);
dma_addr_t handle, size_t size, enum dma_data_direction dir); }
void __xen_dma_sync_single_for_device(struct device *hwdev,
dma_addr_t handle, size_t size, enum dma_data_direction dir); static inline void xen_free_coherent_pages(struct device *hwdev, size_t size,
void *cpu_addr, dma_addr_t dma_handle, unsigned long attrs)
{
dma_direct_free(hwdev, size, cpu_addr, dma_handle, attrs);
}
#endif /* _XEN_ARM_PAGE_COHERENT_H */ #endif /* _XEN_ARM_PAGE_COHERENT_H */
...@@ -4,6 +4,11 @@ ...@@ -4,6 +4,11 @@
#include <linux/swiotlb.h> #include <linux/swiotlb.h>
void xen_dma_sync_for_cpu(struct device *dev, dma_addr_t handle,
phys_addr_t paddr, size_t size, enum dma_data_direction dir);
void xen_dma_sync_for_device(struct device *dev, dma_addr_t handle,
phys_addr_t paddr, size_t size, enum dma_data_direction dir);
extern int xen_swiotlb_init(int verbose, bool early); extern int xen_swiotlb_init(int verbose, bool early);
extern const struct dma_map_ops xen_swiotlb_dma_ops; extern const struct dma_map_ops xen_swiotlb_dma_ops;
......
...@@ -20,6 +20,15 @@ config ARCH_HAS_DMA_COHERENCE_H ...@@ -20,6 +20,15 @@ config ARCH_HAS_DMA_COHERENCE_H
config ARCH_HAS_DMA_SET_MASK config ARCH_HAS_DMA_SET_MASK
bool bool
#
# Select this option if the architecture needs special handling for
# DMA_ATTR_WRITE_COMBINE. Normally the "uncached" mapping should be what
# people thing of when saying write combine, so very few platforms should
# need to enable this.
#
config ARCH_HAS_DMA_WRITE_COMBINE
bool
config DMA_DECLARE_COHERENT config DMA_DECLARE_COHERENT
bool bool
...@@ -45,9 +54,6 @@ config ARCH_HAS_DMA_PREP_COHERENT ...@@ -45,9 +54,6 @@ config ARCH_HAS_DMA_PREP_COHERENT
config ARCH_HAS_DMA_COHERENT_TO_PFN config ARCH_HAS_DMA_COHERENT_TO_PFN
bool bool
config ARCH_HAS_DMA_MMAP_PGPROT
bool
config ARCH_HAS_FORCE_DMA_UNENCRYPTED config ARCH_HAS_FORCE_DMA_UNENCRYPTED
bool bool
......
...@@ -122,18 +122,6 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, ...@@ -122,18 +122,6 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
dma_release_coherent_memory(mem); dma_release_coherent_memory(mem);
return ret; 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);
static void *__dma_alloc_from_coherent(struct dma_coherent_mem *mem, static void *__dma_alloc_from_coherent(struct dma_coherent_mem *mem,
ssize_t size, dma_addr_t *dma_handle) ssize_t size, dma_addr_t *dma_handle)
...@@ -288,7 +276,6 @@ int dma_mmap_from_dev_coherent(struct device *dev, struct vm_area_struct *vma, ...@@ -288,7 +276,6 @@ int dma_mmap_from_dev_coherent(struct device *dev, struct vm_area_struct *vma,
return __dma_mmap_from_coherent(mem, vma, vaddr, size, ret); 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, int dma_mmap_from_global_coherent(struct vm_area_struct *vma, void *vaddr,
size_t size, int *ret) size_t size, int *ret)
......
...@@ -136,17 +136,29 @@ int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, ...@@ -136,17 +136,29 @@ int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
return ret; return ret;
} }
/*
* The whole dma_get_sgtable() idea is fundamentally unsafe - it seems
* that the intention is to allow exporting memory allocated via the
* coherent DMA APIs through the dma_buf API, which only accepts a
* scattertable. This presents a couple of problems:
* 1. Not all memory allocated via the coherent DMA APIs is backed by
* a struct page
* 2. Passing coherent DMA memory into the streaming APIs is not allowed
* as we will try to flush the memory through a different alias to that
* actually being used (and the flushes are redundant.)
*/
int dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, int dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt,
void *cpu_addr, dma_addr_t dma_addr, size_t size, void *cpu_addr, dma_addr_t dma_addr, size_t size,
unsigned long attrs) unsigned long attrs)
{ {
const struct dma_map_ops *ops = get_dma_ops(dev); const struct dma_map_ops *ops = get_dma_ops(dev);
if (!dma_is_direct(ops) && ops->get_sgtable) if (dma_is_direct(ops))
return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size, return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr,
attrs); size, attrs);
return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size, if (!ops->get_sgtable)
attrs); return -ENXIO;
return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size, attrs);
} }
EXPORT_SYMBOL(dma_get_sgtable_attrs); EXPORT_SYMBOL(dma_get_sgtable_attrs);
...@@ -161,9 +173,11 @@ pgprot_t dma_pgprot(struct device *dev, pgprot_t prot, unsigned long attrs) ...@@ -161,9 +173,11 @@ pgprot_t dma_pgprot(struct device *dev, pgprot_t prot, unsigned long attrs)
(IS_ENABLED(CONFIG_DMA_NONCOHERENT_CACHE_SYNC) && (IS_ENABLED(CONFIG_DMA_NONCOHERENT_CACHE_SYNC) &&
(attrs & DMA_ATTR_NON_CONSISTENT))) (attrs & DMA_ATTR_NON_CONSISTENT)))
return prot; return prot;
if (IS_ENABLED(CONFIG_ARCH_HAS_DMA_MMAP_PGPROT)) #ifdef CONFIG_ARCH_HAS_DMA_WRITE_COMBINE
return arch_dma_mmap_pgprot(dev, prot, attrs); if (attrs & DMA_ATTR_WRITE_COMBINE)
return pgprot_noncached(prot); return pgprot_writecombine(prot);
#endif
return pgprot_dmacoherent(prot);
} }
#endif /* CONFIG_MMU */ #endif /* CONFIG_MMU */
...@@ -174,7 +188,7 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, ...@@ -174,7 +188,7 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size, void *cpu_addr, dma_addr_t dma_addr, size_t size,
unsigned long attrs) unsigned long attrs)
{ {
#ifndef CONFIG_ARCH_NO_COHERENT_DMA_MMAP #ifdef CONFIG_MMU
unsigned long user_count = vma_pages(vma); unsigned long user_count = vma_pages(vma);
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
unsigned long off = vma->vm_pgoff; unsigned long off = vma->vm_pgoff;
...@@ -205,8 +219,29 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, ...@@ -205,8 +219,29 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
user_count << PAGE_SHIFT, vma->vm_page_prot); user_count << PAGE_SHIFT, vma->vm_page_prot);
#else #else
return -ENXIO; return -ENXIO;
#endif /* !CONFIG_ARCH_NO_COHERENT_DMA_MMAP */ #endif /* CONFIG_MMU */
}
/**
* dma_can_mmap - check if a given device supports dma_mmap_*
* @dev: device to check
*
* Returns %true if @dev supports dma_mmap_coherent() and dma_mmap_attrs() to
* map DMA allocations to userspace.
*/
bool dma_can_mmap(struct device *dev)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
if (dma_is_direct(ops)) {
return IS_ENABLED(CONFIG_MMU) &&
(dev_is_dma_coherent(dev) ||
IS_ENABLED(CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN));
}
return ops->mmap != NULL;
} }
EXPORT_SYMBOL_GPL(dma_can_mmap);
/** /**
* dma_mmap_attrs - map a coherent DMA allocation into user space * dma_mmap_attrs - map a coherent DMA allocation into user space
...@@ -227,31 +262,15 @@ int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, ...@@ -227,31 +262,15 @@ int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
{ {
const struct dma_map_ops *ops = get_dma_ops(dev); const struct dma_map_ops *ops = get_dma_ops(dev);
if (!dma_is_direct(ops) && ops->mmap) if (dma_is_direct(ops))
return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs); return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size,
return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size, attrs); attrs);
if (!ops->mmap)
return -ENXIO;
return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
} }
EXPORT_SYMBOL(dma_mmap_attrs); EXPORT_SYMBOL(dma_mmap_attrs);
static u64 dma_default_get_required_mask(struct device *dev)
{
u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT);
u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT));
u64 mask;
if (!high_totalram) {
/* convert to mask just covering totalram */
low_totalram = (1 << (fls(low_totalram) - 1));
low_totalram += low_totalram - 1;
mask = low_totalram;
} else {
high_totalram = (1 << (fls(high_totalram) - 1));
high_totalram += high_totalram - 1;
mask = (((u64)high_totalram) << 32) + 0xffffffff;
}
return mask;
}
u64 dma_get_required_mask(struct device *dev) u64 dma_get_required_mask(struct device *dev)
{ {
const struct dma_map_ops *ops = get_dma_ops(dev); const struct dma_map_ops *ops = get_dma_ops(dev);
...@@ -260,7 +279,16 @@ u64 dma_get_required_mask(struct device *dev) ...@@ -260,7 +279,16 @@ u64 dma_get_required_mask(struct device *dev)
return dma_direct_get_required_mask(dev); return dma_direct_get_required_mask(dev);
if (ops->get_required_mask) if (ops->get_required_mask)
return ops->get_required_mask(dev); return ops->get_required_mask(dev);
return dma_default_get_required_mask(dev);
/*
* We require every DMA ops implementation to at least support a 32-bit
* DMA mask (and use bounce buffering if that isn't supported in
* hardware). As the direct mapping code has its own routine to
* actually report an optimal mask we default to 32-bit here as that
* is the right thing for most IOMMUs, and at least not actively
* harmful in general.
*/
return DMA_BIT_MASK(32);
} }
EXPORT_SYMBOL_GPL(dma_get_required_mask); EXPORT_SYMBOL_GPL(dma_get_required_mask);
...@@ -405,3 +433,14 @@ size_t dma_max_mapping_size(struct device *dev) ...@@ -405,3 +433,14 @@ size_t dma_max_mapping_size(struct device *dev)
return size; return size;
} }
EXPORT_SYMBOL_GPL(dma_max_mapping_size); EXPORT_SYMBOL_GPL(dma_max_mapping_size);
unsigned long dma_get_merge_boundary(struct device *dev)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
if (!ops || !ops->get_merge_boundary)
return 0; /* can't merge */
return ops->get_merge_boundary(dev);
}
EXPORT_SYMBOL_GPL(dma_get_merge_boundary);
...@@ -11,13 +11,21 @@ ...@@ -11,13 +11,21 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
struct page **dma_common_find_pages(void *cpu_addr)
{
struct vm_struct *area = find_vm_area(cpu_addr);
if (!area || area->flags != VM_DMA_COHERENT)
return NULL;
return area->pages;
}
static struct vm_struct *__dma_common_pages_remap(struct page **pages, static struct vm_struct *__dma_common_pages_remap(struct page **pages,
size_t size, unsigned long vm_flags, pgprot_t prot, size_t size, pgprot_t prot, const void *caller)
const void *caller)
{ {
struct vm_struct *area; struct vm_struct *area;
area = get_vm_area_caller(size, vm_flags, caller); area = get_vm_area_caller(size, VM_DMA_COHERENT, caller);
if (!area) if (!area)
return NULL; return NULL;
...@@ -34,12 +42,11 @@ static struct vm_struct *__dma_common_pages_remap(struct page **pages, ...@@ -34,12 +42,11 @@ static struct vm_struct *__dma_common_pages_remap(struct page **pages,
* Cannot be used in non-sleeping contexts * Cannot be used in non-sleeping contexts
*/ */
void *dma_common_pages_remap(struct page **pages, size_t size, void *dma_common_pages_remap(struct page **pages, size_t size,
unsigned long vm_flags, pgprot_t prot, pgprot_t prot, const void *caller)
const void *caller)
{ {
struct vm_struct *area; struct vm_struct *area;
area = __dma_common_pages_remap(pages, size, vm_flags, prot, caller); area = __dma_common_pages_remap(pages, size, prot, caller);
if (!area) if (!area)
return NULL; return NULL;
...@@ -53,7 +60,6 @@ void *dma_common_pages_remap(struct page **pages, size_t size, ...@@ -53,7 +60,6 @@ void *dma_common_pages_remap(struct page **pages, size_t size,
* Cannot be used in non-sleeping contexts * Cannot be used in non-sleeping contexts
*/ */
void *dma_common_contiguous_remap(struct page *page, size_t size, void *dma_common_contiguous_remap(struct page *page, size_t size,
unsigned long vm_flags,
pgprot_t prot, const void *caller) pgprot_t prot, const void *caller)
{ {
int i; int i;
...@@ -67,7 +73,7 @@ void *dma_common_contiguous_remap(struct page *page, size_t size, ...@@ -67,7 +73,7 @@ void *dma_common_contiguous_remap(struct page *page, size_t size,
for (i = 0; i < (size >> PAGE_SHIFT); i++) for (i = 0; i < (size >> PAGE_SHIFT); i++)
pages[i] = nth_page(page, i); pages[i] = nth_page(page, i);
area = __dma_common_pages_remap(pages, size, vm_flags, prot, caller); area = __dma_common_pages_remap(pages, size, prot, caller);
kfree(pages); kfree(pages);
...@@ -79,11 +85,11 @@ void *dma_common_contiguous_remap(struct page *page, size_t size, ...@@ -79,11 +85,11 @@ void *dma_common_contiguous_remap(struct page *page, size_t size,
/* /*
* Unmaps a range previously mapped by dma_common_*_remap * Unmaps a range previously mapped by dma_common_*_remap
*/ */
void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags) void dma_common_free_remap(void *cpu_addr, size_t size)
{ {
struct vm_struct *area = find_vm_area(cpu_addr); struct page **pages = dma_common_find_pages(cpu_addr);
if (!area || (area->flags & vm_flags) != vm_flags) { if (!pages) {
WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr); WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
return; return;
} }
...@@ -105,7 +111,16 @@ static int __init early_coherent_pool(char *p) ...@@ -105,7 +111,16 @@ static int __init early_coherent_pool(char *p)
} }
early_param("coherent_pool", early_coherent_pool); early_param("coherent_pool", early_coherent_pool);
int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot) static gfp_t dma_atomic_pool_gfp(void)
{
if (IS_ENABLED(CONFIG_ZONE_DMA))
return GFP_DMA;
if (IS_ENABLED(CONFIG_ZONE_DMA32))
return GFP_DMA32;
return GFP_KERNEL;
}
static int __init dma_atomic_pool_init(void)
{ {
unsigned int pool_size_order = get_order(atomic_pool_size); unsigned int pool_size_order = get_order(atomic_pool_size);
unsigned long nr_pages = atomic_pool_size >> PAGE_SHIFT; unsigned long nr_pages = atomic_pool_size >> PAGE_SHIFT;
...@@ -117,7 +132,7 @@ int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot) ...@@ -117,7 +132,7 @@ int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot)
page = dma_alloc_from_contiguous(NULL, nr_pages, page = dma_alloc_from_contiguous(NULL, nr_pages,
pool_size_order, false); pool_size_order, false);
else else
page = alloc_pages(gfp, pool_size_order); page = alloc_pages(dma_atomic_pool_gfp(), pool_size_order);
if (!page) if (!page)
goto out; goto out;
...@@ -127,8 +142,9 @@ int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot) ...@@ -127,8 +142,9 @@ int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot)
if (!atomic_pool) if (!atomic_pool)
goto free_page; goto free_page;
addr = dma_common_contiguous_remap(page, atomic_pool_size, VM_USERMAP, addr = dma_common_contiguous_remap(page, atomic_pool_size,
prot, __builtin_return_address(0)); pgprot_dmacoherent(PAGE_KERNEL),
__builtin_return_address(0));
if (!addr) if (!addr)
goto destroy_genpool; goto destroy_genpool;
...@@ -143,7 +159,7 @@ int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot) ...@@ -143,7 +159,7 @@ int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot)
return 0; return 0;
remove_mapping: remove_mapping:
dma_common_free_remap(addr, atomic_pool_size, VM_USERMAP); dma_common_free_remap(addr, atomic_pool_size);
destroy_genpool: destroy_genpool:
gen_pool_destroy(atomic_pool); gen_pool_destroy(atomic_pool);
atomic_pool = NULL; atomic_pool = NULL;
...@@ -155,6 +171,7 @@ int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot) ...@@ -155,6 +171,7 @@ int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot)
atomic_pool_size / 1024); atomic_pool_size / 1024);
return -ENOMEM; return -ENOMEM;
} }
postcore_initcall(dma_atomic_pool_init);
bool dma_in_atomic_pool(void *start, size_t size) bool dma_in_atomic_pool(void *start, size_t size)
{ {
...@@ -217,7 +234,7 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, ...@@ -217,7 +234,7 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
arch_dma_prep_coherent(page, size); arch_dma_prep_coherent(page, size);
/* create a coherent mapping */ /* create a coherent mapping */
ret = dma_common_contiguous_remap(page, size, VM_USERMAP, ret = dma_common_contiguous_remap(page, size,
dma_pgprot(dev, PAGE_KERNEL, attrs), dma_pgprot(dev, PAGE_KERNEL, attrs),
__builtin_return_address(0)); __builtin_return_address(0));
if (!ret) { if (!ret) {
......
...@@ -2993,7 +2993,7 @@ int remap_vmalloc_range_partial(struct vm_area_struct *vma, unsigned long uaddr, ...@@ -2993,7 +2993,7 @@ int remap_vmalloc_range_partial(struct vm_area_struct *vma, unsigned long uaddr,
if (!area) if (!area)
return -EINVAL; return -EINVAL;
if (!(area->flags & VM_USERMAP)) if (!(area->flags & (VM_USERMAP | VM_DMA_COHERENT)))
return -EINVAL; return -EINVAL;
if (kaddr + size > area->addr + get_vm_area_size(area)) if (kaddr + size > area->addr + get_vm_area_size(area))
...@@ -3496,6 +3496,9 @@ static int s_show(struct seq_file *m, void *p) ...@@ -3496,6 +3496,9 @@ static int s_show(struct seq_file *m, void *p)
if (v->flags & VM_USERMAP) if (v->flags & VM_USERMAP)
seq_puts(m, " user"); seq_puts(m, " user");
if (v->flags & VM_DMA_COHERENT)
seq_puts(m, " dma-coherent");
if (is_vmalloc_addr(v->pages)) if (is_vmalloc_addr(v->pages))
seq_puts(m, " vpages"); seq_puts(m, " vpages");
......
...@@ -220,13 +220,12 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream) ...@@ -220,13 +220,12 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream)
{ {
if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_MMAP)) if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_MMAP))
return false; return false;
/* architecture supports dma_mmap_coherent()? */
#if defined(CONFIG_ARCH_NO_COHERENT_DMA_MMAP) || !defined(CONFIG_HAS_DMA) if (substream->ops->mmap ||
if (!substream->ops->mmap && substream->dma_buffer.dev.type != SNDRV_DMA_TYPE_DEV)
substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) return true;
return false;
#endif return dma_can_mmap(substream->dma_buffer.dev.dev);
return true;
} }
static int constrain_mask_params(struct snd_pcm_substream *substream, static int constrain_mask_params(struct snd_pcm_substream *substream,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment