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

Configure Feed

Select the types of activity you want to include in your feed.

at v5.7-rc2 421 lines 10 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * r2300.c: R2000 and R3000 specific mmu/cache code. 4 * 5 * Copyright (C) 1996 David S. Miller (davem@davemloft.net) 6 * 7 * with a lot of changes to make this thing work for R3000s 8 * Tx39XX R4k style caches added. HK 9 * Copyright (C) 1998, 1999, 2000 Harald Koerfgen 10 * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov 11 */ 12#include <linux/init.h> 13#include <linux/kernel.h> 14#include <linux/sched.h> 15#include <linux/smp.h> 16#include <linux/mm.h> 17 18#include <asm/cacheops.h> 19#include <asm/page.h> 20#include <asm/pgtable.h> 21#include <asm/mmu_context.h> 22#include <asm/isadep.h> 23#include <asm/io.h> 24#include <asm/bootinfo.h> 25#include <asm/cpu.h> 26 27/* For R3000 cores with R4000 style caches */ 28static unsigned long icache_size, dcache_size; /* Size in bytes */ 29 30#include <asm/r4kcache.h> 31 32/* This sequence is required to ensure icache is disabled immediately */ 33#define TX39_STOP_STREAMING() \ 34__asm__ __volatile__( \ 35 ".set push\n\t" \ 36 ".set noreorder\n\t" \ 37 "b 1f\n\t" \ 38 "nop\n\t" \ 39 "1:\n\t" \ 40 ".set pop" \ 41 ) 42 43/* TX39H-style cache flush routines. */ 44static void tx39h_flush_icache_all(void) 45{ 46 unsigned long flags, config; 47 48 /* disable icache (set ICE#) */ 49 local_irq_save(flags); 50 config = read_c0_conf(); 51 write_c0_conf(config & ~TX39_CONF_ICE); 52 TX39_STOP_STREAMING(); 53 blast_icache16(); 54 write_c0_conf(config); 55 local_irq_restore(flags); 56} 57 58static void tx39h_dma_cache_wback_inv(unsigned long addr, unsigned long size) 59{ 60 /* Catch bad driver code */ 61 BUG_ON(size == 0); 62 63 iob(); 64 blast_inv_dcache_range(addr, addr + size); 65} 66 67 68/* TX39H2,TX39H3 */ 69static inline void tx39_blast_dcache_page(unsigned long addr) 70{ 71 if (current_cpu_type() != CPU_TX3912) 72 blast_dcache16_page(addr); 73} 74 75static inline void tx39_blast_dcache_page_indexed(unsigned long addr) 76{ 77 blast_dcache16_page_indexed(addr); 78} 79 80static inline void tx39_blast_dcache(void) 81{ 82 blast_dcache16(); 83} 84 85static inline void tx39_blast_icache_page(unsigned long addr) 86{ 87 unsigned long flags, config; 88 /* disable icache (set ICE#) */ 89 local_irq_save(flags); 90 config = read_c0_conf(); 91 write_c0_conf(config & ~TX39_CONF_ICE); 92 TX39_STOP_STREAMING(); 93 blast_icache16_page(addr); 94 write_c0_conf(config); 95 local_irq_restore(flags); 96} 97 98static inline void tx39_blast_icache_page_indexed(unsigned long addr) 99{ 100 unsigned long flags, config; 101 /* disable icache (set ICE#) */ 102 local_irq_save(flags); 103 config = read_c0_conf(); 104 write_c0_conf(config & ~TX39_CONF_ICE); 105 TX39_STOP_STREAMING(); 106 blast_icache16_page_indexed(addr); 107 write_c0_conf(config); 108 local_irq_restore(flags); 109} 110 111static inline void tx39_blast_icache(void) 112{ 113 unsigned long flags, config; 114 /* disable icache (set ICE#) */ 115 local_irq_save(flags); 116 config = read_c0_conf(); 117 write_c0_conf(config & ~TX39_CONF_ICE); 118 TX39_STOP_STREAMING(); 119 blast_icache16(); 120 write_c0_conf(config); 121 local_irq_restore(flags); 122} 123 124static void tx39__flush_cache_vmap(void) 125{ 126 tx39_blast_dcache(); 127} 128 129static void tx39__flush_cache_vunmap(void) 130{ 131 tx39_blast_dcache(); 132} 133 134static inline void tx39_flush_cache_all(void) 135{ 136 if (!cpu_has_dc_aliases) 137 return; 138 139 tx39_blast_dcache(); 140} 141 142static inline void tx39___flush_cache_all(void) 143{ 144 tx39_blast_dcache(); 145 tx39_blast_icache(); 146} 147 148static void tx39_flush_cache_mm(struct mm_struct *mm) 149{ 150 if (!cpu_has_dc_aliases) 151 return; 152 153 if (cpu_context(smp_processor_id(), mm) != 0) 154 tx39_blast_dcache(); 155} 156 157static void tx39_flush_cache_range(struct vm_area_struct *vma, 158 unsigned long start, unsigned long end) 159{ 160 if (!cpu_has_dc_aliases) 161 return; 162 if (!(cpu_context(smp_processor_id(), vma->vm_mm))) 163 return; 164 165 tx39_blast_dcache(); 166} 167 168static void tx39_flush_cache_page(struct vm_area_struct *vma, unsigned long page, unsigned long pfn) 169{ 170 int exec = vma->vm_flags & VM_EXEC; 171 struct mm_struct *mm = vma->vm_mm; 172 pgd_t *pgdp; 173 p4d_t *p4dp; 174 pud_t *pudp; 175 pmd_t *pmdp; 176 pte_t *ptep; 177 178 /* 179 * If ownes no valid ASID yet, cannot possibly have gotten 180 * this page into the cache. 181 */ 182 if (cpu_context(smp_processor_id(), mm) == 0) 183 return; 184 185 page &= PAGE_MASK; 186 pgdp = pgd_offset(mm, page); 187 p4dp = p4d_offset(pgdp, page); 188 pudp = pud_offset(p4dp, page); 189 pmdp = pmd_offset(pudp, page); 190 ptep = pte_offset(pmdp, page); 191 192 /* 193 * If the page isn't marked valid, the page cannot possibly be 194 * in the cache. 195 */ 196 if (!(pte_val(*ptep) & _PAGE_PRESENT)) 197 return; 198 199 /* 200 * Doing flushes for another ASID than the current one is 201 * too difficult since stupid R4k caches do a TLB translation 202 * for every cache flush operation. So we do indexed flushes 203 * in that case, which doesn't overly flush the cache too much. 204 */ 205 if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { 206 if (cpu_has_dc_aliases || exec) 207 tx39_blast_dcache_page(page); 208 if (exec) 209 tx39_blast_icache_page(page); 210 211 return; 212 } 213 214 /* 215 * Do indexed flush, too much work to get the (possible) TLB refills 216 * to work correctly. 217 */ 218 if (cpu_has_dc_aliases || exec) 219 tx39_blast_dcache_page_indexed(page); 220 if (exec) 221 tx39_blast_icache_page_indexed(page); 222} 223 224static void local_tx39_flush_data_cache_page(void * addr) 225{ 226 tx39_blast_dcache_page((unsigned long)addr); 227} 228 229static void tx39_flush_data_cache_page(unsigned long addr) 230{ 231 tx39_blast_dcache_page(addr); 232} 233 234static void tx39_flush_icache_range(unsigned long start, unsigned long end) 235{ 236 if (end - start > dcache_size) 237 tx39_blast_dcache(); 238 else 239 protected_blast_dcache_range(start, end); 240 241 if (end - start > icache_size) 242 tx39_blast_icache(); 243 else { 244 unsigned long flags, config; 245 /* disable icache (set ICE#) */ 246 local_irq_save(flags); 247 config = read_c0_conf(); 248 write_c0_conf(config & ~TX39_CONF_ICE); 249 TX39_STOP_STREAMING(); 250 protected_blast_icache_range(start, end); 251 write_c0_conf(config); 252 local_irq_restore(flags); 253 } 254} 255 256static void tx39_flush_kernel_vmap_range(unsigned long vaddr, int size) 257{ 258 BUG(); 259} 260 261static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size) 262{ 263 unsigned long end; 264 265 if (((size | addr) & (PAGE_SIZE - 1)) == 0) { 266 end = addr + size; 267 do { 268 tx39_blast_dcache_page(addr); 269 addr += PAGE_SIZE; 270 } while(addr != end); 271 } else if (size > dcache_size) { 272 tx39_blast_dcache(); 273 } else { 274 blast_dcache_range(addr, addr + size); 275 } 276} 277 278static void tx39_dma_cache_inv(unsigned long addr, unsigned long size) 279{ 280 unsigned long end; 281 282 if (((size | addr) & (PAGE_SIZE - 1)) == 0) { 283 end = addr + size; 284 do { 285 tx39_blast_dcache_page(addr); 286 addr += PAGE_SIZE; 287 } while(addr != end); 288 } else if (size > dcache_size) { 289 tx39_blast_dcache(); 290 } else { 291 blast_inv_dcache_range(addr, addr + size); 292 } 293} 294 295static __init void tx39_probe_cache(void) 296{ 297 unsigned long config; 298 299 config = read_c0_conf(); 300 301 icache_size = 1 << (10 + ((config & TX39_CONF_ICS_MASK) >> 302 TX39_CONF_ICS_SHIFT)); 303 dcache_size = 1 << (10 + ((config & TX39_CONF_DCS_MASK) >> 304 TX39_CONF_DCS_SHIFT)); 305 306 current_cpu_data.icache.linesz = 16; 307 switch (current_cpu_type()) { 308 case CPU_TX3912: 309 current_cpu_data.icache.ways = 1; 310 current_cpu_data.dcache.ways = 1; 311 current_cpu_data.dcache.linesz = 4; 312 break; 313 314 case CPU_TX3927: 315 current_cpu_data.icache.ways = 2; 316 current_cpu_data.dcache.ways = 2; 317 current_cpu_data.dcache.linesz = 16; 318 break; 319 320 case CPU_TX3922: 321 default: 322 current_cpu_data.icache.ways = 1; 323 current_cpu_data.dcache.ways = 1; 324 current_cpu_data.dcache.linesz = 16; 325 break; 326 } 327} 328 329void tx39_cache_init(void) 330{ 331 extern void build_clear_page(void); 332 extern void build_copy_page(void); 333 unsigned long config; 334 335 config = read_c0_conf(); 336 config &= ~TX39_CONF_WBON; 337 write_c0_conf(config); 338 339 tx39_probe_cache(); 340 341 switch (current_cpu_type()) { 342 case CPU_TX3912: 343 /* TX39/H core (writethru direct-map cache) */ 344 __flush_cache_vmap = tx39__flush_cache_vmap; 345 __flush_cache_vunmap = tx39__flush_cache_vunmap; 346 flush_cache_all = tx39h_flush_icache_all; 347 __flush_cache_all = tx39h_flush_icache_all; 348 flush_cache_mm = (void *) tx39h_flush_icache_all; 349 flush_cache_range = (void *) tx39h_flush_icache_all; 350 flush_cache_page = (void *) tx39h_flush_icache_all; 351 flush_icache_range = (void *) tx39h_flush_icache_all; 352 local_flush_icache_range = (void *) tx39h_flush_icache_all; 353 354 local_flush_data_cache_page = (void *) tx39h_flush_icache_all; 355 flush_data_cache_page = (void *) tx39h_flush_icache_all; 356 357 _dma_cache_wback_inv = tx39h_dma_cache_wback_inv; 358 359 shm_align_mask = PAGE_SIZE - 1; 360 361 break; 362 363 case CPU_TX3922: 364 case CPU_TX3927: 365 default: 366 /* TX39/H2,H3 core (writeback 2way-set-associative cache) */ 367 /* board-dependent init code may set WBON */ 368 369 __flush_cache_vmap = tx39__flush_cache_vmap; 370 __flush_cache_vunmap = tx39__flush_cache_vunmap; 371 372 flush_cache_all = tx39_flush_cache_all; 373 __flush_cache_all = tx39___flush_cache_all; 374 flush_cache_mm = tx39_flush_cache_mm; 375 flush_cache_range = tx39_flush_cache_range; 376 flush_cache_page = tx39_flush_cache_page; 377 flush_icache_range = tx39_flush_icache_range; 378 local_flush_icache_range = tx39_flush_icache_range; 379 380 __flush_kernel_vmap_range = tx39_flush_kernel_vmap_range; 381 382 local_flush_data_cache_page = local_tx39_flush_data_cache_page; 383 flush_data_cache_page = tx39_flush_data_cache_page; 384 385 _dma_cache_wback_inv = tx39_dma_cache_wback_inv; 386 _dma_cache_wback = tx39_dma_cache_wback_inv; 387 _dma_cache_inv = tx39_dma_cache_inv; 388 389 shm_align_mask = max_t(unsigned long, 390 (dcache_size / current_cpu_data.dcache.ways) - 1, 391 PAGE_SIZE - 1); 392 393 break; 394 } 395 396 __flush_icache_user_range = flush_icache_range; 397 __local_flush_icache_user_range = local_flush_icache_range; 398 399 current_cpu_data.icache.waysize = icache_size / current_cpu_data.icache.ways; 400 current_cpu_data.dcache.waysize = dcache_size / current_cpu_data.dcache.ways; 401 402 current_cpu_data.icache.sets = 403 current_cpu_data.icache.waysize / current_cpu_data.icache.linesz; 404 current_cpu_data.dcache.sets = 405 current_cpu_data.dcache.waysize / current_cpu_data.dcache.linesz; 406 407 if (current_cpu_data.dcache.waysize > PAGE_SIZE) 408 current_cpu_data.dcache.flags |= MIPS_CACHE_ALIASES; 409 410 current_cpu_data.icache.waybit = 0; 411 current_cpu_data.dcache.waybit = 0; 412 413 pr_info("Primary instruction cache %ldkB, linesize %d bytes\n", 414 icache_size >> 10, current_cpu_data.icache.linesz); 415 pr_info("Primary data cache %ldkB, linesize %d bytes\n", 416 dcache_size >> 10, current_cpu_data.dcache.linesz); 417 418 build_clear_page(); 419 build_copy_page(); 420 tx39h_flush_icache_all(); 421}