]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/mips/cpu.c
Update to Zstandard 1.4.5
[FreeBSD/FreeBSD.git] / sys / mips / mips / cpu.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2004 Juli Mallett.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/module.h>
35 #include <sys/proc.h>
36 #include <sys/stdint.h>
37
38 #include <sys/bus.h>
39 #include <sys/rman.h>
40 #include <sys/sysctl.h>
41 #include <sys/systm.h>
42
43 #include <vm/vm.h>
44 #include <vm/vm_page.h>
45
46 #include <machine/cache.h>
47 #include <machine/cpufunc.h>
48 #include <machine/cpuinfo.h>
49 #include <machine/cpuregs.h>
50 #include <machine/intr_machdep.h>
51 #include <machine/locore.h>
52 #include <machine/pte.h>
53 #include <machine/tlb.h>
54 #include <machine/hwfunc.h>
55 #include <machine/mips_opcode.h>
56 #include <machine/regnum.h>
57 #include <machine/tls.h>
58
59 #if defined(CPU_CNMIPS)
60 #include <contrib/octeon-sdk/cvmx.h>
61 #include <contrib/octeon-sdk/octeon-model.h>
62 #endif
63
64 struct mips_cpuinfo cpuinfo;
65
66 #define _ENCODE_INSN(a,b,c,d,e) \
67     ((uint32_t)(((a) << 26)|((b) << 21)|((c) << 16)|((d) << 11)|(e)))
68
69 #define _JR_RA  _ENCODE_INSN(OP_SPECIAL, RA, 0, 0, OP_JR)
70 #define _NOP    0
71
72 /*
73  * Patch cpu_switch() by removing the UserLocal register code at the end.
74  * For MIPS hardware that don't support UserLocal Register Implementation
75  * we remove the instructions that update this register which may cause a
76  * reserved instruction exception in the kernel.
77  */
78 static void
79 remove_userlocal_code(uint32_t *cpu_switch_code)
80 {
81         uint32_t *instructp;
82
83         instructp = cpu_switch_code;
84         instructp[0] = _JR_RA;
85         instructp[1] = _NOP;
86 }
87
88 /*
89  * Attempt to identify the MIPS CPU as much as possible.
90  *
91  * XXX: Assumes the CPU is MIPS{32,64}{,r2} compliant.
92  * XXX: For now, skip config register selections 2 and 3
93  * as we don't currently use L2/L3 cache or additional
94  * MIPS32 processor features.
95  */
96 static void
97 mips_get_identity(struct mips_cpuinfo *cpuinfo)
98 {
99         u_int32_t prid;
100         u_int32_t cfg0;
101         u_int32_t cfg1;
102         u_int32_t cfg2;
103         u_int32_t cfg3;
104 #if defined(CPU_CNMIPS)
105         u_int32_t cfg4;
106 #endif
107         u_int32_t tmp;
108
109         memset(cpuinfo, 0, sizeof(struct mips_cpuinfo));
110
111         /* Read and store the PrID ID for CPU identification. */
112         prid = mips_rd_prid();
113         cpuinfo->cpu_vendor = MIPS_PRID_CID(prid);
114         cpuinfo->cpu_rev = MIPS_PRID_REV(prid);
115         cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid);
116
117         /* Read config register selection 0 to learn TLB type. */
118         cfg0 = mips_rd_config();
119
120         cpuinfo->tlb_type = 
121             ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT);
122         cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI;
123
124         /* If config register selection 1 does not exist, return. */
125         if (!(cfg0 & MIPS_CONFIG0_M))
126                 return;
127
128         /* Learn TLB size and L1 cache geometry. */
129         cfg1 = mips_rd_config1();
130
131         /* Get the Config2 and Config3 registers as well. */
132         cfg2 = 0;
133         cfg3 = 0;
134         if (cfg1 & MIPS_CONFIG1_M) {
135                 cfg2 = mips_rd_config2();
136                 if (cfg2 & MIPS_CONFIG2_M)
137                         cfg3 = mips_rd_config3();
138         }
139
140         /* Save FP implementation revision if FP is present. */
141         if (cfg1 & MIPS_CONFIG1_FP)
142                 cpuinfo->fpu_id = MipsFPID();
143
144         /* Check to see if UserLocal register is implemented. */
145         if (cfg3 & MIPS_CONFIG3_ULR) {
146                 /* UserLocal register is implemented, enable it. */
147                 cpuinfo->userlocal_reg = true;
148                 tmp = mips_rd_hwrena();
149                 mips_wr_hwrena(tmp | MIPS_HWRENA_UL);
150         } else {
151                 /*
152                  * UserLocal register is not implemented. Patch
153                  * cpu_switch() and remove unsupported code.
154                  */
155                 cpuinfo->userlocal_reg = false;
156                 remove_userlocal_code((uint32_t *)cpu_switch_set_userlocal);
157         }
158
159
160 #if defined(CPU_NLM)
161         /* Account for Extended TLB entries in XLP */
162         tmp = mips_rd_config6();
163         cpuinfo->tlb_nentries = ((tmp >> 16) & 0xffff) + 1;
164 #elif defined(BERI_LARGE_TLB)
165         /* Check if we support extended TLB entries and if so activate. */
166         tmp = mips_rd_config5();
167 #define BERI_CP5_LTLB_SUPPORTED 0x1
168         if (tmp & BERI_CP5_LTLB_SUPPORTED) {
169                 /* See how many extra TLB entries we have. */
170                 tmp = mips_rd_config6();
171                 cpuinfo->tlb_nentries = (tmp >> 16) + 1;
172                 /* Activate the extended entries. */
173                 mips_wr_config6(tmp|0x4);
174         } else
175 #endif
176 #if !defined(CPU_NLM)
177         cpuinfo->tlb_nentries = 
178             ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
179 #endif
180 #if defined(CPU_CNMIPS)
181         /* Add extended TLB size information from config4.  */
182         cfg4 = mips_rd_config4();
183         if ((cfg4 & MIPS_CONFIG4_MMUEXTDEF) == MIPS_CONFIG4_MMUEXTDEF_MMUSIZEEXT)
184                 cpuinfo->tlb_nentries += (cfg4 & MIPS_CONFIG4_MMUSIZEEXT) * 0x40;
185 #endif
186
187         /* L1 instruction cache. */
188 #ifdef MIPS_DISABLE_L1_CACHE
189         cpuinfo->l1.ic_linesize = 0;
190 #else
191         tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT;
192         if (tmp != 0) {
193                 cpuinfo->l1.ic_linesize = 1 << (tmp + 1);
194                 cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
195                 cpuinfo->l1.ic_nsets = 
196                         1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
197         }
198 #endif
199
200         /* L1 data cache. */
201 #ifdef MIPS_DISABLE_L1_CACHE
202         cpuinfo->l1.dc_linesize = 0;
203 #else
204 #ifndef CPU_CNMIPS
205         tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT;
206         if (tmp != 0) {
207                 cpuinfo->l1.dc_linesize = 1 << (tmp + 1);
208                 cpuinfo->l1.dc_nways = 
209                     (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
210                 cpuinfo->l1.dc_nsets = 
211                     1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
212         }
213 #else
214         /*
215          * Some Octeon cache configuration parameters are by model family, not
216          * config1.
217          */
218         if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
219                 /* Octeon and Octeon XL.  */
220                 cpuinfo->l1.dc_nsets = 1;
221                 cpuinfo->l1.dc_nways = 64;
222         } else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
223                 /* Octeon Plus.  */
224                 cpuinfo->l1.dc_nsets = 2;
225                 cpuinfo->l1.dc_nways = 64;
226         } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
227                 /* Octeon II.  */
228                 cpuinfo->l1.dc_nsets = 8;
229                 cpuinfo->l1.dc_nways = 32;
230
231                 cpuinfo->l1.ic_nsets = 8;
232                 cpuinfo->l1.ic_nways = 37;
233         } else {
234                 panic("%s: unsupported Cavium Networks CPU.", __func__);
235         }
236
237         /* All Octeon models use 128 byte line size.  */
238         cpuinfo->l1.dc_linesize = 128;
239 #endif
240 #endif
241
242         cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize
243             * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways;
244         cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize 
245             * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways;
246
247         /*
248          * Probe PageMask register to see what sizes of pages are supported
249          * by writing all one's and then reading it back.
250          */
251         mips_wr_pagemask(~0);
252         cpuinfo->tlb_pgmask = mips_rd_pagemask();
253         mips_wr_pagemask(MIPS3_PGMASK_4K);
254
255 #ifndef CPU_CNMIPS
256         /* L2 cache */
257         if (!(cfg1 & MIPS_CONFIG_CM)) {
258                 /* We don't have valid cfg2 register */
259                 return;
260         }
261
262         cfg2 = mips_rd_config2();
263
264         tmp = (cfg2 >> MIPS_CONFIG2_SL_SHIFT) & MIPS_CONFIG2_SL_MASK;
265         if (0 < tmp && tmp <= 7)
266                 cpuinfo->l2.dc_linesize = 2 << tmp;
267
268         tmp = (cfg2 >> MIPS_CONFIG2_SS_SHIFT) & MIPS_CONFIG2_SS_MASK;
269         if (0 <= tmp && tmp <= 7)
270                 cpuinfo->l2.dc_nsets = 64 << tmp;
271
272         tmp = (cfg2 >> MIPS_CONFIG2_SA_SHIFT) & MIPS_CONFIG2_SA_MASK;
273         if (0 <= tmp && tmp <= 7)
274                 cpuinfo->l2.dc_nways = tmp + 1;
275
276         cpuinfo->l2.dc_size = cpuinfo->l2.dc_linesize
277             * cpuinfo->l2.dc_nsets * cpuinfo->l2.dc_nways;
278 #endif
279 }
280
281 void
282 mips_cpu_init(void)
283 {
284         platform_cpu_init();
285         mips_get_identity(&cpuinfo);
286         num_tlbentries = cpuinfo.tlb_nentries;
287         mips_wr_wired(0);
288         tlb_invalidate_all();
289         mips_wr_wired(VMWIRED_ENTRIES);
290         mips_config_cache(&cpuinfo);
291         mips_vector_init();
292
293         mips_icache_sync_all();
294         mips_dcache_wbinv_all();
295 }
296
297 void
298 cpu_identify(void)
299 {
300         uint32_t cfg0, cfg1, cfg2, cfg3;
301 #if defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || defined (CPU_MIPS24K)
302         uint32_t cfg7;
303 #endif
304         printf("CPU: ");
305         switch (cpuinfo.cpu_vendor) {
306         case MIPS_PRID_CID_MTI:
307                 printf("MIPS Technologies");
308                 break;
309         case MIPS_PRID_CID_BROADCOM:
310         case MIPS_PRID_CID_SIBYTE:
311                 printf("Broadcom");
312                 break;
313         case MIPS_PRID_CID_ALCHEMY:
314                 printf("AMD");
315                 break;
316         case MIPS_PRID_CID_SANDCRAFT:
317                 printf("Sandcraft");
318                 break;
319         case MIPS_PRID_CID_PHILIPS:
320                 printf("Philips");
321                 break;
322         case MIPS_PRID_CID_TOSHIBA:
323                 printf("Toshiba");
324                 break;
325         case MIPS_PRID_CID_LSI:
326                 printf("LSI");
327                 break;
328         case MIPS_PRID_CID_LEXRA:
329                 printf("Lexra");
330                 break;
331         case MIPS_PRID_CID_RMI:
332                 printf("RMI");
333                 break;
334         case MIPS_PRID_CID_CAVIUM:
335                 printf("Cavium");
336                 break;
337         case MIPS_PRID_CID_INGENIC:
338         case MIPS_PRID_CID_INGENIC2:
339                 printf("Ingenic XBurst");
340                 break;
341         case MIPS_PRID_CID_PREHISTORIC:
342         default:
343                 printf("Unknown cid %#x", cpuinfo.cpu_vendor);
344                 break;
345         }
346         if (cpu_model[0] != '\0')
347                 printf(" (%s)", cpu_model);
348         printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
349
350         printf("  MMU: ");
351         if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
352                 printf("none present\n");
353         } else {
354                 if (cpuinfo.tlb_type == MIPS_MMU_TLB) {
355                         printf("Standard TLB");
356                 } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) {
357                         printf("Standard BAT");
358                 } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) {
359                         printf("Fixed mapping");
360                 }
361                 printf(", %d entries ", cpuinfo.tlb_nentries);
362         }
363
364         if (cpuinfo.tlb_pgmask) {
365                 printf("(");
366                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_MASKX)
367                         printf("1K ");
368                 printf("4K ");
369                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16K)
370                         printf("16K ");
371                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64K)
372                         printf("64K ");
373                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256K)
374                         printf("256K ");
375                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_1M)
376                         printf("1M ");
377                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16M)
378                         printf("16M ");
379                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64M)
380                         printf("64M ");
381                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256M)
382                         printf("256M ");
383                 printf("pg sizes)");
384         }
385         printf("\n");
386
387         printf("  L1 i-cache: ");
388         if (cpuinfo.l1.ic_linesize == 0) {
389                 printf("disabled");
390         } else {
391                 if (cpuinfo.l1.ic_nways == 1) {
392                         printf("direct-mapped with");
393                 } else {
394                         printf ("%d ways of", cpuinfo.l1.ic_nways);
395                 }
396                 printf(" %d sets, %d bytes per line\n", 
397                     cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
398         }
399
400         printf("  L1 d-cache: ");
401         if (cpuinfo.l1.dc_linesize == 0) {
402                 printf("disabled");
403         } else {
404                 if (cpuinfo.l1.dc_nways == 1) {
405                         printf("direct-mapped with");
406                 } else {
407                         printf ("%d ways of", cpuinfo.l1.dc_nways);
408                 }
409                 printf(" %d sets, %d bytes per line\n", 
410                     cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
411         }
412
413         printf("  L2 cache: ");
414         if (cpuinfo.l2.dc_linesize == 0) {
415                 printf("disabled\n");
416         } else {
417                 printf("%d ways of %d sets, %d bytes per line, "
418                     "%d KiB total size\n",
419                     cpuinfo.l2.dc_nways,
420                     cpuinfo.l2.dc_nsets,
421                     cpuinfo.l2.dc_linesize,
422                     cpuinfo.l2.dc_size / 1024);
423         }
424
425         cfg0 = mips_rd_config();
426         /* If config register selection 1 does not exist, exit. */
427         if (!(cfg0 & MIPS_CONFIG_CM))
428                 return;
429
430         cfg1 = mips_rd_config1();
431         printf("  Config1=0x%b\n", cfg1, 
432             "\20\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU");
433
434         if (cpuinfo.fpu_id != 0)
435                 printf("  FPU ID=0x%b\n", cpuinfo.fpu_id,
436                     "\020"
437                     "\020S"
438                     "\021D"
439                     "\022PS"
440                     "\0233D"
441                     "\024W"
442                     "\025L"
443                     "\026F64"
444                     "\0272008"
445                     "\034UFRP");
446
447         /* If config register selection 2 does not exist, exit. */
448         if (!(cfg1 & MIPS_CONFIG_CM))
449                 return;
450         cfg2 = mips_rd_config2();
451         /* 
452          * Config2 contains no useful information other then Config3 
453          * existence flag
454          */
455         printf("  Config2=0x%08x\n", cfg2);
456
457         /* If config register selection 3 does not exist, exit. */
458         if (!(cfg2 & MIPS_CONFIG_CM))
459                 return;
460         cfg3 = mips_rd_config3();
461
462         /* Print Config3 if it contains any useful info */
463         if (cfg3 & ~(0x80000000))
464                 printf("  Config3=0x%b\n", cfg3, "\20\16ULRI\2SmartMIPS\1TraceLogic");
465
466 #if defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || defined (CPU_MIPS24K)
467         cfg7 = mips_rd_config7();
468         printf("  Config7=0x%b\n", cfg7, "\20\40WII\21AR");
469 #endif
470 }
471
472 static struct rman cpu_hardirq_rman;
473
474 static devclass_t cpu_devclass;
475
476 /*
477  * Device methods
478  */
479 static int cpu_probe(device_t);
480 static int cpu_attach(device_t);
481 static struct resource *cpu_alloc_resource(device_t, device_t, int, int *,
482                                            rman_res_t, rman_res_t, rman_res_t,
483                                            u_int);
484 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
485                           driver_filter_t *f, driver_intr_t *, void *, 
486                           void **);
487
488 static device_method_t cpu_methods[] = {
489         /* Device interface */
490         DEVMETHOD(device_probe,         cpu_probe),
491         DEVMETHOD(device_attach,        cpu_attach),
492         DEVMETHOD(device_detach,        bus_generic_detach),
493         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
494
495         /* Bus interface */
496         DEVMETHOD(bus_alloc_resource,   cpu_alloc_resource),
497         DEVMETHOD(bus_setup_intr,       cpu_setup_intr),
498         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
499
500         { 0, 0 }
501 };
502
503 static driver_t cpu_driver = {
504         "cpu", cpu_methods, 1
505 };
506
507 static int
508 cpu_probe(device_t dev)
509 {
510
511         return (0);
512 }
513
514 static int
515 cpu_attach(device_t dev)
516 {
517         int error;
518 #ifdef notyet
519         device_t clock;
520 #endif
521
522         cpu_hardirq_rman.rm_start = 0;
523         cpu_hardirq_rman.rm_end = 5;
524         cpu_hardirq_rman.rm_type = RMAN_ARRAY;
525         cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
526
527         error = rman_init(&cpu_hardirq_rman);
528         if (error != 0) {
529                 device_printf(dev, "failed to initialize irq resources\n");
530                 return (error);
531         }
532         /* XXX rman_manage_all. */
533         error = rman_manage_region(&cpu_hardirq_rman,
534                                    cpu_hardirq_rman.rm_start,
535                                    cpu_hardirq_rman.rm_end);
536         if (error != 0) {
537                 device_printf(dev, "failed to manage irq resources\n");
538                 return (error);
539         }
540
541         if (device_get_unit(dev) != 0)
542                 panic("can't attach more cpus");
543         device_set_desc(dev, "MIPS32 processor");
544
545 #ifdef notyet
546         clock = device_add_child(dev, "clock", device_get_unit(dev));
547         if (clock == NULL)
548                 device_printf(dev, "clock failed to attach");
549 #endif
550
551         return (bus_generic_attach(dev));
552 }
553
554 static struct resource *
555 cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
556                    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
557 {
558         struct resource *res;
559
560         if (type != SYS_RES_IRQ)
561                 return (NULL);
562         res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
563                                     child);
564         return (res);
565 }
566
567 static int
568 cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
569                driver_filter_t *filt, driver_intr_t *handler, void *arg, 
570                void **cookiep)
571 {
572         int error;
573         int intr;
574
575         error = rman_activate_resource(res);
576         if (error != 0) {
577                 device_printf(child, "could not activate irq\n");
578                 return (error);
579         }
580
581         intr = rman_get_start(res);
582
583         cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg, 
584             intr, flags, cookiep);
585         device_printf(child, "established CPU interrupt %d\n", intr);
586         return (0);
587 }
588
589 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);