1 /* 2 * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 10 #include <int.h> 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 16 #include <arch/debug_console.h> 17 #include <arch/int.h> 18 #include <boot/kernel_args.h> 19 #include <elf.h> 20 #include <util/kqueue.h> 21 #include <smp.h> 22 23 #include "kernel_debug_config.h" 24 25 26 //#define TRACE_INT 27 #ifdef TRACE_INT 28 # define TRACE(x) dprintf x 29 #else 30 # define TRACE(x) ; 31 #endif 32 33 34 struct io_handler { 35 struct io_handler *next; 36 interrupt_handler func; 37 void *data; 38 bool use_enable_counter; 39 bool no_handled_info; 40 #if DEBUG_INTERRUPTS 41 int64 handled_count; 42 #endif 43 }; 44 45 struct io_vector { 46 struct io_handler *handler_list; 47 spinlock vector_lock; 48 int32 enable_count; 49 bool no_lock_vector; 50 #if DEBUG_INTERRUPTS 51 int64 handled_count; 52 int64 unhandled_count; 53 int trigger_count; 54 int ignored_count; 55 #endif 56 }; 57 58 static struct io_vector sVectors[NUM_IO_VECTORS]; 59 60 61 #if DEBUG_INTERRUPTS 62 static int 63 dump_int_statistics(int argc, char **argv) 64 { 65 int i; 66 for (i = 0; i < NUM_IO_VECTORS; i++) { 67 struct io_handler *io; 68 69 if (!B_SPINLOCK_IS_LOCKED(&sVectors[i].vector_lock) 70 && sVectors[i].enable_count == 0 71 && sVectors[i].handled_count == 0 72 && sVectors[i].unhandled_count == 0 73 && sVectors[i].handler_list == NULL) 74 continue; 75 76 kprintf("int %3d, enabled %ld, handled %8lld, unhandled %8lld%s%s\n", 77 i, sVectors[i].enable_count, sVectors[i].handled_count, 78 sVectors[i].unhandled_count, 79 B_SPINLOCK_IS_LOCKED(&sVectors[i].vector_lock) ? ", ACTIVE" : "", 80 sVectors[i].handler_list == NULL ? ", no handler" : ""); 81 82 for (io = sVectors[i].handler_list; io != NULL; io = io->next) { 83 const char *symbol, *imageName; 84 bool exactMatch; 85 86 status_t error = elf_debug_lookup_symbol_address((addr_t)io->func, 87 NULL, &symbol, &imageName, &exactMatch); 88 if (error == B_OK && exactMatch) { 89 if (strchr(imageName, '/') != NULL) 90 imageName = strrchr(imageName, '/') + 1; 91 92 int length = 4 + strlen(imageName); 93 kprintf(" %s:%-*s (%p)", imageName, 45 - length, symbol, 94 io->func); 95 } else 96 kprintf("\t\t\t\t\t func %p", io->func); 97 98 kprintf(", data %p, handled ", io->data); 99 if (io->no_handled_info) 100 kprintf("<unknown>\n"); 101 else 102 kprintf("%8lld\n", io->handled_count); 103 } 104 105 kprintf("\n"); 106 } 107 return 0; 108 } 109 #endif 110 111 112 // #pragma mark - private kernel API 113 114 115 bool 116 interrupts_enabled(void) 117 { 118 return arch_int_are_interrupts_enabled(); 119 } 120 121 122 status_t 123 int_init(kernel_args* args) 124 { 125 TRACE(("init_int_handlers: entry\n")); 126 127 return arch_int_init(args); 128 } 129 130 131 status_t 132 int_init_post_vm(kernel_args* args) 133 { 134 int i; 135 136 /* initialize the vector list */ 137 for (i = 0; i < NUM_IO_VECTORS; i++) { 138 B_INITIALIZE_SPINLOCK(&sVectors[i].vector_lock); 139 sVectors[i].enable_count = 0; 140 sVectors[i].no_lock_vector = false; 141 #if DEBUG_INTERRUPTS 142 sVectors[i].handled_count = 0; 143 sVectors[i].unhandled_count = 0; 144 sVectors[i].trigger_count = 0; 145 sVectors[i].ignored_count = 0; 146 #endif 147 sVectors[i].handler_list = NULL; 148 } 149 150 #if DEBUG_INTERRUPTS 151 add_debugger_command("ints", &dump_int_statistics, 152 "list interrupt statistics"); 153 #endif 154 155 return arch_int_init_post_vm(args); 156 } 157 158 159 status_t 160 int_init_io(kernel_args* args) 161 { 162 return arch_int_init_io(args); 163 } 164 165 166 status_t 167 int_init_post_device_manager(kernel_args* args) 168 { 169 arch_debug_install_interrupt_handlers(); 170 171 return arch_int_init_post_device_manager(args); 172 } 173 174 175 /*! Actually process an interrupt via the handlers registered for that 176 vector (IRQ). 177 */ 178 int 179 int_io_interrupt_handler(int vector, bool levelTriggered) 180 { 181 int status = B_UNHANDLED_INTERRUPT; 182 struct io_handler* io; 183 bool handled = false; 184 185 if (!sVectors[vector].no_lock_vector) 186 acquire_spinlock(&sVectors[vector].vector_lock); 187 188 #if !DEBUG_INTERRUPTS 189 // The list can be empty at this place 190 if (sVectors[vector].handler_list == NULL) { 191 dprintf("unhandled io interrupt %d\n", vector); 192 if (!sVectors[vector].no_lock_vector) 193 release_spinlock(&sVectors[vector].vector_lock); 194 return B_UNHANDLED_INTERRUPT; 195 } 196 #endif 197 198 // For level-triggered interrupts, we actually handle the return 199 // value (ie. B_HANDLED_INTERRUPT) to decide wether or not we 200 // want to call another interrupt handler. 201 // For edge-triggered interrupts, however, we always need to call 202 // all handlers, as multiple interrupts cannot be identified. We 203 // still make sure the return code of this function will issue 204 // whatever the driver thought would be useful. 205 206 for (io = sVectors[vector].handler_list; io != NULL; io = io->next) { 207 status = io->func(io->data); 208 209 #if DEBUG_INTERRUPTS 210 if (status != B_UNHANDLED_INTERRUPT) 211 io->handled_count++; 212 #endif 213 if (levelTriggered && status != B_UNHANDLED_INTERRUPT) 214 break; 215 216 if (status == B_HANDLED_INTERRUPT || status == B_INVOKE_SCHEDULER) 217 handled = true; 218 } 219 220 #if DEBUG_INTERRUPTS 221 sVectors[vector].trigger_count++; 222 if (status != B_UNHANDLED_INTERRUPT || handled) { 223 sVectors[vector].handled_count++; 224 } else { 225 sVectors[vector].unhandled_count++; 226 sVectors[vector].ignored_count++; 227 } 228 229 if (sVectors[vector].trigger_count > 10000) { 230 if (sVectors[vector].ignored_count > 9900) { 231 struct io_handler *last = sVectors[vector].handler_list; 232 while (last && last->next) 233 last = last->next; 234 235 if (last != NULL && last->no_handled_info) { 236 // we have an interrupt handler installed that does not 237 // know whether or not it has actually handled the interrupt, 238 // so this unhandled count is inaccurate and we can't just 239 // disable 240 } else { 241 if (sVectors[vector].handler_list == NULL 242 || sVectors[vector].handler_list->next == NULL) { 243 // this interrupt vector is not shared, disable it 244 sVectors[vector].enable_count = -100; 245 arch_int_disable_io_interrupt(vector); 246 dprintf("Disabling unhandled io interrupt %d\n", vector); 247 } else { 248 // this is a shared interrupt vector, we cannot just disable it 249 dprintf("More than 99%% interrupts of vector %d are unhandled\n", 250 vector); 251 } 252 } 253 } 254 255 sVectors[vector].trigger_count = 0; 256 sVectors[vector].ignored_count = 0; 257 } 258 #endif 259 260 if (!sVectors[vector].no_lock_vector) 261 release_spinlock(&sVectors[vector].vector_lock); 262 263 if (levelTriggered) 264 return status; 265 266 // edge triggered return value 267 268 if (handled) 269 return B_HANDLED_INTERRUPT; 270 271 return B_UNHANDLED_INTERRUPT; 272 } 273 274 275 // #pragma mark - public API 276 277 278 #undef disable_interrupts 279 #undef restore_interrupts 280 281 282 cpu_status 283 disable_interrupts(void) 284 { 285 return arch_int_disable_interrupts(); 286 } 287 288 289 void 290 restore_interrupts(cpu_status status) 291 { 292 arch_int_restore_interrupts(status); 293 } 294 295 296 /*! Install a handler to be called when an interrupt is triggered 297 for the given interrupt number with \a data as the argument. 298 */ 299 status_t 300 install_io_interrupt_handler(long vector, interrupt_handler handler, void *data, 301 ulong flags) 302 { 303 struct io_handler *io = NULL; 304 cpu_status state; 305 306 if (vector < 0 || vector >= NUM_IO_VECTORS) 307 return B_BAD_VALUE; 308 309 io = (struct io_handler *)malloc(sizeof(struct io_handler)); 310 if (io == NULL) 311 return B_NO_MEMORY; 312 313 arch_debug_remove_interrupt_handler(vector); 314 // There might be a temporary debug interrupt installed on this 315 // vector that should be removed now. 316 317 io->func = handler; 318 io->data = data; 319 io->use_enable_counter = (flags & B_NO_ENABLE_COUNTER) == 0; 320 io->no_handled_info = (flags & B_NO_HANDLED_INFO) != 0; 321 #if DEBUG_INTERRUPTS 322 io->handled_count = 0LL; 323 #endif 324 325 // Disable the interrupts, get the spinlock for this irq only 326 // and then insert the handler 327 state = disable_interrupts(); 328 acquire_spinlock(&sVectors[vector].vector_lock); 329 330 if ((flags & B_NO_HANDLED_INFO) != 0 331 && sVectors[vector].handler_list != NULL) { 332 // The driver registering this interrupt handler doesn't know 333 // whether or not it actually handled the interrupt after the 334 // handler returns. This is incompatible with shared interrupts 335 // as we'd potentially steal interrupts from other handlers 336 // resulting in interrupt storms. Therefore we enqueue this interrupt 337 // handler as the very last one, meaning all other handlers will 338 // get their go at any interrupt first. 339 struct io_handler *last = sVectors[vector].handler_list; 340 while (last->next) 341 last = last->next; 342 343 io->next = NULL; 344 last->next = io; 345 } else { 346 // A normal interrupt handler, just add it to the head of the list. 347 io->next = sVectors[vector].handler_list; 348 sVectors[vector].handler_list = io; 349 } 350 351 // If B_NO_ENABLE_COUNTER is set, we're being asked to not alter 352 // whether the interrupt should be enabled or not 353 if (io->use_enable_counter) { 354 if (sVectors[vector].enable_count++ == 0) 355 arch_int_enable_io_interrupt(vector); 356 } 357 358 // If B_NO_LOCK_VECTOR is specified this is a vector that is not supposed 359 // to have multiple handlers and does not require locking of the vector 360 // when entering the handler. For example this is used by internally 361 // registered interrupt handlers like for handling local APIC interrupts 362 // that may run concurently on multiple CPUs. Locking with a spinlock 363 // would in that case defeat the purpose as it would serialize calling the 364 // handlers in parallel on different CPUs. 365 if (flags & B_NO_LOCK_VECTOR) 366 sVectors[vector].no_lock_vector = true; 367 368 release_spinlock(&sVectors[vector].vector_lock); 369 restore_interrupts(state); 370 371 return B_OK; 372 } 373 374 375 /*! Remove a previously installed interrupt handler */ 376 status_t 377 remove_io_interrupt_handler(long vector, interrupt_handler handler, void *data) 378 { 379 status_t status = B_BAD_VALUE; 380 struct io_handler *io = NULL; 381 struct io_handler *last = NULL; 382 cpu_status state; 383 384 if (vector < 0 || vector >= NUM_IO_VECTORS) 385 return B_BAD_VALUE; 386 387 /* lock the structures down so it is not modified while we search */ 388 state = disable_interrupts(); 389 acquire_spinlock(&sVectors[vector].vector_lock); 390 391 /* loop through the available handlers and try to find a match. 392 * We go forward through the list but this means we start with the 393 * most recently added handlers. 394 */ 395 for (io = sVectors[vector].handler_list; io != NULL; io = io->next) { 396 /* we have to match both function and data */ 397 if (io->func == handler && io->data == data) { 398 if (last != NULL) 399 last->next = io->next; 400 else 401 sVectors[vector].handler_list = io->next; 402 403 // Check if we need to disable the interrupt 404 if (io->use_enable_counter && --sVectors[vector].enable_count == 0) 405 arch_int_disable_io_interrupt(vector); 406 407 status = B_OK; 408 break; 409 } 410 411 last = io; 412 } 413 414 release_spinlock(&sVectors[vector].vector_lock); 415 restore_interrupts(state); 416 417 // if the handler could be found and removed, we still have to free it 418 if (status == B_OK) 419 free(io); 420 421 return status; 422 } 423 424