xref: /openbsd-src/sys/arch/arm64/arm64/intr.c (revision fa6a043a3e96e745636dd0ee4c8bf3f425229476)
1 /* $OpenBSD: intr.c,v 1.29 2024/08/04 12:01:18 kettenis Exp $ */
2 /*
3  * Copyright (c) 2011 Dale Rahn <drahn@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/timetc.h>
21 #include <sys/malloc.h>
22 
23 #include <dev/clock_subr.h>
24 #include <machine/cpu.h>
25 #include <machine/intr.h>
26 
27 #include <dev/ofw/openfirm.h>
28 
29 int arm_intr_get_parent(int);
30 uint32_t arm_intr_map_msi(int, uint64_t *);
31 
32 void *arm_intr_prereg_establish_fdt(void *, int *, int, struct cpu_info *,
33     int (*)(void *), void *, char *);
34 void arm_intr_prereg_disestablish_fdt(void *);
35 void arm_intr_prereg_barrier_fdt(void *);
36 
37 int arm_dflt_splraise(int);
38 int arm_dflt_spllower(int);
39 void arm_dflt_splx(int);
40 void arm_dflt_setipl(int);
41 
42 void arm_dflt_irq(void *);
43 void arm_dflt_fiq(void *);
44 
45 void arm_cpu_irq(void *);
46 void arm_cpu_fiq(void *);
47 
48 #define SI_TO_IRQBIT(x) (1 << (x))
49 uint32_t arm_smask[NIPL];
50 
51 struct arm_intr_func arm_intr_func = {
52 	arm_dflt_splraise,
53 	arm_dflt_spllower,
54 	arm_dflt_splx,
55 	arm_dflt_setipl
56 };
57 
58 void
59 arm_dflt_irq(void *frame)
60 {
61 	panic("%s", __func__);
62 }
63 
64 void
65 arm_dflt_fiq(void *frame)
66 {
67 	panic("%s", __func__);
68 }
69 
70 void (*arm_irq_dispatch)(void *) = arm_dflt_irq;
71 
72 void
73 arm_cpu_irq(void *frame)
74 {
75 	struct cpu_info	*ci = curcpu();
76 
77 	ci->ci_idepth++;
78 	(*arm_irq_dispatch)(frame);
79 	ci->ci_idepth--;
80 }
81 
82 void (*arm_fiq_dispatch)(void *) = arm_dflt_fiq;
83 
84 void
85 arm_cpu_fiq(void *frame)
86 {
87 	struct cpu_info	*ci = curcpu();
88 
89 	ci->ci_idepth++;
90 	(*arm_fiq_dispatch)(frame);
91 	ci->ci_idepth--;
92 }
93 
94 /*
95  * Find the interrupt parent by walking up the tree.
96  */
97 int
98 arm_intr_get_parent(int node)
99 {
100 	uint32_t phandle;
101 
102 	while (node) {
103 		phandle = OF_getpropint(node, "interrupt-parent", 0);
104 		if (phandle)
105 			return OF_getnodebyphandle(phandle);
106 		node = OF_parent(node);
107 		if (OF_getpropbool(node, "interrupt-controller"))
108 			return node;
109 	}
110 
111 	return 0;
112 }
113 
114 uint32_t
115 arm_intr_map_msi(int node, uint64_t *data)
116 {
117 	uint64_t msi_base;
118 	uint32_t phandle = 0;
119 	uint32_t *cell;
120 	uint32_t *map;
121 	uint32_t mask, rid_base, rid;
122 	int i, len, length, mcells, ncells;
123 
124 	len = OF_getproplen(node, "msi-map");
125 	if (len <= 0) {
126 		while (node && !phandle) {
127 			phandle = OF_getpropint(node, "msi-parent", 0);
128 			node = OF_parent(node);
129 		}
130 
131 		return phandle;
132 	}
133 
134 	map = malloc(len, M_TEMP, M_WAITOK);
135 	OF_getpropintarray(node, "msi-map", map, len);
136 
137 	mask = OF_getpropint(node, "msi-map-mask", 0xffff);
138 	rid = *data & mask;
139 
140 	cell = map;
141 	ncells = len / sizeof(uint32_t);
142 	while (ncells > 1) {
143 		node = OF_getnodebyphandle(cell[1]);
144 		if (node == 0)
145 			goto out;
146 
147 		/*
148 		 * Some device trees (e.g. those for the Rockchip
149 		 * RK3399 boards) are missing a #msi-cells property.
150 		 * Assume the msi-specifier uses a single cell in that
151 		 * case.
152 		 */
153 		mcells = OF_getpropint(node, "#msi-cells", 1);
154 		if (ncells < mcells + 3)
155 			goto out;
156 
157 		rid_base = cell[0];
158 		length = cell[2 + mcells];
159 		msi_base = cell[2];
160 		for (i = 1; i < mcells; i++) {
161 			msi_base <<= 32;
162 			msi_base |= cell[2 + i];
163 		}
164 		if (rid >= rid_base && rid < rid_base + length) {
165 			*data = msi_base + (rid - rid_base);
166 			phandle = cell[1];
167 			break;
168 		}
169 
170 		cell += (3 + mcells);
171 		ncells -= (3 + mcells);
172 	}
173 
174 out:
175 	free(map, M_TEMP, len);
176 	return phandle;
177 }
178 
179 /*
180  * Interrupt pre-registration.
181  *
182  * To allow device drivers to establish interrupt handlers before all
183  * relevant interrupt controllers have been attached, we support
184  * pre-registration of interrupt handlers.  For each node in the
185  * device tree that has an "interrupt-controller" property, we
186  * register a dummy interrupt controller that simply stashes away all
187  * relevant details of the interrupt handler being established.
188  * Later, when the real interrupt controller registers itself, we
189  * establish those interrupt handlers based on that information.
190  */
191 
192 #define MAX_INTERRUPT_CELLS	4
193 
194 struct intr_prereg {
195 	LIST_ENTRY(intr_prereg) ip_list;
196 	uint32_t ip_phandle;
197 	uint32_t ip_cell[MAX_INTERRUPT_CELLS];
198 
199 	int ip_level;
200 	struct cpu_info *ip_ci;
201 	int (*ip_func)(void *);
202 	void *ip_arg;
203 	char *ip_name;
204 
205 	struct interrupt_controller *ip_ic;
206 	void *ip_ih;
207 };
208 
209 LIST_HEAD(, intr_prereg) prereg_interrupts =
210 	LIST_HEAD_INITIALIZER(prereg_interrupts);
211 
212 void *
213 arm_intr_prereg_establish_fdt(void *cookie, int *cell, int level,
214     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
215 {
216 	struct interrupt_controller *ic = cookie;
217 	struct intr_prereg *ip;
218 	int i;
219 
220 	ip = malloc(sizeof(struct intr_prereg), M_DEVBUF, M_ZERO | M_WAITOK);
221 	ip->ip_phandle = ic->ic_phandle;
222 	for (i = 0; i < ic->ic_cells; i++)
223 		ip->ip_cell[i] = cell[i];
224 	ip->ip_level = level;
225 	ip->ip_ci = ci;
226 	ip->ip_func = func;
227 	ip->ip_arg = arg;
228 	ip->ip_name = name;
229 	LIST_INSERT_HEAD(&prereg_interrupts, ip, ip_list);
230 
231 	return ip;
232 }
233 
234 void
235 arm_intr_prereg_disestablish_fdt(void *cookie)
236 {
237 	struct intr_prereg *ip = cookie;
238 	struct interrupt_controller *ic = ip->ip_ic;
239 
240 	if (ip->ip_ic != NULL && ip->ip_ih != NULL)
241 		ic->ic_disestablish(ip->ip_ih);
242 
243 	if (ip->ip_ic != NULL)
244 		LIST_REMOVE(ip, ip_list);
245 
246 	free(ip, M_DEVBUF, sizeof(*ip));
247 }
248 
249 void
250 arm_intr_prereg_barrier_fdt(void *cookie)
251 {
252 	struct intr_prereg *ip = cookie;
253 	struct interrupt_controller *ic = ip->ip_ic;
254 
255 	if (ip->ip_ic != NULL && ip->ip_ih != NULL)
256 		ic->ic_barrier(ip->ip_ih);
257 }
258 
259 void
260 arm_intr_init_fdt_recurse(int node)
261 {
262 	struct interrupt_controller *ic;
263 
264 	if (OF_getproplen(node, "interrupt-controller") >= 0) {
265 		ic = malloc(sizeof(struct interrupt_controller),
266 		    M_DEVBUF, M_ZERO | M_WAITOK);
267 		ic->ic_node = node;
268 		ic->ic_cookie = ic;
269 		ic->ic_establish = arm_intr_prereg_establish_fdt;
270 		ic->ic_disestablish = arm_intr_prereg_disestablish_fdt;
271 		ic->ic_barrier = arm_intr_prereg_barrier_fdt;
272 		arm_intr_register_fdt(ic);
273 	}
274 
275 	for (node = OF_child(node); node; node = OF_peer(node))
276 		arm_intr_init_fdt_recurse(node);
277 }
278 
279 void
280 arm_intr_init_fdt(void)
281 {
282 	int node = OF_peer(0);
283 
284 	if (node)
285 		arm_intr_init_fdt_recurse(node);
286 }
287 
288 LIST_HEAD(, interrupt_controller) interrupt_controllers =
289 	LIST_HEAD_INITIALIZER(interrupt_controllers);
290 
291 void
292 arm_intr_register_fdt(struct interrupt_controller *ic)
293 {
294 	struct intr_prereg *ip, *tip;
295 
296 	ic->ic_cells = OF_getpropint(ic->ic_node, "#interrupt-cells", 0);
297 	ic->ic_phandle = OF_getpropint(ic->ic_node, "phandle", 0);
298 	KASSERT(ic->ic_cells <= MAX_INTERRUPT_CELLS);
299 
300 	LIST_INSERT_HEAD(&interrupt_controllers, ic, ic_list);
301 
302 	/* Establish pre-registered interrupt handlers. */
303 	LIST_FOREACH_SAFE(ip, &prereg_interrupts, ip_list, tip) {
304 		if (ip->ip_phandle != ic->ic_phandle)
305 			continue;
306 
307 		ip->ip_ic = ic;
308 		ip->ip_ih = ic->ic_establish(ic->ic_cookie, ip->ip_cell,
309 		    ip->ip_level, ip->ip_ci, ip->ip_func, ip->ip_arg,
310 		    ip->ip_name);
311 		if (ip->ip_ih == NULL)
312 			printf("can't establish interrupt %s\n", ip->ip_name);
313 
314 		LIST_REMOVE(ip, ip_list);
315 	}
316 }
317 
318 void *
319 arm_intr_establish_fdt(int node, int level, int (*func)(void *),
320     void *cookie, char *name)
321 {
322 	return arm_intr_establish_fdt_idx(node, 0, level, func, cookie, name);
323 }
324 
325 void *
326 arm_intr_establish_fdt_cpu(int node, int level, struct cpu_info *ci,
327     int (*func)(void *), void *cookie, char *name)
328 {
329 	return arm_intr_establish_fdt_idx_cpu(node, 0, level, ci, func,
330 	    cookie, name);
331 }
332 
333 void *
334 arm_intr_establish_fdt_idx(int node, int idx, int level, int (*func)(void *),
335     void *cookie, char *name)
336 {
337 	return arm_intr_establish_fdt_idx_cpu(node, idx, level, NULL, func,
338 	    cookie, name);
339 }
340 
341 void *
342 arm_intr_establish_fdt_idx_cpu(int node, int idx, int level, struct cpu_info *ci,
343     int (*func)(void *), void *cookie, char *name)
344 {
345 	struct interrupt_controller *ic;
346 	int i, len, ncells, parent;
347 	int extended = 1;
348 	uint32_t *cell, *cells, phandle;
349 	struct machine_intr_handle *ih;
350 	void *val = NULL;
351 
352 	len = OF_getproplen(node, "interrupts-extended");
353 	if (len <= 0) {
354 		len = OF_getproplen(node, "interrupts");
355 		extended = 0;
356 	}
357 	if (len <= 0 || (len % sizeof(uint32_t) != 0))
358 		return NULL;
359 
360 	/* Old style. */
361 	if (!extended) {
362 		parent = arm_intr_get_parent(node);
363 		LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
364 			if (ic->ic_node == parent)
365 				break;
366 		}
367 
368 		if (ic == NULL)
369 			return NULL;
370 	}
371 
372 	cell = cells = malloc(len, M_TEMP, M_WAITOK);
373 	if (extended)
374 		OF_getpropintarray(node, "interrupts-extended", cells, len);
375 	else
376 		OF_getpropintarray(node, "interrupts", cells, len);
377 	ncells = len / sizeof(uint32_t);
378 
379 	for (i = 0; i <= idx && ncells > 0; i++) {
380 		if (extended) {
381 			phandle = cell[0];
382 
383 			/* Handle "empty" phandle reference. */
384 			if (phandle == 0) {
385 				cell++;
386 				ncells--;
387 				continue;
388 			}
389 
390 			LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
391 				if (ic->ic_phandle == phandle)
392 					break;
393 			}
394 
395 			if (ic == NULL)
396 				break;
397 
398 			cell++;
399 			ncells--;
400 		}
401 
402 		if (i == idx && ncells >= ic->ic_cells && ic->ic_establish) {
403 			val = ic->ic_establish(ic->ic_cookie, cell, level,
404 			    ci, func, cookie, name);
405 			break;
406 		}
407 
408 		cell += ic->ic_cells;
409 		ncells -= ic->ic_cells;
410 	}
411 
412 	free(cells, M_TEMP, len);
413 
414 	if (val == NULL)
415 		return NULL;
416 
417 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
418 	ih->ih_ic = ic;
419 	ih->ih_ih = val;
420 
421 	return ih;
422 }
423 
424 void *
425 arm_intr_establish_fdt_imap(int node, int *reg, int nreg, int level,
426     int (*func)(void *), void *cookie, char *name)
427 {
428 	return arm_intr_establish_fdt_imap_cpu(node, reg, nreg, level, NULL,
429 	    func, cookie, name);
430 }
431 
432 void *
433 arm_intr_establish_fdt_imap_cpu(int node, int *reg, int nreg, int level,
434     struct cpu_info *ci, int (*func)(void *), void *cookie, char *name)
435 {
436 	struct interrupt_controller *ic;
437 	struct machine_intr_handle *ih;
438 	uint32_t *cell;
439 	uint32_t map_mask[4], *map;
440 	int len, acells, ncells;
441 	void *val = NULL;
442 
443 	if (nreg != sizeof(map_mask))
444 		return NULL;
445 
446 	if (OF_getpropintarray(node, "interrupt-map-mask", map_mask,
447 	    sizeof(map_mask)) != sizeof(map_mask))
448 		return NULL;
449 
450 	len = OF_getproplen(node, "interrupt-map");
451 	if (len <= 0)
452 		return NULL;
453 
454 	map = malloc(len, M_DEVBUF, M_WAITOK);
455 	OF_getpropintarray(node, "interrupt-map", map, len);
456 
457 	cell = map;
458 	ncells = len / sizeof(uint32_t);
459 	while (ncells > 5) {
460 		LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
461 			if (ic->ic_phandle == cell[4])
462 				break;
463 		}
464 
465 		if (ic == NULL)
466 			break;
467 
468 		acells = OF_getpropint(ic->ic_node, "#address-cells", 0);
469 		if (ncells >= (5 + acells + ic->ic_cells) &&
470 		    (reg[0] & map_mask[0]) == cell[0] &&
471 		    (reg[1] & map_mask[1]) == cell[1] &&
472 		    (reg[2] & map_mask[2]) == cell[2] &&
473 		    (reg[3] & map_mask[3]) == cell[3] &&
474 		    ic->ic_establish) {
475 			val = ic->ic_establish(ic->ic_cookie, &cell[5 + acells],
476 			    level, ci, func, cookie, name);
477 			break;
478 		}
479 
480 		cell += (5 + acells + ic->ic_cells);
481 		ncells -= (5 + acells + ic->ic_cells);
482 	}
483 
484 	if (val == NULL) {
485 		free(map, M_DEVBUF, len);
486 		return NULL;
487 	}
488 
489 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
490 	ih->ih_ic = ic;
491 	ih->ih_ih = val;
492 
493 	free(map, M_DEVBUF, len);
494 	return ih;
495 }
496 
497 void *
498 arm_intr_establish_fdt_msi(int node, uint64_t *addr, uint64_t *data,
499     int level, int (*func)(void *), void *cookie, char *name)
500 {
501 	return arm_intr_establish_fdt_msi_cpu(node, addr, data, level, NULL,
502 	    func, cookie, name);
503 }
504 
505 void *
506 arm_intr_establish_fdt_msi_cpu(int node, uint64_t *addr, uint64_t *data,
507     int level, struct cpu_info *ci, int (*func)(void *), void *cookie,
508     char *name)
509 {
510 	struct interrupt_controller *ic;
511 	struct machine_intr_handle *ih;
512 	uint32_t phandle;
513 	void *val = NULL;
514 
515 	phandle = arm_intr_map_msi(node, data);
516 	LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
517 		if (ic->ic_phandle == phandle)
518 			break;
519 	}
520 
521 	if (ic == NULL || ic->ic_establish_msi == NULL)
522 		return NULL;
523 
524 	val = ic->ic_establish_msi(ic->ic_cookie, addr, data,
525 	    level, ci, func, cookie, name);
526 
527 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
528 	ih->ih_ic = ic;
529 	ih->ih_ih = val;
530 
531 	return ih;
532 }
533 
534 void
535 arm_intr_disestablish_fdt(void *cookie)
536 {
537 	struct machine_intr_handle *ih = cookie;
538 	struct interrupt_controller *ic = ih->ih_ic;
539 
540 	ic->ic_disestablish(ih->ih_ih);
541 	free(ih, M_DEVBUF, sizeof(*ih));
542 }
543 
544 void
545 arm_intr_enable(void *cookie)
546 {
547 	struct machine_intr_handle *ih = cookie;
548 	struct interrupt_controller *ic = ih->ih_ic;
549 
550 	KASSERT(ic->ic_enable != NULL);
551 	ic->ic_enable(ih->ih_ih);
552 }
553 
554 void
555 arm_intr_disable(void *cookie)
556 {
557 	struct machine_intr_handle *ih = cookie;
558 	struct interrupt_controller *ic = ih->ih_ic;
559 
560 	KASSERT(ic->ic_disable != NULL);
561 	ic->ic_disable(ih->ih_ih);
562 }
563 
564 /*
565  * Some interrupt controllers transparently forward interrupts to
566  * their parent.  Such interrupt controllers can use this function to
567  * delegate the interrupt handler to their parent.
568  */
569 void *
570 arm_intr_parent_establish_fdt(void *cookie, int *cell, int level,
571     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
572 {
573 	struct interrupt_controller *ic = cookie;
574 	struct machine_intr_handle *ih;
575 	int parent;
576 	void *val;
577 
578 	parent = arm_intr_get_parent(ic->ic_node);
579 	LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
580 		if (ic->ic_node == parent)
581 			break;
582 	}
583 	if (ic == NULL)
584 		return NULL;
585 
586 	val = ic->ic_establish(ic->ic_cookie, cell, level, ci, func, arg, name);
587 	if (val == NULL)
588 		return NULL;
589 
590 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
591 	ih->ih_ic = ic;
592 	ih->ih_ih = val;
593 
594 	return ih;
595 }
596 
597 void
598 arm_intr_parent_disestablish_fdt(void *cookie)
599 {
600 	struct machine_intr_handle *ih = cookie;
601 	struct interrupt_controller *ic = ih->ih_ic;
602 
603 	ic->ic_disestablish(ih->ih_ih);
604 	free(ih, M_DEVBUF, sizeof(*ih));
605 }
606 
607 void
608 arm_intr_route(void *cookie, int enable, struct cpu_info *ci)
609 {
610 	struct machine_intr_handle *ih = cookie;
611 	struct interrupt_controller *ic = ih->ih_ic;
612 
613 	if (ic->ic_route)
614 		ic->ic_route(ih->ih_ih, enable, ci);
615 }
616 
617 void
618 arm_intr_cpu_enable(void)
619 {
620 	struct interrupt_controller *ic;
621 
622 	LIST_FOREACH(ic, &interrupt_controllers, ic_list)
623 		if (ic->ic_cpu_enable)
624 			ic->ic_cpu_enable();
625 }
626 
627 int
628 arm_dflt_splraise(int newcpl)
629 {
630 	struct cpu_info *ci = curcpu();
631 	int oldcpl;
632 
633 	oldcpl = ci->ci_cpl;
634 
635 	if (newcpl < oldcpl)
636 		newcpl = oldcpl;
637 
638 	ci->ci_cpl = newcpl;
639 
640 	return oldcpl;
641 }
642 
643 int
644 arm_dflt_spllower(int newcpl)
645 {
646 	struct cpu_info *ci = curcpu();
647 	int oldcpl;
648 
649 	oldcpl = ci->ci_cpl;
650 
651 	splx(newcpl);
652 
653 	return oldcpl;
654 }
655 
656 void
657 arm_dflt_splx(int newcpl)
658 {
659 	struct cpu_info *ci = curcpu();
660 
661 	if (ci->ci_ipending & arm_smask[newcpl])
662 		arm_do_pending_intr(newcpl);
663 	ci->ci_cpl = newcpl;
664 }
665 
666 void
667 arm_dflt_setipl(int newcpl)
668 {
669 	struct cpu_info *ci = curcpu();
670 
671 	ci->ci_cpl = newcpl;
672 }
673 
674 void
675 arm_do_pending_intr(int pcpl)
676 {
677 	struct cpu_info *ci = curcpu();
678 	u_long oldirqstate;
679 
680 	oldirqstate = intr_disable();
681 
682 #define DO_SOFTINT(si, ipl) \
683 	if ((ci->ci_ipending & arm_smask[pcpl]) &	\
684 	    SI_TO_IRQBIT(si)) {				\
685 		ci->ci_ipending &= ~SI_TO_IRQBIT(si);	\
686 		arm_intr_func.setipl(ipl);		\
687 		intr_restore(oldirqstate);		\
688 		softintr_dispatch(si);			\
689 		oldirqstate = intr_disable();		\
690 	}
691 
692 	do {
693 		DO_SOFTINT(SIR_TTY, IPL_SOFTTTY);
694 		DO_SOFTINT(SIR_NET, IPL_SOFTNET);
695 		DO_SOFTINT(SIR_CLOCK, IPL_SOFTCLOCK);
696 		DO_SOFTINT(SIR_SOFT, IPL_SOFT);
697 	} while (ci->ci_ipending & arm_smask[pcpl]);
698 
699 	/* Don't use splx... we are here already! */
700 	arm_intr_func.setipl(pcpl);
701 	intr_restore(oldirqstate);
702 }
703 
704 void
705 arm_set_intr_handler(int (*raise)(int), int (*lower)(int),
706     void (*x)(int), void (*setipl)(int), void (*irq_dispatch)(void *),
707     void (*fiq_dispatch)(void *), void (*enable_wakeup)(void),
708     void (*disable_wakeup)(void))
709 {
710 	arm_intr_func.raise = raise;
711 	arm_intr_func.lower = lower;
712 	arm_intr_func.x	= x;
713 	arm_intr_func.setipl = setipl;
714 	arm_intr_func.enable_wakeup = enable_wakeup;
715 	arm_intr_func.disable_wakeup = disable_wakeup;
716 
717 	if (irq_dispatch)
718 		arm_irq_dispatch = irq_dispatch;
719 	if (fiq_dispatch)
720 		arm_fiq_dispatch = fiq_dispatch;
721 }
722 
723 void
724 arm_init_smask(void)
725 {
726 	static int inited = 0;
727 	int i;
728 
729 	if (inited)
730 		return;
731 	inited = 1;
732 
733 	for (i = IPL_NONE; i <= IPL_HIGH; i++)  {
734 		arm_smask[i] = 0;
735 		if (i < IPL_SOFT)
736 			arm_smask[i] |= SI_TO_IRQBIT(SIR_SOFT);
737 		if (i < IPL_SOFTCLOCK)
738 			arm_smask[i] |= SI_TO_IRQBIT(SIR_CLOCK);
739 		if (i < IPL_SOFTNET)
740 			arm_smask[i] |= SI_TO_IRQBIT(SIR_NET);
741 		if (i < IPL_SOFTTTY)
742 			arm_smask[i] |= SI_TO_IRQBIT(SIR_TTY);
743 	}
744 }
745 
746 /* provide functions for asm */
747 #undef splraise
748 #undef spllower
749 #undef splx
750 
751 int
752 splraise(int ipl)
753 {
754 	return arm_intr_func.raise(ipl);
755 }
756 
757 int _spllower(int ipl); /* XXX - called from asm? */
758 int
759 _spllower(int ipl)
760 {
761 	return arm_intr_func.lower(ipl);
762 }
763 int
764 spllower(int ipl)
765 {
766 	return arm_intr_func.lower(ipl);
767 }
768 
769 void
770 splx(int ipl)
771 {
772 	arm_intr_func.x(ipl);
773 }
774 
775 
776 #ifdef DIAGNOSTIC
777 void
778 arm_splassert_check(int wantipl, const char *func)
779 {
780 	int oldipl = curcpu()->ci_cpl;
781 
782 	if (oldipl < wantipl) {
783 		splassert_fail(wantipl, oldipl, func);
784 		/*
785 		 * If the splassert_ctl is set to not panic, raise the ipl
786 		 * in a feeble attempt to reduce damage.
787 		 */
788 		arm_intr_func.setipl(wantipl);
789 	}
790 
791 	if (wantipl == IPL_NONE && curcpu()->ci_idepth != 0) {
792 		splassert_fail(-1, curcpu()->ci_idepth, func);
793 	}
794 }
795 #endif
796 
797 void arm_dflt_delay(u_int usecs);
798 
799 struct {
800 	void	(*delay)(u_int);
801 	void	(*initclocks)(void);
802 	void	(*setstatclockrate)(int);
803 	void	(*mpstartclock)(void);
804 } arm_clock_func = {
805 	arm_dflt_delay,
806 	NULL,
807 	NULL,
808 	NULL
809 };
810 
811 void
812 arm_clock_register(void (*initclock)(void), void (*delay)(u_int),
813     void (*statclock)(int), void(*mpstartclock)(void))
814 {
815 	if (arm_clock_func.initclocks)
816 		return;
817 
818 	arm_clock_func.initclocks = initclock;
819 	arm_clock_func.delay = delay;
820 	arm_clock_func.setstatclockrate = statclock;
821 	arm_clock_func.mpstartclock = mpstartclock;
822 }
823 
824 
825 void
826 delay(u_int usec)
827 {
828 	arm_clock_func.delay(usec);
829 }
830 
831 void
832 cpu_initclocks(void)
833 {
834 	if (arm_clock_func.initclocks == NULL)
835 		panic("initclocks function not initialized yet");
836 
837 	arm_clock_func.initclocks();
838 }
839 
840 void
841 cpu_startclock(void)
842 {
843 	if (arm_clock_func.mpstartclock == NULL)
844 		panic("startclock function not initialized yet");
845 
846 	arm_clock_func.mpstartclock();
847 }
848 
849 void
850 arm_dflt_delay(u_int usecs)
851 {
852 	int j;
853 	/* BAH - there is no good way to make this close */
854 	/* but this isn't supposed to be used after the real clock attaches */
855 	for (; usecs > 0; usecs--)
856 		for (j = 100; j > 0; j--)
857 			;
858 
859 }
860 
861 void
862 setstatclockrate(int new)
863 {
864 	if (arm_clock_func.setstatclockrate == NULL) {
865 		panic("arm_clock_func.setstatclockrate not initialized");
866 	}
867 	arm_clock_func.setstatclockrate(new);
868 }
869 
870 void
871 intr_barrier(void *cookie)
872 {
873 	struct machine_intr_handle *ih = cookie;
874 	struct interrupt_controller *ic = ih->ih_ic;
875 
876 	ic->ic_barrier(ih->ih_ih);
877 }
878 
879 void
880 intr_set_wakeup(void *cookie)
881 {
882 	struct machine_intr_handle *ih = cookie;
883 	struct interrupt_controller *ic = ih->ih_ic;
884 
885 	if (ic->ic_set_wakeup)
886 		ic->ic_set_wakeup(ih->ih_ih);
887 }
888 
889 void
890 intr_enable_wakeup(void)
891 {
892 	if (arm_intr_func.enable_wakeup)
893 		arm_intr_func.enable_wakeup();
894 }
895 
896 void
897 intr_disable_wakeup(void)
898 {
899 	if (arm_intr_func.disable_wakeup)
900 		arm_intr_func.disable_wakeup();
901 }
902 
903 /*
904  * IPI implementation
905  */
906 
907 void arm_no_send_ipi(struct cpu_info *ci, int id);
908 void (*intr_send_ipi_func)(struct cpu_info *, int) = arm_no_send_ipi;
909 
910 void
911 arm_send_ipi(struct cpu_info *ci, int id)
912 {
913 	(*intr_send_ipi_func)(ci, id);
914 }
915 
916 void
917 arm_no_send_ipi(struct cpu_info *ci, int id)
918 {
919 	panic("arm_send_ipi() called: no ipi function");
920 }
921