FreeBSD/Linux Kernel Cross Reference
sys/mips/mips/cpu.c
1 /*-
2 * Copyright (c) 2004 Juli Mallett. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: releng/8.0/sys/mips/mips/cpu.c 187236 2009-01-14 20:16:44Z gonzo $");
29
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/module.h>
33 #include <sys/stdint.h>
34
35 #include <sys/bus.h>
36 #include <sys/rman.h>
37 #include <sys/sysctl.h>
38 #include <sys/systm.h>
39
40 #include <vm/vm.h>
41 #include <vm/vm_page.h>
42
43 #include <machine/cache.h>
44 #include <machine/cpufunc.h>
45 #include <machine/cpuinfo.h>
46 #include <machine/cpuregs.h>
47 #include <machine/intr_machdep.h>
48 #include <machine/locore.h>
49 #include <machine/pte.h>
50
51 static struct mips_cpuinfo cpuinfo;
52
53 union cpuprid cpu_id;
54 union cpuprid fpu_id;
55
56 /*
57 * Attempt to identify the MIPS CPU as much as possible.
58 *
59 * XXX: Assumes the CPU is MIPS32 compliant.
60 * XXX: For now, skip config register selections 2 and 3
61 * as we don't currently use L2/L3 cache or additional
62 * MIPS32 processor features.
63 */
64 static void
65 mips_get_identity(struct mips_cpuinfo *cpuinfo)
66 {
67 u_int32_t prid;
68 u_int32_t cfg0;
69 u_int32_t cfg1;
70 u_int32_t tmp;
71
72 memset(cpuinfo, 0, sizeof(struct mips_cpuinfo));
73
74 /* Read and store the PrID ID for CPU identification. */
75 prid = mips_rd_prid();
76 cpuinfo->cpu_vendor = MIPS_PRID_CID(prid);
77 cpuinfo->cpu_rev = MIPS_PRID_REV(prid);
78 cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid);
79
80 /* Read config register selection 0 to learn TLB type. */
81 cfg0 = mips_rd_config();
82
83 cpuinfo->tlb_type = ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT);
84 cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI;
85
86 /* If config register selection 1 does not exist, exit. */
87 if (!(cfg0 & MIPS3_CONFIG_CM))
88 return;
89
90 /* Learn TLB size and L1 cache geometry. */
91 cfg1 = mips_rd_config_sel1();
92 cpuinfo->tlb_nentries = ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
93
94 /* L1 instruction cache. */
95 tmp = 1 << (((cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT) + 1);
96 if (tmp != 0) {
97 cpuinfo->l1.ic_linesize = tmp;
98 cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
99 cpuinfo->l1.ic_nsets = 1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
100 cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize * cpuinfo->l1.ic_nsets
101 * cpuinfo->l1.ic_nways;
102 }
103
104 /* L1 data cache. */
105 tmp = 1 << (((cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT) + 1);
106 if (tmp != 0) {
107 cpuinfo->l1.dc_linesize = tmp;
108 cpuinfo->l1.dc_nways = (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
109 cpuinfo->l1.dc_nsets = 1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
110 #ifdef TARGET_OCTEON
111 /*
112 * Octeon does 128 byte line-size. But Config-Sel1 doesn't show
113 * 128 line-size, 1 Set, 64 ways.
114 */
115 cpuinfo->l1.dc_linesize = 128;
116 cpuinfo->l1.dc_nsets = 1;
117 cpuinfo->l1.dc_nways = 64;
118 #endif
119 cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize * cpuinfo->l1.dc_nsets
120 * cpuinfo->l1.dc_nways;
121 }
122 }
123
124 void
125 mips_cpu_init(void)
126 {
127 mips_get_identity(&cpuinfo);
128 num_tlbentries = cpuinfo.tlb_nentries;
129 Mips_SetWIRED(0);
130 Mips_TLBFlush(num_tlbentries);
131 Mips_SetWIRED(VMWIRED_ENTRIES);
132 mips_config_cache(&cpuinfo);
133 mips_vector_init();
134
135 mips_icache_sync_all();
136 mips_dcache_wbinv_all();
137 /* Print some info about CPU */
138 cpu_identify();
139 }
140
141 void
142 cpu_identify(void)
143 {
144 printf("cpu%d: ", 0); /* XXX per-cpu */
145 switch (cpuinfo.cpu_vendor) {
146 case MIPS_PRID_CID_MTI:
147 printf("MIPS Technologies");
148 break;
149 case MIPS_PRID_CID_BROADCOM:
150 case MIPS_PRID_CID_SIBYTE:
151 printf("Broadcom");
152 break;
153 case MIPS_PRID_CID_ALCHEMY:
154 printf("AMD");
155 break;
156 case MIPS_PRID_CID_SANDCRAFT:
157 printf("Sandcraft");
158 break;
159 case MIPS_PRID_CID_PHILIPS:
160 printf("Philips");
161 break;
162 case MIPS_PRID_CID_TOSHIBA:
163 printf("Toshiba");
164 break;
165 case MIPS_PRID_CID_LSI:
166 printf("LSI");
167 break;
168 case MIPS_PRID_CID_LEXRA:
169 printf("Lexra");
170 break;
171 case MIPS_PRID_CID_PREHISTORIC:
172 default:
173 printf("Unknown");
174 break;
175 }
176 printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
177
178 printf(" MMU: ");
179 if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
180 printf("none present\n");
181 } else {
182 if (cpuinfo.tlb_type == MIPS_MMU_TLB) {
183 printf("Standard TLB");
184 } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) {
185 printf("Standard BAT");
186 } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) {
187 printf("Fixed mapping");
188 }
189 printf(", %d entries\n", cpuinfo.tlb_nentries);
190 }
191
192 printf(" L1 i-cache: ");
193 if (cpuinfo.l1.ic_linesize == 0) {
194 printf("disabled");
195 } else {
196 if (cpuinfo.l1.ic_nways == 1) {
197 printf("direct-mapped with");
198 } else {
199 printf ("%d ways of", cpuinfo.l1.ic_nways);
200 }
201 printf(" %d sets, %d bytes per line\n", cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
202 }
203
204 printf(" L1 d-cache: ");
205 if (cpuinfo.l1.dc_linesize == 0) {
206 printf("disabled");
207 } else {
208 if (cpuinfo.l1.dc_nways == 1) {
209 printf("direct-mapped with");
210 } else {
211 printf ("%d ways of", cpuinfo.l1.dc_nways);
212 }
213 printf(" %d sets, %d bytes per line\n", cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
214 }
215 }
216
217 static struct rman cpu_hardirq_rman;
218
219 static devclass_t cpu_devclass;
220
221 /*
222 * Device methods
223 */
224 static int cpu_probe(device_t);
225 static int cpu_attach(device_t);
226 static struct resource *cpu_alloc_resource(device_t, device_t, int, int *,
227 u_long, u_long, u_long, u_int);
228 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
229 driver_filter_t *f, driver_intr_t *, void *,
230 void **);
231
232 static device_method_t cpu_methods[] = {
233 /* Device interface */
234 DEVMETHOD(device_probe, cpu_probe),
235 DEVMETHOD(device_attach, cpu_attach),
236 DEVMETHOD(device_detach, bus_generic_detach),
237 DEVMETHOD(device_shutdown, bus_generic_shutdown),
238
239 /* Bus interface */
240 DEVMETHOD(bus_alloc_resource, cpu_alloc_resource),
241 DEVMETHOD(bus_setup_intr, cpu_setup_intr),
242 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
243
244 { 0, 0 }
245 };
246
247 static driver_t cpu_driver = {
248 "cpu", cpu_methods, 1
249 };
250
251 static int
252 cpu_probe(device_t dev)
253 {
254 return (0);
255 }
256
257 static int
258 cpu_attach(device_t dev)
259 {
260 int error;
261 #ifdef notyet
262 device_t clock;
263 #endif
264
265 cpu_hardirq_rman.rm_start = 0;
266 cpu_hardirq_rman.rm_end = 5;
267 cpu_hardirq_rman.rm_type = RMAN_ARRAY;
268 cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
269
270 error = rman_init(&cpu_hardirq_rman);
271 if (error != 0) {
272 device_printf(dev, "failed to initialize irq resources\n");
273 return (error);
274 }
275 /* XXX rman_manage_all. */
276 error = rman_manage_region(&cpu_hardirq_rman,
277 cpu_hardirq_rman.rm_start,
278 cpu_hardirq_rman.rm_end);
279 if (error != 0) {
280 device_printf(dev, "failed to manage irq resources\n");
281 return (error);
282 }
283
284 if (device_get_unit(dev) != 0)
285 panic("can't attach more cpus");
286 device_set_desc(dev, "MIPS32 processor");
287
288 #ifdef notyet
289 clock = device_add_child(dev, "clock", device_get_unit(dev));
290 if (clock == NULL)
291 device_printf(dev, "clock failed to attach");
292 #endif
293
294 return (bus_generic_attach(dev));
295 }
296
297 static struct resource *
298 cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
299 u_long start, u_long end, u_long count, u_int flags)
300 {
301 struct resource *res;
302
303 if (type != SYS_RES_IRQ)
304 return (NULL);
305 res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
306 child);
307 return (res);
308 }
309
310 static int
311 cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
312 driver_filter_t *filt, driver_intr_t *handler, void *arg,
313 void **cookiep)
314 {
315 int error;
316 int intr;
317
318 error = rman_activate_resource(res);
319 if (error != 0) {
320 device_printf(child, "could not activate irq\n");
321 return (error);
322 }
323
324 intr = rman_get_start(res);
325
326 cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg,
327 intr, flags, cookiep);
328 device_printf(child, "established CPU interrupt %d\n", intr);
329 return (0);
330 }
331
332 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);
Cache object: dda36ecf7c0ee0291b27241f3b92bf54
|