Changes in kernel/generic/src/ipc/irq.c [a70bda4:1d432f9] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/irq.c
ra70bda4 r1d432f9 31 31 * @{ 32 32 */ 33 33 34 /** 34 35 * @file … … 67 68 * structure are finished. Because we hold the hash table lock, we prevent new 68 69 * IRQs from taking new references to the IRQ structure. 70 * 69 71 */ 70 72 … … 81 83 /** Free the top-half pseudocode. 82 84 * 83 * @param code Pointer to the top-half pseudocode. 85 * @param code Pointer to the top-half pseudocode. 86 * 84 87 */ 85 88 static void code_free(irq_code_t *code) … … 93 96 /** Copy the top-half pseudocode from userspace into the kernel. 94 97 * 95 * @param ucode Userspace address of the top-half pseudocode. 96 * 97 * @return Kernel address of the copied pseudocode. 98 * @param ucode Userspace address of the top-half pseudocode. 99 * 100 * @return Kernel address of the copied pseudocode. 101 * 98 102 */ 99 103 static irq_code_t *code_from_uspace(irq_code_t *ucode) 100 104 { 101 irq_code_t *code; 102 irq_cmd_t *ucmds; 103 int rc; 104 105 code = malloc(sizeof(*code), 0); 106 rc = copy_from_uspace(code, ucode, sizeof(*code)); 105 irq_code_t *code = malloc(sizeof(*code), 0); 106 int rc = copy_from_uspace(code, ucode, sizeof(*code)); 107 107 if (rc != 0) { 108 108 free(code); … … 114 114 return NULL; 115 115 } 116 ucmds = code->cmds; 116 117 irq_cmd_t *ucmds = code->cmds; 117 118 code->cmds = malloc(sizeof(code->cmds[0]) * code->cmdcount, 0); 118 119 rc = copy_from_uspace(code->cmds, ucmds, … … 123 124 return NULL; 124 125 } 125 126 126 127 return code; 127 128 } … … 141 142 unative_t method, irq_code_t *ucode) 142 143 { 143 ipl_t ipl;144 irq_code_t *code;145 irq_t *irq;146 link_t *hlp;147 144 unative_t key[] = { 148 145 (unative_t) inr, … … 150 147 }; 151 148 149 irq_code_t *code; 152 150 if (ucode) { 153 151 code = code_from_uspace(ucode); 154 152 if (!code) 155 153 return EBADMEM; 156 } else {154 } else 157 155 code = NULL; 158 }159 156 160 157 /* 161 158 * Allocate and populate the IRQ structure. 162 159 */ 163 irq = malloc(sizeof(irq_t), 0); 160 irq_t *irq = malloc(sizeof(irq_t), 0); 161 164 162 irq_initialize(irq); 165 163 irq->devno = devno; … … 177 175 * answerbox's list. 178 176 */ 179 i pl = interrupts_disable();180 spinlock_lock(&irq_uspace_hash_table_lock);181 hlp = hash_table_find(&irq_uspace_hash_table, key);177 irq_spinlock_lock(&irq_uspace_hash_table_lock, true); 178 179 link_t *hlp = hash_table_find(&irq_uspace_hash_table, key); 182 180 if (hlp) { 183 irq_t *hirq __attribute__((unused)) 184 = hash_table_get_instance(hlp, irq_t, link); 181 irq_t *hirq = hash_table_get_instance(hlp, irq_t, link); 185 182 186 183 /* hirq is locked */ 187 spinlock_unlock(&hirq->lock);184 irq_spinlock_unlock(&hirq->lock, false); 188 185 code_free(code); 189 spinlock_unlock(&irq_uspace_hash_table_lock); 186 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 187 190 188 free(irq); 191 interrupts_restore(ipl);192 189 return EEXISTS; 193 190 } 194 191 195 spinlock_lock(&irq->lock); /* Not really necessary, but paranoid */ 196 spinlock_lock(&box->irq_lock); 192 /* Locking is not really necessary, but paranoid */ 193 irq_spinlock_lock(&irq->lock, false); 194 irq_spinlock_lock(&box->irq_lock, false); 195 197 196 hash_table_insert(&irq_uspace_hash_table, key, &irq->link); 198 197 list_append(&irq->notif_cfg.link, &box->irq_head); 199 spinlock_unlock(&box->irq_lock);200 spinlock_unlock(&irq->lock);201 spinlock_unlock(&irq_uspace_hash_table_lock);202 203 interrupts_restore(ipl);198 199 irq_spinlock_unlock(&box->irq_lock, false); 200 irq_spinlock_unlock(&irq->lock, false); 201 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 202 204 203 return EOK; 205 204 } … … 207 206 /** Unregister task from IRQ notification. 208 207 * 209 * @param box Answerbox associated with the notification. 210 * @param inr IRQ number. 211 * @param devno Device number. 208 * @param box Answerbox associated with the notification. 209 * @param inr IRQ number. 210 * @param devno Device number. 211 * 212 212 */ 213 213 int ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno) 214 214 { 215 ipl_t ipl;216 215 unative_t key[] = { 217 216 (unative_t) inr, 218 217 (unative_t) devno 219 218 }; 220 link_t *lnk; 221 irq_t *irq; 222 223 ipl = interrupts_disable(); 224 spinlock_lock(&irq_uspace_hash_table_lock); 225 lnk = hash_table_find(&irq_uspace_hash_table, key); 219 220 irq_spinlock_lock(&irq_uspace_hash_table_lock, true); 221 link_t *lnk = hash_table_find(&irq_uspace_hash_table, key); 226 222 if (!lnk) { 227 spinlock_unlock(&irq_uspace_hash_table_lock); 228 interrupts_restore(ipl); 223 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 229 224 return ENOENT; 230 225 } 231 irq = hash_table_get_instance(lnk, irq_t, link); 226 227 irq_t *irq = hash_table_get_instance(lnk, irq_t, link); 228 232 229 /* irq is locked */ 233 spinlock_lock(&box->irq_lock);230 irq_spinlock_lock(&box->irq_lock, false); 234 231 235 232 ASSERT(irq->notif_cfg.answerbox == box); … … 237 234 /* Free up the pseudo code and associated structures. */ 238 235 code_free(irq->notif_cfg.code); 239 240 /* Remove the IRQ from the answerbox's list. */ 236 237 /* Remove the IRQ from the answerbox's list. */ 241 238 list_remove(&irq->notif_cfg.link); 242 239 243 240 /* 244 241 * We need to drop the IRQ lock now because hash_table_remove() will try … … 248 245 * the meantime. 249 246 */ 250 spinlock_unlock(&irq->lock);251 247 irq_spinlock_unlock(&irq->lock, false); 248 252 249 /* Remove the IRQ from the uspace IRQ hash table. */ 253 250 hash_table_remove(&irq_uspace_hash_table, key, 2); 254 251 255 spinlock_unlock(&irq_uspace_hash_table_lock);256 spinlock_unlock(&box->irq_lock);252 irq_spinlock_unlock(&box->irq_lock, false); 253 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 257 254 258 255 /* Free up the IRQ structure. */ 259 256 free(irq); 260 257 261 interrupts_restore(ipl);262 258 return EOK; 263 259 } 264 265 260 266 261 /** Disconnect all IRQ notifications from an answerbox. … … 270 265 * send notifications to it. 271 266 * 272 * @param box Answerbox for which we want to carry out the cleanup. 267 * @param box Answerbox for which we want to carry out the cleanup. 268 * 273 269 */ 274 270 void ipc_irq_cleanup(answerbox_t *box) 275 271 { 276 ipl_t ipl;277 278 272 loop: 279 ipl = interrupts_disable(); 280 spinlock_lock(&irq_uspace_hash_table_lock); 281 spinlock_lock(&box->irq_lock); 273 irq_spinlock_lock(&irq_uspace_hash_table_lock, true); 274 irq_spinlock_lock(&box->irq_lock, false); 282 275 283 276 while (box->irq_head.next != &box->irq_head) { 284 link_t *cur = box->irq_head.next;285 irq_t *irq;286 277 DEADLOCK_PROBE_INIT(p_irqlock); 287 unative_t key[2]; 288 289 irq = list_get_instance(cur, irq_t, notif_cfg.link); 290 if (!spinlock_trylock(&irq->lock)) { 278 279 irq_t *irq = list_get_instance(box->irq_head.next, irq_t, 280 notif_cfg.link); 281 282 if (!irq_spinlock_trylock(&irq->lock)) { 291 283 /* 292 284 * Avoid deadlock by trying again. 293 285 */ 294 spinlock_unlock(&box->irq_lock); 295 spinlock_unlock(&irq_uspace_hash_table_lock); 296 interrupts_restore(ipl); 286 irq_spinlock_unlock(&box->irq_lock, false); 287 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 297 288 DEADLOCK_PROBE(p_irqlock, DEADLOCK_THRESHOLD); 298 289 goto loop; 299 290 } 291 292 unative_t key[2]; 300 293 key[0] = irq->inr; 301 294 key[1] = irq->devno; 302 303 295 304 296 ASSERT(irq->notif_cfg.answerbox == box); … … 317 309 * didn't drop the hash table lock in the meantime. 318 310 */ 319 spinlock_unlock(&irq->lock);311 irq_spinlock_unlock(&irq->lock, false); 320 312 321 313 /* Remove from the hash table. */ … … 325 317 } 326 318 327 spinlock_unlock(&box->irq_lock); 328 spinlock_unlock(&irq_uspace_hash_table_lock); 329 interrupts_restore(ipl); 319 irq_spinlock_unlock(&box->irq_lock, false); 320 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true); 330 321 } 331 322 332 323 /** Add a call to the proper answerbox queue. 333 324 * 334 * Assume irq->lock is locked. 335 * 336 * @param irq IRQ structure referencing the target answerbox. 337 * @param call IRQ notification call. 325 * Assume irq->lock is locked and interrupts disabled. 326 * 327 * @param irq IRQ structure referencing the target answerbox. 328 * @param call IRQ notification call. 329 * 338 330 */ 339 331 static void send_call(irq_t *irq, call_t *call) 340 332 { 341 spinlock_lock(&irq->notif_cfg.answerbox->irq_lock);333 irq_spinlock_lock(&irq->notif_cfg.answerbox->irq_lock, false); 342 334 list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs); 343 spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock);344 335 irq_spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock, false); 336 345 337 waitq_wakeup(&irq->notif_cfg.answerbox->wq, WAKEUP_FIRST); 346 338 } … … 348 340 /** Apply the top-half pseudo code to find out whether to accept the IRQ or not. 349 341 * 350 * @param irq IRQ structure. 351 * 352 * @return IRQ_ACCEPT if the interrupt is accepted by the 353 * pseudocode. IRQ_DECLINE otherwise. 342 * @param irq IRQ structure. 343 * 344 * @return IRQ_ACCEPT if the interrupt is accepted by the 345 * pseudocode, IRQ_DECLINE otherwise. 346 * 354 347 */ 355 348 irq_ownership_t ipc_irq_top_half_claim(irq_t *irq) 356 349 { 357 unsigned int i;358 unative_t dstval;359 350 irq_code_t *code = irq->notif_cfg.code; 360 unative_t *scratch = irq->notif_cfg.scratch; 361 351 uint32_t *scratch = irq->notif_cfg.scratch; 362 352 363 353 if (!irq->notif_cfg.notify) … … 367 357 return IRQ_DECLINE; 368 358 359 size_t i; 369 360 for (i = 0; i < code->cmdcount; i++) { 370 unsigned int srcarg = code->cmds[i].srcarg; 371 unsigned int dstarg = code->cmds[i].dstarg; 361 uint32_t dstval; 362 uintptr_t srcarg = code->cmds[i].srcarg; 363 uintptr_t dstarg = code->cmds[i].dstarg; 372 364 373 365 if (srcarg >= IPC_CALL_LEN) 374 366 break; 367 375 368 if (dstarg >= IPC_CALL_LEN) 376 369 break; … … 405 398 break; 406 399 case CMD_BTEST: 407 if ( srcarg && dstarg) {400 if ((srcarg) && (dstarg)) { 408 401 dstval = scratch[srcarg] & code->cmds[i].value; 409 402 scratch[dstarg] = dstval; … … 411 404 break; 412 405 case CMD_PREDICATE: 413 if ( srcarg && !scratch[srcarg]) {406 if ((srcarg) && (!scratch[srcarg])) { 414 407 i += code->cmds[i].value; 415 408 continue; … … 427 420 } 428 421 429 430 422 /* IRQ top-half handler. 431 423 * 432 424 * We expect interrupts to be disabled and the irq->lock already held. 433 425 * 434 * @param irq IRQ structure. 426 * @param irq IRQ structure. 427 * 435 428 */ 436 429 void ipc_irq_top_half_handler(irq_t *irq) … … 438 431 ASSERT(irq); 439 432 433 ASSERT(interrupts_disabled()); 434 ASSERT(irq_spinlock_locked(&irq->lock)); 435 440 436 if (irq->notif_cfg.answerbox) { 441 call_t *call; 442 443 call = ipc_call_alloc(FRAME_ATOMIC); 437 call_t *call = ipc_call_alloc(FRAME_ATOMIC); 444 438 if (!call) 445 439 return; … … 448 442 /* Put a counter to the message */ 449 443 call->priv = ++irq->notif_cfg.counter; 450 444 451 445 /* Set up args */ 452 446 IPC_SET_METHOD(call->data, irq->notif_cfg.method); … … 456 450 IPC_SET_ARG4(call->data, irq->notif_cfg.scratch[4]); 457 451 IPC_SET_ARG5(call->data, irq->notif_cfg.scratch[5]); 458 452 459 453 send_call(irq, call); 460 454 } … … 463 457 /** Send notification message. 464 458 * 465 * @param irq IRQ structure. 466 * @param a1 Driver-specific payload argument. 467 * @param a2 Driver-specific payload argument. 468 * @param a3 Driver-specific payload argument. 469 * @param a4 Driver-specific payload argument. 470 * @param a5 Driver-specific payload argument. 459 * @param irq IRQ structure. 460 * @param a1 Driver-specific payload argument. 461 * @param a2 Driver-specific payload argument. 462 * @param a3 Driver-specific payload argument. 463 * @param a4 Driver-specific payload argument. 464 * @param a5 Driver-specific payload argument. 465 * 471 466 */ 472 467 void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, unative_t a3, 473 468 unative_t a4, unative_t a5) 474 469 { 475 call_t *call; 476 477 spinlock_lock(&irq->lock); 478 470 irq_spinlock_lock(&irq->lock, true); 471 479 472 if (irq->notif_cfg.answerbox) { 480 call = ipc_call_alloc(FRAME_ATOMIC);473 call_t *call = ipc_call_alloc(FRAME_ATOMIC); 481 474 if (!call) { 482 spinlock_unlock(&irq->lock);475 irq_spinlock_unlock(&irq->lock, true); 483 476 return; 484 477 } 478 485 479 call->flags |= IPC_CALL_NOTIF; 486 480 /* Put a counter to the message */ 487 481 call->priv = ++irq->notif_cfg.counter; 488 482 489 483 IPC_SET_METHOD(call->data, irq->notif_cfg.method); 490 484 IPC_SET_ARG1(call->data, a1); … … 496 490 send_call(irq, call); 497 491 } 498 spinlock_unlock(&irq->lock); 492 493 irq_spinlock_unlock(&irq->lock, true); 499 494 } 500 495
Note:
See TracChangeset
for help on using the changeset viewer.