2 * Copyright (c) 2004 Juli Mallett. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/module.h>
34 #include <sys/stdint.h>
38 #include <sys/sysctl.h>
39 #include <sys/systm.h>
42 #include <vm/vm_page.h>
44 #include <machine/cache.h>
45 #include <machine/cpufunc.h>
46 #include <machine/cpuinfo.h>
47 #include <machine/cpuregs.h>
48 #include <machine/intr_machdep.h>
49 #include <machine/locore.h>
50 #include <machine/pte.h>
51 #include <machine/tlb.h>
52 #include <machine/hwfunc.h>
53 #include <machine/mips_opcode.h>
54 #include <machine/regnum.h>
55 #include <machine/tls.h>
57 #if defined(CPU_CNMIPS)
58 #include <contrib/octeon-sdk/cvmx.h>
59 #include <contrib/octeon-sdk/octeon-model.h>
62 static void cpu_identify(void);
64 struct mips_cpuinfo cpuinfo;
66 #define _ENCODE_INSN(a,b,c,d,e) \
67 ((uint32_t)(((a) << 26)|((b) << 21)|((c) << 16)|((d) << 11)|(e)))
69 #if defined(__mips_n64)
71 # define _LOAD_T0_MDTLS_A1 \
72 _ENCODE_INSN(OP_LD, A1, T0, 0, offsetof(struct thread, td_md.md_tls))
74 # define _LOAD_T0_MDTLS_TCV_OFFSET_A1 \
75 _ENCODE_INSN(OP_LD, A1, T1, 0, \
76 offsetof(struct thread, td_md.md_tls_tcb_offset))
78 # define _ADDU_V0_T0_T1 \
79 _ENCODE_INSN(0, T0, T1, V0, OP_DADDU)
83 # define _LOAD_T0_MDTLS_A1 \
84 _ENCODE_INSN(OP_LW, A1, T0, 0, offsetof(struct thread, td_md.md_tls))
86 # define _LOAD_T0_MDTLS_TCV_OFFSET_A1 \
87 _ENCODE_INSN(OP_LW, A1, T1, 0, \
88 offsetof(struct thread, td_md.md_tls_tcb_offset))
90 # define _ADDU_V0_T0_T1 \
91 _ENCODE_INSN(0, T0, T1, V0, OP_ADDU)
93 #endif /* ! __mips_n64 */
95 #if defined(__mips_n64) || defined(__mips_n32)
97 # define _MTC0_V0_USERLOCAL \
98 _ENCODE_INSN(OP_COP0, OP_DMT, V0, 4, 2)
102 # define _MTC0_V0_USERLOCAL \
103 _ENCODE_INSN(OP_COP0, OP_MT, V0, 4, 2)
105 #endif /* ! (__mips_n64 || __mipsn32) */
107 #define _JR_RA _ENCODE_INSN(OP_SPECIAL, RA, 0, 0, OP_JR)
111 * Patch cpu_switch() by removing the UserLocal register code at the end.
112 * For MIPS hardware that don't support UserLocal Register Implementation
113 * we remove the instructions that update this register which may cause a
114 * reserved instruction exception in the kernel.
117 remove_userlocal_code(uint32_t *cpu_switch_code)
121 for (instructp = cpu_switch_code;; instructp++) {
122 if (instructp[0] == _JR_RA)
123 panic("%s: Unable to patch cpu_switch().", __func__);
124 if (instructp[0] == _LOAD_T0_MDTLS_A1 &&
125 instructp[1] == _LOAD_T0_MDTLS_TCV_OFFSET_A1 &&
126 instructp[2] == _ADDU_V0_T0_T1 &&
127 instructp[3] == _MTC0_V0_USERLOCAL) {
128 instructp[0] = _JR_RA;
136 * Attempt to identify the MIPS CPU as much as possible.
138 * XXX: Assumes the CPU is MIPS{32,64}{,r2} compliant.
139 * XXX: For now, skip config register selections 2 and 3
140 * as we don't currently use L2/L3 cache or additional
141 * MIPS32 processor features.
144 mips_get_identity(struct mips_cpuinfo *cpuinfo)
151 #if defined(CPU_CNMIPS)
156 memset(cpuinfo, 0, sizeof(struct mips_cpuinfo));
158 /* Read and store the PrID ID for CPU identification. */
159 prid = mips_rd_prid();
160 cpuinfo->cpu_vendor = MIPS_PRID_CID(prid);
161 cpuinfo->cpu_rev = MIPS_PRID_REV(prid);
162 cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid);
164 /* Read config register selection 0 to learn TLB type. */
165 cfg0 = mips_rd_config();
168 ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT);
169 cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI;
171 /* If config register selection 1 does not exist, return. */
172 if (!(cfg0 & MIPS_CONFIG0_M))
175 /* Learn TLB size and L1 cache geometry. */
176 cfg1 = mips_rd_config1();
178 /* Get the Config2 and Config3 registers as well. */
181 if (cfg1 & MIPS_CONFIG1_M) {
182 cfg2 = mips_rd_config2();
183 if (cfg2 & MIPS_CONFIG2_M)
184 cfg3 = mips_rd_config3();
187 /* Check to see if UserLocal register is implemented. */
188 if (cfg3 & MIPS_CONFIG3_ULR) {
189 /* UserLocal register is implemented, enable it. */
190 cpuinfo->userlocal_reg = true;
191 tmp = mips_rd_hwrena();
192 mips_wr_hwrena(tmp | MIPS_HWRENA_UL);
195 * UserLocal register is not implemented. Patch
196 * cpu_switch() and remove unsupported code.
198 cpuinfo->userlocal_reg = false;
199 remove_userlocal_code((uint32_t *)cpu_switch);
204 /* Account for Extended TLB entries in XLP */
205 tmp = mips_rd_config6();
206 cpuinfo->tlb_nentries = ((tmp >> 16) & 0xffff) + 1;
207 #elif defined(BERI_LARGE_TLB)
208 /* Check if we support extended TLB entries and if so activate. */
209 tmp = mips_rd_config5();
210 #define BERI_CP5_LTLB_SUPPORTED 0x1
211 if (tmp & BERI_CP5_LTLB_SUPPORTED) {
212 /* See how many extra TLB entries we have. */
213 tmp = mips_rd_config6();
214 cpuinfo->tlb_nentries = (tmp >> 16) + 1;
215 /* Activate the extended entries. */
216 mips_wr_config6(tmp|0x4);
219 #if !defined(CPU_NLM)
220 cpuinfo->tlb_nentries =
221 ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
223 #if defined(CPU_CNMIPS)
224 /* Add extended TLB size information from config4. */
225 cfg4 = mips_rd_config4();
226 if ((cfg4 & MIPS_CONFIG4_MMUEXTDEF) == MIPS_CONFIG4_MMUEXTDEF_MMUSIZEEXT)
227 cpuinfo->tlb_nentries += (cfg4 & MIPS_CONFIG4_MMUSIZEEXT) * 0x40;
230 /* L1 instruction cache. */
231 #ifdef MIPS_DISABLE_L1_CACHE
232 cpuinfo->l1.ic_linesize = 0;
234 tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT;
236 cpuinfo->l1.ic_linesize = 1 << (tmp + 1);
237 cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
238 cpuinfo->l1.ic_nsets =
239 1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
244 #ifdef MIPS_DISABLE_L1_CACHE
245 cpuinfo->l1.dc_linesize = 0;
248 tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT;
250 cpuinfo->l1.dc_linesize = 1 << (tmp + 1);
251 cpuinfo->l1.dc_nways =
252 (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
253 cpuinfo->l1.dc_nsets =
254 1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
258 * Some Octeon cache configuration parameters are by model family, not
261 if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
262 /* Octeon and Octeon XL. */
263 cpuinfo->l1.dc_nsets = 1;
264 cpuinfo->l1.dc_nways = 64;
265 } else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
267 cpuinfo->l1.dc_nsets = 2;
268 cpuinfo->l1.dc_nways = 64;
269 } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
271 cpuinfo->l1.dc_nsets = 8;
272 cpuinfo->l1.dc_nways = 32;
274 cpuinfo->l1.ic_nsets = 8;
275 cpuinfo->l1.ic_nways = 37;
277 panic("%s: unsupported Cavium Networks CPU.", __func__);
280 /* All Octeon models use 128 byte line size. */
281 cpuinfo->l1.dc_linesize = 128;
285 cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize
286 * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways;
287 cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize
288 * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways;
291 * Probe PageMask register to see what sizes of pages are supported
292 * by writing all one's and then reading it back.
294 mips_wr_pagemask(~0);
295 cpuinfo->tlb_pgmask = mips_rd_pagemask();
296 mips_wr_pagemask(MIPS3_PGMASK_4K);
300 if (!(cfg1 & MIPS_CONFIG_CM)) {
301 /* We don't have valid cfg2 register */
305 cfg2 = mips_rd_config2();
307 tmp = (cfg2 >> MIPS_CONFIG2_SL_SHIFT) & MIPS_CONFIG2_SL_MASK;
308 if (0 < tmp && tmp <= 7)
309 cpuinfo->l2.dc_linesize = 2 << tmp;
311 tmp = (cfg2 >> MIPS_CONFIG2_SS_SHIFT) & MIPS_CONFIG2_SS_MASK;
312 if (0 <= tmp && tmp <= 7)
313 cpuinfo->l2.dc_nsets = 64 << tmp;
315 tmp = (cfg2 >> MIPS_CONFIG2_SA_SHIFT) & MIPS_CONFIG2_SA_MASK;
316 if (0 <= tmp && tmp <= 7)
317 cpuinfo->l2.dc_nways = tmp + 1;
319 cpuinfo->l2.dc_size = cpuinfo->l2.dc_linesize
320 * cpuinfo->l2.dc_nsets * cpuinfo->l2.dc_nways;
328 mips_get_identity(&cpuinfo);
329 num_tlbentries = cpuinfo.tlb_nentries;
331 tlb_invalidate_all();
332 mips_wr_wired(VMWIRED_ENTRIES);
333 mips_config_cache(&cpuinfo);
336 mips_icache_sync_all();
337 mips_dcache_wbinv_all();
338 /* Print some info about CPU */
345 uint32_t cfg0, cfg1, cfg2, cfg3;
346 #if defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || defined (CPU_MIPS24K)
349 printf("cpu%d: ", 0); /* XXX per-cpu */
350 switch (cpuinfo.cpu_vendor) {
351 case MIPS_PRID_CID_MTI:
352 printf("MIPS Technologies");
354 case MIPS_PRID_CID_BROADCOM:
355 case MIPS_PRID_CID_SIBYTE:
358 case MIPS_PRID_CID_ALCHEMY:
361 case MIPS_PRID_CID_SANDCRAFT:
364 case MIPS_PRID_CID_PHILIPS:
367 case MIPS_PRID_CID_TOSHIBA:
370 case MIPS_PRID_CID_LSI:
373 case MIPS_PRID_CID_LEXRA:
376 case MIPS_PRID_CID_RMI:
379 case MIPS_PRID_CID_CAVIUM:
382 case MIPS_PRID_CID_INGENIC:
383 case MIPS_PRID_CID_INGENIC2:
384 printf("Ingenic XBurst");
386 case MIPS_PRID_CID_PREHISTORIC:
388 printf("Unknown cid %#x", cpuinfo.cpu_vendor);
391 printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
394 if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
395 printf("none present\n");
397 if (cpuinfo.tlb_type == MIPS_MMU_TLB) {
398 printf("Standard TLB");
399 } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) {
400 printf("Standard BAT");
401 } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) {
402 printf("Fixed mapping");
404 printf(", %d entries ", cpuinfo.tlb_nentries);
407 if (cpuinfo.tlb_pgmask) {
409 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_MASKX)
412 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16K)
414 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64K)
416 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256K)
418 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_1M)
420 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16M)
422 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64M)
424 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256M)
430 printf(" L1 i-cache: ");
431 if (cpuinfo.l1.ic_linesize == 0) {
434 if (cpuinfo.l1.ic_nways == 1) {
435 printf("direct-mapped with");
437 printf ("%d ways of", cpuinfo.l1.ic_nways);
439 printf(" %d sets, %d bytes per line\n",
440 cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
443 printf(" L1 d-cache: ");
444 if (cpuinfo.l1.dc_linesize == 0) {
447 if (cpuinfo.l1.dc_nways == 1) {
448 printf("direct-mapped with");
450 printf ("%d ways of", cpuinfo.l1.dc_nways);
452 printf(" %d sets, %d bytes per line\n",
453 cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
456 printf(" L2 cache: ");
457 if (cpuinfo.l2.dc_linesize == 0) {
458 printf("disabled\n");
460 printf("%d ways of %d sets, %d bytes per line, "
461 "%d KiB total size\n",
464 cpuinfo.l2.dc_linesize,
465 cpuinfo.l2.dc_size / 1024);
468 cfg0 = mips_rd_config();
469 /* If config register selection 1 does not exist, exit. */
470 if (!(cfg0 & MIPS_CONFIG_CM))
473 cfg1 = mips_rd_config1();
474 printf(" Config1=0x%b\n", cfg1,
475 "\20\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU");
477 /* If config register selection 2 does not exist, exit. */
478 if (!(cfg1 & MIPS_CONFIG_CM))
480 cfg2 = mips_rd_config2();
482 * Config2 contains no useful information other then Config3
485 printf(" Config2=0x%08x\n", cfg2);
487 /* If config register selection 3 does not exist, exit. */
488 if (!(cfg2 & MIPS_CONFIG_CM))
490 cfg3 = mips_rd_config3();
492 /* Print Config3 if it contains any useful info */
493 if (cfg3 & ~(0x80000000))
494 printf(" Config3=0x%b\n", cfg3, "\20\16ULRI\2SmartMIPS\1TraceLogic");
496 #if defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || defined (CPU_MIPS24K)
497 cfg7 = mips_rd_config7();
498 printf(" Config7=0x%b\n", cfg7, "\20\40WII\21AR");
502 static struct rman cpu_hardirq_rman;
504 static devclass_t cpu_devclass;
509 static int cpu_probe(device_t);
510 static int cpu_attach(device_t);
511 static struct resource *cpu_alloc_resource(device_t, device_t, int, int *,
512 rman_res_t, rman_res_t, rman_res_t,
514 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
515 driver_filter_t *f, driver_intr_t *, void *,
518 static device_method_t cpu_methods[] = {
519 /* Device interface */
520 DEVMETHOD(device_probe, cpu_probe),
521 DEVMETHOD(device_attach, cpu_attach),
522 DEVMETHOD(device_detach, bus_generic_detach),
523 DEVMETHOD(device_shutdown, bus_generic_shutdown),
526 DEVMETHOD(bus_alloc_resource, cpu_alloc_resource),
527 DEVMETHOD(bus_setup_intr, cpu_setup_intr),
528 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
533 static driver_t cpu_driver = {
534 "cpu", cpu_methods, 1
538 cpu_probe(device_t dev)
545 cpu_attach(device_t dev)
552 cpu_hardirq_rman.rm_start = 0;
553 cpu_hardirq_rman.rm_end = 5;
554 cpu_hardirq_rman.rm_type = RMAN_ARRAY;
555 cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
557 error = rman_init(&cpu_hardirq_rman);
559 device_printf(dev, "failed to initialize irq resources\n");
562 /* XXX rman_manage_all. */
563 error = rman_manage_region(&cpu_hardirq_rman,
564 cpu_hardirq_rman.rm_start,
565 cpu_hardirq_rman.rm_end);
567 device_printf(dev, "failed to manage irq resources\n");
571 if (device_get_unit(dev) != 0)
572 panic("can't attach more cpus");
573 device_set_desc(dev, "MIPS32 processor");
576 clock = device_add_child(dev, "clock", device_get_unit(dev));
578 device_printf(dev, "clock failed to attach");
581 return (bus_generic_attach(dev));
584 static struct resource *
585 cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
586 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
588 struct resource *res;
590 if (type != SYS_RES_IRQ)
592 res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
598 cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
599 driver_filter_t *filt, driver_intr_t *handler, void *arg,
605 error = rman_activate_resource(res);
607 device_printf(child, "could not activate irq\n");
611 intr = rman_get_start(res);
613 cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg,
614 intr, flags, cookiep);
615 device_printf(child, "established CPU interrupt %d\n", intr);
619 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);