Skip to content

Commit 2820a70

Browse files
Eugeniy Paltsevvineetgarc
authored andcommitted
ARC: dma [IOC] Enable per device io coherency
So far the IOC treatment was global on ARC, being turned on (or off) for all devices in the system. With this patch, this can now be done per device using the "dma-coherent" DT property; IOW with this patch we can use both HW-coherent and regular DMA peripherals simultaneously. The changes involved are too many so enlisting the summary below: 1. common code calls ARC arch_setup_dma_ops() per device. 2. For coherent dma (IOC) it plugs in generic @dma_direct_ops which doesn't need any arch specific backend: No need for any explicit cache flushes or MMU mappings to provide for uncached access - dma_(map|sync)_single* return early as corresponding dma ops callbacks are NULL in generic code. So arch_sync_dma_*() -> dma_cache_*() need not handle the coherent dma case, hence drop ARC __dma_cache_*_ioc() which were no-op anyways 3. For noncoherent dma (non IOC) generic @dma_noncoherent_ops is used which in turns calls ARC specific routines - arch_dma_alloc() no longer checks for @ioc_enable since this is called only for !IOC case. Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> Signed-off-by: Vineet Gupta <vgupta@synopsys.com> [vgupta: rewrote changelog]
1 parent 678c811 commit 2820a70

File tree

3 files changed

+50
-40
lines changed

3 files changed

+50
-40
lines changed

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
// (C) 2018 Synopsys, Inc. (www.synopsys.com)
3+
4+
#ifndef ASM_ARC_DMA_MAPPING_H
5+
#define ASM_ARC_DMA_MAPPING_H
6+
7+
#include <asm-generic/dma-mapping.h>
8+
9+
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
10+
const struct iommu_ops *iommu, bool coherent);
11+
#define arch_setup_dma_ops arch_setup_dma_ops
12+
13+
#endif

arch/arc/mm/cache.c

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ char *arc_cache_mumbojumbo(int c, char *buf, int len)
6565

6666
n += scnprintf(buf + n, len - n, "Peripherals\t: %#lx%s%s\n",
6767
perip_base,
68-
IS_AVAIL3(ioc_exists, ioc_enable, ", IO-Coherency "));
68+
IS_AVAIL3(ioc_exists, ioc_enable, ", IO-Coherency (per-device) "));
6969

7070
return buf;
7171
}
@@ -896,15 +896,6 @@ static void __dma_cache_wback_slc(phys_addr_t start, unsigned long sz)
896896
slc_op(start, sz, OP_FLUSH);
897897
}
898898

899-
/*
900-
* DMA ops for systems with IOC
901-
* IOC hardware snoops all DMA traffic keeping the caches consistent with
902-
* memory - eliding need for any explicit cache maintenance of DMA buffers
903-
*/
904-
static void __dma_cache_wback_inv_ioc(phys_addr_t start, unsigned long sz) {}
905-
static void __dma_cache_inv_ioc(phys_addr_t start, unsigned long sz) {}
906-
static void __dma_cache_wback_ioc(phys_addr_t start, unsigned long sz) {}
907-
908899
/*
909900
* Exported DMA API
910901
*/
@@ -1264,11 +1255,7 @@ void __init arc_cache_init_master(void)
12641255
if (is_isa_arcv2() && ioc_enable)
12651256
arc_ioc_setup();
12661257

1267-
if (is_isa_arcv2() && ioc_enable) {
1268-
__dma_cache_wback_inv = __dma_cache_wback_inv_ioc;
1269-
__dma_cache_inv = __dma_cache_inv_ioc;
1270-
__dma_cache_wback = __dma_cache_wback_ioc;
1271-
} else if (is_isa_arcv2() && l2_line_sz && slc_enable) {
1258+
if (is_isa_arcv2() && l2_line_sz && slc_enable) {
12721259
__dma_cache_wback_inv = __dma_cache_wback_inv_slc;
12731260
__dma_cache_inv = __dma_cache_inv_slc;
12741261
__dma_cache_wback = __dma_cache_wback_slc;
@@ -1277,6 +1264,12 @@ void __init arc_cache_init_master(void)
12771264
__dma_cache_inv = __dma_cache_inv_l1;
12781265
__dma_cache_wback = __dma_cache_wback_l1;
12791266
}
1267+
/*
1268+
* In case of IOC (say IOC+SLC case), pointers above could still be set
1269+
* but end up not being relevant as the first function in chain is not
1270+
* called at all for @dma_direct_ops
1271+
* arch_sync_dma_for_cpu() -> dma_cache_*() -> __dma_cache_*()
1272+
*/
12801273
}
12811274

12821275
void __ref arc_cache_init(void)

arch/arc/mm/dma.c

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,17 @@
66
* published by the Free Software Foundation.
77
*/
88

9-
/*
10-
* DMA Coherent API Notes
11-
*
12-
* I/O is inherently non-coherent on ARC. So a coherent DMA buffer is
13-
* implemented by accessing it using a kernel virtual address, with
14-
* Cache bit off in the TLB entry.
15-
*
16-
* The default DMA address == Phy address which is 0x8000_0000 based.
17-
*/
18-
199
#include <linux/dma-noncoherent.h>
2010
#include <asm/cache.h>
2111
#include <asm/cacheflush.h>
2212

13+
/*
14+
* ARCH specific callbacks for generic noncoherent DMA ops (dma/noncoherent.c)
15+
* - hardware IOC not available (or "dma-coherent" not set for device in DT)
16+
* - But still handle both coherent and non-coherent requests from caller
17+
*
18+
* For DMA coherent hardware (IOC) generic code suffices
19+
*/
2320
void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
2421
gfp_t gfp, unsigned long attrs)
2522
{
@@ -33,19 +30,7 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
3330
if (!page)
3431
return NULL;
3532

36-
/*
37-
* IOC relies on all data (even coherent DMA data) being in cache
38-
* Thus allocate normal cached memory
39-
*
40-
* The gains with IOC are two pronged:
41-
* -For streaming data, elides need for cache maintenance, saving
42-
* cycles in flush code, and bus bandwidth as all the lines of a
43-
* buffer need to be flushed out to memory
44-
* -For coherent data, Read/Write to buffers terminate early in cache
45-
* (vs. always going to memory - thus are faster)
46-
*/
47-
if ((is_isa_arcv2() && ioc_enable) ||
48-
(attrs & DMA_ATTR_NON_CONSISTENT))
33+
if (attrs & DMA_ATTR_NON_CONSISTENT)
4934
need_coh = 0;
5035

5136
/*
@@ -95,8 +80,7 @@ void arch_dma_free(struct device *dev, size_t size, void *vaddr,
9580
struct page *page = virt_to_page(paddr);
9681
int is_non_coh = 1;
9782

98-
is_non_coh = (attrs & DMA_ATTR_NON_CONSISTENT) ||
99-
(is_isa_arcv2() && ioc_enable);
83+
is_non_coh = (attrs & DMA_ATTR_NON_CONSISTENT);
10084

10185
if (PageHighMem(page) || !is_non_coh)
10286
iounmap((void __force __iomem *)vaddr);
@@ -185,3 +169,23 @@ void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
185169
break;
186170
}
187171
}
172+
173+
/*
174+
* Plug in coherent or noncoherent dma ops
175+
*/
176+
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
177+
const struct iommu_ops *iommu, bool coherent)
178+
{
179+
/*
180+
* IOC hardware snoops all DMA traffic keeping the caches consistent
181+
* with memory - eliding need for any explicit cache maintenance of
182+
* DMA buffers - so we can use dma_direct cache ops.
183+
*/
184+
if (is_isa_arcv2() && ioc_enable && coherent) {
185+
set_dma_ops(dev, &dma_direct_ops);
186+
dev_info(dev, "use dma_direct_ops cache ops\n");
187+
} else {
188+
set_dma_ops(dev, &dma_noncoherent_ops);
189+
dev_info(dev, "use dma_noncoherent_ops cache ops\n");
190+
}
191+
}

0 commit comments

Comments
 (0)