xref: /openbsd/sys/arch/armv7/armv7/intr.c (revision d5cabab1)
1 /* $OpenBSD: intr.c,v 1.23 2024/08/05 13:55:34 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/malloc.h>
21 
22 #include <arm/cpufunc.h>
23 #include <machine/cpu.h>
24 #include <machine/intr.h>
25 
26 #include <dev/ofw/openfirm.h>
27 
28 int arm_intr_get_parent(int);
29 uint32_t arm_intr_map_msi(int, uint64_t *);
30 
31 void *arm_intr_prereg_establish_fdt(void *, int *, int, struct cpu_info *,
32     int (*)(void *), void *, char *);
33 void arm_intr_prereg_disestablish_fdt(void *);
34 
35 int arm_dflt_splraise(int);
36 int arm_dflt_spllower(int);
37 void arm_dflt_splx(int);
38 void arm_dflt_setipl(int);
39 void *arm_dflt_intr_establish(int irqno, int level, struct cpu_info *,
40     int (*func)(void *), void *cookie, char *name);
41 void arm_dflt_intr_disestablish(void *cookie);
42 const char *arm_dflt_intr_string(void *cookie);
43 
44 void arm_dflt_intr(void *);
45 void arm_intr(void *);
46 
47 #define SI_TO_IRQBIT(x) (1 << (x))
48 uint32_t arm_smask[NIPL];
49 
50 struct arm_intr_func arm_intr_func = {
51 	arm_dflt_splraise,
52 	arm_dflt_spllower,
53 	arm_dflt_splx,
54 	arm_dflt_setipl,
55 	arm_dflt_intr_establish,
56 	arm_dflt_intr_disestablish,
57 	arm_dflt_intr_string
58 };
59 
60 void (*arm_intr_dispatch)(void *) = arm_dflt_intr;
61 
62 void
arm_intr(void * frame)63 arm_intr(void *frame)
64 {
65 	/* XXX - change this to have irq_dispatch use function pointer */
66 	(*arm_intr_dispatch)(frame);
67 }
68 void
arm_dflt_intr(void * frame)69 arm_dflt_intr(void *frame)
70 {
71 	panic("arm_dflt_intr() called");
72 }
73 
74 
75 void *
arm_intr_establish(int irqno,int level,int (* func)(void *),void * cookie,char * name)76 arm_intr_establish(int irqno, int level, int (*func)(void *),
77     void *cookie, char *name)
78 {
79 	return arm_intr_func.intr_establish(irqno, level, NULL, func, cookie, name);
80 }
81 
82 void
arm_intr_disestablish(void * cookie)83 arm_intr_disestablish(void *cookie)
84 {
85 	arm_intr_func.intr_disestablish(cookie);
86 }
87 
88 const char *
arm_intr_string(void * cookie)89 arm_intr_string(void *cookie)
90 {
91 	return arm_intr_func.intr_string(cookie);
92 }
93 
94 /*
95  * Find the interrupt parent by walking up the tree.
96  */
97 int
arm_intr_get_parent(int node)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
arm_intr_map_msi(int node,uint64_t * data)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 *
arm_intr_prereg_establish_fdt(void * cookie,int * cell,int level,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)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
arm_intr_prereg_disestablish_fdt(void * cookie)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
arm_intr_init_fdt_recurse(int node)250 arm_intr_init_fdt_recurse(int node)
251 {
252 	struct interrupt_controller *ic;
253 
254 	if (OF_getproplen(node, "interrupt-controller") >= 0) {
255 		ic = malloc(sizeof(struct interrupt_controller),
256 		    M_DEVBUF, M_ZERO | M_WAITOK);
257 		ic->ic_node = node;
258 		ic->ic_cookie = ic;
259 		ic->ic_establish = arm_intr_prereg_establish_fdt;
260 		ic->ic_disestablish = arm_intr_prereg_disestablish_fdt;
261 		arm_intr_register_fdt(ic);
262 	}
263 
264 	for (node = OF_child(node); node; node = OF_peer(node))
265 		arm_intr_init_fdt_recurse(node);
266 }
267 
268 void
arm_intr_init_fdt(void)269 arm_intr_init_fdt(void)
270 {
271 	int node = OF_peer(0);
272 
273 	if (node)
274 		arm_intr_init_fdt_recurse(node);
275 }
276 
277 LIST_HEAD(, interrupt_controller) interrupt_controllers =
278 	LIST_HEAD_INITIALIZER(interrupt_controllers);
279 
280 void
arm_intr_register_fdt(struct interrupt_controller * ic)281 arm_intr_register_fdt(struct interrupt_controller *ic)
282 {
283 	struct intr_prereg *ip, *tip;
284 
285 	ic->ic_cells = OF_getpropint(ic->ic_node, "#interrupt-cells", 0);
286 	ic->ic_phandle = OF_getpropint(ic->ic_node, "phandle", 0);
287 	KASSERT(ic->ic_cells <= MAX_INTERRUPT_CELLS);
288 
289 	LIST_INSERT_HEAD(&interrupt_controllers, ic, ic_list);
290 
291 	/* Establish pre-registered interrupt handlers. */
292 	LIST_FOREACH_SAFE(ip, &prereg_interrupts, ip_list, tip) {
293 		if (ip->ip_phandle != ic->ic_phandle)
294 			continue;
295 
296 		ip->ip_ic = ic;
297 		ip->ip_ih = ic->ic_establish(ic->ic_cookie, ip->ip_cell,
298 		    ip->ip_level, ip->ip_ci, ip->ip_func, ip->ip_arg,
299 		    ip->ip_name);
300 		if (ip->ip_ih == NULL)
301 			printf("can't establish interrupt %s\n", ip->ip_name);
302 
303 		LIST_REMOVE(ip, ip_list);
304 	}
305 }
306 
307 struct arm_intr_handle {
308 	struct interrupt_controller *ih_ic;
309 	void *ih_ih;
310 };
311 
312 void *
arm_intr_establish_fdt(int node,int level,int (* func)(void *),void * cookie,char * name)313 arm_intr_establish_fdt(int node, int level, int (*func)(void *),
314     void *cookie, char *name)
315 {
316 	return arm_intr_establish_fdt_idx(node, 0, level, func, cookie, name);
317 }
318 
319 void *
arm_intr_establish_fdt_cpu(int node,int level,struct cpu_info * ci,int (* func)(void *),void * cookie,char * name)320 arm_intr_establish_fdt_cpu(int node, int level, struct cpu_info *ci,
321     int (*func)(void *), void *cookie, char *name)
322 {
323 	return arm_intr_establish_fdt_idx_cpu(node, 0, level, ci, func,
324 	    cookie, name);
325 }
326 
327 void *
arm_intr_establish_fdt_idx(int node,int idx,int level,int (* func)(void *),void * cookie,char * name)328 arm_intr_establish_fdt_idx(int node, int idx, int level, int (*func)(void *),
329     void *cookie, char *name)
330 {
331 	return arm_intr_establish_fdt_idx_cpu(node, idx, level, NULL, func,
332 	    cookie, name);
333 }
334 
335 void *
arm_intr_establish_fdt_idx_cpu(int node,int idx,int level,struct cpu_info * ci,int (* func)(void *),void * cookie,char * name)336 arm_intr_establish_fdt_idx_cpu(int node, int idx, int level, struct cpu_info *ci,
337     int (*func)(void *), void *cookie, char *name)
338 {
339 	struct interrupt_controller *ic;
340 	int i, len, ncells, parent;
341 	int extended = 1;
342 	uint32_t *cell, *cells, phandle;
343 	struct arm_intr_handle *ih;
344 	void *val = NULL;
345 
346 	len = OF_getproplen(node, "interrupts-extended");
347 	if (len <= 0) {
348 		len = OF_getproplen(node, "interrupts");
349 		extended = 0;
350 	}
351 	if (len <= 0 || (len % sizeof(uint32_t) != 0))
352 		return NULL;
353 
354 	/* Old style. */
355 	if (!extended) {
356 		parent = arm_intr_get_parent(node);
357 		LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
358 			if (ic->ic_node == parent)
359 				break;
360 		}
361 
362 		if (ic == NULL)
363 			return NULL;
364 	}
365 
366 	cell = cells = malloc(len, M_TEMP, M_WAITOK);
367 	if (extended)
368 		OF_getpropintarray(node, "interrupts-extended", cells, len);
369 	else
370 		OF_getpropintarray(node, "interrupts", cells, len);
371 	ncells = len / sizeof(uint32_t);
372 
373 	for (i = 0; i <= idx && ncells > 0; i++) {
374 		if (extended) {
375 			phandle = cell[0];
376 
377 			/* Handle "empty" phandle reference. */
378 			if (phandle == 0) {
379 				cell++;
380 				ncells--;
381 				continue;
382 			}
383 
384 			LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
385 				if (ic->ic_phandle == phandle)
386 					break;
387 			}
388 
389 			if (ic == NULL)
390 				break;
391 
392 			cell++;
393 			ncells--;
394 		}
395 
396 		if (i == idx && ncells >= ic->ic_cells && ic->ic_establish) {
397 			val = ic->ic_establish(ic->ic_cookie, cell, level,
398 			    ci, func, cookie, name);
399 			break;
400 		}
401 
402 		cell += ic->ic_cells;
403 		ncells -= ic->ic_cells;
404 	}
405 
406 	free(cells, M_TEMP, len);
407 
408 	if (val == NULL)
409 		return NULL;
410 
411 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
412 	ih->ih_ic = ic;
413 	ih->ih_ih = val;
414 
415 	return ih;
416 }
417 
418 void *
arm_intr_establish_fdt_imap(int node,int * reg,int nreg,int level,int (* func)(void *),void * cookie,char * name)419 arm_intr_establish_fdt_imap(int node, int *reg, int nreg, int level,
420     int (*func)(void *), void *cookie, char *name)
421 {
422 	return arm_intr_establish_fdt_imap_cpu(node, reg, nreg, level, NULL,
423 	    func, cookie, name);
424 }
425 
426 void *
arm_intr_establish_fdt_imap_cpu(int node,int * reg,int nreg,int level,struct cpu_info * ci,int (* func)(void *),void * cookie,char * name)427 arm_intr_establish_fdt_imap_cpu(int node, int *reg, int nreg, int level,
428     struct cpu_info *ci, int (*func)(void *), void *cookie, char *name)
429 {
430 	struct interrupt_controller *ic;
431 	struct arm_intr_handle *ih;
432 	uint32_t *cell;
433 	uint32_t map_mask[4], *map;
434 	int len, acells, ncells;
435 	void *val = NULL;
436 
437 	if (nreg != sizeof(map_mask))
438 		return NULL;
439 
440 	if (OF_getpropintarray(node, "interrupt-map-mask", map_mask,
441 	    sizeof(map_mask)) != sizeof(map_mask))
442 		return NULL;
443 
444 	len = OF_getproplen(node, "interrupt-map");
445 	if (len <= 0)
446 		return NULL;
447 
448 	map = malloc(len, M_DEVBUF, M_WAITOK);
449 	OF_getpropintarray(node, "interrupt-map", map, len);
450 
451 	cell = map;
452 	ncells = len / sizeof(uint32_t);
453 	while (ncells > 5) {
454 		LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
455 			if (ic->ic_phandle == cell[4])
456 				break;
457 		}
458 
459 		if (ic == NULL)
460 			break;
461 
462 		acells = OF_getpropint(ic->ic_node, "#address-cells", 0);
463 		if (ncells >= (5 + acells + ic->ic_cells) &&
464 		    (reg[0] & map_mask[0]) == cell[0] &&
465 		    (reg[1] & map_mask[1]) == cell[1] &&
466 		    (reg[2] & map_mask[2]) == cell[2] &&
467 		    (reg[3] & map_mask[3]) == cell[3] &&
468 		    ic->ic_establish) {
469 			val = ic->ic_establish(ic->ic_cookie, &cell[5 + acells],
470 			    level, ci, func, cookie, name);
471 			break;
472 		}
473 
474 		cell += (5 + acells + ic->ic_cells);
475 		ncells -= (5 + acells + ic->ic_cells);
476 	}
477 
478 	if (val == NULL) {
479 		free(map, M_DEVBUF, len);
480 		return NULL;
481 	}
482 
483 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
484 	ih->ih_ic = ic;
485 	ih->ih_ih = val;
486 
487 	free(map, M_DEVBUF, len);
488 	return ih;
489 }
490 
491 void *
arm_intr_establish_fdt_msi(int node,uint64_t * addr,uint64_t * data,int level,int (* func)(void *),void * cookie,char * name)492 arm_intr_establish_fdt_msi(int node, uint64_t *addr, uint64_t *data,
493     int level, int (*func)(void *), void *cookie, char *name)
494 {
495 	return arm_intr_establish_fdt_msi_cpu(node, addr, data, level, NULL,
496 	    func, cookie, name);
497 }
498 
499 void *
arm_intr_establish_fdt_msi_cpu(int node,uint64_t * addr,uint64_t * data,int level,struct cpu_info * ci,int (* func)(void *),void * cookie,char * name)500 arm_intr_establish_fdt_msi_cpu(int node, uint64_t *addr, uint64_t *data,
501     int level, struct cpu_info *ci, int (*func)(void *), void *cookie,
502     char *name)
503 {
504 	struct interrupt_controller *ic;
505 	struct arm_intr_handle *ih;
506 	uint32_t phandle;
507 	void *val = NULL;
508 
509 	phandle = arm_intr_map_msi(node, data);
510 	LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
511 		if (ic->ic_phandle == phandle)
512 			break;
513 	}
514 
515 	if (ic == NULL || ic->ic_establish_msi == NULL)
516 		return NULL;
517 
518 	val = ic->ic_establish_msi(ic->ic_cookie, addr, data,
519 	    level, ci, func, cookie, name);
520 
521 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
522 	ih->ih_ic = ic;
523 	ih->ih_ih = val;
524 
525 	return ih;
526 }
527 
528 void
arm_intr_disestablish_fdt(void * cookie)529 arm_intr_disestablish_fdt(void *cookie)
530 {
531 	struct arm_intr_handle *ih = cookie;
532 	struct interrupt_controller *ic = ih->ih_ic;
533 
534 	ic->ic_disestablish(ih->ih_ih);
535 	free(ih, M_DEVBUF, sizeof(*ih));
536 }
537 
538 void
arm_intr_enable(void * cookie)539 arm_intr_enable(void *cookie)
540 {
541 	struct arm_intr_handle *ih = cookie;
542 	struct interrupt_controller *ic = ih->ih_ic;
543 
544 	KASSERT(ic->ic_enable != NULL);
545 	ic->ic_enable(ih->ih_ih);
546 }
547 
548 void
arm_intr_disable(void * cookie)549 arm_intr_disable(void *cookie)
550 {
551 	struct arm_intr_handle *ih = cookie;
552 	struct interrupt_controller *ic = ih->ih_ic;
553 
554 	KASSERT(ic->ic_disable != NULL);
555 	ic->ic_disable(ih->ih_ih);
556 }
557 
558 /*
559  * Some interrupt controllers transparently forward interrupts to
560  * their parent.  Such interrupt controllers can use this function to
561  * delegate the interrupt handler to their parent.
562  */
563 void *
arm_intr_parent_establish_fdt(void * cookie,int * cell,int level,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)564 arm_intr_parent_establish_fdt(void *cookie, int *cell, int level,
565     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
566 {
567 	struct interrupt_controller *ic = cookie;
568 	struct arm_intr_handle *ih;
569 	int parent;
570 	void *val;
571 
572 	parent = arm_intr_get_parent(ic->ic_node);
573 	LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
574 		if (ic->ic_node == parent)
575 			break;
576 	}
577 	if (ic == NULL)
578 		return NULL;
579 
580 	val = ic->ic_establish(ic->ic_cookie, cell, level, ci, func, arg, name);
581 	if (val == NULL)
582 		return NULL;
583 
584 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
585 	ih->ih_ic = ic;
586 	ih->ih_ih = val;
587 
588 	return ih;
589 }
590 
591 void
arm_intr_parent_disestablish_fdt(void * cookie)592 arm_intr_parent_disestablish_fdt(void *cookie)
593 {
594 	struct arm_intr_handle *ih = cookie;
595 	struct interrupt_controller *ic = ih->ih_ic;
596 
597 	ic->ic_disestablish(ih->ih_ih);
598 	free(ih, M_DEVBUF, sizeof(*ih));
599 }
600 
601 void
arm_intr_route(void * cookie,int enable,struct cpu_info * ci)602 arm_intr_route(void *cookie, int enable, struct cpu_info *ci)
603 {
604 	struct arm_intr_handle *ih = cookie;
605 	struct interrupt_controller *ic = ih->ih_ic;
606 
607 	if (ic->ic_route)
608 		ic->ic_route(ih->ih_ih, enable, ci);
609 }
610 
611 void
arm_intr_cpu_enable(void)612 arm_intr_cpu_enable(void)
613 {
614 	struct interrupt_controller *ic;
615 
616 	LIST_FOREACH(ic, &interrupt_controllers, ic_list)
617 		if (ic->ic_cpu_enable)
618 			ic->ic_cpu_enable();
619 }
620 
621 int
arm_dflt_splraise(int newcpl)622 arm_dflt_splraise(int newcpl)
623 {
624 	struct cpu_info *ci = curcpu();
625 	int oldcpl;
626 
627 	oldcpl = ci->ci_cpl;
628 
629 	if (newcpl < oldcpl)
630 		newcpl = oldcpl;
631 
632 	ci->ci_cpl = newcpl;
633 
634 	return oldcpl;
635 }
636 
637 int
arm_dflt_spllower(int newcpl)638 arm_dflt_spllower(int newcpl)
639 {
640 	struct cpu_info *ci = curcpu();
641 	int oldcpl;
642 
643 	oldcpl = ci->ci_cpl;
644 
645 	splx(newcpl);
646 
647 	return oldcpl;
648 }
649 
650 void
arm_dflt_splx(int newcpl)651 arm_dflt_splx(int newcpl)
652 {
653 	struct cpu_info *ci = curcpu();
654 
655 	if (ci->ci_ipending & arm_smask[newcpl])
656 		arm_do_pending_intr(newcpl);
657 	ci->ci_cpl = newcpl;
658 }
659 
660 void
arm_dflt_setipl(int newcpl)661 arm_dflt_setipl(int newcpl)
662 {
663 	struct cpu_info *ci = curcpu();
664 
665 	ci->ci_cpl = newcpl;
666 }
667 
668 void *
arm_dflt_intr_establish(int irqno,int level,struct cpu_info * ci,int (* func)(void *),void * cookie,char * name)669 arm_dflt_intr_establish(int irqno, int level, struct cpu_info *ci,
670     int (*func)(void *), void *cookie, char *name)
671 {
672 	panic("arm_dflt_intr_establish called");
673 }
674 
675 void
arm_dflt_intr_disestablish(void * cookie)676 arm_dflt_intr_disestablish(void *cookie)
677 {
678 	panic("arm_dflt_intr_disestablish called");
679 }
680 
681 const char *
arm_dflt_intr_string(void * cookie)682 arm_dflt_intr_string(void *cookie)
683 {
684 	panic("arm_dflt_intr_string called");
685 }
686 
687 void
arm_setsoftintr(int si)688 arm_setsoftintr(int si)
689 {
690 	struct cpu_info *ci = curcpu();
691 	int oldirqstate;
692 
693 	/* XXX atomic? */
694 	oldirqstate = disable_interrupts(PSR_I);
695 	ci->ci_ipending |= SI_TO_IRQBIT(si);
696 
697 	restore_interrupts(oldirqstate);
698 
699 	/* Process unmasked pending soft interrupts. */
700 	if (ci->ci_ipending & arm_smask[ci->ci_cpl])
701 		arm_do_pending_intr(ci->ci_cpl);
702 }
703 
704 void
arm_do_pending_intr(int pcpl)705 arm_do_pending_intr(int pcpl)
706 {
707 	struct cpu_info *ci = curcpu();
708 	int oldirqstate;
709 
710 	oldirqstate = disable_interrupts(PSR_I);
711 
712 #define DO_SOFTINT(si, ipl) \
713 	if ((ci->ci_ipending & arm_smask[pcpl]) &	\
714 	    SI_TO_IRQBIT(si)) {						\
715 		ci->ci_ipending &= ~SI_TO_IRQBIT(si);			\
716 		arm_intr_func.setipl(ipl);				\
717 		restore_interrupts(oldirqstate);			\
718 		softintr_dispatch(si);					\
719 		oldirqstate = disable_interrupts(PSR_I);		\
720 	}
721 
722 	do {
723 		DO_SOFTINT(SI_SOFTTTY, IPL_SOFTTTY);
724 		DO_SOFTINT(SI_SOFTNET, IPL_SOFTNET);
725 		DO_SOFTINT(SI_SOFTCLOCK, IPL_SOFTCLOCK);
726 		DO_SOFTINT(SI_SOFT, IPL_SOFT);
727 	} while (ci->ci_ipending & arm_smask[pcpl]);
728 
729 	/* Don't use splx... we are here already! */
730 	arm_intr_func.setipl(pcpl);
731 	restore_interrupts(oldirqstate);
732 }
733 
734 void
arm_set_intr_handler(int (* raise)(int),int (* lower)(int),void (* x)(int),void (* setipl)(int),void * (* intr_establish)(int irqno,int level,struct cpu_info * ci,int (* func)(void *),void * cookie,char * name),void (* intr_disestablish)(void * cookie),const char * (intr_string)(void * cookie),void (* intr_handle)(void *))735 arm_set_intr_handler(int (*raise)(int), int (*lower)(int),
736     void (*x)(int), void (*setipl)(int),
737 	void *(*intr_establish)(int irqno, int level, struct cpu_info *ci,
738 	    int (*func)(void *), void *cookie, char *name),
739 	void (*intr_disestablish)(void *cookie),
740 	const char *(intr_string)(void *cookie),
741 	void (*intr_handle)(void *))
742 {
743 	arm_intr_func.raise		= raise;
744 	arm_intr_func.lower		= lower;
745 	arm_intr_func.x			= x;
746 	arm_intr_func.setipl		= setipl;
747 	arm_intr_func.intr_establish	= intr_establish;
748 	arm_intr_func.intr_disestablish	= intr_disestablish;
749 	arm_intr_func.intr_string	= intr_string;
750 	arm_intr_dispatch		= intr_handle;
751 }
752 
753 void
arm_init_smask(void)754 arm_init_smask(void)
755 {
756 	static int inited = 0;
757 	int i;
758 
759 	if (inited)
760 		return;
761 	inited = 1;
762 
763 	for (i = IPL_NONE; i <= IPL_HIGH; i++)  {
764 		arm_smask[i] = 0;
765 		if (i < IPL_SOFT)
766 			arm_smask[i] |= SI_TO_IRQBIT(SI_SOFT);
767 		if (i < IPL_SOFTCLOCK)
768 			arm_smask[i] |= SI_TO_IRQBIT(SI_SOFTCLOCK);
769 		if (i < IPL_SOFTNET)
770 			arm_smask[i] |= SI_TO_IRQBIT(SI_SOFTNET);
771 		if (i < IPL_SOFTTTY)
772 			arm_smask[i] |= SI_TO_IRQBIT(SI_SOFTTTY);
773 	}
774 }
775 
776 /* provide functions for asm */
777 #undef splraise
778 #undef spllower
779 #undef splx
780 
781 int
splraise(int ipl)782 splraise(int ipl)
783 {
784 	return arm_intr_func.raise(ipl);
785 }
786 
787 int _spllower(int ipl); /* XXX - called from asm? */
788 int
_spllower(int ipl)789 _spllower(int ipl)
790 {
791 	return arm_intr_func.lower(ipl);
792 }
793 int
spllower(int ipl)794 spllower(int ipl)
795 {
796 	return arm_intr_func.lower(ipl);
797 }
798 
799 void
splx(int ipl)800 splx(int ipl)
801 {
802 	arm_intr_func.x(ipl);
803 }
804 
805 
806 #ifdef DIAGNOSTIC
807 void
arm_splassert_check(int wantipl,const char * func)808 arm_splassert_check(int wantipl, const char *func)
809 {
810 	int oldipl = curcpu()->ci_cpl;
811 
812 	if (oldipl < wantipl) {
813 		splassert_fail(wantipl, oldipl, func);
814 		/*
815 		 * If the splassert_ctl is set to not panic, raise the ipl
816 		 * in a feeble attempt to reduce damage.
817 		 */
818 		arm_intr_func.setipl(wantipl);
819 	}
820 
821 	if (wantipl == IPL_NONE && curcpu()->ci_idepth != 0) {
822 		splassert_fail(-1, curcpu()->ci_idepth, func);
823 	}
824 }
825 #endif
826 
827 void arm_dflt_delay(u_int usecs);
828 
829 struct {
830 	void	(*delay)(u_int);
831 	void	(*initclocks)(void);
832 	void	(*setstatclockrate)(int);
833 	void	(*mpstartclock)(void);
834 } arm_clock_func = {
835 	arm_dflt_delay,
836 	NULL,
837 	NULL,
838 	NULL
839 };
840 
841 void
arm_clock_register(void (* initclock)(void),void (* delay)(u_int),void (* statclock)(int),void (* mpstartclock)(void))842 arm_clock_register(void (*initclock)(void), void (*delay)(u_int),
843     void (*statclock)(int), void(*mpstartclock)(void))
844 {
845 	if (arm_clock_func.initclocks)
846 		return;
847 
848 	arm_clock_func.initclocks = initclock;
849 	arm_clock_func.delay = delay;
850 	arm_clock_func.setstatclockrate = statclock;
851 	arm_clock_func.mpstartclock = mpstartclock;
852 }
853 
854 
855 void
delay(u_int usec)856 delay(u_int usec)
857 {
858 	arm_clock_func.delay(usec);
859 }
860 
861 void
cpu_initclocks(void)862 cpu_initclocks(void)
863 {
864 	if (arm_clock_func.initclocks == NULL)
865 		panic("initclocks function not initialized yet");
866 
867 	arm_clock_func.initclocks();
868 }
869 
870 void
cpu_startclock(void)871 cpu_startclock(void)
872 {
873 	if (arm_clock_func.mpstartclock == NULL)
874 		panic("startclock function not initialized yet");
875 
876 	arm_clock_func.mpstartclock();
877 }
878 
879 void
arm_dflt_delay(u_int usecs)880 arm_dflt_delay(u_int usecs)
881 {
882 	int j;
883 	/* BAH - there is no good way to make this close */
884 	/* but this isn't supposed to be used after the real clock attaches */
885 	for (; usecs > 0; usecs--)
886 		for (j = 100; j > 0; j--)
887 			;
888 
889 }
890 
891 void
setstatclockrate(int new)892 setstatclockrate(int new)
893 {
894 	if (arm_clock_func.setstatclockrate == NULL) {
895 		panic("arm_clock_func.setstatclockrate not initialized");
896 	}
897 	arm_clock_func.setstatclockrate(new);
898 }
899 
900 void
intr_barrier(void * ih)901 intr_barrier(void *ih)
902 {
903 	sched_barrier(NULL);
904 }
905 
906 /*
907  * IPI implementation
908  */
909 
910 void arm_no_send_ipi(struct cpu_info *ci, int id);
911 void (*intr_send_ipi_func)(struct cpu_info *, int) = arm_no_send_ipi;
912 
913 void
arm_send_ipi(struct cpu_info * ci,int id)914 arm_send_ipi(struct cpu_info *ci, int id)
915 {
916 	(*intr_send_ipi_func)(ci, id);
917 }
918 
919 void
arm_no_send_ipi(struct cpu_info * ci,int id)920 arm_no_send_ipi(struct cpu_info *ci, int id)
921 {
922 	panic("arm_send_ipi() called: no ipi function");
923 }
924