Merge tag 'dma-mapping-5.3' of git://git.infradead.org/users/hch/dma-mapping
Pull dma-mapping updates from Christoph Hellwig: - move the USB special case that bounced DMA through a device bar into the USB code instead of handling it in the common DMA code (Laurentiu Tudor and Fredrik Noring) - don't dip into the global CMA pool for single page allocations (Nicolin Chen) - fix a crash when allocating memory for the atomic pool failed during boot (Florian Fainelli) - move support for MIPS-style uncached segments to the common code and use that for MIPS and nios2 (me) - make support for DMA_ATTR_NON_CONSISTENT and DMA_ATTR_NO_KERNEL_MAPPING generic (me) - convert nds32 to the generic remapping allocator (me) * tag 'dma-mapping-5.3' of git://git.infradead.org/users/hch/dma-mapping: (29 commits) dma-mapping: mark dma_alloc_need_uncached as __always_inline MIPS: only select ARCH_HAS_UNCACHED_SEGMENT for non-coherent platforms usb: host: Fix excessive alignment restriction for local memory allocations lib/genalloc.c: Add algorithm, align and zeroed family of DMA allocators nios2: use the generic uncached segment support in dma-direct nds32: use the generic remapping allocator for coherent DMA allocations arc: use the generic remapping allocator for coherent DMA allocations dma-direct: handle DMA_ATTR_NO_KERNEL_MAPPING in common code dma-direct: handle DMA_ATTR_NON_CONSISTENT in common code dma-mapping: add a dma_alloc_need_uncached helper openrisc: remove the partial DMA_ATTR_NON_CONSISTENT support arc: remove the partial DMA_ATTR_NON_CONSISTENT support arm-nommu: remove the partial DMA_ATTR_NON_CONSISTENT support ARM: dma-mapping: allow larger DMA mask than supported dma-mapping: truncate dma masks to what dma_addr_t can hold iommu/dma: Apply dma_{alloc,free}_contiguous functions dma-remap: Avoid de-referencing NULL atomic_pool MIPS: use the generic uncached segment support in dma-direct dma-direct: provide generic support for uncached kernel segments au1100fb: fix DMA API abuse ...
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
@@ -67,7 +68,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
|
||||
|
||||
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
|
||||
(!is_device_dma_capable(hcd->self.sysdev) &&
|
||||
!(hcd->driver->flags & HCD_LOCAL_MEM)))
|
||||
!hcd->localmem_pool))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
|
||||
@@ -124,10 +125,12 @@ void *hcd_buffer_alloc(
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
if (hcd->localmem_pool)
|
||||
return gen_pool_dma_alloc(hcd->localmem_pool, size, dma);
|
||||
|
||||
/* some USB hosts just use PIO */
|
||||
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
|
||||
(!is_device_dma_capable(bus->sysdev) &&
|
||||
!(hcd->driver->flags & HCD_LOCAL_MEM))) {
|
||||
!is_device_dma_capable(bus->sysdev)) {
|
||||
*dma = ~(dma_addr_t) 0;
|
||||
return kmalloc(size, mem_flags);
|
||||
}
|
||||
@@ -152,9 +155,13 @@ void hcd_buffer_free(
|
||||
if (!addr)
|
||||
return;
|
||||
|
||||
if (hcd->localmem_pool) {
|
||||
gen_pool_free(hcd->localmem_pool, (unsigned long)addr, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
|
||||
(!is_device_dma_capable(bus->sysdev) &&
|
||||
!(hcd->driver->flags & HCD_LOCAL_MEM))) {
|
||||
!is_device_dma_capable(bus->sysdev)) {
|
||||
kfree(addr);
|
||||
return;
|
||||
}
|
||||
|
@@ -29,6 +29,8 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/usb.h>
|
||||
@@ -1345,14 +1347,14 @@ EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
|
||||
* using regular system memory - like pci devices doing bus mastering.
|
||||
*
|
||||
* To support host controllers with limited dma capabilities we provide dma
|
||||
* bounce buffers. This feature can be enabled using the HCD_LOCAL_MEM flag.
|
||||
* bounce buffers. This feature can be enabled by initializing
|
||||
* hcd->localmem_pool using usb_hcd_setup_local_mem().
|
||||
* For this to work properly the host controller code must first use the
|
||||
* function dma_declare_coherent_memory() to point out which memory area
|
||||
* that should be used for dma allocations.
|
||||
*
|
||||
* The HCD_LOCAL_MEM flag then tells the usb code to allocate all data for
|
||||
* dma using dma_alloc_coherent() which in turn allocates from the memory
|
||||
* area pointed out with dma_declare_coherent_memory().
|
||||
* The initialized hcd->localmem_pool then tells the usb code to allocate all
|
||||
* data for dma using the genalloc API.
|
||||
*
|
||||
* So, to summarize...
|
||||
*
|
||||
@@ -1362,9 +1364,6 @@ EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
|
||||
* (a) "normal" kernel memory is no good, and
|
||||
* (b) there's not enough to share
|
||||
*
|
||||
* - The only *portable* hook for such stuff in the
|
||||
* DMA framework is dma_declare_coherent_memory()
|
||||
*
|
||||
* - So we use that, even though the primary requirement
|
||||
* is that the memory be "local" (hence addressable
|
||||
* by that device), not "coherent".
|
||||
@@ -1531,7 +1530,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
||||
urb->setup_dma))
|
||||
return -EAGAIN;
|
||||
urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
|
||||
} else if (hcd->driver->flags & HCD_LOCAL_MEM) {
|
||||
} else if (hcd->localmem_pool) {
|
||||
ret = hcd_alloc_coherent(
|
||||
urb->dev->bus, mem_flags,
|
||||
&urb->setup_dma,
|
||||
@@ -1601,7 +1600,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
||||
else
|
||||
urb->transfer_flags |= URB_DMA_MAP_SINGLE;
|
||||
}
|
||||
} else if (hcd->driver->flags & HCD_LOCAL_MEM) {
|
||||
} else if (hcd->localmem_pool) {
|
||||
ret = hcd_alloc_coherent(
|
||||
urb->dev->bus, mem_flags,
|
||||
&urb->transfer_dma,
|
||||
@@ -3039,6 +3038,40 @@ usb_hcd_platform_shutdown(struct platform_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown);
|
||||
|
||||
int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr,
|
||||
dma_addr_t dma, size_t size)
|
||||
{
|
||||
int err;
|
||||
void *local_mem;
|
||||
|
||||
hcd->localmem_pool = devm_gen_pool_create(hcd->self.sysdev, 4,
|
||||
dev_to_node(hcd->self.sysdev),
|
||||
dev_name(hcd->self.sysdev));
|
||||
if (IS_ERR(hcd->localmem_pool))
|
||||
return PTR_ERR(hcd->localmem_pool);
|
||||
|
||||
local_mem = devm_memremap(hcd->self.sysdev, phys_addr,
|
||||
size, MEMREMAP_WC);
|
||||
if (!local_mem)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Here we pass a dma_addr_t but the arg type is a phys_addr_t.
|
||||
* It's not backed by system memory and thus there's no kernel mapping
|
||||
* for it.
|
||||
*/
|
||||
err = gen_pool_add_virt(hcd->localmem_pool, (unsigned long)local_mem,
|
||||
dma, size, dev_to_node(hcd->self.sysdev));
|
||||
if (err < 0) {
|
||||
dev_err(hcd->self.sysdev, "gen_pool_add_virt failed with %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_setup_local_mem);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_MON)
|
||||
|
Reference in New Issue
Block a user