]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/mips/mips/cpu.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / 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$");
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);