aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips/lib/Makefile4
-rw-r--r--arch/mips/lib/uncached.c76
-rw-r--r--arch/mips/mm/c-r4k.c6
-rw-r--r--arch/mips/mm/sc-rm7k.c29
-rw-r--r--include/asm-mips/cacheflush.h3
-rw-r--r--include/asm-mips/mipsregs.h3
6 files changed, 94 insertions, 27 deletions
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index 037303412909..cf12caf80774 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -2,8 +2,8 @@
2# Makefile for MIPS-specific library files.. 2# Makefile for MIPS-specific library files..
3# 3#
4 4
5lib-y += csum_partial_copy.o memcpy.o promlib.o \ 5lib-y += csum_partial_copy.o memcpy.o promlib.o strlen_user.o strncpy_user.o \
6 strlen_user.o strncpy_user.o strnlen_user.o 6 strnlen_user.o uncached.o
7 7
8obj-y += iomap.o 8obj-y += iomap.o
9 9
diff --git a/arch/mips/lib/uncached.c b/arch/mips/lib/uncached.c
new file mode 100644
index 000000000000..98ce89f8068b
--- /dev/null
+++ b/arch/mips/lib/uncached.c
@@ -0,0 +1,76 @@
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 */
38unsigned 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}
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 48d731c2f08a..b90147399ea4 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -26,6 +26,7 @@
26#include <asm/system.h> 26#include <asm/system.h>
27#include <asm/mmu_context.h> 27#include <asm/mmu_context.h>
28#include <asm/war.h> 28#include <asm/war.h>
29#include <asm/cacheflush.h> /* for run_uncached() */
29 30
30static unsigned long icache_size, dcache_size, scache_size; 31static unsigned long icache_size, dcache_size, scache_size;
31 32
@@ -1119,7 +1120,6 @@ static int __init probe_scache(void)
1119 return 1; 1120 return 1;
1120} 1121}
1121 1122
1122typedef int (*probe_func_t)(unsigned long);
1123extern int r5k_sc_init(void); 1123extern int r5k_sc_init(void);
1124extern int rm7k_sc_init(void); 1124extern int rm7k_sc_init(void);
1125 1125
@@ -1127,7 +1127,6 @@ static void __init setup_scache(void)
1127{ 1127{
1128 struct cpuinfo_mips *c = &current_cpu_data; 1128 struct cpuinfo_mips *c = &current_cpu_data;
1129 unsigned int config = read_c0_config(); 1129 unsigned int config = read_c0_config();
1130 probe_func_t probe_scache_kseg1;
1131 int sc_present = 0; 1130 int sc_present = 0;
1132 1131
1133 /* 1132 /*
@@ -1140,8 +1139,7 @@ static void __init setup_scache(void)
1140 case CPU_R4000MC: 1139 case CPU_R4000MC:
1141 case CPU_R4400SC: 1140 case CPU_R4400SC:
1142 case CPU_R4400MC: 1141 case CPU_R4400MC:
1143 probe_scache_kseg1 = (probe_func_t) (CKSEG1ADDR(&probe_scache)); 1142 sc_present = run_uncached(probe_scache);
1144 sc_present = probe_scache_kseg1(config);
1145 if (sc_present) 1143 if (sc_present)
1146 c->options |= MIPS_CPU_CACHE_CDEX_S; 1144 c->options |= MIPS_CPU_CACHE_CDEX_S;
1147 break; 1145 break;
diff --git a/arch/mips/mm/sc-rm7k.c b/arch/mips/mm/sc-rm7k.c
index 4e92f931aaba..1df5aab82c13 100644
--- a/arch/mips/mm/sc-rm7k.c
+++ b/arch/mips/mm/sc-rm7k.c
@@ -15,6 +15,7 @@
15#include <asm/cacheops.h> 15#include <asm/cacheops.h>
16#include <asm/mipsregs.h> 16#include <asm/mipsregs.h>
17#include <asm/processor.h> 17#include <asm/processor.h>
18#include <asm/cacheflush.h> /* for run_uncached() */
18 19
19/* Primary cache parameters. */ 20/* Primary cache parameters. */
20#define sc_lsize 32 21#define sc_lsize 32
@@ -96,25 +97,13 @@ static void rm7k_sc_inv(unsigned long addr, unsigned long size)
96} 97}
97 98
98/* 99/*
99 * This function is executed in the uncached segment CKSEG1. 100 * This function is executed in uncached address space.
100 * It must not touch the stack, because the stack pointer still points
101 * into CKSEG0.
102 *
103 * Three options:
104 * - Write it in assembly and guarantee that we don't use the stack.
105 * - Disable caching for CKSEG0 before calling it.
106 * - Pray that GCC doesn't randomly start using the stack.
107 *
108 * This being Linux, we obviously take the least sane of those options -
109 * following DaveM's lead in c-r4k.c
110 *
111 * It seems we get our kicks from relying on unguaranteed behaviour in GCC
112 */ 101 */
113static __init void __rm7k_sc_enable(void) 102static __init void __rm7k_sc_enable(void)
114{ 103{
115 int i; 104 int i;
116 105
117 set_c0_config(1 << 3); /* CONF_SE */ 106 set_c0_config(R7K_CONF_SE);
118 107
119 write_c0_taglo(0); 108 write_c0_taglo(0);
120 write_c0_taghi(0); 109 write_c0_taghi(0);
@@ -127,24 +116,22 @@ static __init void __rm7k_sc_enable(void)
127 ".set mips0\n\t" 116 ".set mips0\n\t"
128 ".set reorder" 117 ".set reorder"
129 : 118 :
130 : "r" (KSEG0ADDR(i)), "i" (Index_Store_Tag_SD)); 119 : "r" (CKSEG0ADDR(i)), "i" (Index_Store_Tag_SD));
131 } 120 }
132} 121}
133 122
134static __init void rm7k_sc_enable(void) 123static __init void rm7k_sc_enable(void)
135{ 124{
136 void (*func)(void) = (void *) KSEG1ADDR(&__rm7k_sc_enable); 125 if (read_c0_config() & R7K_CONF_SE)
137
138 if (read_c0_config() & 0x08) /* CONF_SE */
139 return; 126 return;
140 127
141 printk(KERN_INFO "Enabling secondary cache..."); 128 printk(KERN_INFO "Enabling secondary cache...");
142 func(); 129 run_uncached(__rm7k_sc_enable);
143} 130}
144 131
145static void rm7k_sc_disable(void) 132static void rm7k_sc_disable(void)
146{ 133{
147 clear_c0_config(1<<3); /* CONF_SE */ 134 clear_c0_config(R7K_CONF_SE);
148} 135}
149 136
150struct bcache_ops rm7k_sc_ops = { 137struct bcache_ops rm7k_sc_ops = {
@@ -164,7 +151,7 @@ void __init rm7k_sc_init(void)
164 printk(KERN_INFO "Secondary cache size %dK, linesize %d bytes.\n", 151 printk(KERN_INFO "Secondary cache size %dK, linesize %d bytes.\n",
165 (scache_size >> 10), sc_lsize); 152 (scache_size >> 10), sc_lsize);
166 153
167 if (!((config >> 3) & 1)) /* CONF_SE */ 154 if (!(config & R7K_CONF_SE))
168 rm7k_sc_enable(); 155 rm7k_sc_enable();
169 156
170 /* 157 /*
diff --git a/include/asm-mips/cacheflush.h b/include/asm-mips/cacheflush.h
index 4213d2c8bb8a..a18ba2edc0b6 100644
--- a/include/asm-mips/cacheflush.h
+++ b/include/asm-mips/cacheflush.h
@@ -90,4 +90,7 @@ extern void (*flush_data_cache_page)(unsigned long addr);
90#define ClearPageDcacheDirty(page) \ 90#define ClearPageDcacheDirty(page) \
91 clear_bit(PG_dcache_dirty, &(page)->flags) 91 clear_bit(PG_dcache_dirty, &(page)->flags)
92 92
93/* Run kernel code uncached, useful for cache probing functions. */
94unsigned long __init run_uncached(void *func);
95
93#endif /* _ASM_CACHEFLUSH_H */ 96#endif /* _ASM_CACHEFLUSH_H */
diff --git a/include/asm-mips/mipsregs.h b/include/asm-mips/mipsregs.h
index 006354ed2e29..f3b0b4181508 100644
--- a/include/asm-mips/mipsregs.h
+++ b/include/asm-mips/mipsregs.h
@@ -433,6 +433,9 @@
433#define R5K_CONF_SE (_ULCAST_(1) << 12) 433#define R5K_CONF_SE (_ULCAST_(1) << 12)
434#define R5K_CONF_SS (_ULCAST_(3) << 20) 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/* Bits specific to the R10000. */ 439/* Bits specific to the R10000. */
437#define R10K_CONF_DN (_ULCAST_(3) << 3) 440#define R10K_CONF_DN (_ULCAST_(3) << 3)
438#define R10K_CONF_CT (_ULCAST_(1) << 5) 441#define R10K_CONF_CT (_ULCAST_(1) << 5)