Skip to content

Commit ad3c7b1

Browse files
author
Christoph Hellwig
committed
arm: use swiotlb for bounce buffering on LPAE configs
The DMA API requires that 32-bit DMA masks are always supported, but on arm LPAE configs they do not currently work when memory is present above 4GB. Wire up the swiotlb code like for all other architectures to provide the bounce buffering in that case. Fixes: 21e07db ("scsi: reduce use of block bounce buffers"). Reported-by: Roger Quadros <rogerq@ti.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Tested-by: Vignesh Raghavendra <vigneshr@ti.com>
1 parent 66d7780 commit ad3c7b1

File tree

4 files changed

+74
-1
lines changed

4 files changed

+74
-1
lines changed

arch/arm/include/asm/dma-mapping.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ extern const struct dma_map_ops arm_coherent_dma_ops;
1818

1919
static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus)
2020
{
21-
return IS_ENABLED(CONFIG_MMU) ? &arm_dma_ops : NULL;
21+
if (IS_ENABLED(CONFIG_MMU) && !IS_ENABLED(CONFIG_ARM_LPAE))
22+
return &arm_dma_ops;
23+
return NULL;
2224
}
2325

2426
#ifdef __arch_page_to_dma

arch/arm/mm/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,11 @@ config ARM_LPAE
663663
depends on MMU && CPU_32v7 && !CPU_32v6 && !CPU_32v5 && \
664664
!CPU_32v4 && !CPU_32v3
665665
select PHYS_ADDR_T_64BIT
666+
select SWIOTLB
667+
select ARCH_HAS_DMA_COHERENT_TO_PFN
668+
select ARCH_HAS_DMA_MMAP_PGPROT
669+
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
670+
select ARCH_HAS_SYNC_DMA_FOR_CPU
666671
help
667672
Say Y if you have an ARMv7 processor supporting the LPAE page
668673
table format and you would like to access memory beyond the

arch/arm/mm/dma-mapping.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/init.h>
1616
#include <linux/device.h>
1717
#include <linux/dma-mapping.h>
18+
#include <linux/dma-noncoherent.h>
1819
#include <linux/dma-contiguous.h>
1920
#include <linux/highmem.h>
2021
#include <linux/memblock.h>
@@ -1125,6 +1126,19 @@ int arm_dma_supported(struct device *dev, u64 mask)
11251126

11261127
static const struct dma_map_ops *arm_get_dma_map_ops(bool coherent)
11271128
{
1129+
/*
1130+
* When CONFIG_ARM_LPAE is set, physical address can extend above
1131+
* 32-bits, which then can't be addressed by devices that only support
1132+
* 32-bit DMA.
1133+
* Use the generic dma-direct / swiotlb ops code in that case, as that
1134+
* handles bounce buffering for us.
1135+
*
1136+
* Note: this checks CONFIG_ARM_LPAE instead of CONFIG_SWIOTLB as the
1137+
* latter is also selected by the Xen code, but that code for now relies
1138+
* on non-NULL dev_dma_ops. To be cleaned up later.
1139+
*/
1140+
if (IS_ENABLED(CONFIG_ARM_LPAE))
1141+
return NULL;
11281142
return coherent ? &arm_coherent_dma_ops : &arm_dma_ops;
11291143
}
11301144

@@ -2329,6 +2343,9 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
23292343
const struct dma_map_ops *dma_ops;
23302344

23312345
dev->archdata.dma_coherent = coherent;
2346+
#ifdef CONFIG_SWIOTLB
2347+
dev->dma_coherent = coherent;
2348+
#endif
23322349

23332350
/*
23342351
* Don't override the dma_ops if they have already been set. Ideally
@@ -2363,3 +2380,47 @@ void arch_teardown_dma_ops(struct device *dev)
23632380
/* Let arch_setup_dma_ops() start again from scratch upon re-probe */
23642381
set_dma_ops(dev, NULL);
23652382
}
2383+
2384+
#ifdef CONFIG_SWIOTLB
2385+
void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
2386+
size_t size, enum dma_data_direction dir)
2387+
{
2388+
__dma_page_cpu_to_dev(phys_to_page(paddr), paddr & (PAGE_SIZE - 1),
2389+
size, dir);
2390+
}
2391+
2392+
void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
2393+
size_t size, enum dma_data_direction dir)
2394+
{
2395+
__dma_page_dev_to_cpu(phys_to_page(paddr), paddr & (PAGE_SIZE - 1),
2396+
size, dir);
2397+
}
2398+
2399+
long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
2400+
dma_addr_t dma_addr)
2401+
{
2402+
return dma_to_pfn(dev, dma_addr);
2403+
}
2404+
2405+
pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
2406+
unsigned long attrs)
2407+
{
2408+
if (!dev_is_dma_coherent(dev))
2409+
return __get_dma_pgprot(attrs, prot);
2410+
return prot;
2411+
}
2412+
2413+
void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
2414+
gfp_t gfp, unsigned long attrs)
2415+
{
2416+
return __dma_alloc(dev, size, dma_handle, gfp,
2417+
__get_dma_pgprot(attrs, PAGE_KERNEL), false,
2418+
attrs, __builtin_return_address(0));
2419+
}
2420+
2421+
void arch_dma_free(struct device *dev, size_t size, void *cpu_addr,
2422+
dma_addr_t dma_handle, unsigned long attrs)
2423+
{
2424+
__arm_dma_free(dev, size, cpu_addr, dma_handle, attrs, false);
2425+
}
2426+
#endif /* CONFIG_SWIOTLB */

arch/arm/mm/init.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/dma-contiguous.h>
2222
#include <linux/sizes.h>
2323
#include <linux/stop_machine.h>
24+
#include <linux/swiotlb.h>
2425

2526
#include <asm/cp15.h>
2627
#include <asm/mach-types.h>
@@ -463,6 +464,10 @@ static void __init free_highpages(void)
463464
*/
464465
void __init mem_init(void)
465466
{
467+
#ifdef CONFIG_ARM_LPAE
468+
swiotlb_init(1);
469+
#endif
470+
466471
set_max_mapnr(pfn_to_page(max_pfn) - mem_map);
467472

468473
/* this will put all unused low memory onto the freelists */

0 commit comments

Comments
 (0)