]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/mips/mips/cpu.c
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.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 #include <machine/tlb.h>
51 #include <machine/hwfunc.h>
52
53 #if defined(CPU_CNMIPS)
54 #include <contrib/octeon-sdk/cvmx.h>
55 #include <contrib/octeon-sdk/octeon-model.h>
56 #endif
57
58 static void cpu_identify(void);
59
60 struct mips_cpuinfo cpuinfo;
61
62 /*
63  * Attempt to identify the MIPS CPU as much as possible.
64  *
65  * XXX: Assumes the CPU is MIPS{32,64}{,r2} compliant.
66  * XXX: For now, skip config register selections 2 and 3
67  * as we don't currently use L2/L3 cache or additional
68  * MIPS32 processor features.
69  */
70 static void
71 mips_get_identity(struct mips_cpuinfo *cpuinfo)
72 {
73         u_int32_t prid;
74         u_int32_t cfg0;
75         u_int32_t cfg1;
76 #if defined(CPU_CNMIPS)
77         u_int32_t cfg4;
78 #endif
79         u_int32_t tmp;
80
81         memset(cpuinfo, 0, sizeof(struct mips_cpuinfo));
82
83         /* Read and store the PrID ID for CPU identification. */
84         prid = mips_rd_prid();
85         cpuinfo->cpu_vendor = MIPS_PRID_CID(prid);
86         cpuinfo->cpu_rev = MIPS_PRID_REV(prid);
87         cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid);
88
89         /* Read config register selection 0 to learn TLB type. */
90         cfg0 = mips_rd_config();
91
92         cpuinfo->tlb_type = 
93             ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT);
94         cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI;
95
96         /* If config register selection 1 does not exist, exit. */
97         if (!(cfg0 & MIPS_CONFIG_CM))
98                 return;
99
100         /* Learn TLB size and L1 cache geometry. */
101         cfg1 = mips_rd_config1();
102 #ifndef CPU_NLM
103         cpuinfo->tlb_nentries = 
104             ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
105 #else
106         /* Account for Extended TLB entries in XLP */
107         tmp = mips_rd_config6();
108         cpuinfo->tlb_nentries = ((tmp >> 16) & 0xffff) + 1;
109 #endif
110
111         /* Add extended TLB size information from config4.  */
112 #if defined(CPU_CNMIPS)
113         cfg4 = mips_rd_config4();
114         if ((cfg4 & MIPS_CONFIG4_MMUEXTDEF) == MIPS_CONFIG4_MMUEXTDEF_MMUSIZEEXT)
115                 cpuinfo->tlb_nentries += (cfg4 & MIPS_CONFIG4_MMUSIZEEXT) * 0x40;
116 #endif
117
118         /* L1 instruction cache. */
119         tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT;
120         if (tmp != 0) {
121                 cpuinfo->l1.ic_linesize = 1 << (tmp + 1);
122                 cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
123                 cpuinfo->l1.ic_nsets = 
124                         1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
125         }
126
127 #ifndef CPU_CNMIPS
128         /* L1 data cache. */
129         tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT;
130         if (tmp != 0) {
131                 cpuinfo->l1.dc_linesize = 1 << (tmp + 1);
132                 cpuinfo->l1.dc_nways = 
133                     (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
134                 cpuinfo->l1.dc_nsets = 
135                     1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
136         }
137 #else
138         /*
139          * Some Octeon cache configuration parameters are by model family, not
140          * config1.
141          */
142         if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
143                 /* Octeon and Octeon XL.  */
144                 cpuinfo->l1.dc_nsets = 1;
145                 cpuinfo->l1.dc_nways = 64;
146         } else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
147                 /* Octeon Plus.  */
148                 cpuinfo->l1.dc_nsets = 2;
149                 cpuinfo->l1.dc_nways = 64;
150         } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
151                 /* Octeon II.  */
152                 cpuinfo->l1.dc_nsets = 8;
153                 cpuinfo->l1.dc_nways = 32;
154
155                 cpuinfo->l1.ic_nsets = 8;
156                 cpuinfo->l1.ic_nways = 37;
157         } else {
158                 panic("%s: unsupported Cavium Networks CPU.", __func__);
159         }
160
161         /* All Octeon models use 128 byte line size.  */
162         cpuinfo->l1.dc_linesize = 128;
163 #endif
164
165         cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize
166             * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways;
167         cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize 
168             * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways;
169 }
170
171 void
172 mips_cpu_init(void)
173 {
174         platform_cpu_init();
175         mips_get_identity(&cpuinfo);
176         num_tlbentries = cpuinfo.tlb_nentries;
177         mips_wr_wired(0);
178         tlb_invalidate_all();
179         mips_wr_wired(VMWIRED_ENTRIES);
180         mips_config_cache(&cpuinfo);
181         mips_vector_init();
182
183         mips_icache_sync_all();
184         mips_dcache_wbinv_all();
185         /* Print some info about CPU */
186         cpu_identify();
187 }
188
189 static void
190 cpu_identify(void)
191 {
192         uint32_t cfg0, cfg1, cfg2, cfg3;
193         printf("cpu%d: ", 0);   /* XXX per-cpu */
194         switch (cpuinfo.cpu_vendor) {
195         case MIPS_PRID_CID_MTI:
196                 printf("MIPS Technologies");
197                 break;
198         case MIPS_PRID_CID_BROADCOM:
199         case MIPS_PRID_CID_SIBYTE:
200                 printf("Broadcom");
201                 break;
202         case MIPS_PRID_CID_ALCHEMY:
203                 printf("AMD");
204                 break;
205         case MIPS_PRID_CID_SANDCRAFT:
206                 printf("Sandcraft");
207                 break;
208         case MIPS_PRID_CID_PHILIPS:
209                 printf("Philips");
210                 break;
211         case MIPS_PRID_CID_TOSHIBA:
212                 printf("Toshiba");
213                 break;
214         case MIPS_PRID_CID_LSI:
215                 printf("LSI");
216                 break;
217         case MIPS_PRID_CID_LEXRA:
218                 printf("Lexra");
219                 break;
220         case MIPS_PRID_CID_RMI:
221                 printf("RMI");
222                 break;
223         case MIPS_PRID_CID_CAVIUM:
224                 printf("Cavium");
225                 break;
226         case MIPS_PRID_CID_PREHISTORIC:
227         default:
228                 printf("Unknown cid %#x", cpuinfo.cpu_vendor);
229                 break;
230         }
231         printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
232
233         printf("  MMU: ");
234         if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
235                 printf("none present\n");
236         } else {
237                 if (cpuinfo.tlb_type == MIPS_MMU_TLB) {
238                         printf("Standard TLB");
239                 } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) {
240                         printf("Standard BAT");
241                 } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) {
242                         printf("Fixed mapping");
243                 }
244                 printf(", %d entries\n", cpuinfo.tlb_nentries);
245         }
246
247         printf("  L1 i-cache: ");
248         if (cpuinfo.l1.ic_linesize == 0) {
249                 printf("disabled");
250         } else {
251                 if (cpuinfo.l1.ic_nways == 1) {
252                         printf("direct-mapped with");
253                 } else {
254                         printf ("%d ways of", cpuinfo.l1.ic_nways);
255                 }
256                 printf(" %d sets, %d bytes per line\n", 
257                     cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
258         }
259
260         printf("  L1 d-cache: ");
261         if (cpuinfo.l1.dc_linesize == 0) {
262                 printf("disabled");
263         } else {
264                 if (cpuinfo.l1.dc_nways == 1) {
265                         printf("direct-mapped with");
266                 } else {
267                         printf ("%d ways of", cpuinfo.l1.dc_nways);
268                 }
269                 printf(" %d sets, %d bytes per line\n", 
270                     cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
271         }
272
273         cfg0 = mips_rd_config();
274         /* If config register selection 1 does not exist, exit. */
275         if (!(cfg0 & MIPS_CONFIG_CM))
276                 return;
277
278         cfg1 = mips_rd_config1();
279         printf("  Config1=0x%b\n", cfg1, 
280             "\20\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU");
281
282         /* If config register selection 2 does not exist, exit. */
283         if (!(cfg1 & MIPS_CONFIG_CM))
284                 return;
285         cfg2 = mips_rd_config2();
286         /* 
287          * Config2 contains no useful information other then Config3 
288          * existence flag
289          */
290
291         /* If config register selection 3 does not exist, exit. */
292         if (!(cfg2 & MIPS_CONFIG_CM))
293                 return;
294         cfg3 = mips_rd_config3();
295
296         /* Print Config3 if it contains any useful info */
297         if (cfg3 & ~(0x80000000))
298                 printf("  Config3=0x%b\n", cfg3, "\20\2SmartMIPS\1TraceLogic");
299 }
300
301 static struct rman cpu_hardirq_rman;
302
303 static devclass_t cpu_devclass;
304
305 /*
306  * Device methods
307  */
308 static int cpu_probe(device_t);
309 static int cpu_attach(device_t);
310 static struct resource *cpu_alloc_resource(device_t, device_t, int, int *,
311                                            u_long, u_long, u_long, u_int);
312 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
313                           driver_filter_t *f, driver_intr_t *, void *, 
314                           void **);
315
316 static device_method_t cpu_methods[] = {
317         /* Device interface */
318         DEVMETHOD(device_probe,         cpu_probe),
319         DEVMETHOD(device_attach,        cpu_attach),
320         DEVMETHOD(device_detach,        bus_generic_detach),
321         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
322
323         /* Bus interface */
324         DEVMETHOD(bus_alloc_resource,   cpu_alloc_resource),
325         DEVMETHOD(bus_setup_intr,       cpu_setup_intr),
326         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
327
328         { 0, 0 }
329 };
330
331 static driver_t cpu_driver = {
332         "cpu", cpu_methods, 1
333 };
334
335 static int
336 cpu_probe(device_t dev)
337 {
338         return (0);
339 }
340
341 static int
342 cpu_attach(device_t dev)
343 {
344         int error;
345 #ifdef notyet
346         device_t clock;
347 #endif
348
349         cpu_hardirq_rman.rm_start = 0;
350         cpu_hardirq_rman.rm_end = 5;
351         cpu_hardirq_rman.rm_type = RMAN_ARRAY;
352         cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
353
354         error = rman_init(&cpu_hardirq_rman);
355         if (error != 0) {
356                 device_printf(dev, "failed to initialize irq resources\n");
357                 return (error);
358         }
359         /* XXX rman_manage_all. */
360         error = rman_manage_region(&cpu_hardirq_rman,
361                                    cpu_hardirq_rman.rm_start,
362                                    cpu_hardirq_rman.rm_end);
363         if (error != 0) {
364                 device_printf(dev, "failed to manage irq resources\n");
365                 return (error);
366         }
367
368         if (device_get_unit(dev) != 0)
369                 panic("can't attach more cpus");
370         device_set_desc(dev, "MIPS32 processor");
371
372 #ifdef notyet
373         clock = device_add_child(dev, "clock", device_get_unit(dev));
374         if (clock == NULL)
375                 device_printf(dev, "clock failed to attach");
376 #endif
377
378         return (bus_generic_attach(dev));
379 }
380
381 static struct resource *
382 cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
383                    u_long start, u_long end, u_long count, u_int flags)
384 {
385         struct resource *res;
386
387         if (type != SYS_RES_IRQ)
388                 return (NULL);
389         res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
390                                     child);
391         return (res);
392 }
393
394 static int
395 cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
396                driver_filter_t *filt, driver_intr_t *handler, void *arg, 
397                void **cookiep)
398 {
399         int error;
400         int intr;
401
402         error = rman_activate_resource(res);
403         if (error != 0) {
404                 device_printf(child, "could not activate irq\n");
405                 return (error);
406         }
407
408         intr = rman_get_start(res);
409
410         cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg, 
411             intr, flags, cookiep);
412         device_printf(child, "established CPU interrupt %d\n", intr);
413         return (0);
414 }
415
416 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);