2 /* $NetBSD: interrupt.c,v 1.23 1998/02/24 07:38:01 thorpej Exp $ */
5 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
8 * Authors: Keith Bostic, Chris G. Demetriou
10 * Permission to use, copy, modify and distribute this software and
11 * its documentation is hereby granted, provided that both the copyright
12 * notice and this permission notice appear in all copies of the
13 * software, derivative works or modified versions, and any portions
14 * thereof, and that both notices appear in supporting documentation.
16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
18 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
20 * Carnegie Mellon requests users of this software to return to
22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
23 * School of Computer Science
24 * Carnegie Mellon University
25 * Pittsburgh PA 15213-3890
27 * any improvements or extensions that they make and grant Carnegie the
28 * rights to redistribute these changes.
31 * Additional Copyright (c) 1997 by Matthew Jacob for NASA/Ames Research Center.
32 * Redistribute and modify at will, leaving only this additional copyright
38 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
44 #include <sys/vmmeter.h>
46 #include <sys/interrupt.h>
47 #include <sys/malloc.h>
50 #include <sys/mutex.h>
51 #include <sys/sched.h>
53 #include <sys/sysctl.h>
54 #include <sys/syslog.h>
56 #include <machine/cpu.h>
57 #include <machine/fpu.h>
58 #include <machine/frame.h>
59 #include <machine/intr.h>
60 #include <machine/intrcnt.h>
61 #include <machine/md_var.h>
62 #include <machine/pcb.h>
63 #include <machine/reg.h>
64 #include <machine/smp.h>
71 struct intr_event *event; /* interrupt event */
72 volatile long *cntp; /* interrupt counter */
77 ia64_ihtype *ia64_handler[IA64_NXIVS];
79 static enum ia64_xiv_use ia64_xiv[IA64_NXIVS];
80 static struct ia64_intr *ia64_intrs[IA64_NXIVS];
82 static ia64_ihtype ia64_ih_invalid;
83 static ia64_ihtype ia64_ih_irq;
90 for (xiv = 0; xiv < IA64_NXIVS; xiv++) {
91 ia64_handler[xiv] = ia64_ih_invalid;
92 ia64_xiv[xiv] = IA64_XIV_FREE;
93 ia64_intrs[xiv] = NULL;
95 (void)ia64_xiv_reserve(15, IA64_XIV_ARCH, NULL);
99 ia64_xiv_free(u_int xiv, enum ia64_xiv_use what)
102 if (xiv >= IA64_NXIVS)
104 if (what == IA64_XIV_FREE || what == IA64_XIV_ARCH)
106 if (ia64_xiv[xiv] != what)
108 ia64_xiv[xiv] = IA64_XIV_FREE;
109 ia64_handler[xiv] = ia64_ih_invalid;
114 ia64_xiv_reserve(u_int xiv, enum ia64_xiv_use what, ia64_ihtype ih)
117 if (xiv >= IA64_NXIVS)
119 if (what == IA64_XIV_FREE)
121 if (ia64_xiv[xiv] != IA64_XIV_FREE)
123 ia64_xiv[xiv] = what;
124 ia64_handler[xiv] = (ih == NULL) ? ia64_ih_invalid: ih;
126 printf("XIV %u: use=%u, IH=%p\n", xiv, what, ih);
131 ia64_xiv_alloc(u_int prio, enum ia64_xiv_use what, ia64_ihtype ih)
137 if (hwprio > IA64_MAX_HWPRIO)
138 hwprio = IA64_MAX_HWPRIO;
140 xiv0 = IA64_NXIVS - (hwprio + 1) * 16;
142 KASSERT(xiv0 >= IA64_MIN_XIV, ("%s: min XIV", __func__));
143 KASSERT(xiv0 < IA64_NXIVS, ("%s: max XIV", __func__));
146 while (xiv < IA64_NXIVS && ia64_xiv_reserve(xiv, what, ih))
149 if (xiv < IA64_NXIVS)
153 while (xiv >= IA64_MIN_XIV && ia64_xiv_reserve(xiv, what, ih))
156 return ((xiv >= IA64_MIN_XIV) ? xiv : 0);
160 ia64_intr_eoi(void *arg)
162 u_int xiv = (uintptr_t)arg;
166 KASSERT(i != NULL, ("%s", __func__));
167 sapic_eoi(i->sapic, xiv);
171 ia64_intr_mask(void *arg)
173 u_int xiv = (uintptr_t)arg;
177 KASSERT(i != NULL, ("%s", __func__));
178 sapic_mask(i->sapic, i->irq);
179 sapic_eoi(i->sapic, xiv);
183 ia64_intr_unmask(void *arg)
185 u_int xiv = (uintptr_t)arg;
189 KASSERT(i != NULL, ("%s", __func__));
190 sapic_unmask(i->sapic, i->irq);
194 ia64_setup_intr(const char *name, int irq, driver_filter_t filter,
195 driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep)
203 prio = intr_priority(flags);
204 if (prio > PRI_MAX_ITHD)
209 /* Get the I/O SAPIC and XIV that corresponds to the IRQ. */
210 sa = sapic_lookup(irq, &xiv);
218 i = malloc(sizeof(struct ia64_intr), M_DEVBUF,
221 sa = sapic_lookup(irq, &xiv);
222 KASSERT(sa != NULL, ("sapic_lookup"));
228 * If the IRQ has no XIV assigned to it yet, assign one based
232 xiv = ia64_xiv_alloc(prio, IA64_XIV_IRQ, ia64_ih_irq);
239 error = intr_event_create(&i->event, (void *)(uintptr_t)xiv,
240 0, irq, ia64_intr_mask, ia64_intr_unmask, ia64_intr_eoi,
241 NULL, "irq%u:", irq);
243 ia64_xiv_free(xiv, IA64_XIV_IRQ);
251 i->cntp = intrcnt + xiv;
256 sapic_enable(sa, irq, xiv);
258 if (name != NULL && *name != '\0') {
259 /* XXX needs abstraction. Too error prone. */
260 intrname = intrnames + xiv * INTRNAME_LEN;
261 memset(intrname, ' ', INTRNAME_LEN - 1);
262 bcopy(name, intrname, strlen(name));
269 KASSERT(i != NULL, ("XIV mapping bug"));
271 error = intr_event_add_handler(i->event, name, filter, handler, arg,
272 prio, flags, cookiep);
277 ia64_teardown_intr(void *cookie)
280 return (intr_event_remove_handler(cookie));
292 for (xiv = IA64_NXIVS - 1; xiv >= IA64_MIN_XIV; xiv--) {
293 if (ia64_xiv[xiv] != IA64_XIV_IRQ)
297 cpu = (cpu == 0) ? MAXCPU - 1 : cpu - 1;
298 pc = cpuid_to_pcpu[cpu];
299 } while (pc == NULL || !pc->pc_md.awake);
300 sapic_bind_intr(i->irq, pc);
305 * Interrupt handlers.
309 ia64_handle_intr(struct trapframe *tf)
315 ia64_set_fpsr(IA64_FPSR_DEFAULT);
316 PCPU_INC(cnt.v_intr);
318 xiv = ia64_get_ivr();
321 PCPU_INC(md.stats.pcs_nstrays);
328 CTR2(KTR_INTR, "INTR: ITC=%u, XIV=%u",
329 (u_int)tf->tf_special.ifa, xiv);
330 (ia64_handler[xiv])(td, xiv, tf);
333 xiv = ia64_get_ivr();
340 if (TRAPF_USERMODE(tf)) {
341 while (td->td_flags & (TDF_ASTPENDING|TDF_NEEDRESCHED)) {
350 ia64_ih_invalid(struct thread *td, u_int xiv, struct trapframe *tf)
353 panic("invalid XIV: %u", xiv);
358 ia64_ih_irq(struct thread *td, u_int xiv, struct trapframe *tf)
361 struct intr_event *ie; /* our interrupt event */
363 PCPU_INC(md.stats.pcs_nhwints);
365 /* Find the interrupt thread for this XIV. */
367 KASSERT(i != NULL, ("%s: unassigned XIV", __func__));
372 KASSERT(ie != NULL, ("%s: interrupt without event", __func__));
374 if (intr_event_handle(ie, tf) != 0) {
375 ia64_intr_mask((void *)(uintptr_t)xiv);
376 log(LOG_ERR, "stray irq%u\n", i->irq);
385 db_print_xiv(u_int xiv, int always)
391 db_printf("XIV %u (%p): ", xiv, i);
392 sapic_print(i->sapic, i->irq);
394 db_printf("XIV %u: unassigned\n", xiv);
397 DB_SHOW_COMMAND(xiv, db_show_xiv)
402 xiv = ((addr >> 4) % 16) * 10 + (addr % 16);
403 if (xiv >= IA64_NXIVS)
404 db_printf("error: XIV %u not in range [0..%u]\n",
405 xiv, IA64_NXIVS - 1);
407 db_print_xiv(xiv, 1);
409 for (xiv = 0; xiv < IA64_NXIVS; xiv++)
410 db_print_xiv(xiv, 0);