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