]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/commitdiff
xtensa: platform-specific handling of coherent memory
authorMax Filippov <jcmvbkbc@gmail.com>
Wed, 11 Jul 2018 21:33:41 +0000 (14:33 -0700)
committerMax Filippov <jcmvbkbc@gmail.com>
Wed, 11 Jul 2018 22:59:41 +0000 (15:59 -0700)
Memory layout is not fixed for noMMU xtensa configurations. Platforms
that need to use coherent DMA should implement platform_vaddr_* helpers
that check address type (cached/uncached) and convert addresses between
these types.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
arch/xtensa/include/asm/kmem_layout.h
arch/xtensa/include/asm/pgtable.h
arch/xtensa/include/asm/platform.h
arch/xtensa/kernel/pci-dma.c

index 2317c835a4db3d2f6717ce130549d88bf0f6cfaf..9c12babc016cd996b1b9f27ff9ee0fb88b43b941 100644 (file)
 #error XCHAL_KSEG_PADDR is not properly aligned to XCHAL_KSEG_ALIGNMENT
 #endif
 
-#else
-
-#define XCHAL_KSEG_CACHED_VADDR        __XTENSA_UL_CONST(0xd0000000)
-#define XCHAL_KSEG_BYPASS_VADDR        __XTENSA_UL_CONST(0xd8000000)
-#define XCHAL_KSEG_SIZE                __XTENSA_UL_CONST(0x08000000)
-
 #endif
 
 #ifndef CONFIG_KASAN
index 38802259978fd3fbaa571a3afdb425eaa52adde0..29cfe421cf41c4e58f3259bf4dc64b0771155884 100644 (file)
@@ -66,6 +66,7 @@
 #define FIRST_USER_ADDRESS     0UL
 #define FIRST_USER_PGD_NR      (FIRST_USER_ADDRESS >> PGDIR_SHIFT)
 
+#ifdef CONFIG_MMU
 /*
  * Virtual memory area. We keep a distance to other memory regions to be
  * on the safe side. We also use this area for cache aliasing.
 #define TLBTEMP_SIZE           ICACHE_WAY_SIZE
 #endif
 
+#else
+
+#define VMALLOC_START          __XTENSA_UL_CONST(0)
+#define VMALLOC_END            __XTENSA_UL_CONST(0xffffffff)
+
+#endif
+
 /*
  * For the Xtensa architecture, the PTE layout is as follows:
  *
index f8fbef67bc5f20590df28e635950faeecce521e2..560483356a06a2fcf9ad619bfd6c83602791dc72 100644 (file)
@@ -75,4 +75,31 @@ extern void platform_calibrate_ccount (void);
  */
 void cpu_reset(void) __attribute__((noreturn));
 
+/*
+ * Memory caching is platform-dependent in noMMU xtensa configurations.
+ * The following set of functions should be implemented in platform code
+ * in order to enable coherent DMA memory operations when CONFIG_MMU is not
+ * enabled. Default implementations do nothing and issue a warning.
+ */
+
+/*
+ * Check whether p points to a cached memory.
+ */
+bool platform_vaddr_cached(const void *p);
+
+/*
+ * Check whether p points to an uncached memory.
+ */
+bool platform_vaddr_uncached(const void *p);
+
+/*
+ * Return pointer to an uncached view of the cached sddress p.
+ */
+void *platform_vaddr_to_uncached(void *p);
+
+/*
+ * Return pointer to a cached view of the uncached sddress p.
+ */
+void *platform_vaddr_to_cached(void *p);
+
 #endif /* _XTENSA_PLATFORM_H */
index 5c8a67fc3aa17e6950670c07e882beae3678155c..fe3343ddccafaea74206d4a06eacf40d85dd4482 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/types.h>
 #include <asm/cacheflush.h>
 #include <asm/io.h>
+#include <asm/platform.h>
 
 static void do_cache_op(phys_addr_t paddr, size_t size,
                        void (*fn)(unsigned long, unsigned long))
@@ -84,6 +85,58 @@ void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
        }
 }
 
+#ifdef CONFIG_MMU
+bool platform_vaddr_cached(const void *p)
+{
+       unsigned long addr = (unsigned long)p;
+
+       return addr >= XCHAL_KSEG_CACHED_VADDR &&
+              addr - XCHAL_KSEG_CACHED_VADDR < XCHAL_KSEG_SIZE;
+}
+
+bool platform_vaddr_uncached(const void *p)
+{
+       unsigned long addr = (unsigned long)p;
+
+       return addr >= XCHAL_KSEG_BYPASS_VADDR &&
+              addr - XCHAL_KSEG_BYPASS_VADDR < XCHAL_KSEG_SIZE;
+}
+
+void *platform_vaddr_to_uncached(void *p)
+{
+       return p + XCHAL_KSEG_BYPASS_VADDR - XCHAL_KSEG_CACHED_VADDR;
+}
+
+void *platform_vaddr_to_cached(void *p)
+{
+       return p + XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR;
+}
+#else
+bool __attribute__((weak)) platform_vaddr_cached(const void *p)
+{
+       WARN_ONCE(1, "Default %s implementation is used\n", __func__);
+       return true;
+}
+
+bool __attribute__((weak)) platform_vaddr_uncached(const void *p)
+{
+       WARN_ONCE(1, "Default %s implementation is used\n", __func__);
+       return false;
+}
+
+void __attribute__((weak)) *platform_vaddr_to_uncached(void *p)
+{
+       WARN_ONCE(1, "Default %s implementation is used\n", __func__);
+       return p;
+}
+
+void __attribute__((weak)) *platform_vaddr_to_cached(void *p)
+{
+       WARN_ONCE(1, "Default %s implementation is used\n", __func__);
+       return p;
+}
+#endif
+
 /*
  * Note: We assume that the full memory space is always mapped to 'kseg'
  *      Otherwise we have to use page attributes (not implemented).
@@ -92,8 +145,6 @@ void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
 void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
                gfp_t flag, unsigned long attrs)
 {
-       unsigned long ret;
-       unsigned long uncached;
        unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        struct page *page = NULL;
 
@@ -134,29 +185,21 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
                return p;
        }
 #endif
-       ret = (unsigned long)page_address(page);
-       BUG_ON(ret < XCHAL_KSEG_CACHED_VADDR ||
-              ret > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1);
-
-       uncached = ret + XCHAL_KSEG_BYPASS_VADDR - XCHAL_KSEG_CACHED_VADDR;
-       __invalidate_dcache_range(ret, size);
-
-       return (void *)uncached;
+       BUG_ON(!platform_vaddr_cached(page_address(page)));
+       __invalidate_dcache_range((unsigned long)page_address(page), size);
+       return platform_vaddr_to_uncached(page_address(page));
 }
 
 void arch_dma_free(struct device *dev, size_t size, void *vaddr,
                dma_addr_t dma_handle, unsigned long attrs)
 {
        unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
-       unsigned long addr = (unsigned long)vaddr;
        struct page *page;
 
        if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) {
                page = vaddr;
-       } else if (addr >= XCHAL_KSEG_BYPASS_VADDR &&
-                  addr - XCHAL_KSEG_BYPASS_VADDR < XCHAL_KSEG_SIZE) {
-               addr += XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR;
-               page = virt_to_page(addr);
+       } else if (platform_vaddr_uncached(vaddr)) {
+               page = virt_to_page(platform_vaddr_to_cached(vaddr));
        } else {
 #ifdef CONFIG_MMU
                dma_common_free_remap(vaddr, size, VM_MAP);