cpu.c revision 1.17 1 /* $NetBSD: cpu.c,v 1.17 2003/09/23 15:25:26 shige 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.17 2003/09/23 15:25:26 shige 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 char cpu_model[80];
80
81 int cpufound = 0;
82
83 static int
84 cpumatch(struct device *parent, struct cfdata *cf, void *aux)
85 {
86 struct plb_attach_args *paa = aux;
87
88 /* make sure that we're looking for a CPU */
89 if (strcmp(paa->plb_name, cf->cf_name) != 0)
90 return (0);
91
92 return !cpufound;
93 }
94
95 static void
96 cpuattach(struct device *parent, struct device *self, void *aux)
97 {
98 int pvr, cpu;
99 int own, pcf, cas, pcl, aid;
100 struct cputab *cp = models;
101 unsigned int processor_freq;
102
103 if (board_info_get("processor-frequency",
104 &processor_freq, sizeof(processor_freq)) == -1)
105 panic("no processor-frequency");
106
107 cpufound++;
108 ncpus++;
109
110 asm ("mfpvr %0" : "=r"(pvr));
111 cpu = pvr >> 16;
112
113 /* Break PVR up into separate fields and print them out. */
114 own = (pvr >> 20) & 0xfff;
115 pcf = (pvr >> 16) & 0xf;
116 cas = (pvr >> 10) & 0x3f;
117 pcl = (pvr >> 6) & 0xf;
118 aid = pvr & 0x3f;
119
120 while (cp->name) {
121 if (cp->version == cpu)
122 break;
123 cp++;
124 }
125 if (cp->name)
126 strcpy(cpu_model, cp->name);
127 else
128 sprintf(cpu_model, "Version 0x%x", cpu);
129 sprintf(cpu_model + strlen(cpu_model), " (Revision %d.%d)",
130 (pvr >> 8) & 0xff, pvr & 0xff);
131
132 #if 1
133 printf(": %dMHz %s\n", processor_freq / 1000 / 1000,
134 cpu_model);
135 #endif
136
137 cpu_probe_cache();
138
139 printf("Instruction cache size %d line size %d\n",
140 curcpu()->ci_ci.icache_size, curcpu()->ci_ci.icache_line_size);
141 printf("Data cache size %d line size %d\n",
142 curcpu()->ci_ci.dcache_size, curcpu()->ci_ci.dcache_line_size);
143
144 #ifdef DEBUG
145 /* It sux that the cache info here is useless. */
146 printf("PVR: owner %x core family %x cache %x version %x asic %x\n",
147 own, pcf, cas, pcl, aid);
148 #endif
149 }
150
151 /*
152 * This routine must be explicitly called to initialize the
153 * CPU cache information so cache flushe and memcpy operation
154 * work.
155 */
156 void
157 cpu_probe_cache()
158 {
159 int version;
160
161 /*
162 * First we need to identify the cpu and determine the
163 * cache line size, or things like memset/memcpy may lose
164 * badly.
165 */
166 __asm __volatile("mfpvr %0" : "=r" (version));
167 switch (version & 0xffff0000) {
168 case PVR_401A1:
169 curcpu()->ci_ci.dcache_size = 1024;
170 curcpu()->ci_ci.dcache_line_size = 16;
171 curcpu()->ci_ci.icache_size = 2848;
172 curcpu()->ci_ci.icache_line_size = 16;
173 break;
174 case PVR_401B2:
175 curcpu()->ci_ci.dcache_size = 8192;
176 curcpu()->ci_ci.dcache_line_size = 16;
177 curcpu()->ci_ci.icache_size = 16384;
178 curcpu()->ci_ci.icache_line_size = 16;
179 break;
180 case PVR_401C2:
181 curcpu()->ci_ci.dcache_size = 8192;
182 curcpu()->ci_ci.dcache_line_size = 16;
183 curcpu()->ci_ci.icache_size = 0;
184 curcpu()->ci_ci.icache_line_size = 16;
185 break;
186 case PVR_401D2:
187 curcpu()->ci_ci.dcache_size = 2848;
188 curcpu()->ci_ci.dcache_line_size = 16;
189 curcpu()->ci_ci.icache_size = 4096;
190 curcpu()->ci_ci.icache_line_size = 16;
191 break;
192 case PVR_401E2:
193 curcpu()->ci_ci.dcache_size = 0;
194 curcpu()->ci_ci.dcache_line_size = 16;
195 curcpu()->ci_ci.icache_size = 0;
196 curcpu()->ci_ci.icache_line_size = 16;
197 break;
198 case PVR_401F2:
199 curcpu()->ci_ci.dcache_size = 2048;
200 curcpu()->ci_ci.dcache_line_size = 16;
201 curcpu()->ci_ci.icache_size = 2848;
202 curcpu()->ci_ci.icache_line_size = 16;
203 break;
204 case PVR_401G2:
205 curcpu()->ci_ci.dcache_size = 2848;
206 curcpu()->ci_ci.dcache_line_size = 16;
207 curcpu()->ci_ci.icache_size = 8192;
208 curcpu()->ci_ci.icache_line_size = 16;
209 break;
210 case PVR_403:
211 curcpu()->ci_ci.dcache_size = 8192;
212 curcpu()->ci_ci.dcache_line_size = 16;
213 curcpu()->ci_ci.icache_size = 16384;
214 curcpu()->ci_ci.icache_line_size = 16;
215 break;
216 case PVR_405GP:
217 curcpu()->ci_ci.dcache_size = 8192;
218 curcpu()->ci_ci.dcache_line_size = 32;
219 curcpu()->ci_ci.icache_size = 8192;
220 curcpu()->ci_ci.icache_line_size = 32;
221 break;
222 case PVR_405GPR:
223 curcpu()->ci_ci.dcache_size = 16384;
224 curcpu()->ci_ci.dcache_line_size = 32;
225 curcpu()->ci_ci.icache_size = 16384;
226 curcpu()->ci_ci.icache_line_size = 32;
227 break;
228 default:
229 /*
230 * Unknown CPU type. For safety we'll specify a
231 * cache with a 4-byte line size. That way cache
232 * flush routines won't miss any lines.
233 */
234 curcpu()->ci_ci.dcache_line_size = 4;
235 curcpu()->ci_ci.icache_line_size = 4;
236 break;
237 }
238
239 }
240
241 /*
242 * These small routines may have to be replaced,
243 * if/when we support processors other that the 604.
244 */
245
246 void
247 dcache_flush_page(vaddr_t va)
248 {
249 int i;
250
251 if (curcpu()->ci_ci.dcache_line_size)
252 for (i = 0; i < PAGE_SIZE;
253 i += curcpu()->ci_ci.dcache_line_size)
254 asm volatile("dcbf %0,%1" : : "r" (va), "r" (i));
255 asm volatile("sync;isync" : : );
256 }
257
258 void
259 icache_flush_page(vaddr_t va)
260 {
261 int i;
262
263 if (curcpu()->ci_ci.icache_line_size)
264 for (i = 0; i < PAGE_SIZE;
265 i += curcpu()->ci_ci.icache_line_size)
266 asm volatile("icbi %0,%1" : : "r" (va), "r" (i));
267 asm volatile("sync;isync" : : );
268 }
269
270 void
271 dcache_flush(vaddr_t va, vsize_t len)
272 {
273 int i;
274
275 if (len == 0)
276 return;
277
278 /* Make sure we flush all cache lines */
279 len += va & (curcpu()->ci_ci.dcache_line_size-1);
280 if (curcpu()->ci_ci.dcache_line_size)
281 for (i = 0; i < len; i += curcpu()->ci_ci.dcache_line_size)
282 asm volatile("dcbf %0,%1" : : "r" (va), "r" (i));
283 asm volatile("sync;isync" : : );
284 }
285
286 void
287 icache_flush(vaddr_t va, vsize_t len)
288 {
289 int i;
290
291 if (len == 0)
292 return;
293
294 /* Make sure we flush all cache lines */
295 len += va & (curcpu()->ci_ci.icache_line_size-1);
296 if (curcpu()->ci_ci.icache_line_size)
297 for (i = 0; i < len; i += curcpu()->ci_ci.icache_line_size)
298 asm volatile("icbi %0,%1" : : "r" (va), "r" (i));
299 asm volatile("sync;isync" : : );
300 }
301