1 /* 2 * arch/sh/mm/cache-sh4.c 3 * 4 * Copyright (C) 1999, 2000, 2002 Niibe Yutaka 5 * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt 6 * Copyright (C) 2003 Richard Curnow 7 * 8 * This file is subject to the terms and conditions of the GNU General Public 9 * License. See the file "COPYING" in the main directory of this archive 10 * for more details. 11 */ 12 13 #include <linux/init.h> 14 #include <linux/mman.h> 15 #include <linux/mm.h> 16 #include <linux/threads.h> 17 #include <asm/addrspace.h> 18 #include <asm/page.h> 19 #include <asm/pgtable.h> 20 #include <asm/processor.h> 21 #include <asm/cache.h> 22 #include <asm/io.h> 23 #include <asm/uaccess.h> 24 #include <asm/pgalloc.h> 25 #include <asm/mmu_context.h> 26 #include <asm/cacheflush.h> 27 28 extern void __flush_cache_4096_all(unsigned long start); 29 static void __flush_cache_4096_all_ex(unsigned long start); 30 extern void __flush_dcache_all(void); 31 static void __flush_dcache_all_ex(void); 32 33 /* 34 * SH-4 has virtually indexed and physically tagged cache. 35 */ 36 37 struct semaphore p3map_sem[4]; 38 39 void __init p3_cache_init(void) 40 { 41 if (remap_area_pages(P3SEG, 0, PAGE_SIZE*4, _PAGE_CACHABLE)) 42 panic("%s failed.", __FUNCTION__); 43 44 sema_init (&p3map_sem[0], 1); 45 sema_init (&p3map_sem[1], 1); 46 sema_init (&p3map_sem[2], 1); 47 sema_init (&p3map_sem[3], 1); 48 } 49 50 /* 51 * Write back the dirty D-caches, but not invalidate them. 52 * 53 * START: Virtual Address (U0, P1, or P3) 54 * SIZE: Size of the region. 55 */ 56 void __flush_wback_region(void *start, int size) 57 { 58 unsigned long v; 59 unsigned long begin, end; 60 61 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 62 end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 63 & ~(L1_CACHE_BYTES-1); 64 for (v = begin; v < end; v+=L1_CACHE_BYTES) { 65 asm volatile("ocbwb %0" 66 : /* no output */ 67 : "m" (__m(v))); 68 } 69 } 70 71 /* 72 * Write back the dirty D-caches and invalidate them. 73 * 74 * START: Virtual Address (U0, P1, or P3) 75 * SIZE: Size of the region. 76 */ 77 void __flush_purge_region(void *start, int size) 78 { 79 unsigned long v; 80 unsigned long begin, end; 81 82 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 83 end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 84 & ~(L1_CACHE_BYTES-1); 85 for (v = begin; v < end; v+=L1_CACHE_BYTES) { 86 asm volatile("ocbp %0" 87 : /* no output */ 88 : "m" (__m(v))); 89 } 90 } 91 92 93 /* 94 * No write back please 95 */ 96 void __flush_invalidate_region(void *start, int size) 97 { 98 unsigned long v; 99 unsigned long begin, end; 100 101 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 102 end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 103 & ~(L1_CACHE_BYTES-1); 104 for (v = begin; v < end; v+=L1_CACHE_BYTES) { 105 asm volatile("ocbi %0" 106 : /* no output */ 107 : "m" (__m(v))); 108 } 109 } 110 111 static void __flush_dcache_all_ex(void) 112 { 113 unsigned long addr, end_addr, entry_offset; 114 115 end_addr = CACHE_OC_ADDRESS_ARRAY + (cpu_data->dcache.sets << cpu_data->dcache.entry_shift) * cpu_data->dcache.ways; 116 entry_offset = 1 << cpu_data->dcache.entry_shift; 117 for (addr = CACHE_OC_ADDRESS_ARRAY; addr < end_addr; addr += entry_offset) { 118 ctrl_outl(0, addr); 119 } 120 } 121 122 static void __flush_cache_4096_all_ex(unsigned long start) 123 { 124 unsigned long addr, entry_offset; 125 int i; 126 127 entry_offset = 1 << cpu_data->dcache.entry_shift; 128 for (i = 0; i < cpu_data->dcache.ways; i++, start += cpu_data->dcache.way_incr) { 129 for (addr = CACHE_OC_ADDRESS_ARRAY + start; 130 addr < CACHE_OC_ADDRESS_ARRAY + 4096 + start; 131 addr += entry_offset) { 132 ctrl_outl(0, addr); 133 } 134 } 135 } 136 137 void flush_cache_4096_all(unsigned long start) 138 { 139 if (cpu_data->dcache.ways == 1) 140 __flush_cache_4096_all(start); 141 else 142 __flush_cache_4096_all_ex(start); 143 } 144 145 /* 146 * Write back the range of D-cache, and purge the I-cache. 147 * 148 * Called from kernel/module.c:sys_init_module and routine for a.out format. 149 */ 150 void flush_icache_range(unsigned long start, unsigned long end) 151 { 152 flush_cache_all(); 153 } 154 155 /* 156 * Write back the D-cache and purge the I-cache for signal trampoline. 157 * .. which happens to be the same behavior as flush_icache_range(). 158 * So, we simply flush out a line. 159 */ 160 void flush_cache_sigtramp(unsigned long addr) 161 { 162 unsigned long v, index; 163 unsigned long flags; 164 int i; 165 166 v = addr & ~(L1_CACHE_BYTES-1); 167 asm volatile("ocbwb %0" 168 : /* no output */ 169 : "m" (__m(v))); 170 171 index = CACHE_IC_ADDRESS_ARRAY | (v & cpu_data->icache.entry_mask); 172 173 local_irq_save(flags); 174 jump_to_P2(); 175 for(i = 0; i < cpu_data->icache.ways; i++, index += cpu_data->icache.way_incr) 176 ctrl_outl(0, index); /* Clear out Valid-bit */ 177 back_to_P1(); 178 local_irq_restore(flags); 179 } 180 181 static inline void flush_cache_4096(unsigned long start, 182 unsigned long phys) 183 { 184 unsigned long flags; 185 extern void __flush_cache_4096(unsigned long addr, unsigned long phys, unsigned long exec_offset); 186 187 /* 188 * SH7751, SH7751R, and ST40 have no restriction to handle cache. 189 * (While SH7750 must do that at P2 area.) 190 */ 191 if ((cpu_data->flags & CPU_HAS_P2_FLUSH_BUG) 192 || start < CACHE_OC_ADDRESS_ARRAY) { 193 local_irq_save(flags); 194 __flush_cache_4096(start | SH_CACHE_ASSOC, P1SEGADDR(phys), 0x20000000); 195 local_irq_restore(flags); 196 } else { 197 __flush_cache_4096(start | SH_CACHE_ASSOC, P1SEGADDR(phys), 0); 198 } 199 } 200 201 /* 202 * Write back & invalidate the D-cache of the page. 203 * (To avoid "alias" issues) 204 */ 205 void flush_dcache_page(struct page *page) 206 { 207 if (test_bit(PG_mapped, &page->flags)) { 208 unsigned long phys = PHYSADDR(page_address(page)); 209 210 /* Loop all the D-cache */ 211 flush_cache_4096(CACHE_OC_ADDRESS_ARRAY, phys); 212 flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x1000, phys); 213 flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x2000, phys); 214 flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x3000, phys); 215 } 216 } 217 218 static inline void flush_icache_all(void) 219 { 220 unsigned long flags, ccr; 221 222 local_irq_save(flags); 223 jump_to_P2(); 224 225 /* Flush I-cache */ 226 ccr = ctrl_inl(CCR); 227 ccr |= CCR_CACHE_ICI; 228 ctrl_outl(ccr, CCR); 229 230 back_to_P1(); 231 local_irq_restore(flags); 232 } 233 234 void flush_cache_all(void) 235 { 236 if (cpu_data->dcache.ways == 1) 237 __flush_dcache_all(); 238 else 239 __flush_dcache_all_ex(); 240 flush_icache_all(); 241 } 242 243 void flush_cache_mm(struct mm_struct *mm) 244 { 245 /* Is there any good way? */ 246 /* XXX: possibly call flush_cache_range for each vm area */ 247 /* 248 * FIXME: Really, the optimal solution here would be able to flush out 249 * individual lines created by the specified context, but this isn't 250 * feasible for a number of architectures (such as MIPS, and some 251 * SPARC) .. is this possible for SuperH? 252 * 253 * In the meantime, we'll just flush all of the caches.. this 254 * seems to be the simplest way to avoid at least a few wasted 255 * cache flushes. -Lethal 256 */ 257 flush_cache_all(); 258 } 259 260 /* 261 * Write back and invalidate I/D-caches for the page. 262 * 263 * ADDR: Virtual Address (U0 address) 264 * PFN: Physical page number 265 */ 266 void flush_cache_page(struct vm_area_struct *vma, unsigned long address, unsigned long pfn) 267 { 268 unsigned long phys = pfn << PAGE_SHIFT; 269 270 /* We only need to flush D-cache when we have alias */ 271 if ((address^phys) & CACHE_ALIAS) { 272 /* Loop 4K of the D-cache */ 273 flush_cache_4096( 274 CACHE_OC_ADDRESS_ARRAY | (address & CACHE_ALIAS), 275 phys); 276 /* Loop another 4K of the D-cache */ 277 flush_cache_4096( 278 CACHE_OC_ADDRESS_ARRAY | (phys & CACHE_ALIAS), 279 phys); 280 } 281 282 if (vma->vm_flags & VM_EXEC) 283 /* Loop 4K (half) of the I-cache */ 284 flush_cache_4096( 285 CACHE_IC_ADDRESS_ARRAY | (address & 0x1000), 286 phys); 287 } 288 289 /* 290 * Write back and invalidate D-caches. 291 * 292 * START, END: Virtual Address (U0 address) 293 * 294 * NOTE: We need to flush the _physical_ page entry. 295 * Flushing the cache lines for U0 only isn't enough. 296 * We need to flush for P1 too, which may contain aliases. 297 */ 298 void flush_cache_range(struct vm_area_struct *vma, unsigned long start, 299 unsigned long end) 300 { 301 unsigned long p = start & PAGE_MASK; 302 pgd_t *dir; 303 pmd_t *pmd; 304 pte_t *pte; 305 pte_t entry; 306 unsigned long phys; 307 unsigned long d = 0; 308 309 dir = pgd_offset(vma->vm_mm, p); 310 pmd = pmd_offset(dir, p); 311 312 do { 313 if (pmd_none(*pmd) || pmd_bad(*pmd)) { 314 p &= ~((1 << PMD_SHIFT) -1); 315 p += (1 << PMD_SHIFT); 316 pmd++; 317 continue; 318 } 319 pte = pte_offset_kernel(pmd, p); 320 do { 321 entry = *pte; 322 if ((pte_val(entry) & _PAGE_PRESENT)) { 323 phys = pte_val(entry)&PTE_PHYS_MASK; 324 if ((p^phys) & CACHE_ALIAS) { 325 d |= 1 << ((p & CACHE_ALIAS)>>12); 326 d |= 1 << ((phys & CACHE_ALIAS)>>12); 327 if (d == 0x0f) 328 goto loop_exit; 329 } 330 } 331 pte++; 332 p += PAGE_SIZE; 333 } while (p < end && ((unsigned long)pte & ~PAGE_MASK)); 334 pmd++; 335 } while (p < end); 336 loop_exit: 337 if (d & 1) 338 flush_cache_4096_all(0); 339 if (d & 2) 340 flush_cache_4096_all(0x1000); 341 if (d & 4) 342 flush_cache_4096_all(0x2000); 343 if (d & 8) 344 flush_cache_4096_all(0x3000); 345 if (vma->vm_flags & VM_EXEC) 346 flush_icache_all(); 347 } 348 349 /* 350 * flush_icache_user_range 351 * @vma: VMA of the process 352 * @page: page 353 * @addr: U0 address 354 * @len: length of the range (< page size) 355 */ 356 void flush_icache_user_range(struct vm_area_struct *vma, 357 struct page *page, unsigned long addr, int len) 358 { 359 flush_cache_page(vma, addr, page_to_pfn(page)); 360 } 361 362