Commit 9318c51acd9689505850152cc98277a6d6f2d752
Committed by
Ralf Baechle
1 parent
f7a849153b
Exists in
master
and in
7 other branches
[MIPS] MIPS32/MIPS64 secondary cache management
Signed-off-by: Chris Dearman <chris@mips.com> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Showing 5 changed files with 168 additions and 7 deletions Side-by-side Diff
arch/mips/Kconfig
... | ... | @@ -325,6 +325,7 @@ |
325 | 325 | select I8259 |
326 | 326 | select MIPS_BOARDS_GEN |
327 | 327 | select MIPS_BONITO64 |
328 | + select MIPS_CPU_SCACHE | |
328 | 329 | select MIPS_GT64120 |
329 | 330 | select MIPS_MSC |
330 | 331 | select SWAP_IO_SPACE |
... | ... | @@ -1475,6 +1476,13 @@ |
1475 | 1476 | bool |
1476 | 1477 | |
1477 | 1478 | config IP22_CPU_SCACHE |
1479 | + bool | |
1480 | + select BOARD_SCACHE | |
1481 | + | |
1482 | +# | |
1483 | +# Support for a MIPS32 / MIPS64 style S-caches | |
1484 | +# | |
1485 | +config MIPS_CPU_SCACHE | |
1478 | 1486 | bool |
1479 | 1487 | select BOARD_SCACHE |
1480 | 1488 |
arch/mips/kernel/cpu-probe.c
arch/mips/mm/Makefile
arch/mips/mm/c-r4k.c
... | ... | @@ -1092,6 +1092,7 @@ |
1092 | 1092 | |
1093 | 1093 | extern int r5k_sc_init(void); |
1094 | 1094 | extern int rm7k_sc_init(void); |
1095 | +extern int mips_sc_init(void); | |
1095 | 1096 | |
1096 | 1097 | static void __init setup_scache(void) |
1097 | 1098 | { |
1098 | 1099 | |
... | ... | @@ -1139,16 +1140,28 @@ |
1139 | 1140 | return; |
1140 | 1141 | |
1141 | 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 | 1160 | sc_present = 0; |
1143 | 1161 | } |
1144 | 1162 | |
1145 | 1163 | if (!sc_present) |
1146 | 1164 | return; |
1147 | - | |
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 | 1165 | |
1153 | 1166 | /* compute a couple of other cache variables */ |
1154 | 1167 | c->scache.waysize = scache_size / c->scache.ways; |
arch/mips/mm/sc-mips.c
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 | +} |