Rev 1260 | Rev 1342 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 1260 | Rev 1281 | ||
|---|---|---|---|
| Line 42... | Line 42... | ||
| 42 | #include <debug.h> |
42 | #include <debug.h> |
| 43 | 43 | ||
| 44 | #include <print.h> |
44 | #include <print.h> |
| 45 | #include <proc/thread.h> |
45 | #include <proc/thread.h> |
| 46 | #include <arch/interrupt.h> |
46 | #include <arch/interrupt.h> |
| - | 47 | #include <ipc/irq.h> |
|
| 47 | 48 | ||
| 48 | /* Open channel that is assigned automatically to new tasks */ |
49 | /* Open channel that is assigned automatically to new tasks */ |
| 49 | answerbox_t *ipc_phone_0 = NULL; |
50 | answerbox_t *ipc_phone_0 = NULL; |
| 50 | 51 | ||
| 51 | static slab_cache_t *ipc_call_slab; |
52 | static slab_cache_t *ipc_call_slab; |
| 52 | 53 | ||
| 53 | typedef struct { |
- | |
| 54 | SPINLOCK_DECLARE(lock); |
- | |
| 55 | answerbox_t *box; |
- | |
| 56 | } ipc_irq_t; |
- | |
| 57 | - | ||
| 58 | static ipc_irq_t *irq_conns = NULL; |
- | |
| 59 | static int irq_conns_size; |
- | |
| 60 | - | ||
| 61 | /* Initialize new call */ |
54 | /* Initialize new call */ |
| 62 | static void _ipc_call_init(call_t *call) |
55 | static void _ipc_call_init(call_t *call) |
| 63 | { |
56 | { |
| 64 | memsetb((__address)call, sizeof(*call), 0); |
57 | memsetb((__address)call, sizeof(*call), 0); |
| 65 | call->callerbox = &TASK->answerbox; |
58 | call->callerbox = &TASK->answerbox; |
| Line 326... | Line 319... | ||
| 326 | spinlock_lock(&box->lock); |
319 | spinlock_lock(&box->lock); |
| 327 | if (!list_empty(&box->irq_notifs)) { |
320 | if (!list_empty(&box->irq_notifs)) { |
| 328 | ipl = interrupts_disable(); |
321 | ipl = interrupts_disable(); |
| 329 | spinlock_lock(&box->irq_lock); |
322 | spinlock_lock(&box->irq_lock); |
| 330 | 323 | ||
| 331 | request = list_get_instance(box->answers.next, call_t, list); |
324 | request = list_get_instance(box->irq_notifs.next, call_t, list); |
| 332 | list_remove(&request->list); |
325 | list_remove(&request->list); |
| 333 | 326 | ||
| 334 | spinlock_unlock(&box->irq_lock); |
327 | spinlock_unlock(&box->irq_lock); |
| 335 | interrupts_restore(ipl); |
328 | interrupts_restore(ipl); |
| 336 | } else if (!list_empty(&box->answers)) { |
329 | } else if (!list_empty(&box->answers)) { |
| Line 368... | Line 361... | ||
| 368 | IPC_SET_RETVAL(call->data, EHANGUP); |
361 | IPC_SET_RETVAL(call->data, EHANGUP); |
| 369 | _ipc_answer_free_call(call); |
362 | _ipc_answer_free_call(call); |
| 370 | } |
363 | } |
| 371 | } |
364 | } |
| 372 | 365 | ||
| 373 | /** Disconnect all irq's notifications |
- | |
| 374 | * |
- | |
| 375 | * TODO: It may be better to do some linked list, so that |
- | |
| 376 | * we wouldn't need to go through whole array every cleanup |
- | |
| 377 | */ |
- | |
| 378 | static void ipc_irq_cleanup(answerbox_t *box) |
- | |
| 379 | { |
- | |
| 380 | int i; |
- | |
| 381 | ipl_t ipl; |
- | |
| 382 | - | ||
| 383 | for (i=0; i < irq_conns_size; i++) { |
- | |
| 384 | ipl = interrupts_disable(); |
- | |
| 385 | spinlock_lock(&irq_conns[i].lock); |
- | |
| 386 | if (irq_conns[i].box == box) |
- | |
| 387 | irq_conns[i].box = NULL; |
- | |
| 388 | spinlock_unlock(&irq_conns[i].lock); |
- | |
| 389 | interrupts_restore(ipl); |
- | |
| 390 | } |
- | |
| 391 | } |
- | |
| 392 | - | ||
| 393 | /** Cleans up all IPC communication of the given task |
366 | /** Cleans up all IPC communication of the given task |
| 394 | * |
367 | * |
| 395 | * |
368 | * |
| 396 | */ |
369 | */ |
| 397 | void ipc_cleanup(task_t *task) |
370 | void ipc_cleanup(task_t *task) |
| Line 441... | Line 414... | ||
| 441 | atomic_dec(&task->active_calls); |
414 | atomic_dec(&task->active_calls); |
| 442 | ipc_call_free(call); |
415 | ipc_call_free(call); |
| 443 | } |
416 | } |
| 444 | } |
417 | } |
| 445 | 418 | ||
| 446 | /** Initialize table of interrupt handlers */ |
- | |
| 447 | static void ipc_irq_make_table(int irqcount) |
- | |
| 448 | { |
- | |
| 449 | int i; |
- | |
| 450 | - | ||
| 451 | irq_conns_size = irqcount; |
- | |
| 452 | irq_conns = malloc(irqcount * (sizeof(*irq_conns)), 0); |
- | |
| 453 | for (i=0; i < irqcount; i++) { |
- | |
| 454 | spinlock_initialize(&irq_conns[i].lock, "irq_ipc_lock"); |
- | |
| 455 | irq_conns[i].box = NULL; |
- | |
| 456 | } |
- | |
| 457 | } |
- | |
| 458 | - | ||
| 459 | void ipc_irq_unregister(answerbox_t *box, int irq) |
- | |
| 460 | { |
- | |
| 461 | ipl_t ipl; |
- | |
| 462 | - | ||
| 463 | ipl = interrupts_disable(); |
- | |
| 464 | spinlock_lock(&irq_conns[irq].lock); |
- | |
| 465 | if (irq_conns[irq].box == box) |
- | |
| 466 | irq_conns[irq].box = NULL; |
- | |
| 467 | - | ||
| 468 | spinlock_unlock(&irq_conns[irq].lock); |
- | |
| 469 | interrupts_restore(ipl); |
- | |
| 470 | } |
- | |
| 471 | - | ||
| 472 | /** Register an answerbox as a receiving end of interrupts notifications */ |
- | |
| 473 | int ipc_irq_register(answerbox_t *box, int irq) |
- | |
| 474 | { |
- | |
| 475 | ipl_t ipl; |
- | |
| 476 | - | ||
| 477 | ASSERT(irq_conns); |
- | |
| 478 | - | ||
| 479 | ipl = interrupts_disable(); |
- | |
| 480 | spinlock_lock(&irq_conns[irq].lock); |
- | |
| 481 | - | ||
| 482 | if (irq_conns[irq].box) { |
- | |
| 483 | spinlock_unlock(&irq_conns[irq].lock); |
- | |
| 484 | interrupts_restore(ipl); |
- | |
| 485 | return EEXISTS; |
- | |
| 486 | } |
- | |
| 487 | irq_conns[irq].box = box; |
- | |
| 488 | spinlock_unlock(&irq_conns[irq].lock); |
- | |
| 489 | interrupts_restore(ipl); |
- | |
| 490 | - | ||
| 491 | return 0; |
- | |
| 492 | } |
- | |
| 493 | - | ||
| 494 | /** Notify process that an irq had happend |
- | |
| 495 | * |
- | |
| 496 | * We expect interrupts to be disabled |
- | |
| 497 | */ |
- | |
| 498 | void ipc_irq_send_notif(int irq) |
- | |
| 499 | { |
- | |
| 500 | call_t *call; |
- | |
| 501 | - | ||
| 502 | ASSERT(irq_conns); |
- | |
| 503 | spinlock_lock(&irq_conns[irq].lock); |
- | |
| 504 | - | ||
| 505 | if (irq_conns[irq].box) { |
- | |
| 506 | call = ipc_call_alloc(FRAME_ATOMIC); |
- | |
| 507 | call->flags |= IPC_CALL_NOTIF; |
- | |
| 508 | IPC_SET_METHOD(call->data, IPC_M_INTERRUPT); |
- | |
| 509 | IPC_SET_ARG1(call->data, irq); |
- | |
| 510 | - | ||
| 511 | spinlock_lock(&irq_conns[irq].box->irq_lock); |
- | |
| 512 | list_append(&call->list, &irq_conns[irq].box->irq_notifs); |
- | |
| 513 | spinlock_unlock(&irq_conns[irq].box->irq_lock); |
- | |
| 514 | - | ||
| 515 | waitq_wakeup(&irq_conns[irq].box->wq, 0); |
- | |
| 516 | } |
- | |
| 517 | - | ||
| 518 | spinlock_unlock(&irq_conns[irq].lock); |
- | |
| 519 | } |
- | |
| 520 | 419 | ||
| 521 | /** Initilize ipc subsystem */ |
420 | /** Initilize ipc subsystem */ |
| 522 | void ipc_init(void) |
421 | void ipc_init(void) |
| 523 | { |
422 | { |
| 524 | ipc_call_slab = slab_cache_create("ipc_call", |
423 | ipc_call_slab = slab_cache_create("ipc_call", |