]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/mips/cpu.c
Update our device tree files to a Linux 4.10
[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/proc.h>
34 #include <sys/stdint.h>
35
36 #include <sys/bus.h>
37 #include <sys/rman.h>
38 #include <sys/sysctl.h>
39 #include <sys/systm.h>
40
41 #include <vm/vm.h>
42 #include <vm/vm_page.h>
43
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>
56
57 #if defined(CPU_CNMIPS)
58 #include <contrib/octeon-sdk/cvmx.h>
59 #include <contrib/octeon-sdk/octeon-model.h>
60 #endif
61
62 static void cpu_identify(void);
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 #if defined(__mips_n64)
70
71 #   define      _LOAD_T0_MDTLS_A1 \
72     _ENCODE_INSN(OP_LD, A1, T0, 0, offsetof(struct thread, td_md.md_tls))
73
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))
77
78 #   define      _ADDU_V0_T0_T1 \
79     _ENCODE_INSN(0, T0, T1, V0, OP_DADDU)
80
81 #else /* mips 32 */
82
83 #   define      _LOAD_T0_MDTLS_A1 \
84     _ENCODE_INSN(OP_LW, A1, T0, 0, offsetof(struct thread, td_md.md_tls))
85
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))
89
90 #   define      _ADDU_V0_T0_T1 \
91     _ENCODE_INSN(0, T0, T1, V0, OP_ADDU)
92
93 #endif /* ! __mips_n64 */
94
95 #if defined(__mips_n64) || defined(__mips_n32)
96
97 #   define _MTC0_V0_USERLOCAL \
98     _ENCODE_INSN(OP_COP0, OP_DMT, V0, 4, 2)
99
100 #else /* mips o32 */
101
102 #   define _MTC0_V0_USERLOCAL \
103     _ENCODE_INSN(OP_COP0, OP_MT, V0, 4, 2)
104
105 #endif /* ! (__mips_n64 || __mipsn32) */
106
107 #define _JR_RA  _ENCODE_INSN(OP_SPECIAL, RA, 0, 0, OP_JR)
108 #define _NOP    0
109
110 /*
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.
115  */
116 static void
117 remove_userlocal_code(uint32_t *cpu_switch_code)
118 {
119         uint32_t *instructp;
120
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;
129                         instructp[1] = _NOP;
130                         break;
131                 }
132         }
133 }
134
135 /*
136  * Attempt to identify the MIPS CPU as much as possible.
137  *
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.
142  */
143 static void
144 mips_get_identity(struct mips_cpuinfo *cpuinfo)
145 {
146         u_int32_t prid;
147         u_int32_t cfg0;
148         u_int32_t cfg1;
149         u_int32_t cfg2;
150         u_int32_t cfg3;
151 #if defined(CPU_CNMIPS)
152         u_int32_t cfg4;
153 #endif
154         u_int32_t tmp;
155
156         memset(cpuinfo, 0, sizeof(struct mips_cpuinfo));
157
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);
163
164         /* Read config register selection 0 to learn TLB type. */
165         cfg0 = mips_rd_config();
166
167         cpuinfo->tlb_type = 
168             ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT);
169         cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI;
170
171         /* If config register selection 1 does not exist, return. */
172         if (!(cfg0 & MIPS_CONFIG0_M))
173                 return;
174
175         /* Learn TLB size and L1 cache geometry. */
176         cfg1 = mips_rd_config1();
177
178         /* Get the Config2 and Config3 registers as well. */
179         cfg2 = 0;
180         cfg3 = 0;
181         if (cfg1 & MIPS_CONFIG1_M) {
182                 cfg2 = mips_rd_config2();
183                 if (cfg2 & MIPS_CONFIG2_M)
184                         cfg3 = mips_rd_config3();
185         }
186
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);
193         } else {
194                 /*
195                  * UserLocal register is not implemented. Patch
196                  * cpu_switch() and remove unsupported code.
197                  */
198                 cpuinfo->userlocal_reg = false;
199                 remove_userlocal_code((uint32_t *)cpu_switch);
200         }
201
202
203 #if defined(CPU_NLM)
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);
217         } else
218 #endif
219 #if !defined(CPU_NLM)
220         cpuinfo->tlb_nentries = 
221             ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
222 #endif
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;
228 #endif
229
230         /* L1 instruction cache. */
231 #ifdef MIPS_DISABLE_L1_CACHE
232         cpuinfo->l1.ic_linesize = 0;
233 #else
234         tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT;
235         if (tmp != 0) {
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);
240         }
241 #endif
242
243         /* L1 data cache. */
244 #ifdef MIPS_DISABLE_L1_CACHE
245         cpuinfo->l1.dc_linesize = 0;
246 #else
247 #ifndef CPU_CNMIPS
248         tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT;
249         if (tmp != 0) {
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);
255         }
256 #else
257         /*
258          * Some Octeon cache configuration parameters are by model family, not
259          * config1.
260          */
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)) {
266                 /* Octeon Plus.  */
267                 cpuinfo->l1.dc_nsets = 2;
268                 cpuinfo->l1.dc_nways = 64;
269         } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
270                 /* Octeon II.  */
271                 cpuinfo->l1.dc_nsets = 8;
272                 cpuinfo->l1.dc_nways = 32;
273
274                 cpuinfo->l1.ic_nsets = 8;
275                 cpuinfo->l1.ic_nways = 37;
276         } else {
277                 panic("%s: unsupported Cavium Networks CPU.", __func__);
278         }
279
280         /* All Octeon models use 128 byte line size.  */
281         cpuinfo->l1.dc_linesize = 128;
282 #endif
283 #endif
284
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;
289
290         /*
291          * Probe PageMask register to see what sizes of pages are supported
292          * by writing all one's and then reading it back.
293          */
294         mips_wr_pagemask(~0);
295         cpuinfo->tlb_pgmask = mips_rd_pagemask();
296         mips_wr_pagemask(MIPS3_PGMASK_4K);
297
298 #ifndef CPU_CNMIPS
299         /* L2 cache */
300         if (!(cfg1 & MIPS_CONFIG_CM)) {
301                 /* We don't have valid cfg2 register */
302                 return;
303         }
304
305         cfg2 = mips_rd_config2();
306
307         tmp = (cfg2 >> MIPS_CONFIG2_SL_SHIFT) & MIPS_CONFIG2_SL_MASK;
308         if (0 < tmp && tmp <= 7)
309                 cpuinfo->l2.dc_linesize = 2 << tmp;
310
311         tmp = (cfg2 >> MIPS_CONFIG2_SS_SHIFT) & MIPS_CONFIG2_SS_MASK;
312         if (0 <= tmp && tmp <= 7)
313                 cpuinfo->l2.dc_nsets = 64 << tmp;
314
315         tmp = (cfg2 >> MIPS_CONFIG2_SA_SHIFT) & MIPS_CONFIG2_SA_MASK;
316         if (0 <= tmp && tmp <= 7)
317                 cpuinfo->l2.dc_nways = tmp + 1;
318
319         cpuinfo->l2.dc_size = cpuinfo->l2.dc_linesize
320             * cpuinfo->l2.dc_nsets * cpuinfo->l2.dc_nways;
321 #endif
322 }
323
324 void
325 mips_cpu_init(void)
326 {
327         platform_cpu_init();
328         mips_get_identity(&cpuinfo);
329         num_tlbentries = cpuinfo.tlb_nentries;
330         mips_wr_wired(0);
331         tlb_invalidate_all();
332         mips_wr_wired(VMWIRED_ENTRIES);
333         mips_config_cache(&cpuinfo);
334         mips_vector_init();
335
336         mips_icache_sync_all();
337         mips_dcache_wbinv_all();
338         /* Print some info about CPU */
339         cpu_identify();
340 }
341
342 static void
343 cpu_identify(void)
344 {
345         uint32_t cfg0, cfg1, cfg2, cfg3;
346 #if defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || defined (CPU_MIPS24K)
347         uint32_t cfg7;
348 #endif
349         printf("cpu%d: ", 0);   /* XXX per-cpu */
350         switch (cpuinfo.cpu_vendor) {
351         case MIPS_PRID_CID_MTI:
352                 printf("MIPS Technologies");
353                 break;
354         case MIPS_PRID_CID_BROADCOM:
355         case MIPS_PRID_CID_SIBYTE:
356                 printf("Broadcom");
357                 break;
358         case MIPS_PRID_CID_ALCHEMY:
359                 printf("AMD");
360                 break;
361         case MIPS_PRID_CID_SANDCRAFT:
362                 printf("Sandcraft");
363                 break;
364         case MIPS_PRID_CID_PHILIPS:
365                 printf("Philips");
366                 break;
367         case MIPS_PRID_CID_TOSHIBA:
368                 printf("Toshiba");
369                 break;
370         case MIPS_PRID_CID_LSI:
371                 printf("LSI");
372                 break;
373         case MIPS_PRID_CID_LEXRA:
374                 printf("Lexra");
375                 break;
376         case MIPS_PRID_CID_RMI:
377                 printf("RMI");
378                 break;
379         case MIPS_PRID_CID_CAVIUM:
380                 printf("Cavium");
381                 break;
382         case MIPS_PRID_CID_INGENIC:
383         case MIPS_PRID_CID_INGENIC2:
384                 printf("Ingenic XBurst");
385                 break;
386         case MIPS_PRID_CID_PREHISTORIC:
387         default:
388                 printf("Unknown cid %#x", cpuinfo.cpu_vendor);
389                 break;
390         }
391         printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
392
393         printf("  MMU: ");
394         if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
395                 printf("none present\n");
396         } else {
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");
403                 }
404                 printf(", %d entries ", cpuinfo.tlb_nentries);
405         }
406
407         if (cpuinfo.tlb_pgmask) {
408                 printf("(");
409                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_MASKX)
410                         printf("1K ");
411                 printf("4K ");
412                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16K)
413                         printf("16K ");
414                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64K)
415                         printf("64K ");
416                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256K)
417                         printf("256K ");
418                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_1M)
419                         printf("1M ");
420                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16M)
421                         printf("16M ");
422                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64M)
423                         printf("64M ");
424                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256M)
425                         printf("256M ");
426                 printf("pg sizes)");
427         }
428         printf("\n");
429
430         printf("  L1 i-cache: ");
431         if (cpuinfo.l1.ic_linesize == 0) {
432                 printf("disabled");
433         } else {
434                 if (cpuinfo.l1.ic_nways == 1) {
435                         printf("direct-mapped with");
436                 } else {
437                         printf ("%d ways of", cpuinfo.l1.ic_nways);
438                 }
439                 printf(" %d sets, %d bytes per line\n", 
440                     cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
441         }
442
443         printf("  L1 d-cache: ");
444         if (cpuinfo.l1.dc_linesize == 0) {
445                 printf("disabled");
446         } else {
447                 if (cpuinfo.l1.dc_nways == 1) {
448                         printf("direct-mapped with");
449                 } else {
450                         printf ("%d ways of", cpuinfo.l1.dc_nways);
451                 }
452                 printf(" %d sets, %d bytes per line\n", 
453                     cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
454         }
455
456         printf("  L2 cache: ");
457         if (cpuinfo.l2.dc_linesize == 0) {
458                 printf("disabled\n");
459         } else {
460                 printf("%d ways of %d sets, %d bytes per line, "
461                     "%d KiB total size\n",
462                     cpuinfo.l2.dc_nways,
463                     cpuinfo.l2.dc_nsets,
464                     cpuinfo.l2.dc_linesize,
465                     cpuinfo.l2.dc_size / 1024);
466         }
467
468         cfg0 = mips_rd_config();
469         /* If config register selection 1 does not exist, exit. */
470         if (!(cfg0 & MIPS_CONFIG_CM))
471                 return;
472
473         cfg1 = mips_rd_config1();
474         printf("  Config1=0x%b\n", cfg1, 
475             "\20\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU");
476
477         /* If config register selection 2 does not exist, exit. */
478         if (!(cfg1 & MIPS_CONFIG_CM))
479                 return;
480         cfg2 = mips_rd_config2();
481         /* 
482          * Config2 contains no useful information other then Config3 
483          * existence flag
484          */
485         printf("  Config2=0x%08x\n", cfg2);
486
487         /* If config register selection 3 does not exist, exit. */
488         if (!(cfg2 & MIPS_CONFIG_CM))
489                 return;
490         cfg3 = mips_rd_config3();
491
492         /* Print Config3 if it contains any useful info */
493         if (cfg3 & ~(0x80000000))
494                 printf("  Config3=0x%b\n", cfg3, "\20\16ULRI\2SmartMIPS\1TraceLogic");
495
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");
499 #endif
500 }
501
502 static struct rman cpu_hardirq_rman;
503
504 static devclass_t cpu_devclass;
505
506 /*
507  * Device methods
508  */
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,
513                                            u_int);
514 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
515                           driver_filter_t *f, driver_intr_t *, void *, 
516                           void **);
517
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),
524
525         /* Bus interface */
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),
529
530         { 0, 0 }
531 };
532
533 static driver_t cpu_driver = {
534         "cpu", cpu_methods, 1
535 };
536
537 static int
538 cpu_probe(device_t dev)
539 {
540
541         return (0);
542 }
543
544 static int
545 cpu_attach(device_t dev)
546 {
547         int error;
548 #ifdef notyet
549         device_t clock;
550 #endif
551
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";
556
557         error = rman_init(&cpu_hardirq_rman);
558         if (error != 0) {
559                 device_printf(dev, "failed to initialize irq resources\n");
560                 return (error);
561         }
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);
566         if (error != 0) {
567                 device_printf(dev, "failed to manage irq resources\n");
568                 return (error);
569         }
570
571         if (device_get_unit(dev) != 0)
572                 panic("can't attach more cpus");
573         device_set_desc(dev, "MIPS32 processor");
574
575 #ifdef notyet
576         clock = device_add_child(dev, "clock", device_get_unit(dev));
577         if (clock == NULL)
578                 device_printf(dev, "clock failed to attach");
579 #endif
580
581         return (bus_generic_attach(dev));
582 }
583
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)
587 {
588         struct resource *res;
589
590         if (type != SYS_RES_IRQ)
591                 return (NULL);
592         res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
593                                     child);
594         return (res);
595 }
596
597 static int
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, 
600                void **cookiep)
601 {
602         int error;
603         int intr;
604
605         error = rman_activate_resource(res);
606         if (error != 0) {
607                 device_printf(child, "could not activate irq\n");
608                 return (error);
609         }
610
611         intr = rman_get_start(res);
612
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);
616         return (0);
617 }
618
619 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);