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