cpu.c revision 1.16 1 /* $NetBSD: cpu.c,v 1.16 2003/07/15 02:54:43 lukem Exp $ */
2
3 /*
4 * Copyright 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.16 2003/07/15 02:54:43 lukem Exp $");
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/device.h>
44 #include <sys/properties.h>
45
46 #include <uvm/uvm_extern.h>
47
48 #include <machine/cpu.h>
49 #include <powerpc/ibm4xx/dev/plbvar.h>
50
51 struct cputab {
52 int version;
53 char *name;
54 };
55 static struct cputab models[] = {
56 { PVR_401A1 >> 16, "401A1" },
57 { PVR_401B2 >> 16, "401B21" },
58 { PVR_401C2 >> 16, "401C2" },
59 { PVR_401D2 >> 16, "401D2" },
60 { PVR_401E2 >> 16, "401E2" },
61 { PVR_401F2 >> 16, "401F2" },
62 { PVR_401G2 >> 16, "401G2" },
63 { PVR_403 >> 16, "403" },
64 { PVR_405GP >> 16, "405GP" },
65 { PVR_405GPR >> 16, "405GPr" },
66 { 0, NULL }
67 };
68
69 static int cpumatch(struct device *, struct cfdata *, void *);
70 static void cpuattach(struct device *, struct device *, void *);
71
72 CFATTACH_DECL(cpu, sizeof(struct device),
73 cpumatch, cpuattach, NULL, NULL);
74
75 int ncpus;
76
77 struct cpu_info cpu_info[1];
78
79 int cpufound = 0;
80
81 static int
82 cpumatch(struct device *parent, struct cfdata *cf, void *aux)
83 {
84 struct plb_attach_args *paa = aux;
85
86 /* make sure that we're looking for a CPU */
87 if (strcmp(paa->plb_name, cf->cf_name) != 0)
88 return (0);
89
90 return !cpufound;
91 }
92
93 static void
94 cpuattach(struct device *parent, struct device *self, void *aux)
95 {
96 int pvr, cpu;
97 int own, pcf, cas, pcl, aid;
98 struct cputab *cp = models;
99 unsigned int processor_freq;
100
101 if (board_info_get("processor-frequency",
102 &processor_freq, sizeof(processor_freq)) == -1)
103 panic("no processor-frequency");
104
105 cpufound++;
106 ncpus++;
107
108 asm ("mfpvr %0" : "=r"(pvr));
109 cpu = pvr >> 16;
110
111 /* Break PVR up into separate fields and print them out. */
112 own = (pvr >> 20) & 0xfff;
113 pcf = (pvr >> 16) & 0xf;
114 cas = (pvr >> 10) & 0x3f;
115 pcl = (pvr >> 6) & 0xf;
116 aid = pvr & 0x3f;
117
118 while (cp->name) {
119 if (cp->version == cpu)
120 break;
121 cp++;
122 }
123 if (cp->name)
124 strcpy(cpu_model, cp->name);
125 else
126 sprintf(cpu_model, "Version 0x%x", cpu);
127 sprintf(cpu_model + strlen(cpu_model), " (Revision %d.%d)",
128 (pvr >> 8) & 0xff, pvr & 0xff);
129
130 #if 1
131 printf(": %dMHz %s\n", processor_freq / 1000 / 1000,
132 cpu_model);
133 #endif
134
135 cpu_probe_cache();
136
137 printf("Instruction cache size %d line size %d\n",
138 curcpu()->ci_ci.icache_size, curcpu()->ci_ci.icache_line_size);
139 printf("Data cache size %d line size %d\n",
140 curcpu()->ci_ci.dcache_size, curcpu()->ci_ci.dcache_line_size);
141
142 #ifdef DEBUG
143 /* It sux that the cache info here is useless. */
144 printf("PVR: owner %x core family %x cache %x version %x asic %x\n",
145 own, pcf, cas, pcl, aid);
146 #endif
147 }
148
149 /*
150 * This routine must be explicitly called to initialize the
151 * CPU cache information so cache flushe and memcpy operation
152 * work.
153 */
154 void
155 cpu_probe_cache()
156 {
157 int version;
158
159 /*
160 * First we need to identify the cpu and determine the
161 * cache line size, or things like memset/memcpy may lose
162 * badly.
163 */
164 __asm __volatile("mfpvr %0" : "=r" (version));
165 switch (version & 0xffff0000) {
166 case PVR_401A1:
167 curcpu()->ci_ci.dcache_size = 1024;
168 curcpu()->ci_ci.dcache_line_size = 16;
169 curcpu()->ci_ci.icache_size = 2848;
170 curcpu()->ci_ci.icache_line_size = 16;
171 break;
172 case PVR_401B2:
173 curcpu()->ci_ci.dcache_size = 8192;
174 curcpu()->ci_ci.dcache_line_size = 16;
175 curcpu()->ci_ci.icache_size = 16384;
176 curcpu()->ci_ci.icache_line_size = 16;
177 break;
178 case PVR_401C2:
179 curcpu()->ci_ci.dcache_size = 8192;
180 curcpu()->ci_ci.dcache_line_size = 16;
181 curcpu()->ci_ci.icache_size = 0;
182 curcpu()->ci_ci.icache_line_size = 16;
183 break;
184 case PVR_401D2:
185 curcpu()->ci_ci.dcache_size = 2848;
186 curcpu()->ci_ci.dcache_line_size = 16;
187 curcpu()->ci_ci.icache_size = 4096;
188 curcpu()->ci_ci.icache_line_size = 16;
189 break;
190 case PVR_401E2:
191 curcpu()->ci_ci.dcache_size = 0;
192 curcpu()->ci_ci.dcache_line_size = 16;
193 curcpu()->ci_ci.icache_size = 0;
194 curcpu()->ci_ci.icache_line_size = 16;
195 break;
196 case PVR_401F2:
197 curcpu()->ci_ci.dcache_size = 2048;
198 curcpu()->ci_ci.dcache_line_size = 16;
199 curcpu()->ci_ci.icache_size = 2848;
200 curcpu()->ci_ci.icache_line_size = 16;
201 break;
202 case PVR_401G2:
203 curcpu()->ci_ci.dcache_size = 2848;
204 curcpu()->ci_ci.dcache_line_size = 16;
205 curcpu()->ci_ci.icache_size = 8192;
206 curcpu()->ci_ci.icache_line_size = 16;
207 break;
208 case PVR_403:
209 curcpu()->ci_ci.dcache_size = 8192;
210 curcpu()->ci_ci.dcache_line_size = 16;
211 curcpu()->ci_ci.icache_size = 16384;
212 curcpu()->ci_ci.icache_line_size = 16;
213 break;
214 case PVR_405GP:
215 curcpu()->ci_ci.dcache_size = 8192;
216 curcpu()->ci_ci.dcache_line_size = 32;
217 curcpu()->ci_ci.icache_size = 8192;
218 curcpu()->ci_ci.icache_line_size = 32;
219 break;
220 case PVR_405GPR:
221 curcpu()->ci_ci.dcache_size = 16384;
222 curcpu()->ci_ci.dcache_line_size = 32;
223 curcpu()->ci_ci.icache_size = 16384;
224 curcpu()->ci_ci.icache_line_size = 32;
225 break;
226 default:
227 /*
228 * Unknown CPU type. For safety we'll specify a
229 * cache with a 4-byte line size. That way cache
230 * flush routines won't miss any lines.
231 */
232 curcpu()->ci_ci.dcache_line_size = 4;
233 curcpu()->ci_ci.icache_line_size = 4;
234 break;
235 }
236
237 }
238
239 /*
240 * These small routines may have to be replaced,
241 * if/when we support processors other that the 604.
242 */
243
244 void
245 dcache_flush_page(vaddr_t va)
246 {
247 int i;
248
249 if (curcpu()->ci_ci.dcache_line_size)
250 for (i = 0; i < PAGE_SIZE;
251 i += curcpu()->ci_ci.dcache_line_size)
252 asm volatile("dcbf %0,%1" : : "r" (va), "r" (i));
253 asm volatile("sync;isync" : : );
254 }
255
256 void
257 icache_flush_page(vaddr_t va)
258 {
259 int i;
260
261 if (curcpu()->ci_ci.icache_line_size)
262 for (i = 0; i < PAGE_SIZE;
263 i += curcpu()->ci_ci.icache_line_size)
264 asm volatile("icbi %0,%1" : : "r" (va), "r" (i));
265 asm volatile("sync;isync" : : );
266 }
267
268 void
269 dcache_flush(vaddr_t va, vsize_t len)
270 {
271 int i;
272
273 if (len == 0)
274 return;
275
276 /* Make sure we flush all cache lines */
277 len += va & (curcpu()->ci_ci.dcache_line_size-1);
278 if (curcpu()->ci_ci.dcache_line_size)
279 for (i = 0; i < len; i += curcpu()->ci_ci.dcache_line_size)
280 asm volatile("dcbf %0,%1" : : "r" (va), "r" (i));
281 asm volatile("sync;isync" : : );
282 }
283
284 void
285 icache_flush(vaddr_t va, vsize_t len)
286 {
287 int i;
288
289 if (len == 0)
290 return;
291
292 /* Make sure we flush all cache lines */
293 len += va & (curcpu()->ci_ci.icache_line_size-1);
294 if (curcpu()->ci_ci.icache_line_size)
295 for (i = 0; i < len; i += curcpu()->ci_ci.icache_line_size)
296 asm volatile("icbi %0,%1" : : "r" (va), "r" (i));
297 asm volatile("sync;isync" : : );
298 }
299