Changes in kernel/generic/src/ddi/irq.c [431c402:ee50130] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ddi/irq.c
r431c402 ree50130 32 32 /** 33 33 * @file 34 * @brief IRQ dispatcher 35 * 36 * This file provides means of connecting IRQs with respective device drivers 37 * and logic for dispatching interrupts to IRQ handlers defined by those 38 * drivers. 34 * @brief IRQ dispatcher. 35 * 36 * This file provides means of connecting IRQs with particular devices and logic 37 * for dispatching interrupts to IRQ handlers defined by those devices. 38 * 39 * This code is designed to support: 40 * - multiple devices sharing single IRQ 41 * - multiple IRQs per single device 42 * - multiple instances of the same device 43 * 44 * 45 * Note about architectures. 46 * 47 * Some architectures have the term IRQ well defined. Examples of such 48 * architectures include amd64, ia32 and mips32. Some other architectures, such 49 * as sparc64, don't use the term at all. In those cases, we boldly step forward 50 * and define what an IRQ is. 51 * 52 * The implementation is generic enough and still allows the architectures to 53 * use the hardware layout effectively. For instance, on amd64 and ia32, where 54 * there is only 16 IRQs, the irq_hash_table can be optimized to a 55 * one-dimensional array. Next, when it is known that the IRQ numbers (aka 56 * INR's) are unique, the claim functions can always return IRQ_ACCEPT. 57 * 58 * 59 * Note about the irq_hash_table. 60 * 61 * The hash table is configured to use two keys: inr and devno. However, the 62 * hash index is computed only from inr. Moreover, if devno is -1, the match is 63 * based on the return value of the claim() function instead of on devno. 39 64 */ 40 65 … … 49 74 #include <arch.h> 50 75 51 slab_cache_t *irq_slab = NULL; 52 53 /** Spinlock protecting the kernel IRQ hash table 76 #define KEY_INR 0 77 #define KEY_DEVNO 1 78 79 /** Spinlock protecting the kernel IRQ hash table. 54 80 * 55 81 * This lock must be taken only when interrupts are disabled. … … 61 87 static hash_table_t irq_kernel_hash_table; 62 88 63 /** Spinlock protecting the uspace IRQ hash table 89 /** Spinlock protecting the uspace IRQ hash table. 64 90 * 65 91 * This lock must be taken only when interrupts are disabled. … … 68 94 IRQ_SPINLOCK_INITIALIZE(irq_uspace_hash_table_lock); 69 95 70 /** The uspace IRQ hash table */96 /** The uspace IRQ hash table. */ 71 97 hash_table_t irq_uspace_hash_table; 72 98 99 /** 100 * Hash table operations for cases when we know that there will be collisions 101 * between different keys. 102 */ 73 103 static size_t irq_ht_hash(sysarg_t *key); 74 104 static bool irq_ht_compare(sysarg_t *key, size_t keys, link_t *item); … … 81 111 }; 82 112 83 /** Number of buckets in either of the hash tables */ 113 /** 114 * Hash table operations for cases when we know that there will be no collisions 115 * between different keys. However, there might be still collisions among 116 * elements with single key (sharing of one IRQ). 117 */ 118 static size_t irq_lin_hash(sysarg_t *key); 119 static bool irq_lin_compare(sysarg_t *key, size_t keys, link_t *item); 120 static void irq_lin_remove(link_t *item); 121 122 static hash_table_operations_t irq_lin_ops = { 123 .hash = irq_lin_hash, 124 .compare = irq_lin_compare, 125 .remove_callback = irq_lin_remove, 126 }; 127 128 /** Number of buckets in either of the hash tables. */ 84 129 static size_t buckets; 85 130 86 /** Last valid INR */131 /** Last valid INR. */ 87 132 inr_t last_inr = 0; 88 133 89 /** Initialize IRQ subsystem 90 * 91 * @param inrs 92 * @param chains Number of buckets in the hash table.134 /** Initialize IRQ subsystem. 135 * 136 * @param inrs Numbers of unique IRQ numbers or INRs. 137 * @param chains Number of chains in the hash table. 93 138 * 94 139 */ … … 98 143 last_inr = inrs - 1; 99 144 100 irq_slab = slab_cache_create("irq_t", sizeof(irq_t), 0, NULL, NULL, 101 FRAME_ATOMIC); 102 assert(irq_slab); 103 104 hash_table_create(&irq_uspace_hash_table, chains, 2, &irq_ht_ops); 105 hash_table_create(&irq_kernel_hash_table, chains, 2, &irq_ht_ops); 106 } 107 108 /** Initialize one IRQ structure 109 * 110 * @param irq Pointer to the IRQ structure to be initialized. 145 /* 146 * Be smart about the choice of the hash table operations. In cases in 147 * which inrs equals the requested number of chains (i.e. where there is 148 * no collision between different keys), we can use optimized set of 149 * operations. 150 */ 151 if (inrs == chains) { 152 hash_table_create(&irq_uspace_hash_table, chains, 2, 153 &irq_lin_ops); 154 hash_table_create(&irq_kernel_hash_table, chains, 2, 155 &irq_lin_ops); 156 } else { 157 hash_table_create(&irq_uspace_hash_table, chains, 2, 158 &irq_ht_ops); 159 hash_table_create(&irq_kernel_hash_table, chains, 2, 160 &irq_ht_ops); 161 } 162 } 163 164 /** Initialize one IRQ structure. 165 * 166 * @param irq Pointer to the IRQ structure to be initialized. 111 167 * 112 168 */ … … 116 172 link_initialize(&irq->link); 117 173 irq_spinlock_initialize(&irq->lock, "irq.lock"); 174 link_initialize(&irq->notif_cfg.link); 118 175 irq->inr = -1; 176 irq->devno = -1; 119 177 120 178 irq_initialize_arch(irq); 121 179 } 122 180 123 /** Register IRQ for device 181 /** Register IRQ for device. 124 182 * 125 183 * The irq structure must be filled with information about the interrupt source 126 184 * and with the claim() function pointer and handler() function pointer. 127 185 * 128 * @param irq 186 * @param irq IRQ structure belonging to a device. 129 187 * 130 188 */ … … 132 190 { 133 191 sysarg_t key[] = { 134 [IRQ_HT_KEY_INR] =(sysarg_t) irq->inr,135 [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_NO_CLAIM192 (sysarg_t) irq->inr, 193 (sysarg_t) irq->devno 136 194 }; 137 195 … … 143 201 } 144 202 145 /** Search and lock the uspace IRQ hash table */ 203 /** Search and lock the uspace IRQ hash table. 204 * 205 */ 146 206 static irq_t *irq_dispatch_and_lock_uspace(inr_t inr) 147 207 { 148 208 link_t *lnk; 149 209 sysarg_t key[] = { 150 [IRQ_HT_KEY_INR] =(sysarg_t) inr,151 [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_CLAIM210 (sysarg_t) inr, 211 (sysarg_t) -1 /* Search will use claim() instead of devno */ 152 212 }; 153 213 … … 164 224 } 165 225 166 /** Search and lock the kernel IRQ hash table */ 226 /** Search and lock the kernel IRQ hash table. 227 * 228 */ 167 229 static irq_t *irq_dispatch_and_lock_kernel(inr_t inr) 168 230 { 169 231 link_t *lnk; 170 232 sysarg_t key[] = { 171 [IRQ_HT_KEY_INR] =(sysarg_t) inr,172 [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_CLAIM233 (sysarg_t) inr, 234 (sysarg_t) -1 /* Search will use claim() instead of devno */ 173 235 }; 174 236 … … 185 247 } 186 248 187 /** Dispatch the IRQ 249 /** Dispatch the IRQ. 188 250 * 189 251 * We assume this function is only called from interrupt context (i.e. that … … 193 255 * return with interrupts disabled and holding the respective structure. 194 256 * 195 * @param inr 257 * @param inr Interrupt number (aka inr or irq). 196 258 * 197 259 * @return IRQ structure of the respective device … … 223 285 } 224 286 225 /** Compute hash index for the key 226 * 227 * @param key The first of the keys is inr and the second is mode. Only inr is 228 * used to compute the hash. 287 /** Compute hash index for the key. 288 * 289 * This function computes hash index into the IRQ hash table for which there can 290 * be collisions between different INRs. 291 * 292 * The devno is not used to compute the hash. 293 * 294 * @param key The first of the keys is inr and the second is devno or -1. 229 295 * 230 296 * @return Index into the hash table. … … 233 299 size_t irq_ht_hash(sysarg_t key[]) 234 300 { 235 inr_t inr = (inr_t) key[ IRQ_HT_KEY_INR];301 inr_t inr = (inr_t) key[KEY_INR]; 236 302 return inr % buckets; 237 303 } 238 304 239 /** Compare hash table element with a key 240 * 241 * If mode is IRQ_HT_MODE_CLAIM, the result of the claim() function is used for 242 * the match. Otherwise the key does not match. 305 /** Compare hash table element with a key. 306 * 307 * There are two things to note about this function. First, it is used for the 308 * more complex architecture setup in which there are way too many interrupt 309 * numbers (i.e. inr's) to arrange the hash table so that collisions occur only 310 * among same inrs of different devnos. So the explicit check for inr match must 311 * be done. Second, if devno is -1, the second key (i.e. devno) is not used for 312 * the match and the result of the claim() function is used instead. 243 313 * 244 314 * This function assumes interrupts are already disabled. 245 315 * 246 * @param key Keys (i.e. inr and mode).247 * @param keys 248 * @param item 249 * 250 * @return True on match251 * @return False on no match316 * @param key Keys (i.e. inr and devno). 317 * @param keys This is 2. 318 * @param item The item to compare the key with. 319 * 320 * @return true on match 321 * @return false on no match 252 322 * 253 323 */ … … 255 325 { 256 326 irq_t *irq = hash_table_get_instance(item, irq_t, link); 257 inr_t inr = (inr_t) key[ IRQ_HT_KEY_INR];258 irq_ht_mode_t mode = (irq_ht_mode_t) key[IRQ_HT_KEY_MODE];327 inr_t inr = (inr_t) key[KEY_INR]; 328 devno_t devno = (devno_t) key[KEY_DEVNO]; 259 329 260 330 bool rv; 261 331 262 332 irq_spinlock_lock(&irq->lock, false); 263 if ( mode == IRQ_HT_MODE_CLAIM) {333 if (devno == -1) { 264 334 /* Invoked by irq_dispatch_and_lock(). */ 265 rv = ((irq->inr == inr) && (irq->claim(irq) == IRQ_ACCEPT)); 335 rv = ((irq->inr == inr) && 336 (irq->claim(irq) == IRQ_ACCEPT)); 266 337 } else { 267 338 /* Invoked by irq_find_and_lock(). */ 268 rv = false;339 rv = ((irq->inr == inr) && (irq->devno == devno)); 269 340 } 270 341 … … 276 347 } 277 348 278 /** Unlock IRQ structure after hash_table_remove() 279 * 280 * @param lnk 349 /** Unlock IRQ structure after hash_table_remove(). 350 * 351 * @param lnk Link in the removed and locked IRQ structure. 281 352 */ 282 353 void irq_ht_remove(link_t *lnk) … … 287 358 } 288 359 360 /** Compute hash index for the key. 361 * 362 * This function computes hash index into the IRQ hash table for which there are 363 * no collisions between different INRs. 364 * 365 * @param key The first of the keys is inr and the second is devno or -1. 366 * 367 * @return Index into the hash table. 368 * 369 */ 370 size_t irq_lin_hash(sysarg_t key[]) 371 { 372 inr_t inr = (inr_t) key[KEY_INR]; 373 return inr; 374 } 375 376 /** Compare hash table element with a key. 377 * 378 * There are two things to note about this function. First, it is used for the 379 * less complex architecture setup in which there are not too many interrupt 380 * numbers (i.e. inr's) to arrange the hash table so that collisions occur only 381 * among same inrs of different devnos. So the explicit check for inr match is 382 * not done. Second, if devno is -1, the second key (i.e. devno) is not used 383 * for the match and the result of the claim() function is used instead. 384 * 385 * This function assumes interrupts are already disabled. 386 * 387 * @param key Keys (i.e. inr and devno). 388 * @param keys This is 2. 389 * @param item The item to compare the key with. 390 * 391 * @return true on match 392 * @return false on no match 393 * 394 */ 395 bool irq_lin_compare(sysarg_t key[], size_t keys, link_t *item) 396 { 397 irq_t *irq = list_get_instance(item, irq_t, link); 398 devno_t devno = (devno_t) key[KEY_DEVNO]; 399 bool rv; 400 401 irq_spinlock_lock(&irq->lock, false); 402 if (devno == -1) { 403 /* Invoked by irq_dispatch_and_lock() */ 404 rv = (irq->claim(irq) == IRQ_ACCEPT); 405 } else { 406 /* Invoked by irq_find_and_lock() */ 407 rv = (irq->devno == devno); 408 } 409 410 /* unlock only on non-match */ 411 if (!rv) 412 irq_spinlock_unlock(&irq->lock, false); 413 414 return rv; 415 } 416 417 /** Unlock IRQ structure after hash_table_remove(). 418 * 419 * @param lnk Link in the removed and locked IRQ structure. 420 * 421 */ 422 void irq_lin_remove(link_t *lnk) 423 { 424 irq_t *irq __attribute__((unused)) 425 = hash_table_get_instance(lnk, irq_t, link); 426 irq_spinlock_unlock(&irq->lock, false); 427 } 428 289 429 /** @} 290 430 */
Note:
See TracChangeset
for help on using the changeset viewer.