interrupt.c revision 84541
1/* $FreeBSD: head/sys/ia64/ia64/interrupt.c 84541 2001-10-05 10:30:09Z dfr $ */ 2/* $NetBSD: interrupt.c,v 1.23 1998/02/24 07:38:01 thorpej Exp $ */ 3 4/* 5 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. 6 * All rights reserved. 7 * 8 * Authors: Keith Bostic, Chris G. Demetriou 9 * 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. 15 * 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. 19 * 20 * Carnegie Mellon requests users of this software to return to 21 * 22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 23 * School of Computer Science 24 * Carnegie Mellon University 25 * Pittsburgh PA 15213-3890 26 * 27 * any improvements or extensions that they make and grant Carnegie the 28 * rights to redistribute these changes. 29 */ 30/* 31 * Additional Copyright (c) 1997 by Matthew Jacob for NASA/Ames Research Center. 32 * Redistribute and modify at will, leaving only this additional copyright 33 * notice. 34 */ 35 36#include "opt_ddb.h" 37 38#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 39 40/* __KERNEL_RCSID(0, "$NetBSD: interrupt.c,v 1.23 1998/02/24 07:38:01 thorpej Exp $");*/ 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/kernel.h> 45#include <sys/proc.h> 46#include <sys/vmmeter.h> 47#include <sys/bus.h> 48#include <sys/malloc.h> 49#include <sys/ktr.h> 50#include <sys/lock.h> 51#include <sys/mutex.h> 52 53#include <machine/clock.h> 54#include <machine/reg.h> 55#include <machine/frame.h> 56#include <machine/intr.h> 57#include <machine/sapicvar.h> 58 59#ifdef EVCNT_COUNTERS 60struct evcnt clock_intr_evcnt; /* event counter for clock intrs. */ 61#else 62#include <sys/interrupt.h> 63#include <machine/intrcnt.h> 64#endif 65 66#ifdef DDB 67#include <ddb/ddb.h> 68#endif 69 70volatile int mc_expected, mc_received; 71 72static void 73dummy_perf(unsigned long vector, struct trapframe *framep) 74{ 75 printf("performance interrupt!\n"); 76} 77 78void (*perf_irq)(unsigned long, struct trapframe *) = dummy_perf; 79 80 81static u_int schedclk2; 82 83void 84interrupt(u_int64_t vector, struct trapframe *framep) 85{ 86 struct thread *td; 87 volatile struct ia64_interrupt_block *ib = IA64_INTERRUPT_BLOCK; 88 89 td = curthread; 90 atomic_add_int(&td->td_intr_nesting_level, 1); 91 92 /* 93 * Handle ExtINT interrupts by generating an INTA cycle to 94 * read the vector. 95 */ 96 if (vector == 0) { 97 vector = ib->ib_inta; 98 printf("ExtINT interrupt: vector=%ld\n", vector); 99 goto out; /* XXX */ 100 } 101 102 if (vector == 240) {/* clock interrupt */ 103 /* CTR0(KTR_INTR, "clock interrupt"); */ 104 105 cnt.v_intr++; 106#ifdef EVCNT_COUNTERS 107 clock_intr_evcnt.ev_count++; 108#else 109 intrcnt[INTRCNT_CLOCK]++; 110#endif 111 handleclock(framep); 112 113 /* divide hz (1024) by 8 to get stathz (128) */ 114 if((++schedclk2 & 0x7) == 0) 115 statclock((struct clockframe *)framep); 116 } else { 117 ia64_dispatch_intr(framep, vector); 118 } 119 120 out: 121 atomic_subtract_int(&td->td_intr_nesting_level, 1); 122} 123 124int 125badaddr(addr, size) 126 void *addr; 127 size_t size; 128{ 129 return(badaddr_read(addr, size, NULL)); 130} 131 132int 133badaddr_read(addr, size, rptr) 134 void *addr; 135 size_t size; 136 void *rptr; 137{ 138 return (1); /* XXX implement */ 139} 140 141/* 142 * Hardware irqs have vectors starting at this offset. 143 */ 144#define IA64_HARDWARE_IRQ_BASE 0x20 145 146struct ia64_intr { 147 struct ithd *ithd; /* interrupt thread */ 148 volatile long *cntp; /* interrupt counter */ 149}; 150 151static struct sapic *ia64_sapics[16]; /* XXX make this resizable */ 152static int ia64_sapic_count; 153static struct mtx ia64_intrs_lock; 154static struct ia64_intr *ia64_intrs[256]; 155 156static void ithds_init(void *dummy); 157 158static void 159ithds_init(void *dummy) 160{ 161 162 mtx_init(&ia64_intrs_lock, "ithread table lock", MTX_SPIN); 163} 164SYSINIT(ithds_init, SI_SUB_INTR, SI_ORDER_SECOND, ithds_init, NULL); 165 166void 167ia64_add_sapic(struct sapic *sa) 168{ 169 ia64_sapics[ia64_sapic_count++] = sa; 170} 171 172static void 173ia64_enable(int vector) 174{ 175 int irq, i; 176 177 irq = vector - IA64_HARDWARE_IRQ_BASE; 178 for (i = 0; i < ia64_sapic_count; i++) { 179 struct sapic *sa = ia64_sapics[i]; 180 if (irq >= sa->sa_base && irq <= sa->sa_limit) 181 sapic_enable(sa, irq - sa->sa_base, vector, 182 (irq < 16 183 ? SAPIC_TRIGGER_EDGE 184 : SAPIC_TRIGGER_LEVEL), 185 (irq < 16 186 ? SAPIC_POLARITY_HIGH 187 : SAPIC_POLARITY_LOW)); 188 } 189} 190 191static void 192ia64_send_eoi(int vector) 193{ 194 int irq, i; 195 196 irq = vector - IA64_HARDWARE_IRQ_BASE; 197 for (i = 0; i < ia64_sapic_count; i++) { 198 struct sapic *sa = ia64_sapics[i]; 199 if (irq >= sa->sa_base && irq <= sa->sa_limit) 200 sapic_eoi(sa, vector); 201 } 202} 203 204int 205ia64_setup_intr(const char *name, int irq, driver_intr_t handler, void *arg, 206 enum intr_type flags, void **cookiep, volatile long *cntp) 207{ 208 struct ia64_intr *i; 209 int errcode; 210 int vector = irq + IA64_HARDWARE_IRQ_BASE; 211 212 /* 213 * XXX - Can we have more than one device on a vector? If so, we have 214 * a race condition here that needs to be worked around similar to 215 * the fashion done in the i386 inthand_add() function. 216 */ 217 218 /* First, check for an existing hash table entry for this vector. */ 219 mtx_lock_spin(&ia64_intrs_lock); 220 i = ia64_intrs[vector]; 221 mtx_unlock_spin(&ia64_intrs_lock); 222 223 if (i == NULL) { 224 /* None was found, so create an entry. */ 225 i = malloc(sizeof(struct ia64_intr), M_DEVBUF, M_NOWAIT); 226 if (i == NULL) 227 return ENOMEM; 228 i->cntp = cntp; 229 errcode = ithread_create(&i->ithd, vector, 0, 0, 230 ia64_send_eoi, "intr:"); 231 if (errcode) { 232 free(i, M_DEVBUF); 233 return errcode; 234 } 235 236 mtx_lock_spin(&ia64_intrs_lock); 237 ia64_intrs[vector] = i; 238 mtx_unlock_spin(&ia64_intrs_lock); 239 } 240 241 /* Second, add this handler. */ 242 errcode = ithread_add_handler(i->ithd, name, handler, arg, 243 ithread_priority(flags), flags, cookiep); 244 if (errcode) 245 return errcode; 246 247 ia64_enable(vector); 248 return 0; 249} 250 251int 252ia64_teardown_intr(void *cookie) 253{ 254 255 return (ithread_remove_handler(cookie)); 256} 257 258void 259ia64_dispatch_intr(void *frame, unsigned long vector) 260{ 261 struct ia64_intr *i; 262 struct ithd *ithd; /* our interrupt thread */ 263 struct intrhand *ih; 264 int error; 265 266 /* 267 * Find the interrupt thread for this vector. 268 */ 269 i = ia64_intrs[vector]; 270 if (i == NULL) 271 return; /* no ithread for this vector */ 272 273 ithd = i->ithd; 274 KASSERT(ithd != NULL, ("interrupt vector without a thread")); 275 276 /* 277 * As an optomization, if an ithread has no handlers, don't 278 * schedule it to run. 279 */ 280 if (TAILQ_EMPTY(&ithd->it_handlers)) 281 return; 282 283 if (i->cntp) 284 atomic_add_long(i->cntp, 1); 285 286 /* 287 * Handle a fast interrupt if there is no actual thread for this 288 * interrupt by calling the handler directly without Giant. Note 289 * that this means that any fast interrupt handler must be MP safe. 290 */ 291 ih = TAILQ_FIRST(&ithd->it_handlers); 292 if ((ih->ih_flags & IH_FAST) != 0) { 293 ih->ih_handler(ih->ih_argument); 294 ia64_send_eoi(vector); 295 return; 296 } 297 298 error = ithread_schedule(ithd, 0); /* XXX:no preemption for now */ 299 KASSERT(error == 0, ("got an impossible stray interrupt")); 300} 301 302