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

Better interface to run uncached cache setup code.

Signed-off-by: Thiemo Seufer <ths@networkno.de>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Thiemo Seufer and committed by
Ralf Baechle
ba5187db 7de8d232

+94 -27
+2 -2
arch/mips/lib/Makefile
··· 2 2 # Makefile for MIPS-specific library files.. 3 3 # 4 4 5 - lib-y += csum_partial_copy.o memcpy.o promlib.o \ 6 - strlen_user.o strncpy_user.o strnlen_user.o 5 + lib-y += csum_partial_copy.o memcpy.o promlib.o strlen_user.o strncpy_user.o \ 6 + strnlen_user.o uncached.o 7 7 8 8 obj-y += iomap.o 9 9
+76
arch/mips/lib/uncached.c
··· 1 + /* 2 + * This file is subject to the terms and conditions of the GNU General Public 3 + * License. See the file "COPYING" in the main directory of this archive 4 + * for more details. 5 + * 6 + * Copyright (C) 2005 Thiemo Seufer 7 + * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. 8 + * Author: Maciej W. Rozycki <macro@mips.com> 9 + */ 10 + 11 + #include <linux/init.h> 12 + 13 + #include <asm/addrspace.h> 14 + #include <asm/bug.h> 15 + 16 + #ifndef CKSEG2 17 + #define CKSEG2 CKSSEG 18 + #endif 19 + #ifndef TO_PHYS_MASK 20 + #define TO_PHYS_MASK -1 21 + #endif 22 + 23 + /* 24 + * FUNC is executed in one of the uncached segments, depending on its 25 + * original address as follows: 26 + * 27 + * 1. If the original address is in CKSEG0 or CKSEG1, then the uncached 28 + * segment used is CKSEG1. 29 + * 2. If the original address is in XKPHYS, then the uncached segment 30 + * used is XKPHYS(2). 31 + * 3. Otherwise it's a bug. 32 + * 33 + * The same remapping is done with the stack pointer. Stack handling 34 + * works because we don't handle stack arguments or more complex return 35 + * values, so we can avoid sharing the same stack area between a cached 36 + * and the uncached mode. 37 + */ 38 + unsigned long __init run_uncached(void *func) 39 + { 40 + register long sp __asm__("$sp"); 41 + register long ret __asm__("$2"); 42 + long lfunc = (long)func, ufunc; 43 + long usp; 44 + 45 + if (sp >= (long)CKSEG0 && sp < (long)CKSEG2) 46 + usp = CKSEG1ADDR(sp); 47 + else if ((long long)sp >= (long long)PHYS_TO_XKPHYS(0LL, 0) && 48 + (long long)sp < (long long)PHYS_TO_XKPHYS(8LL, 0)) 49 + usp = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED, 50 + XKPHYS_TO_PHYS((long long)sp)); 51 + else { 52 + BUG(); 53 + usp = sp; 54 + } 55 + if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2) 56 + ufunc = CKSEG1ADDR(lfunc); 57 + else if ((long long)lfunc >= (long long)PHYS_TO_XKPHYS(0LL, 0) && 58 + (long long)lfunc < (long long)PHYS_TO_XKPHYS(8LL, 0)) 59 + ufunc = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED, 60 + XKPHYS_TO_PHYS((long long)lfunc)); 61 + else { 62 + BUG(); 63 + ufunc = lfunc; 64 + } 65 + 66 + __asm__ __volatile__ ( 67 + " move $16, $sp\n" 68 + " move $sp, %1\n" 69 + " jalr %2\n" 70 + " move $sp, $16" 71 + : "=r" (ret) 72 + : "r" (usp), "r" (ufunc) 73 + : "$16", "$31"); 74 + 75 + return ret; 76 + }
+2 -4
arch/mips/mm/c-r4k.c
··· 26 26 #include <asm/system.h> 27 27 #include <asm/mmu_context.h> 28 28 #include <asm/war.h> 29 + #include <asm/cacheflush.h> /* for run_uncached() */ 29 30 30 31 static unsigned long icache_size, dcache_size, scache_size; 31 32 ··· 1120 1119 return 1; 1121 1120 } 1122 1121 1123 - typedef int (*probe_func_t)(unsigned long); 1124 1122 extern int r5k_sc_init(void); 1125 1123 extern int rm7k_sc_init(void); 1126 1124 ··· 1127 1127 { 1128 1128 struct cpuinfo_mips *c = &current_cpu_data; 1129 1129 unsigned int config = read_c0_config(); 1130 - probe_func_t probe_scache_kseg1; 1131 1130 int sc_present = 0; 1132 1131 1133 1132 /* ··· 1139 1140 case CPU_R4000MC: 1140 1141 case CPU_R4400SC: 1141 1142 case CPU_R4400MC: 1142 - probe_scache_kseg1 = (probe_func_t) (CKSEG1ADDR(&probe_scache)); 1143 - sc_present = probe_scache_kseg1(config); 1143 + sc_present = run_uncached(probe_scache); 1144 1144 if (sc_present) 1145 1145 c->options |= MIPS_CPU_CACHE_CDEX_S; 1146 1146 break;
+8 -21
arch/mips/mm/sc-rm7k.c
··· 15 15 #include <asm/cacheops.h> 16 16 #include <asm/mipsregs.h> 17 17 #include <asm/processor.h> 18 + #include <asm/cacheflush.h> /* for run_uncached() */ 18 19 19 20 /* Primary cache parameters. */ 20 21 #define sc_lsize 32 ··· 97 96 } 98 97 99 98 /* 100 - * This function is executed in the uncached segment CKSEG1. 101 - * It must not touch the stack, because the stack pointer still points 102 - * into CKSEG0. 103 - * 104 - * Three options: 105 - * - Write it in assembly and guarantee that we don't use the stack. 106 - * - Disable caching for CKSEG0 before calling it. 107 - * - Pray that GCC doesn't randomly start using the stack. 108 - * 109 - * This being Linux, we obviously take the least sane of those options - 110 - * following DaveM's lead in c-r4k.c 111 - * 112 - * It seems we get our kicks from relying on unguaranteed behaviour in GCC 99 + * This function is executed in uncached address space. 113 100 */ 114 101 static __init void __rm7k_sc_enable(void) 115 102 { 116 103 int i; 117 104 118 - set_c0_config(1 << 3); /* CONF_SE */ 105 + set_c0_config(R7K_CONF_SE); 119 106 120 107 write_c0_taglo(0); 121 108 write_c0_taghi(0); ··· 116 127 ".set mips0\n\t" 117 128 ".set reorder" 118 129 : 119 - : "r" (KSEG0ADDR(i)), "i" (Index_Store_Tag_SD)); 130 + : "r" (CKSEG0ADDR(i)), "i" (Index_Store_Tag_SD)); 120 131 } 121 132 } 122 133 123 134 static __init void rm7k_sc_enable(void) 124 135 { 125 - void (*func)(void) = (void *) KSEG1ADDR(&__rm7k_sc_enable); 126 - 127 - if (read_c0_config() & 0x08) /* CONF_SE */ 136 + if (read_c0_config() & R7K_CONF_SE) 128 137 return; 129 138 130 139 printk(KERN_INFO "Enabling secondary cache..."); 131 - func(); 140 + run_uncached(__rm7k_sc_enable); 132 141 } 133 142 134 143 static void rm7k_sc_disable(void) 135 144 { 136 - clear_c0_config(1<<3); /* CONF_SE */ 145 + clear_c0_config(R7K_CONF_SE); 137 146 } 138 147 139 148 struct bcache_ops rm7k_sc_ops = { ··· 151 164 printk(KERN_INFO "Secondary cache size %dK, linesize %d bytes.\n", 152 165 (scache_size >> 10), sc_lsize); 153 166 154 - if (!((config >> 3) & 1)) /* CONF_SE */ 167 + if (!(config & R7K_CONF_SE)) 155 168 rm7k_sc_enable(); 156 169 157 170 /*
+3
include/asm-mips/cacheflush.h
··· 90 90 #define ClearPageDcacheDirty(page) \ 91 91 clear_bit(PG_dcache_dirty, &(page)->flags) 92 92 93 + /* Run kernel code uncached, useful for cache probing functions. */ 94 + unsigned long __init run_uncached(void *func); 95 + 93 96 #endif /* _ASM_CACHEFLUSH_H */
+3
include/asm-mips/mipsregs.h
··· 433 433 #define R5K_CONF_SE (_ULCAST_(1) << 12) 434 434 #define R5K_CONF_SS (_ULCAST_(3) << 20) 435 435 436 + /* Bits specific to the RM7000. */ 437 + #define R7K_CONF_SE (_ULCAST_(1) << 3) 438 + 436 439 /* Bits specific to the R10000. */ 437 440 #define R10K_CONF_DN (_ULCAST_(3) << 3) 438 441 #define R10K_CONF_CT (_ULCAST_(1) << 5)