]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/mips/cpu.c
Remove spurious newline
[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 static void cpu_identify(void);
65
66 struct mips_cpuinfo cpuinfo;
67
68 #define _ENCODE_INSN(a,b,c,d,e) \
69     ((uint32_t)(((a) << 26)|((b) << 21)|((c) << 16)|((d) << 11)|(e)))
70
71 #if defined(__mips_n64)
72
73 #   define      _LOAD_T0_MDTLS_A1 \
74     _ENCODE_INSN(OP_LD, A1, T0, 0, offsetof(struct thread, td_md.md_tls))
75
76 #   define      _LOAD_T0_MDTLS_TCV_OFFSET_A1 \
77     _ENCODE_INSN(OP_LD, A1, T1, 0, \
78     offsetof(struct thread, td_md.md_tls_tcb_offset))
79
80 #   define      _ADDU_V0_T0_T1 \
81     _ENCODE_INSN(0, T0, T1, V0, OP_DADDU)
82
83 #else /* mips 32 */
84
85 #   define      _LOAD_T0_MDTLS_A1 \
86     _ENCODE_INSN(OP_LW, A1, T0, 0, offsetof(struct thread, td_md.md_tls))
87
88 #   define      _LOAD_T0_MDTLS_TCV_OFFSET_A1 \
89     _ENCODE_INSN(OP_LW, A1, T1, 0, \
90     offsetof(struct thread, td_md.md_tls_tcb_offset))
91
92 #   define      _ADDU_V0_T0_T1 \
93     _ENCODE_INSN(0, T0, T1, V0, OP_ADDU)
94
95 #endif /* ! __mips_n64 */
96
97 #if defined(__mips_n64) || defined(__mips_n32)
98
99 #   define _MTC0_V0_USERLOCAL \
100     _ENCODE_INSN(OP_COP0, OP_DMT, V0, 4, 2)
101
102 #else /* mips o32 */
103
104 #   define _MTC0_V0_USERLOCAL \
105     _ENCODE_INSN(OP_COP0, OP_MT, V0, 4, 2)
106
107 #endif /* ! (__mips_n64 || __mipsn32) */
108
109 #define _JR_RA  _ENCODE_INSN(OP_SPECIAL, RA, 0, 0, OP_JR)
110 #define _NOP    0
111
112 /*
113  * Patch cpu_switch() by removing the UserLocal register code at the end.
114  * For MIPS hardware that don't support UserLocal Register Implementation
115  * we remove the instructions that update this register which may cause a
116  * reserved instruction exception in the kernel.
117  */
118 static void
119 remove_userlocal_code(uint32_t *cpu_switch_code)
120 {
121         uint32_t *instructp;
122
123         for (instructp = cpu_switch_code;; instructp++) {
124                 if (instructp[0] == _JR_RA)
125                         panic("%s: Unable to patch cpu_switch().", __func__);
126                 if (instructp[0] == _LOAD_T0_MDTLS_A1 &&
127                     instructp[1] == _LOAD_T0_MDTLS_TCV_OFFSET_A1 &&
128                     instructp[2] == _ADDU_V0_T0_T1 &&
129                     instructp[3] == _MTC0_V0_USERLOCAL) {
130                         instructp[0] = _JR_RA;
131                         instructp[1] = _NOP;
132                         break;
133                 }
134         }
135 }
136
137 /*
138  * Attempt to identify the MIPS CPU as much as possible.
139  *
140  * XXX: Assumes the CPU is MIPS{32,64}{,r2} compliant.
141  * XXX: For now, skip config register selections 2 and 3
142  * as we don't currently use L2/L3 cache or additional
143  * MIPS32 processor features.
144  */
145 static void
146 mips_get_identity(struct mips_cpuinfo *cpuinfo)
147 {
148         u_int32_t prid;
149         u_int32_t cfg0;
150         u_int32_t cfg1;
151         u_int32_t cfg2;
152         u_int32_t cfg3;
153 #if defined(CPU_CNMIPS)
154         u_int32_t cfg4;
155 #endif
156         u_int32_t tmp;
157
158         memset(cpuinfo, 0, sizeof(struct mips_cpuinfo));
159
160         /* Read and store the PrID ID for CPU identification. */
161         prid = mips_rd_prid();
162         cpuinfo->cpu_vendor = MIPS_PRID_CID(prid);
163         cpuinfo->cpu_rev = MIPS_PRID_REV(prid);
164         cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid);
165
166         /* Read config register selection 0 to learn TLB type. */
167         cfg0 = mips_rd_config();
168
169         cpuinfo->tlb_type = 
170             ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT);
171         cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI;
172
173         /* If config register selection 1 does not exist, return. */
174         if (!(cfg0 & MIPS_CONFIG0_M))
175                 return;
176
177         /* Learn TLB size and L1 cache geometry. */
178         cfg1 = mips_rd_config1();
179
180         /* Get the Config2 and Config3 registers as well. */
181         cfg2 = 0;
182         cfg3 = 0;
183         if (cfg1 & MIPS_CONFIG1_M) {
184                 cfg2 = mips_rd_config2();
185                 if (cfg2 & MIPS_CONFIG2_M)
186                         cfg3 = mips_rd_config3();
187         }
188
189         /* Save FP implementation revision if FP is present. */
190         if (cfg1 & MIPS_CONFIG1_FP)
191                 cpuinfo->fpu_id = MipsFPID();
192
193         /* Check to see if UserLocal register is implemented. */
194         if (cfg3 & MIPS_CONFIG3_ULR) {
195                 /* UserLocal register is implemented, enable it. */
196                 cpuinfo->userlocal_reg = true;
197                 tmp = mips_rd_hwrena();
198                 mips_wr_hwrena(tmp | MIPS_HWRENA_UL);
199         } else {
200                 /*
201                  * UserLocal register is not implemented. Patch
202                  * cpu_switch() and remove unsupported code.
203                  */
204                 cpuinfo->userlocal_reg = false;
205                 remove_userlocal_code((uint32_t *)cpu_switch);
206         }
207
208
209 #if defined(CPU_NLM)
210         /* Account for Extended TLB entries in XLP */
211         tmp = mips_rd_config6();
212         cpuinfo->tlb_nentries = ((tmp >> 16) & 0xffff) + 1;
213 #elif defined(BERI_LARGE_TLB)
214         /* Check if we support extended TLB entries and if so activate. */
215         tmp = mips_rd_config5();
216 #define BERI_CP5_LTLB_SUPPORTED 0x1
217         if (tmp & BERI_CP5_LTLB_SUPPORTED) {
218                 /* See how many extra TLB entries we have. */
219                 tmp = mips_rd_config6();
220                 cpuinfo->tlb_nentries = (tmp >> 16) + 1;
221                 /* Activate the extended entries. */
222                 mips_wr_config6(tmp|0x4);
223         } else
224 #endif
225 #if !defined(CPU_NLM)
226         cpuinfo->tlb_nentries = 
227             ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
228 #endif
229 #if defined(CPU_CNMIPS)
230         /* Add extended TLB size information from config4.  */
231         cfg4 = mips_rd_config4();
232         if ((cfg4 & MIPS_CONFIG4_MMUEXTDEF) == MIPS_CONFIG4_MMUEXTDEF_MMUSIZEEXT)
233                 cpuinfo->tlb_nentries += (cfg4 & MIPS_CONFIG4_MMUSIZEEXT) * 0x40;
234 #endif
235
236         /* L1 instruction cache. */
237 #ifdef MIPS_DISABLE_L1_CACHE
238         cpuinfo->l1.ic_linesize = 0;
239 #else
240         tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT;
241         if (tmp != 0) {
242                 cpuinfo->l1.ic_linesize = 1 << (tmp + 1);
243                 cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
244                 cpuinfo->l1.ic_nsets = 
245                         1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
246         }
247 #endif
248
249         /* L1 data cache. */
250 #ifdef MIPS_DISABLE_L1_CACHE
251         cpuinfo->l1.dc_linesize = 0;
252 #else
253 #ifndef CPU_CNMIPS
254         tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT;
255         if (tmp != 0) {
256                 cpuinfo->l1.dc_linesize = 1 << (tmp + 1);
257                 cpuinfo->l1.dc_nways = 
258                     (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
259                 cpuinfo->l1.dc_nsets = 
260                     1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
261         }
262 #else
263         /*
264          * Some Octeon cache configuration parameters are by model family, not
265          * config1.
266          */
267         if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
268                 /* Octeon and Octeon XL.  */
269                 cpuinfo->l1.dc_nsets = 1;
270                 cpuinfo->l1.dc_nways = 64;
271         } else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
272                 /* Octeon Plus.  */
273                 cpuinfo->l1.dc_nsets = 2;
274                 cpuinfo->l1.dc_nways = 64;
275         } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
276                 /* Octeon II.  */
277                 cpuinfo->l1.dc_nsets = 8;
278                 cpuinfo->l1.dc_nways = 32;
279
280                 cpuinfo->l1.ic_nsets = 8;
281                 cpuinfo->l1.ic_nways = 37;
282         } else {
283                 panic("%s: unsupported Cavium Networks CPU.", __func__);
284         }
285
286         /* All Octeon models use 128 byte line size.  */
287         cpuinfo->l1.dc_linesize = 128;
288 #endif
289 #endif
290
291         cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize
292             * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways;
293         cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize 
294             * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways;
295
296         /*
297          * Probe PageMask register to see what sizes of pages are supported
298          * by writing all one's and then reading it back.
299          */
300         mips_wr_pagemask(~0);
301         cpuinfo->tlb_pgmask = mips_rd_pagemask();
302         mips_wr_pagemask(MIPS3_PGMASK_4K);
303
304 #ifndef CPU_CNMIPS
305         /* L2 cache */
306         if (!(cfg1 & MIPS_CONFIG_CM)) {
307                 /* We don't have valid cfg2 register */
308                 return;
309         }
310
311         cfg2 = mips_rd_config2();
312
313         tmp = (cfg2 >> MIPS_CONFIG2_SL_SHIFT) & MIPS_CONFIG2_SL_MASK;
314         if (0 < tmp && tmp <= 7)
315                 cpuinfo->l2.dc_linesize = 2 << tmp;
316
317         tmp = (cfg2 >> MIPS_CONFIG2_SS_SHIFT) & MIPS_CONFIG2_SS_MASK;
318         if (0 <= tmp && tmp <= 7)
319                 cpuinfo->l2.dc_nsets = 64 << tmp;
320
321         tmp = (cfg2 >> MIPS_CONFIG2_SA_SHIFT) & MIPS_CONFIG2_SA_MASK;
322         if (0 <= tmp && tmp <= 7)
323                 cpuinfo->l2.dc_nways = tmp + 1;
324
325         cpuinfo->l2.dc_size = cpuinfo->l2.dc_linesize
326             * cpuinfo->l2.dc_nsets * cpuinfo->l2.dc_nways;
327 #endif
328 }
329
330 void
331 mips_cpu_init(void)
332 {
333         platform_cpu_init();
334         mips_get_identity(&cpuinfo);
335         num_tlbentries = cpuinfo.tlb_nentries;
336         mips_wr_wired(0);
337         tlb_invalidate_all();
338         mips_wr_wired(VMWIRED_ENTRIES);
339         mips_config_cache(&cpuinfo);
340         mips_vector_init();
341
342         mips_icache_sync_all();
343         mips_dcache_wbinv_all();
344         /* Print some info about CPU */
345         cpu_identify();
346 }
347
348 static void
349 cpu_identify(void)
350 {
351         uint32_t cfg0, cfg1, cfg2, cfg3;
352 #if defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || defined (CPU_MIPS24K)
353         uint32_t cfg7;
354 #endif
355         printf("cpu%d: ", 0);   /* XXX per-cpu */
356         switch (cpuinfo.cpu_vendor) {
357         case MIPS_PRID_CID_MTI:
358                 printf("MIPS Technologies");
359                 break;
360         case MIPS_PRID_CID_BROADCOM:
361         case MIPS_PRID_CID_SIBYTE:
362                 printf("Broadcom");
363                 break;
364         case MIPS_PRID_CID_ALCHEMY:
365                 printf("AMD");
366                 break;
367         case MIPS_PRID_CID_SANDCRAFT:
368                 printf("Sandcraft");
369                 break;
370         case MIPS_PRID_CID_PHILIPS:
371                 printf("Philips");
372                 break;
373         case MIPS_PRID_CID_TOSHIBA:
374                 printf("Toshiba");
375                 break;
376         case MIPS_PRID_CID_LSI:
377                 printf("LSI");
378                 break;
379         case MIPS_PRID_CID_LEXRA:
380                 printf("Lexra");
381                 break;
382         case MIPS_PRID_CID_RMI:
383                 printf("RMI");
384                 break;
385         case MIPS_PRID_CID_CAVIUM:
386                 printf("Cavium");
387                 break;
388         case MIPS_PRID_CID_INGENIC:
389         case MIPS_PRID_CID_INGENIC2:
390                 printf("Ingenic XBurst");
391                 break;
392         case MIPS_PRID_CID_PREHISTORIC:
393         default:
394                 printf("Unknown cid %#x", cpuinfo.cpu_vendor);
395                 break;
396         }
397         printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
398
399         printf("  MMU: ");
400         if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
401                 printf("none present\n");
402         } else {
403                 if (cpuinfo.tlb_type == MIPS_MMU_TLB) {
404                         printf("Standard TLB");
405                 } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) {
406                         printf("Standard BAT");
407                 } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) {
408                         printf("Fixed mapping");
409                 }
410                 printf(", %d entries ", cpuinfo.tlb_nentries);
411         }
412
413         if (cpuinfo.tlb_pgmask) {
414                 printf("(");
415                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_MASKX)
416                         printf("1K ");
417                 printf("4K ");
418                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16K)
419                         printf("16K ");
420                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64K)
421                         printf("64K ");
422                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256K)
423                         printf("256K ");
424                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_1M)
425                         printf("1M ");
426                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16M)
427                         printf("16M ");
428                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64M)
429                         printf("64M ");
430                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256M)
431                         printf("256M ");
432                 printf("pg sizes)");
433         }
434         printf("\n");
435
436         printf("  L1 i-cache: ");
437         if (cpuinfo.l1.ic_linesize == 0) {
438                 printf("disabled");
439         } else {
440                 if (cpuinfo.l1.ic_nways == 1) {
441                         printf("direct-mapped with");
442                 } else {
443                         printf ("%d ways of", cpuinfo.l1.ic_nways);
444                 }
445                 printf(" %d sets, %d bytes per line\n", 
446                     cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
447         }
448
449         printf("  L1 d-cache: ");
450         if (cpuinfo.l1.dc_linesize == 0) {
451                 printf("disabled");
452         } else {
453                 if (cpuinfo.l1.dc_nways == 1) {
454                         printf("direct-mapped with");
455                 } else {
456                         printf ("%d ways of", cpuinfo.l1.dc_nways);
457                 }
458                 printf(" %d sets, %d bytes per line\n", 
459                     cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
460         }
461
462         printf("  L2 cache: ");
463         if (cpuinfo.l2.dc_linesize == 0) {
464                 printf("disabled\n");
465         } else {
466                 printf("%d ways of %d sets, %d bytes per line, "
467                     "%d KiB total size\n",
468                     cpuinfo.l2.dc_nways,
469                     cpuinfo.l2.dc_nsets,
470                     cpuinfo.l2.dc_linesize,
471                     cpuinfo.l2.dc_size / 1024);
472         }
473
474         cfg0 = mips_rd_config();
475         /* If config register selection 1 does not exist, exit. */
476         if (!(cfg0 & MIPS_CONFIG_CM))
477                 return;
478
479         cfg1 = mips_rd_config1();
480         printf("  Config1=0x%b\n", cfg1, 
481             "\20\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU");
482
483         if (cpuinfo.fpu_id != 0)
484                 printf("  FPU ID=0x%b\n", cpuinfo.fpu_id,
485                     "\020"
486                     "\020S"
487                     "\021D"
488                     "\022PS"
489                     "\0233D"
490                     "\024W"
491                     "\025L"
492                     "\026F64"
493                     "\0272008"
494                     "\034UFRP");
495
496         /* If config register selection 2 does not exist, exit. */
497         if (!(cfg1 & MIPS_CONFIG_CM))
498                 return;
499         cfg2 = mips_rd_config2();
500         /* 
501          * Config2 contains no useful information other then Config3 
502          * existence flag
503          */
504         printf("  Config2=0x%08x\n", cfg2);
505
506         /* If config register selection 3 does not exist, exit. */
507         if (!(cfg2 & MIPS_CONFIG_CM))
508                 return;
509         cfg3 = mips_rd_config3();
510
511         /* Print Config3 if it contains any useful info */
512         if (cfg3 & ~(0x80000000))
513                 printf("  Config3=0x%b\n", cfg3, "\20\16ULRI\2SmartMIPS\1TraceLogic");
514
515 #if defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || defined (CPU_MIPS24K)
516         cfg7 = mips_rd_config7();
517         printf("  Config7=0x%b\n", cfg7, "\20\40WII\21AR");
518 #endif
519 }
520
521 static struct rman cpu_hardirq_rman;
522
523 static devclass_t cpu_devclass;
524
525 /*
526  * Device methods
527  */
528 static int cpu_probe(device_t);
529 static int cpu_attach(device_t);
530 static struct resource *cpu_alloc_resource(device_t, device_t, int, int *,
531                                            rman_res_t, rman_res_t, rman_res_t,
532                                            u_int);
533 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
534                           driver_filter_t *f, driver_intr_t *, void *, 
535                           void **);
536
537 static device_method_t cpu_methods[] = {
538         /* Device interface */
539         DEVMETHOD(device_probe,         cpu_probe),
540         DEVMETHOD(device_attach,        cpu_attach),
541         DEVMETHOD(device_detach,        bus_generic_detach),
542         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
543
544         /* Bus interface */
545         DEVMETHOD(bus_alloc_resource,   cpu_alloc_resource),
546         DEVMETHOD(bus_setup_intr,       cpu_setup_intr),
547         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
548
549         { 0, 0 }
550 };
551
552 static driver_t cpu_driver = {
553         "cpu", cpu_methods, 1
554 };
555
556 static int
557 cpu_probe(device_t dev)
558 {
559
560         return (0);
561 }
562
563 static int
564 cpu_attach(device_t dev)
565 {
566         int error;
567 #ifdef notyet
568         device_t clock;
569 #endif
570
571         cpu_hardirq_rman.rm_start = 0;
572         cpu_hardirq_rman.rm_end = 5;
573         cpu_hardirq_rman.rm_type = RMAN_ARRAY;
574         cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
575
576         error = rman_init(&cpu_hardirq_rman);
577         if (error != 0) {
578                 device_printf(dev, "failed to initialize irq resources\n");
579                 return (error);
580         }
581         /* XXX rman_manage_all. */
582         error = rman_manage_region(&cpu_hardirq_rman,
583                                    cpu_hardirq_rman.rm_start,
584                                    cpu_hardirq_rman.rm_end);
585         if (error != 0) {
586                 device_printf(dev, "failed to manage irq resources\n");
587                 return (error);
588         }
589
590         if (device_get_unit(dev) != 0)
591                 panic("can't attach more cpus");
592         device_set_desc(dev, "MIPS32 processor");
593
594 #ifdef notyet
595         clock = device_add_child(dev, "clock", device_get_unit(dev));
596         if (clock == NULL)
597                 device_printf(dev, "clock failed to attach");
598 #endif
599
600         return (bus_generic_attach(dev));
601 }
602
603 static struct resource *
604 cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
605                    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
606 {
607         struct resource *res;
608
609         if (type != SYS_RES_IRQ)
610                 return (NULL);
611         res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
612                                     child);
613         return (res);
614 }
615
616 static int
617 cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
618                driver_filter_t *filt, driver_intr_t *handler, void *arg, 
619                void **cookiep)
620 {
621         int error;
622         int intr;
623
624         error = rman_activate_resource(res);
625         if (error != 0) {
626                 device_printf(child, "could not activate irq\n");
627                 return (error);
628         }
629
630         intr = rman_get_start(res);
631
632         cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg, 
633             intr, flags, cookiep);
634         device_printf(child, "established CPU interrupt %d\n", intr);
635         return (0);
636 }
637
638 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);