microblaze/nommu: use the generic uncached segment support
authorChristoph Hellwig <hch@lst.de>
Wed, 14 Aug 2019 14:03:47 +0000 (16:03 +0200)
committerMichal Simek <michal.simek@xilinx.com>
Fri, 30 Aug 2019 09:47:16 +0000 (11:47 +0200)
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>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
arch/microblaze/Kconfig
arch/microblaze/mm/consistent.c

index d411de05b6282ddddfc7b31d4eb0739fe947e0a4..a0d749c309f3e44e88c3ce2ab3a8b1af0dcaacd6 100644 (file)
@@ -5,9 +5,11 @@ config MICROBLAZE
        select ARCH_NO_SWAP
        select ARCH_HAS_BINFMT_FLAT if !MMU
        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
index bc7042209c57a39725a764b22b68371d6b17e4bc..1a859e8b58c2e1682c33f0826f48420fa6a5af8c 100644 (file)
 #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;
+
+       return (void *)(addr & ~UNCACHED_SHADOW_MASK);
+}
+#else /* CONFIG_MMU */
 void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
                gfp_t gfp, unsigned long attrs)
 {
@@ -64,12 +91,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();
@@ -86,26 +110,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) {
@@ -117,7 +123,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
@@ -131,10 +136,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++;
@@ -154,7 +157,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;
@@ -172,7 +174,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.
@@ -187,18 +188,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;
@@ -216,5 +205,5 @@ void arch_dma_free(struct device *dev, size_t size, void *vaddr,
 
        /* flush tlb */
        flush_tlb_all();
-#endif
 }
+#endif /* CONFIG_MMU */