* [PATCH 1/2] nios2: use the generic uncached segment support in dma-direct
2019-06-03 6:53 switch nios2 and microblaze to use the generic uncached segement support Christoph Hellwig
@ 2019-06-03 6:53 ` Christoph Hellwig
2019-06-25 5:29 ` Ley Foon Tan
2019-06-03 6:53 ` [PATCH 2/2] microblaze: " Christoph Hellwig
2019-06-14 1:40 ` switch nios2 and microblaze to use the generic uncached segement support Ley Foon Tan
2 siblings, 1 reply; 9+ messages in thread
From: Christoph Hellwig @ 2019-06-03 6:53 UTC (permalink / raw)
To: Ley Foon Tan, Michal Simek; +Cc: linux-mips, iommu, linux-kernel
Stop providing our own arch alloc/free hooks and just expose the segment
offset and use the generic dma-direct allocator.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
arch/nios2/Kconfig | 1 +
arch/nios2/include/asm/page.h | 6 ------
arch/nios2/mm/dma-mapping.c | 34 +++++++++++++++-------------------
3 files changed, 16 insertions(+), 25 deletions(-)
diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig
index 26a9c760a98b..44b5da37e8bd 100644
--- a/arch/nios2/Kconfig
+++ b/arch/nios2/Kconfig
@@ -4,6 +4,7 @@ config NIOS2
select ARCH_32BIT_OFF_T
select ARCH_HAS_SYNC_DMA_FOR_CPU
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
+ select ARCH_HAS_UNCACHED_SEGMENT
select ARCH_NO_SWAP
select TIMER_OF
select GENERIC_ATOMIC64
diff --git a/arch/nios2/include/asm/page.h b/arch/nios2/include/asm/page.h
index f1fbdc47bdaf..79fcac61f6ef 100644
--- a/arch/nios2/include/asm/page.h
+++ b/arch/nios2/include/asm/page.h
@@ -101,12 +101,6 @@ static inline bool pfn_valid(unsigned long pfn)
# define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-# define UNCAC_ADDR(addr) \
- ((void *)((unsigned)(addr) | CONFIG_NIOS2_IO_REGION_BASE))
-# define CAC_ADDR(addr) \
- ((void *)(((unsigned)(addr) & ~CONFIG_NIOS2_IO_REGION_BASE) | \
- CONFIG_NIOS2_KERNEL_REGION_BASE))
-
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>
diff --git a/arch/nios2/mm/dma-mapping.c b/arch/nios2/mm/dma-mapping.c
index 4af9e5b5ba1c..9cb238664584 100644
--- a/arch/nios2/mm/dma-mapping.c
+++ b/arch/nios2/mm/dma-mapping.c
@@ -60,32 +60,28 @@ void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
}
}
-void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
- gfp_t gfp, unsigned long attrs)
+void arch_dma_prep_coherent(struct page *page, size_t size)
{
- void *ret;
+ unsigned long start = (unsigned long)page_address(page);
- /* optimized page clearing */
- gfp |= __GFP_ZERO;
+ flush_dcache_range(start, start + size);
+}
- if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
- gfp |= GFP_DMA;
+void *uncached_kernel_address(void *ptr)
+{
+ unsigned long addr = (unsigned long)ptr;
- ret = (void *) __get_free_pages(gfp, get_order(size));
- if (ret != NULL) {
- *dma_handle = virt_to_phys(ret);
- flush_dcache_range((unsigned long) ret,
- (unsigned long) ret + size);
- ret = UNCAC_ADDR(ret);
- }
+ addr |= CONFIG_NIOS2_IO_REGION_BASE;
- return ret;
+ return (void *)ptr;
}
-void arch_dma_free(struct device *dev, size_t size, void *vaddr,
- dma_addr_t dma_handle, unsigned long attrs)
+void *cached_kernel_address(void *ptr)
{
- unsigned long addr = (unsigned long) CAC_ADDR((unsigned long) vaddr);
+ unsigned long addr = (unsigned long)ptr;
+
+ addr &= ~CONFIG_NIOS2_IO_REGION_BASE;
+ addr |= CONFIG_NIOS2_KERNEL_REGION_BASE;
- free_pages(addr, get_order(size));
+ return (void *)ptr;
}
--
2.20.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/2] microblaze: use the generic uncached segment support in dma-direct
2019-06-03 6:53 switch nios2 and microblaze to use the generic uncached segement support Christoph Hellwig
2019-06-03 6:53 ` [PATCH 1/2] nios2: use the generic uncached segment support in dma-direct Christoph Hellwig
@ 2019-06-03 6:53 ` Christoph Hellwig
2019-06-14 1:40 ` switch nios2 and microblaze to use the generic uncached segement support Ley Foon Tan
2 siblings, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2019-06-03 6:53 UTC (permalink / raw)
To: Ley Foon Tan, Michal Simek; +Cc: linux-mips, iommu, linux-kernel
Stop providing our own arch alloc/free hooks for nommu platforms and
just expose the segment offset and use the generic dma-direct
allocator.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
arch/microblaze/Kconfig | 2 +
arch/microblaze/mm/consistent.c | 97 +++++++++++++++------------------
2 files changed, 47 insertions(+), 52 deletions(-)
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index f11433daab4a..7dc7f264ccfa 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -4,9 +4,11 @@ config MICROBLAZE
select ARCH_32BIT_OFF_T
select ARCH_NO_SWAP
select ARCH_HAS_DMA_COHERENT_TO_PFN if MMU
+ select ARCH_HAS_DMA_PREP_COHERENT
select ARCH_HAS_GCOV_PROFILE_ALL
select ARCH_HAS_SYNC_DMA_FOR_CPU
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
+ select ARCH_HAS_UNCACHED_SEGMENT if !MMU
select ARCH_MIGHT_HAVE_PC_PARPORT
select ARCH_NO_COHERENT_DMA_MMAP if !MMU
select ARCH_WANT_IPC_PARSE_VERSION
diff --git a/arch/microblaze/mm/consistent.c b/arch/microblaze/mm/consistent.c
index 3002cbca3059..a525194a754e 100644
--- a/arch/microblaze/mm/consistent.c
+++ b/arch/microblaze/mm/consistent.c
@@ -45,21 +45,52 @@
#include <asm/cpuinfo.h>
#include <asm/tlbflush.h>
-#ifndef CONFIG_MMU
-/* I have to use dcache values because I can't relate on ram size */
-# define UNCACHED_SHADOW_MASK (cpuinfo.dcache_high - cpuinfo.dcache_base + 1)
-#endif
+void arch_dma_prep_coherent(struct page *page, size_t size)
+{
+ phys_addr_t paddr = page_to_phys(page);
+
+ flush_dcache_range(paddr, paddr + size);
+}
+#ifndef CONFIG_MMU
/*
- * Consistent memory allocators. Used for DMA devices that want to
- * share uncached memory with the processor core.
- * My crufty no-MMU approach is simple. In the HW platform we can optionally
- * mirror the DDR up above the processor cacheable region. So, memory accessed
- * in this mirror region will not be cached. It's alloced from the same
- * pool as normal memory, but the handle we return is shifted up into the
- * uncached region. This will no doubt cause big problems if memory allocated
- * here is not also freed properly. -- JW
+ * Consistent memory allocators. Used for DMA devices that want to share
+ * uncached memory with the processor core. My crufty no-MMU approach is
+ * simple. In the HW platform we can optionally mirror the DDR up above the
+ * processor cacheable region. So, memory accessed in this mirror region will
+ * not be cached. It's alloced from the same pool as normal memory, but the
+ * handle we return is shifted up into the uncached region. This will no doubt
+ * cause big problems if memory allocated here is not also freed properly. -- JW
+ *
+ * I have to use dcache values because I can't relate on ram size:
*/
+#ifdef CONFIG_XILINX_UNCACHED_SHADOW
+#define UNCACHED_SHADOW_MASK (cpuinfo.dcache_high - cpuinfo.dcache_base + 1)
+#else
+#define UNCACHED_SHADOW_MASK 0
+#endif /* CONFIG_XILINX_UNCACHED_SHADOW */
+
+void *uncached_kernel_address(void *ptr)
+{
+ unsigned long addr = (unsigned long)ptr;
+
+ addr |= UNCACHED_SHADOW_MASK;
+ if (addr > cpuinfo.dcache_base && addr < cpuinfo.dcache_high)
+ pr_warn("ERROR: Your cache coherent area is CACHED!!!\n");
+ return (void *)addr;
+}
+
+void *cached_kernel_address(void *ptr)
+{
+ unsigned long addr = (unsigned long)ptr;
+
+ addr &= ~UNCACHED_SHADOW_MASK;
+
+ return (void *)addr;
+}
+
+#else /* CONFIG_MMU */
+
void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
gfp_t gfp, unsigned long attrs)
{
@@ -67,12 +98,9 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
void *ret;
unsigned int i, err = 0;
struct page *page, *end;
-
-#ifdef CONFIG_MMU
phys_addr_t pa;
struct vm_struct *area;
unsigned long va;
-#endif
if (in_interrupt())
BUG();
@@ -89,26 +117,8 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
* we need to ensure that there are no cachelines in use,
* or worse dirty in this area.
*/
- flush_dcache_range(virt_to_phys((void *)vaddr),
- virt_to_phys((void *)vaddr) + size);
-
-#ifndef CONFIG_MMU
- ret = (void *)vaddr;
- /*
- * Here's the magic! Note if the uncached shadow is not implemented,
- * it's up to the calling code to also test that condition and make
- * other arranegments, such as manually flushing the cache and so on.
- */
-# ifdef CONFIG_XILINX_UNCACHED_SHADOW
- ret = (void *)((unsigned) ret | UNCACHED_SHADOW_MASK);
-# endif
- if ((unsigned int)ret > cpuinfo.dcache_base &&
- (unsigned int)ret < cpuinfo.dcache_high)
- pr_warn("ERROR: Your cache coherent area is CACHED!!!\n");
+ arch_dma_prep_coherent(virt_to_page((unsigned long)vaddr), size);
- /* dma_handle is same as physical (shadowed) address */
- *dma_handle = (dma_addr_t)ret;
-#else
/* Allocate some common virtual space to map the new pages. */
area = get_vm_area(size, VM_ALLOC);
if (!area) {
@@ -120,7 +130,6 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
/* This gives us the real physical address of the first page. */
*dma_handle = pa = __virt_to_phys(vaddr);
-#endif
/*
* free wasted pages. We skip the first page since we know
@@ -134,10 +143,8 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
split_page(page, order);
for (i = 0; i < size && err == 0; i += PAGE_SIZE) {
-#ifdef CONFIG_MMU
/* MS: This is the whole magic - use cache inhibit pages */
err = map_page(va + i, pa + i, _PAGE_KERNEL | _PAGE_NO_CACHE);
-#endif
SetPageReserved(page);
page++;
@@ -157,7 +164,6 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
return ret;
}
-#ifdef CONFIG_MMU
static pte_t *consistent_virt_to_pte(void *vaddr)
{
unsigned long addr = (unsigned long)vaddr;
@@ -175,7 +181,6 @@ long arch_dma_coherent_to_pfn(struct device *dev, void *vaddr,
return pte_pfn(*ptep);
}
-#endif
/*
* free page(s) as defined by the above mapping.
@@ -190,18 +195,6 @@ void arch_dma_free(struct device *dev, size_t size, void *vaddr,
size = PAGE_ALIGN(size);
-#ifndef CONFIG_MMU
- /* Clear SHADOW_MASK bit in address, and free as per usual */
-# ifdef CONFIG_XILINX_UNCACHED_SHADOW
- vaddr = (void *)((unsigned)vaddr & ~UNCACHED_SHADOW_MASK);
-# endif
- page = virt_to_page(vaddr);
-
- do {
- __free_reserved_page(page);
- page++;
- } while (size -= PAGE_SIZE);
-#else
do {
pte_t *ptep = consistent_virt_to_pte(vaddr);
unsigned long pfn;
@@ -219,5 +212,5 @@ void arch_dma_free(struct device *dev, size_t size, void *vaddr,
/* flush tlb */
flush_tlb_all();
-#endif
}
+#endif /* CONFIG_MMU */
--
2.20.1
^ permalink raw reply related [flat|nested] 9+ messages in thread