Changeset 91b60499 in mainline for kernel/generic/src/ddi/irq.c
- Timestamp:
- 2017-09-30T06:29:42Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 300f4c4
- Parents:
- d076f16 (diff), 6636fb19 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ddi/irq.c
rd076f16 r91b60499 32 32 /** 33 33 * @file 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. 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. 64 39 */ 65 40 … … 74 49 #include <arch.h> 75 50 76 #define KEY_INR 0 77 #define KEY_DEVNO 1 78 79 /** Spinlock protecting the kernel IRQ hash table. 51 slab_cache_t *irq_slab = NULL; 52 53 /** Spinlock protecting the kernel IRQ hash table 80 54 * 81 55 * This lock must be taken only when interrupts are disabled. … … 87 61 static hash_table_t irq_kernel_hash_table; 88 62 89 /** Spinlock protecting the uspace IRQ hash table .63 /** Spinlock protecting the uspace IRQ hash table 90 64 * 91 65 * This lock must be taken only when interrupts are disabled. … … 94 68 IRQ_SPINLOCK_INITIALIZE(irq_uspace_hash_table_lock); 95 69 96 /** The uspace IRQ hash table .*/70 /** The uspace IRQ hash table */ 97 71 hash_table_t irq_uspace_hash_table; 98 72 99 /**100 * Hash table operations for cases when we know that there will be collisions101 * between different keys.102 */103 73 static size_t irq_ht_hash(sysarg_t *key); 104 74 static bool irq_ht_compare(sysarg_t *key, size_t keys, link_t *item); … … 111 81 }; 112 82 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. */ 83 /** Number of buckets in either of the hash tables */ 129 84 static size_t buckets; 130 85 131 /** Last valid INR .*/86 /** Last valid INR */ 132 87 inr_t last_inr = 0; 133 88 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.89 /** Initialize IRQ subsystem 90 * 91 * @param inrs Numbers of unique IRQ numbers or INRs. 92 * @param chains Number of buckets in the hash table. 138 93 * 139 94 */ … … 143 98 last_inr = inrs - 1; 144 99 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. 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. 167 111 * 168 112 */ … … 172 116 link_initialize(&irq->link); 173 117 irq_spinlock_initialize(&irq->lock, "irq.lock"); 174 link_initialize(&irq->notif_cfg.link);175 118 irq->inr = -1; 176 irq->devno = -1;177 119 178 120 irq_initialize_arch(irq); 179 121 } 180 122 181 /** Register IRQ for device .123 /** Register IRQ for device 182 124 * 183 125 * The irq structure must be filled with information about the interrupt source 184 126 * and with the claim() function pointer and handler() function pointer. 185 127 * 186 * @param irq IRQ structure belonging to a device.128 * @param irq IRQ structure belonging to a device. 187 129 * 188 130 */ … … 190 132 { 191 133 sysarg_t key[] = { 192 (sysarg_t) irq->inr,193 (sysarg_t) irq->devno134 [IRQ_HT_KEY_INR] = (sysarg_t) irq->inr, 135 [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_NO_CLAIM 194 136 }; 195 137 … … 201 143 } 202 144 203 /** Search and lock the uspace IRQ hash table. 204 * 205 */ 145 /** Search and lock the uspace IRQ hash table */ 206 146 static irq_t *irq_dispatch_and_lock_uspace(inr_t inr) 207 147 { 208 148 link_t *lnk; 209 149 sysarg_t key[] = { 210 (sysarg_t) inr,211 (sysarg_t) -1 /* Search will use claim() instead of devno */150 [IRQ_HT_KEY_INR] = (sysarg_t) inr, 151 [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_CLAIM 212 152 }; 213 153 … … 224 164 } 225 165 226 /** Search and lock the kernel IRQ hash table. 227 * 228 */ 166 /** Search and lock the kernel IRQ hash table */ 229 167 static irq_t *irq_dispatch_and_lock_kernel(inr_t inr) 230 168 { 231 169 link_t *lnk; 232 170 sysarg_t key[] = { 233 (sysarg_t) inr,234 (sysarg_t) -1 /* Search will use claim() instead of devno */171 [IRQ_HT_KEY_INR] = (sysarg_t) inr, 172 [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_CLAIM 235 173 }; 236 174 … … 247 185 } 248 186 249 /** Dispatch the IRQ .187 /** Dispatch the IRQ 250 188 * 251 189 * We assume this function is only called from interrupt context (i.e. that … … 255 193 * return with interrupts disabled and holding the respective structure. 256 194 * 257 * @param inr Interrupt number (aka inr or irq).195 * @param inr Interrupt number (aka inr or irq). 258 196 * 259 197 * @return IRQ structure of the respective device … … 285 223 } 286 224 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. 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. 295 229 * 296 230 * @return Index into the hash table. … … 299 233 size_t irq_ht_hash(sysarg_t key[]) 300 234 { 301 inr_t inr = (inr_t) key[ KEY_INR];235 inr_t inr = (inr_t) key[IRQ_HT_KEY_INR]; 302 236 return inr % buckets; 303 237 } 304 238 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. 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. 313 243 * 314 244 * This function assumes interrupts are already disabled. 315 245 * 316 * @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 match321 * @return false on no match246 * @param key Keys (i.e. inr and mode). 247 * @param keys This is 2. 248 * @param item The item to compare the key with. 249 * 250 * @return True on match 251 * @return False on no match 322 252 * 323 253 */ … … 325 255 { 326 256 irq_t *irq = hash_table_get_instance(item, irq_t, link); 327 inr_t inr = (inr_t) key[ KEY_INR];328 devno_t devno = (devno_t) key[KEY_DEVNO];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]; 329 259 330 260 bool rv; 331 261 332 262 irq_spinlock_lock(&irq->lock, false); 333 if ( devno == -1) {263 if (mode == IRQ_HT_MODE_CLAIM) { 334 264 /* Invoked by irq_dispatch_and_lock(). */ 335 rv = ((irq->inr == inr) && 336 (irq->claim(irq) == IRQ_ACCEPT)); 265 rv = ((irq->inr == inr) && (irq->claim(irq) == IRQ_ACCEPT)); 337 266 } else { 338 267 /* Invoked by irq_find_and_lock(). */ 339 rv = ((irq->inr == inr) && (irq->devno == devno));268 rv = false; 340 269 } 341 270 … … 347 276 } 348 277 349 /** Unlock IRQ structure after hash_table_remove() .350 * 351 * @param lnk Link in the removed and locked IRQ structure.278 /** Unlock IRQ structure after hash_table_remove() 279 * 280 * @param lnk Link in the removed and locked IRQ structure. 352 281 */ 353 282 void irq_ht_remove(link_t *lnk) … … 358 287 } 359 288 360 /** Compute hash index for the key.361 *362 * This function computes hash index into the IRQ hash table for which there are363 * 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 the379 * less complex architecture setup in which there are not too many interrupt380 * numbers (i.e. inr's) to arrange the hash table so that collisions occur only381 * among same inrs of different devnos. So the explicit check for inr match is382 * not done. Second, if devno is -1, the second key (i.e. devno) is not used383 * 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 match392 * @return false on no match393 *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 429 289 /** @} 430 290 */
Note:
See TracChangeset
for help on using the changeset viewer.