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