Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

SH2(A) cache update

Includes:
- SH2 (7619) Writeback support.
- SH2A cache handling fix.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>

authored by

Yoshinori Sato and committed by
Paul Mundt
cce2d453 1af446ed

+213 -16
+4 -2
arch/sh/include/cpu-sh2/cpu/cache.h
··· 21 21 #define CCR 0xffffffec 22 22 23 23 #define CCR_CACHE_CE 0x01 /* Cache enable */ 24 - #define CCR_CACHE_WT 0x06 /* CCR[bit1=1,bit2=1] */ 24 + #define CCR_CACHE_WT 0x02 /* CCR[bit1=1,bit2=1] */ 25 25 /* 0x00000000-0x7fffffff: Write-through */ 26 26 /* 0x80000000-0x9fffffff: Write-back */ 27 27 /* 0xc0000000-0xdfffffff: Write-through */ 28 - #define CCR_CACHE_CB 0x00 /* CCR[bit1=0,bit2=0] */ 28 + #define CCR_CACHE_CB 0x04 /* CCR[bit1=0,bit2=0] */ 29 29 /* 0x00000000-0x7fffffff: Write-back */ 30 30 /* 0x80000000-0x9fffffff: Write-through */ 31 31 /* 0xc0000000-0xdfffffff: Write-back */ ··· 36 36 37 37 #define CCR_CACHE_ENABLE CCR_CACHE_CE 38 38 #define CCR_CACHE_INVALIDATE CCR_CACHE_CF 39 + #define CACHE_PHYSADDR_MASK 0x1ffffc00 40 + 39 41 #endif 40 42 41 43 #endif /* __ASM_CPU_SH2_CACHE_H */
+3
arch/sh/include/cpu-sh2a/cpu/cache.h
··· 36 36 37 37 #define CCR_CACHE_ENABLE (CCR_CACHE_OCE | CCR_CACHE_ICE) 38 38 #define CCR_CACHE_INVALIDATE (CCR_CACHE_OCI | CCR_CACHE_ICI) 39 + #define CCR_ICACHE_INVALIDATE CCR_CACHE_ICI 40 + #define CCR_OCACHE_INVALIDATE CCR_CACHE_OCI 41 + #define CACHE_PHYSADDR_MASK 0x1ffffc00 39 42 40 43 #endif /* __ASM_CPU_SH2A_CACHE_H */
+34
arch/sh/include/cpu-sh2a/cpu/cacheflush.h
··· 1 + #ifndef __ASM_CPU_SH2A_CACHEFLUSH_H 2 + #define __ASM_CPU_SH2A_CACHEFLUSH_H 3 + 4 + /* 5 + * Cache flushing: 6 + * 7 + * - flush_cache_all() flushes entire cache 8 + * - flush_cache_mm(mm) flushes the specified mm context's cache lines 9 + * - flush_cache_dup mm(mm) handles cache flushing when forking 10 + * - flush_cache_page(mm, vmaddr, pfn) flushes a single page 11 + * - flush_cache_range(vma, start, end) flushes a range of pages 12 + * 13 + * - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache 14 + * - flush_icache_range(start, end) flushes(invalidates) a range for icache 15 + * - flush_icache_page(vma, pg) flushes(invalidates) a page for icache 16 + * 17 + * Caches are indexed (effectively) by physical address on SH-2, so 18 + * we don't need them. 19 + */ 20 + #define flush_cache_all() do { } while (0) 21 + #define flush_cache_mm(mm) do { } while (0) 22 + #define flush_cache_dup_mm(mm) do { } while (0) 23 + #define flush_cache_range(vma, start, end) do { } while (0) 24 + #define flush_cache_page(vma, vmaddr, pfn) do { } while (0) 25 + #define flush_dcache_page(page) do { } while (0) 26 + #define flush_dcache_mmap_lock(mapping) do { } while (0) 27 + #define flush_dcache_mmap_unlock(mapping) do { } while (0) 28 + void flush_icache_range(unsigned long start, unsigned long end); 29 + #define flush_icache_page(vma,pg) do { } while (0) 30 + #define flush_icache_user_range(vma,pg,adr,len) do { } while (0) 31 + #define flush_cache_sigtramp(vaddr) do { } while (0) 32 + 33 + #define p3_cache_init() do { } while (0) 34 + #endif /* __ASM_CPU_SH2A_CACHEFLUSH_H */
-1
arch/sh/mm/Kconfig
··· 237 237 238 238 config CACHE_WRITEBACK 239 239 bool "Write-back" 240 - depends on CPU_SH2A || CPU_SH3 || CPU_SH4 || CPU_SH5 241 240 242 241 config CACHE_WRITETHROUGH 243 242 bool "Write-through"
+7 -4
arch/sh/mm/Makefile_32
··· 5 5 obj-y := init.o extable_32.o consistent.o 6 6 7 7 ifndef CONFIG_CACHE_OFF 8 - obj-$(CONFIG_CPU_SH2) += cache-sh2.o 9 - obj-$(CONFIG_CPU_SH3) += cache-sh3.o 10 - obj-$(CONFIG_CPU_SH4) += cache-sh4.o 11 - obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o 8 + cache-$(CONFIG_CPU_SH2) := cache-sh2.o 9 + cache-$(CONFIG_CPU_SH2A) := cache-sh2a.o 10 + cache-$(CONFIG_CPU_SH3) := cache-sh3.o 11 + cache-$(CONFIG_CPU_SH4) := cache-sh4.o 12 + cache-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o 12 13 endif 14 + 15 + obj-y += $(cache-y) 13 16 14 17 mmu-y := tlb-nommu.o pg-nommu.o 15 18 mmu-$(CONFIG_MMU) := fault_32.o tlbflush_32.o ioremap_32.o
+36 -9
arch/sh/mm/cache-sh2.c
··· 2 2 * arch/sh/mm/cache-sh2.c 3 3 * 4 4 * Copyright (C) 2002 Paul Mundt 5 + * Copyright (C) 2008 Yoshinori Sato 5 6 * 6 7 * Released under the terms of the GNU GPL v2.0. 7 8 */ ··· 25 24 end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 26 25 & ~(L1_CACHE_BYTES-1); 27 26 for (v = begin; v < end; v+=L1_CACHE_BYTES) { 28 - /* FIXME cache purge */ 29 - ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008); 27 + unsigned long addr = CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0); 28 + int way; 29 + for (way = 0; way < 4; way++) { 30 + unsigned long data = ctrl_inl(addr | (way << 12)); 31 + if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { 32 + data &= ~SH_CACHE_UPDATED; 33 + ctrl_outl(data, addr | (way << 12)); 34 + } 35 + } 30 36 } 31 37 } 32 38 ··· 45 37 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 46 38 end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 47 39 & ~(L1_CACHE_BYTES-1); 48 - for (v = begin; v < end; v+=L1_CACHE_BYTES) { 49 - ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008); 50 - } 40 + 41 + for (v = begin; v < end; v+=L1_CACHE_BYTES) 42 + ctrl_outl((v & CACHE_PHYSADDR_MASK), 43 + CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0) | 0x00000008); 51 44 } 52 45 53 46 void __flush_invalidate_region(void *start, int size) 54 47 { 48 + #ifdef CONFIG_CACHE_WRITEBACK 49 + /* 50 + * SH-2 does not support individual line invalidation, only a 51 + * global invalidate. 52 + */ 53 + unsigned long ccr; 54 + unsigned long flags; 55 + local_irq_save(flags); 56 + jump_to_uncached(); 57 + 58 + ccr = ctrl_inl(CCR); 59 + ccr |= CCR_CACHE_INVALIDATE; 60 + ctrl_outl(ccr, CCR); 61 + 62 + back_to_cached(); 63 + local_irq_restore(flags); 64 + #else 55 65 unsigned long v; 56 66 unsigned long begin, end; 57 67 58 68 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 59 69 end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 60 70 & ~(L1_CACHE_BYTES-1); 61 - for (v = begin; v < end; v+=L1_CACHE_BYTES) { 62 - ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008); 63 - } 64 - } 65 71 72 + for (v = begin; v < end; v+=L1_CACHE_BYTES) 73 + ctrl_outl((v & CACHE_PHYSADDR_MASK), 74 + CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0) | 0x00000008); 75 + #endif 76 + }
+129
arch/sh/mm/cache-sh2a.c
··· 1 + /* 2 + * arch/sh/mm/cache-sh2a.c 3 + * 4 + * Copyright (C) 2008 Yoshinori Sato 5 + * 6 + * Released under the terms of the GNU GPL v2.0. 7 + */ 8 + 9 + #include <linux/init.h> 10 + #include <linux/mm.h> 11 + 12 + #include <asm/cache.h> 13 + #include <asm/addrspace.h> 14 + #include <asm/processor.h> 15 + #include <asm/cacheflush.h> 16 + #include <asm/io.h> 17 + 18 + void __flush_wback_region(void *start, int size) 19 + { 20 + unsigned long v; 21 + unsigned long begin, end; 22 + unsigned long flags; 23 + 24 + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 25 + end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 26 + & ~(L1_CACHE_BYTES-1); 27 + 28 + local_irq_save(flags); 29 + jump_to_uncached(); 30 + 31 + for (v = begin; v < end; v+=L1_CACHE_BYTES) { 32 + unsigned long addr = CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0); 33 + int way; 34 + for (way = 0; way < 4; way++) { 35 + unsigned long data = ctrl_inl(addr | (way << 11)); 36 + if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { 37 + data &= ~SH_CACHE_UPDATED; 38 + ctrl_outl(data, addr | (way << 11)); 39 + } 40 + } 41 + } 42 + 43 + back_to_cached(); 44 + local_irq_restore(flags); 45 + } 46 + 47 + void __flush_purge_region(void *start, int size) 48 + { 49 + unsigned long v; 50 + unsigned long begin, end; 51 + unsigned long flags; 52 + 53 + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 54 + end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 55 + & ~(L1_CACHE_BYTES-1); 56 + 57 + local_irq_save(flags); 58 + jump_to_uncached(); 59 + 60 + for (v = begin; v < end; v+=L1_CACHE_BYTES) { 61 + ctrl_outl((v & CACHE_PHYSADDR_MASK), 62 + CACHE_OC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008); 63 + } 64 + back_to_cached(); 65 + local_irq_restore(flags); 66 + } 67 + 68 + void __flush_invalidate_region(void *start, int size) 69 + { 70 + unsigned long v; 71 + unsigned long begin, end; 72 + unsigned long flags; 73 + 74 + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 75 + end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 76 + & ~(L1_CACHE_BYTES-1); 77 + local_irq_save(flags); 78 + jump_to_uncached(); 79 + 80 + #ifdef CONFIG_CACHE_WRITEBACK 81 + ctrl_outl(ctrl_inl(CCR) | CCR_OCACHE_INVALIDATE, CCR); 82 + /* I-cache invalidate */ 83 + for (v = begin; v < end; v+=L1_CACHE_BYTES) { 84 + ctrl_outl((v & CACHE_PHYSADDR_MASK), 85 + CACHE_IC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008); 86 + } 87 + #else 88 + for (v = begin; v < end; v+=L1_CACHE_BYTES) { 89 + ctrl_outl((v & CACHE_PHYSADDR_MASK), 90 + CACHE_IC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008); 91 + ctrl_outl((v & CACHE_PHYSADDR_MASK), 92 + CACHE_OC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008); 93 + } 94 + #endif 95 + back_to_cached(); 96 + local_irq_restore(flags); 97 + } 98 + 99 + /* WBack O-Cache and flush I-Cache */ 100 + void flush_icache_range(unsigned long start, unsigned long end) 101 + { 102 + unsigned long v; 103 + unsigned long flags; 104 + 105 + start = start & ~(L1_CACHE_BYTES-1); 106 + end = (end + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); 107 + 108 + local_irq_save(flags); 109 + jump_to_uncached(); 110 + 111 + for (v = start; v < end; v+=L1_CACHE_BYTES) { 112 + unsigned long addr = (v & 0x000007f0); 113 + int way; 114 + /* O-Cache writeback */ 115 + for (way = 0; way < 4; way++) { 116 + unsigned long data = ctrl_inl(CACHE_OC_ADDRESS_ARRAY | addr | (way << 11)); 117 + if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { 118 + data &= ~SH_CACHE_UPDATED; 119 + ctrl_outl(data, CACHE_OC_ADDRESS_ARRAY | addr | (way << 11)); 120 + } 121 + } 122 + /* I-Cache invalidate */ 123 + ctrl_outl(addr, 124 + CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008); 125 + } 126 + 127 + back_to_cached(); 128 + local_irq_restore(flags); 129 + }