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