diff options
-rw-r--r-- | arch/arc/include/asm/io.h | 95 | ||||
-rw-r--r-- | arch/arc/lib/cache.c | 10 | ||||
-rw-r--r-- | board/synopsys/axs101/axs101.c | 2 | ||||
-rw-r--r-- | configs/axs103_defconfig | 2 |
4 files changed, 86 insertions, 23 deletions
diff --git a/arch/arc/include/asm/io.h b/arch/arc/include/asm/io.h index b6f7724..42e7f22 100644 --- a/arch/arc/include/asm/io.h +++ b/arch/arc/include/asm/io.h @@ -10,6 +10,46 @@ #include <linux/types.h> #include <asm/byteorder.h> +#ifdef CONFIG_ISA_ARCV2 + +/* + * ARCv2 based HS38 cores are in-order issue, but still weakly ordered + * due to micro-arch buffering/queuing of load/store, cache hit vs. miss ... + * + * Explicit barrier provided by DMB instruction + * - Operand supports fine grained load/store/load+store semantics + * - Ensures that selected memory operation issued before it will complete + * before any subsequent memory operation of same type + * - DMB guarantees SMP as well as local barrier semantics + * (asm-generic/barrier.h ensures sane smp_*mb if not defined here, i.e. + * UP: barrier(), SMP: smp_*mb == *mb) + * - DSYNC provides DMB+completion_of_cache_bpu_maintenance_ops hence not needed + * in the general case. Plus it only provides full barrier. + */ + +#define mb() asm volatile("dmb 3\n" : : : "memory") +#define rmb() asm volatile("dmb 1\n" : : : "memory") +#define wmb() asm volatile("dmb 2\n" : : : "memory") + +#else + +/* + * ARCompact based cores (ARC700) only have SYNC instruction which is super + * heavy weight as it flushes the pipeline as well. + * There are no real SMP implementations of such cores. + */ + +#define mb() asm volatile("sync\n" : : : "memory") +#endif + +#ifdef CONFIG_ISA_ARCV2 +#define __iormb() rmb() +#define __iowmb() wmb() +#else +#define __iormb() do { } while (0) +#define __iowmb() do { } while (0) +#endif + /* * Given a physical address and a length, return a virtual address * that can be used to access the memory range with the caching @@ -72,18 +112,6 @@ static inline u32 __raw_readl(const volatile void __iomem *addr) return w; } -#define readb __raw_readb - -static inline u16 readw(const volatile void __iomem *addr) -{ - return __le16_to_cpu(__raw_readw(addr)); -} - -static inline u32 readl(const volatile void __iomem *addr) -{ - return __le32_to_cpu(__raw_readl(addr)); -} - static inline void __raw_writeb(u8 b, volatile void __iomem *addr) { __asm__ __volatile__("stb%U1 %0, %1\n" @@ -108,10 +136,6 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr) : "memory"); } -#define writeb __raw_writeb -#define writew(b, addr) __raw_writew(__cpu_to_le16(b), addr) -#define writel(b, addr) __raw_writel(__cpu_to_le32(b), addr) - static inline int __raw_readsb(unsigned int addr, void *data, int bytelen) { __asm__ __volatile__ ("1:ld.di r8, [r0]\n" @@ -184,6 +208,45 @@ static inline int __raw_writesl(unsigned int addr, void *data, int longlen) return longlen; } +/* + * MMIO can also get buffered/optimized in micro-arch, so barriers needed + * Based on ARM model for the typical use case + * + * <ST [DMA buffer]> + * <writel MMIO "go" reg> + * or: + * <readl MMIO "status" reg> + * <LD [DMA buffer]> + * + * http://lkml.kernel.org/r/20150622133656.GG1583@arm.com + */ +#define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; }) +#define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; }) +#define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; }) + +#define writeb(v,c) ({ __iowmb(); writeb_relaxed(v,c); }) +#define writew(v,c) ({ __iowmb(); writew_relaxed(v,c); }) +#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); }) + +/* + * Relaxed API for drivers which can handle barrier ordering themselves + * + * Also these are defined to perform little endian accesses. + * To provide the typical device register semantics of fixed endian, + * swap the byte order for Big Endian + * + * http://lkml.kernel.org/r/201603100845.30602.arnd@arndb.de + */ +#define readb_relaxed(c) __raw_readb(c) +#define readw_relaxed(c) ({ u16 __r = le16_to_cpu((__force __le16) \ + __raw_readw(c)); __r; }) +#define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \ + __raw_readl(c)); __r; }) + +#define writeb_relaxed(v,c) __raw_writeb(v,c) +#define writew_relaxed(v,c) __raw_writew((__force u16) cpu_to_le16(v),c) +#define writel_relaxed(v,c) __raw_writel((__force u32) cpu_to_le32(v),c) + #define out_arch(type, endian, a, v) __raw_write##type(cpu_to_##endian(v), a) #define in_arch(type, endian, a) endian##_to_cpu(__raw_read##type(a)) diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c index d1fb661..b6ec831 100644 --- a/arch/arc/lib/cache.c +++ b/arch/arc/lib/cache.c @@ -209,6 +209,9 @@ void cache_init(void) read_decode_cache_bcr_arcv2(); if (ioc_exists) { + flush_dcache_all(); + invalidate_dcache_all(); + /* IO coherency base - 0x8z */ write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, 0x80000); /* IO coherency aperture size - 512Mb: 0x8z-0xAz */ @@ -417,13 +420,10 @@ void flush_cache(unsigned long start, unsigned long size) void invalidate_dcache_all(void) { -#ifdef CONFIG_ISA_ARCV2 - if (!ioc_exists) -#endif - __dc_entire_op(OP_INV); + __dc_entire_op(OP_INV); #ifdef CONFIG_ISA_ARCV2 - if (slc_exists && !ioc_exists) + if (slc_exists) __slc_entire_op(OP_INV); #endif } diff --git a/board/synopsys/axs101/axs101.c b/board/synopsys/axs101/axs101.c index 84ee2bf..a5e774b 100644 --- a/board/synopsys/axs101/axs101.c +++ b/board/synopsys/axs101/axs101.c @@ -54,7 +54,7 @@ void smp_set_core_boot_addr(unsigned long addr, int corenr) writel(addr, (void __iomem *)RESET_VECTOR_ADDR); /* Make sure other cores see written value in memory */ - flush_dcache_range(RESET_VECTOR_ADDR, RESET_VECTOR_ADDR + sizeof(int)); + flush_dcache_all(); } void smp_kick_all_cpus(void) diff --git a/configs/axs103_defconfig b/configs/axs103_defconfig index 96a3de6..c8474de 100644 --- a/configs/axs103_defconfig +++ b/configs/axs103_defconfig @@ -1,7 +1,7 @@ CONFIG_ARC=y CONFIG_ISA_ARCV2=y CONFIG_DM_SERIAL=y -CONFIG_SYS_CLK_FREQ=50000000 +CONFIG_SYS_CLK_FREQ=100000000 CONFIG_SYS_TEXT_BASE=0x81000000 CONFIG_DEFAULT_DEVICE_TREE="axs10x" CONFIG_BOOTDELAY=3 |