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