xref: /f-stack/freebsd/mips/mips/cpu.c (revision 22ce4aff)
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
remove_userlocal_code(uint32_t * cpu_switch_code)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
mips_get_identity(struct mips_cpuinfo * cpuinfo)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 #if defined(CPU_NLM)
160 	/* Account for Extended TLB entries in XLP */
161 	tmp = mips_rd_config6();
162 	cpuinfo->tlb_nentries = ((tmp >> 16) & 0xffff) + 1;
163 #elif defined(BERI_LARGE_TLB)
164 	/* Check if we support extended TLB entries and if so activate. */
165 	tmp = mips_rd_config5();
166 #define	BERI_CP5_LTLB_SUPPORTED	0x1
167 	if (tmp & BERI_CP5_LTLB_SUPPORTED) {
168 		/* See how many extra TLB entries we have. */
169 		tmp = mips_rd_config6();
170 		cpuinfo->tlb_nentries = (tmp >> 16) + 1;
171 		/* Activate the extended entries. */
172 		mips_wr_config6(tmp|0x4);
173 	} else
174 #endif
175 #if !defined(CPU_NLM)
176 	cpuinfo->tlb_nentries =
177 	    ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
178 #endif
179 #if defined(CPU_CNMIPS)
180 	/* Add extended TLB size information from config4.  */
181 	cfg4 = mips_rd_config4();
182 	if ((cfg4 & MIPS_CONFIG4_MMUEXTDEF) == MIPS_CONFIG4_MMUEXTDEF_MMUSIZEEXT)
183 		cpuinfo->tlb_nentries += (cfg4 & MIPS_CONFIG4_MMUSIZEEXT) * 0x40;
184 #endif
185 
186 	/* L1 instruction cache. */
187 #ifdef MIPS_DISABLE_L1_CACHE
188 	cpuinfo->l1.ic_linesize = 0;
189 #else
190 	tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT;
191 	if (tmp != 0) {
192 		cpuinfo->l1.ic_linesize = 1 << (tmp + 1);
193 		cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
194 		cpuinfo->l1.ic_nsets =
195 	    		1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
196 	}
197 #endif
198 
199 	/* L1 data cache. */
200 #ifdef MIPS_DISABLE_L1_CACHE
201 	cpuinfo->l1.dc_linesize = 0;
202 #else
203 #ifndef CPU_CNMIPS
204 	tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT;
205 	if (tmp != 0) {
206 		cpuinfo->l1.dc_linesize = 1 << (tmp + 1);
207 		cpuinfo->l1.dc_nways =
208 		    (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
209 		cpuinfo->l1.dc_nsets =
210 		    1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
211 	}
212 #else
213 	/*
214 	 * Some Octeon cache configuration parameters are by model family, not
215 	 * config1.
216 	 */
217 	if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
218 		/* Octeon and Octeon XL.  */
219 		cpuinfo->l1.dc_nsets = 1;
220 		cpuinfo->l1.dc_nways = 64;
221 	} else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
222 		/* Octeon Plus.  */
223 		cpuinfo->l1.dc_nsets = 2;
224 		cpuinfo->l1.dc_nways = 64;
225 	} else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
226 		/* Octeon II.  */
227 		cpuinfo->l1.dc_nsets = 8;
228 		cpuinfo->l1.dc_nways = 32;
229 
230 		cpuinfo->l1.ic_nsets = 8;
231 		cpuinfo->l1.ic_nways = 37;
232 	} else {
233 		panic("%s: unsupported Cavium Networks CPU.", __func__);
234 	}
235 
236 	/* All Octeon models use 128 byte line size.  */
237 	cpuinfo->l1.dc_linesize = 128;
238 #endif
239 #endif
240 
241 	cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize
242 	    * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways;
243 	cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize
244 	    * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways;
245 
246 	/*
247 	 * Probe PageMask register to see what sizes of pages are supported
248 	 * by writing all one's and then reading it back.
249 	 */
250 	mips_wr_pagemask(~0);
251 	cpuinfo->tlb_pgmask = mips_rd_pagemask();
252 	mips_wr_pagemask(MIPS3_PGMASK_4K);
253 
254 #ifndef CPU_CNMIPS
255 	/* L2 cache */
256 	if (!(cfg1 & MIPS_CONFIG_CM)) {
257 		/* We don't have valid cfg2 register */
258 		return;
259 	}
260 
261 	cfg2 = mips_rd_config2();
262 
263 	tmp = (cfg2 >> MIPS_CONFIG2_SL_SHIFT) & MIPS_CONFIG2_SL_MASK;
264 	if (0 < tmp && tmp <= 7)
265 		cpuinfo->l2.dc_linesize = 2 << tmp;
266 
267 	tmp = (cfg2 >> MIPS_CONFIG2_SS_SHIFT) & MIPS_CONFIG2_SS_MASK;
268 	if (0 <= tmp && tmp <= 7)
269 		cpuinfo->l2.dc_nsets = 64 << tmp;
270 
271 	tmp = (cfg2 >> MIPS_CONFIG2_SA_SHIFT) & MIPS_CONFIG2_SA_MASK;
272 	if (0 <= tmp && tmp <= 7)
273 		cpuinfo->l2.dc_nways = tmp + 1;
274 
275 	cpuinfo->l2.dc_size = cpuinfo->l2.dc_linesize
276 	    * cpuinfo->l2.dc_nsets * cpuinfo->l2.dc_nways;
277 #endif
278 }
279 
280 void
mips_cpu_init(void)281 mips_cpu_init(void)
282 {
283 	platform_cpu_init();
284 	mips_get_identity(&cpuinfo);
285 	num_tlbentries = cpuinfo.tlb_nentries;
286 	mips_wr_wired(0);
287 	tlb_invalidate_all();
288 	mips_wr_wired(VMWIRED_ENTRIES);
289 	mips_config_cache(&cpuinfo);
290 	mips_vector_init();
291 
292 	mips_icache_sync_all();
293 	mips_dcache_wbinv_all();
294 }
295 
296 void
cpu_identify(void)297 cpu_identify(void)
298 {
299 	uint32_t cfg0, cfg1, cfg2, cfg3;
300 #if defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || defined (CPU_MIPS24K)
301 	uint32_t cfg7;
302 #endif
303 	printf("CPU: ");
304 	switch (cpuinfo.cpu_vendor) {
305 	case MIPS_PRID_CID_MTI:
306 		printf("MIPS Technologies");
307 		break;
308 	case MIPS_PRID_CID_BROADCOM:
309 	case MIPS_PRID_CID_SIBYTE:
310 		printf("Broadcom");
311 		break;
312 	case MIPS_PRID_CID_ALCHEMY:
313 		printf("AMD");
314 		break;
315 	case MIPS_PRID_CID_SANDCRAFT:
316 		printf("Sandcraft");
317 		break;
318 	case MIPS_PRID_CID_PHILIPS:
319 		printf("Philips");
320 		break;
321 	case MIPS_PRID_CID_TOSHIBA:
322 		printf("Toshiba");
323 		break;
324 	case MIPS_PRID_CID_LSI:
325 		printf("LSI");
326 		break;
327 	case MIPS_PRID_CID_LEXRA:
328 		printf("Lexra");
329 		break;
330 	case MIPS_PRID_CID_RMI:
331 		printf("RMI");
332 		break;
333 	case MIPS_PRID_CID_CAVIUM:
334 		printf("Cavium");
335 		break;
336 	case MIPS_PRID_CID_INGENIC:
337 	case MIPS_PRID_CID_INGENIC2:
338 		printf("Ingenic XBurst");
339 		break;
340 	case MIPS_PRID_CID_PREHISTORIC:
341 	default:
342 		printf("Unknown cid %#x", cpuinfo.cpu_vendor);
343 		break;
344 	}
345 	if (cpu_model[0] != '\0')
346 		printf(" (%s)", cpu_model);
347 	printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
348 
349 	printf("  MMU: ");
350 	if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
351 		printf("none present\n");
352 	} else {
353 		if (cpuinfo.tlb_type == MIPS_MMU_TLB) {
354 			printf("Standard TLB");
355 		} else if (cpuinfo.tlb_type == MIPS_MMU_BAT) {
356 			printf("Standard BAT");
357 		} else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) {
358 			printf("Fixed mapping");
359 		}
360 		printf(", %d entries ", cpuinfo.tlb_nentries);
361 	}
362 
363 	if (cpuinfo.tlb_pgmask) {
364 		printf("(");
365 		if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_MASKX)
366 			printf("1K ");
367 		printf("4K ");
368 		if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16K)
369 			printf("16K ");
370 		if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64K)
371 			printf("64K ");
372 		if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256K)
373 			printf("256K ");
374 		if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_1M)
375 			printf("1M ");
376 		if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16M)
377 			printf("16M ");
378 		if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64M)
379 			printf("64M ");
380 		if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256M)
381 			printf("256M ");
382 		printf("pg sizes)");
383 	}
384 	printf("\n");
385 
386 	printf("  L1 i-cache: ");
387 	if (cpuinfo.l1.ic_linesize == 0) {
388 		printf("disabled");
389 	} else {
390 		if (cpuinfo.l1.ic_nways == 1) {
391 			printf("direct-mapped with");
392 		} else {
393 			printf ("%d ways of", cpuinfo.l1.ic_nways);
394 		}
395 		printf(" %d sets, %d bytes per line\n",
396 		    cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
397 	}
398 
399 	printf("  L1 d-cache: ");
400 	if (cpuinfo.l1.dc_linesize == 0) {
401 		printf("disabled");
402 	} else {
403 		if (cpuinfo.l1.dc_nways == 1) {
404 			printf("direct-mapped with");
405 		} else {
406 			printf ("%d ways of", cpuinfo.l1.dc_nways);
407 		}
408 		printf(" %d sets, %d bytes per line\n",
409 		    cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
410 	}
411 
412 	printf("  L2 cache: ");
413 	if (cpuinfo.l2.dc_linesize == 0) {
414 		printf("disabled\n");
415 	} else {
416 		printf("%d ways of %d sets, %d bytes per line, "
417 		    "%d KiB total size\n",
418 		    cpuinfo.l2.dc_nways,
419 		    cpuinfo.l2.dc_nsets,
420 		    cpuinfo.l2.dc_linesize,
421 		    cpuinfo.l2.dc_size / 1024);
422 	}
423 
424 	cfg0 = mips_rd_config();
425 	/* If config register selection 1 does not exist, exit. */
426 	if (!(cfg0 & MIPS_CONFIG_CM))
427 		return;
428 
429 	cfg1 = mips_rd_config1();
430 	printf("  Config1=0x%b\n", cfg1,
431 	    "\20\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU");
432 
433 	if (cpuinfo.fpu_id != 0)
434 		printf("  FPU ID=0x%b\n", cpuinfo.fpu_id,
435 		    "\020"
436 		    "\020S"
437 		    "\021D"
438 		    "\022PS"
439 		    "\0233D"
440 		    "\024W"
441 		    "\025L"
442 		    "\026F64"
443 		    "\0272008"
444 		    "\034UFRP");
445 
446 	/* If config register selection 2 does not exist, exit. */
447 	if (!(cfg1 & MIPS_CONFIG_CM))
448 		return;
449 	cfg2 = mips_rd_config2();
450 	/*
451 	 * Config2 contains no useful information other then Config3
452 	 * existence flag
453 	 */
454 	printf("  Config2=0x%08x\n", cfg2);
455 
456 	/* If config register selection 3 does not exist, exit. */
457 	if (!(cfg2 & MIPS_CONFIG_CM))
458 		return;
459 	cfg3 = mips_rd_config3();
460 
461 	/* Print Config3 if it contains any useful info */
462 	if (cfg3 & ~(0x80000000))
463 		printf("  Config3=0x%b\n", cfg3, "\20\16ULRI\2SmartMIPS\1TraceLogic");
464 
465 #if defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || defined (CPU_MIPS24K)
466 	cfg7 = mips_rd_config7();
467 	printf("  Config7=0x%b\n", cfg7, "\20\40WII\21AR");
468 #endif
469 }
470 
471 static struct rman cpu_hardirq_rman;
472 
473 static devclass_t cpu_devclass;
474 
475 /*
476  * Device methods
477  */
478 static int cpu_probe(device_t);
479 static int cpu_attach(device_t);
480 static struct resource *cpu_alloc_resource(device_t, device_t, int, int *,
481 					   rman_res_t, rman_res_t, rman_res_t,
482 					   u_int);
483 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
484 			  driver_filter_t *f, driver_intr_t *, void *,
485 			  void **);
486 
487 static device_method_t cpu_methods[] = {
488 	/* Device interface */
489 	DEVMETHOD(device_probe,		cpu_probe),
490 	DEVMETHOD(device_attach,	cpu_attach),
491 	DEVMETHOD(device_detach,	bus_generic_detach),
492 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
493 
494 	/* Bus interface */
495 	DEVMETHOD(bus_alloc_resource,	cpu_alloc_resource),
496 	DEVMETHOD(bus_setup_intr,	cpu_setup_intr),
497 	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
498 	{ 0, 0 }
499 };
500 
501 static driver_t cpu_driver = {
502 	"cpu", cpu_methods, 1
503 };
504 
505 static int
cpu_probe(device_t dev)506 cpu_probe(device_t dev)
507 {
508 
509 	return (0);
510 }
511 
512 static int
cpu_attach(device_t dev)513 cpu_attach(device_t dev)
514 {
515 	int error;
516 #ifdef notyet
517 	device_t clock;
518 #endif
519 
520 	cpu_hardirq_rman.rm_start = 0;
521 	cpu_hardirq_rman.rm_end = 5;
522 	cpu_hardirq_rman.rm_type = RMAN_ARRAY;
523 	cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
524 
525 	error = rman_init(&cpu_hardirq_rman);
526 	if (error != 0) {
527 		device_printf(dev, "failed to initialize irq resources\n");
528 		return (error);
529 	}
530 	/* XXX rman_manage_all. */
531 	error = rman_manage_region(&cpu_hardirq_rman,
532 				   cpu_hardirq_rman.rm_start,
533 				   cpu_hardirq_rman.rm_end);
534 	if (error != 0) {
535 		device_printf(dev, "failed to manage irq resources\n");
536 		return (error);
537 	}
538 
539 	if (device_get_unit(dev) != 0)
540 		panic("can't attach more cpus");
541 	device_set_desc(dev, "MIPS32 processor");
542 
543 #ifdef notyet
544 	clock = device_add_child(dev, "clock", device_get_unit(dev));
545 	if (clock == NULL)
546 		device_printf(dev, "clock failed to attach");
547 #endif
548 
549 	return (bus_generic_attach(dev));
550 }
551 
552 static struct resource *
cpu_alloc_resource(device_t dev,device_t child,int type,int * rid,rman_res_t start,rman_res_t end,rman_res_t count,u_int flags)553 cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
554 		   rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
555 {
556 	struct resource *res;
557 
558 	if (type != SYS_RES_IRQ)
559 		return (NULL);
560 	res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
561 				    child);
562 	return (res);
563 }
564 
565 static int
cpu_setup_intr(device_t dev,device_t child,struct resource * res,int flags,driver_filter_t * filt,driver_intr_t * handler,void * arg,void ** cookiep)566 cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
567 	       driver_filter_t *filt, driver_intr_t *handler, void *arg,
568 	       void **cookiep)
569 {
570 	int error;
571 	int intr;
572 
573 	error = rman_activate_resource(res);
574 	if (error != 0) {
575 		device_printf(child, "could not activate irq\n");
576 		return (error);
577 	}
578 
579 	intr = rman_get_start(res);
580 
581 	cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg,
582 	    intr, flags, cookiep);
583 	device_printf(child, "established CPU interrupt %d\n", intr);
584 	return (0);
585 }
586 
587 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);
588