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