diff options
author | Chris Dearman <chris@mips.com> | 2006-06-20 12:15:20 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2006-06-29 16:10:52 -0400 |
commit | 9318c51acd9689505850152cc98277a6d6f2d752 (patch) | |
tree | 7a8d49a377bed11ba2a45643c08af47f1222c51b /arch/mips/mm | |
parent | f7a849153be3b66326b52dce0d07896b56cb4cd7 (diff) |
[MIPS] MIPS32/MIPS64 secondary cache management
Signed-off-by: Chris Dearman <chris@mips.com>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/mm')
-rw-r--r-- | arch/mips/mm/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/mm/c-r4k.c | 23 | ||||
-rw-r--r-- | arch/mips/mm/sc-mips.c | 141 |
3 files changed, 160 insertions, 5 deletions
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index 4a6220116c96..19e41fd186c4 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile | |||
@@ -30,6 +30,7 @@ obj-$(CONFIG_CPU_VR41XX) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o | |||
30 | obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o | 30 | obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o |
31 | obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o | 31 | obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o |
32 | obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o | 32 | obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o |
33 | obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o | ||
33 | 34 | ||
34 | # | 35 | # |
35 | # Choose one DMA coherency model | 36 | # Choose one DMA coherency model |
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 4a43924cd4fc..01450938db8b 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c | |||
@@ -1092,6 +1092,7 @@ static int __init probe_scache(void) | |||
1092 | 1092 | ||
1093 | extern int r5k_sc_init(void); | 1093 | extern int r5k_sc_init(void); |
1094 | extern int rm7k_sc_init(void); | 1094 | extern int rm7k_sc_init(void); |
1095 | extern int mips_sc_init(void); | ||
1095 | 1096 | ||
1096 | static void __init setup_scache(void) | 1097 | static void __init setup_scache(void) |
1097 | { | 1098 | { |
@@ -1139,17 +1140,29 @@ static void __init setup_scache(void) | |||
1139 | return; | 1140 | return; |
1140 | 1141 | ||
1141 | default: | 1142 | default: |
1143 | if (c->isa_level == MIPS_CPU_ISA_M32R1 || | ||
1144 | c->isa_level == MIPS_CPU_ISA_M32R2 || | ||
1145 | c->isa_level == MIPS_CPU_ISA_M64R1 || | ||
1146 | c->isa_level == MIPS_CPU_ISA_M64R2) { | ||
1147 | #ifdef CONFIG_MIPS_CPU_SCACHE | ||
1148 | if (mips_sc_init ()) { | ||
1149 | scache_size = c->scache.ways * c->scache.sets * c->scache.linesz; | ||
1150 | printk("MIPS secondary cache %ldkB, %s, linesize %d bytes.\n", | ||
1151 | scache_size >> 10, | ||
1152 | way_string[c->scache.ways], c->scache.linesz); | ||
1153 | } | ||
1154 | #else | ||
1155 | if (!(c->scache.flags & MIPS_CACHE_NOT_PRESENT)) | ||
1156 | panic("Dunno how to handle MIPS32 / MIPS64 second level cache"); | ||
1157 | #endif | ||
1158 | return; | ||
1159 | } | ||
1142 | sc_present = 0; | 1160 | sc_present = 0; |
1143 | } | 1161 | } |
1144 | 1162 | ||
1145 | if (!sc_present) | 1163 | if (!sc_present) |
1146 | return; | 1164 | return; |
1147 | 1165 | ||
1148 | if ((c->isa_level == MIPS_CPU_ISA_M32R1 || | ||
1149 | c->isa_level == MIPS_CPU_ISA_M64R1) && | ||
1150 | !(c->scache.flags & MIPS_CACHE_NOT_PRESENT)) | ||
1151 | panic("Dunno how to handle MIPS32 / MIPS64 second level cache"); | ||
1152 | |||
1153 | /* compute a couple of other cache variables */ | 1166 | /* compute a couple of other cache variables */ |
1154 | c->scache.waysize = scache_size / c->scache.ways; | 1167 | c->scache.waysize = scache_size / c->scache.ways; |
1155 | 1168 | ||
diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c new file mode 100644 index 000000000000..d3f92a9e8310 --- /dev/null +++ b/arch/mips/mm/sc-mips.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 Chris Dearman (chris@mips.com), | ||
3 | */ | ||
4 | #include <linux/init.h> | ||
5 | #include <linux/kernel.h> | ||
6 | #include <linux/sched.h> | ||
7 | #include <linux/mm.h> | ||
8 | |||
9 | #include <asm/mipsregs.h> | ||
10 | #include <asm/bcache.h> | ||
11 | #include <asm/cacheops.h> | ||
12 | #include <asm/page.h> | ||
13 | #include <asm/pgtable.h> | ||
14 | #include <asm/system.h> | ||
15 | #include <asm/mmu_context.h> | ||
16 | #include <asm/r4kcache.h> | ||
17 | |||
18 | /* | ||
19 | * MIPS32/MIPS64 L2 cache handling | ||
20 | */ | ||
21 | |||
22 | /* | ||
23 | * Writeback and invalidate the secondary cache before DMA. | ||
24 | */ | ||
25 | static void mips_sc_wback_inv(unsigned long addr, unsigned long size) | ||
26 | { | ||
27 | unsigned long sc_lsize = cpu_scache_line_size(); | ||
28 | unsigned long end, a; | ||
29 | |||
30 | pr_debug("mips_sc_wback_inv[%08lx,%08lx]", addr, size); | ||
31 | |||
32 | /* Catch bad driver code */ | ||
33 | BUG_ON(size == 0); | ||
34 | |||
35 | a = addr & ~(sc_lsize - 1); | ||
36 | end = (addr + size - 1) & ~(sc_lsize - 1); | ||
37 | while (1) { | ||
38 | flush_scache_line(a); /* Hit_Writeback_Inv_SD */ | ||
39 | if (a == end) | ||
40 | break; | ||
41 | a += sc_lsize; | ||
42 | } | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * Invalidate the secondary cache before DMA. | ||
47 | */ | ||
48 | static void mips_sc_inv(unsigned long addr, unsigned long size) | ||
49 | { | ||
50 | unsigned long sc_lsize = cpu_scache_line_size(); | ||
51 | unsigned long end, a; | ||
52 | |||
53 | pr_debug("mips_sc_inv[%08lx,%08lx]", addr, size); | ||
54 | |||
55 | /* Catch bad driver code */ | ||
56 | BUG_ON(size == 0); | ||
57 | |||
58 | a = addr & ~(sc_lsize - 1); | ||
59 | end = (addr + size - 1) & ~(sc_lsize - 1); | ||
60 | while (1) { | ||
61 | invalidate_scache_line(a); /* Hit_Invalidate_SD */ | ||
62 | if (a == end) | ||
63 | break; | ||
64 | a += sc_lsize; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | static void mips_sc_enable(void) | ||
69 | { | ||
70 | /* L2 cache is permanently enabled */ | ||
71 | } | ||
72 | |||
73 | static void mips_sc_disable(void) | ||
74 | { | ||
75 | /* L2 cache is permanently enabled */ | ||
76 | } | ||
77 | |||
78 | static struct bcache_ops mips_sc_ops = { | ||
79 | .bc_enable = mips_sc_enable, | ||
80 | .bc_disable = mips_sc_disable, | ||
81 | .bc_wback_inv = mips_sc_wback_inv, | ||
82 | .bc_inv = mips_sc_inv | ||
83 | }; | ||
84 | |||
85 | static inline int __init mips_sc_probe(void) | ||
86 | { | ||
87 | struct cpuinfo_mips *c = ¤t_cpu_data; | ||
88 | unsigned int config1, config2; | ||
89 | unsigned int tmp; | ||
90 | |||
91 | /* Mark as not present until probe completed */ | ||
92 | c->scache.flags |= MIPS_CACHE_NOT_PRESENT; | ||
93 | |||
94 | /* Ignore anything but MIPSxx processors */ | ||
95 | if (c->isa_level != MIPS_CPU_ISA_M32R1 && | ||
96 | c->isa_level != MIPS_CPU_ISA_M32R2 && | ||
97 | c->isa_level != MIPS_CPU_ISA_M64R1 && | ||
98 | c->isa_level != MIPS_CPU_ISA_M64R2) | ||
99 | return 0; | ||
100 | |||
101 | /* Does this MIPS32/MIPS64 CPU have a config2 register? */ | ||
102 | config1 = read_c0_config1(); | ||
103 | if (!(config1 & MIPS_CONF_M)) | ||
104 | return 0; | ||
105 | |||
106 | config2 = read_c0_config2(); | ||
107 | tmp = (config2 >> 4) & 0x0f; | ||
108 | if (0 < tmp && tmp <= 7) | ||
109 | c->scache.linesz = 2 << tmp; | ||
110 | else | ||
111 | return 0; | ||
112 | |||
113 | tmp = (config2 >> 8) & 0x0f; | ||
114 | if (0 <= tmp && tmp <= 7) | ||
115 | c->scache.sets = 64 << tmp; | ||
116 | else | ||
117 | return 0; | ||
118 | |||
119 | tmp = (config2 >> 0) & 0x0f; | ||
120 | if (0 <= tmp && tmp <= 7) | ||
121 | c->scache.ways = tmp + 1; | ||
122 | else | ||
123 | return 0; | ||
124 | |||
125 | c->scache.waysize = c->scache.sets * c->scache.linesz; | ||
126 | |||
127 | c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; | ||
128 | |||
129 | return 1; | ||
130 | } | ||
131 | |||
132 | int __init mips_sc_init(void) | ||
133 | { | ||
134 | int found = mips_sc_probe (); | ||
135 | if (found) { | ||
136 | mips_sc_enable(); | ||
137 | bcops = &mips_sc_ops; | ||
138 | } | ||
139 | return found; | ||
140 | } | ||
141 | |||