Changeset 5626277 in mainline for generic/src/ipc/ipc.c


Ignore:
Timestamp:
2006-04-29T22:12:40Z (19 years ago)
Author:
Ondrej Palkovsky <ondrap@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
51a7dc1
Parents:
407862e
Message:

Added support for IRQ notifiactions.

  • seems to work correctly on ia32, amd64
  • the mips kbd probably lowers interrupts when the char is read from the port, we will have to find a way how to deal with it.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • generic/src/ipc/ipc.c

    r407862e r5626277  
    4444#include <print.h>
    4545#include <proc/thread.h>
     46#include <arch/interrupt.h>
    4647
    4748/* Open channel that is assigned automatically to new tasks */
     
    4950
    5051static slab_cache_t *ipc_call_slab;
     52
     53typedef struct {
     54        SPINLOCK_DECLARE(lock);
     55        answerbox_t *box;
     56} ipc_irq_t;
     57
     58static ipc_irq_t *irq_conns = NULL;
     59static int irq_conns_size;
    5160
    5261/* Initialize new call */
     
    6271 * The call is initialized, so that the reply will be directed
    6372 * to TASK->answerbox
    64  */
    65 call_t * ipc_call_alloc(void)
     73 *
     74 * @param flags Parameters for slab_alloc (ATOMIC, etc.)
     75 */
     76call_t * ipc_call_alloc(int flags)
    6677{
    6778        call_t *call;
    6879
    69         call = slab_alloc(ipc_call_slab, 0);
     80        call = slab_alloc(ipc_call_slab, flags);
    7081        _ipc_call_init(call);
    7182
     
    91102{
    92103        spinlock_initialize(&box->lock, "ipc_box_lock");
     104        spinlock_initialize(&box->irq_lock, "ipc_box_irqlock");
    93105        waitq_initialize(&box->wq);
    94106        list_initialize(&box->connected_phones);
     
    96108        list_initialize(&box->dispatched_calls);
    97109        list_initialize(&box->answers);
     110        list_initialize(&box->irq_notifs);
    98111        box->task = TASK;
    99112}
     
    262275        spinlock_unlock(&box->lock);
    263276
    264         call = ipc_call_alloc();
     277        call = ipc_call_alloc(0);
    265278        IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
    266279        call->flags |= IPC_CALL_DISCARD_ANSWER;
     
    302315{
    303316        call_t *request;
     317        ipl_t ipl;
    304318
    305319restart:     
     
    311325       
    312326        spinlock_lock(&box->lock);
    313         if (!list_empty(&box->answers)) {
     327        if (!list_empty(&box->irq_notifs)) {
     328                ipl = interrupts_disable();
     329                spinlock_lock(&box->irq_lock);
     330
     331                request = list_get_instance(box->answers.next, call_t, list);
     332                list_remove(&request->list);
     333
     334                spinlock_unlock(&box->irq_lock);
     335                interrupts_restore(ipl);
     336        } else if (!list_empty(&box->answers)) {
    314337                /* Handle asynchronous answers */
    315338                request = list_get_instance(box->answers.next, call_t, list);
     
    334357}
    335358
    336 /** Initilize ipc subsystem */
    337 void ipc_init(void)
    338 {
    339         ipc_call_slab = slab_cache_create("ipc_call",
    340                                           sizeof(call_t),
    341                                           0,
    342                                           NULL, NULL, 0);
    343 }
    344 
    345359/** Answer all calls from list with EHANGUP msg */
    346360static void ipc_cleanup_call_list(link_t *lst)
     
    354368                IPC_SET_RETVAL(call->data, EHANGUP);
    355369                _ipc_answer_free_call(call);
     370        }
     371}
     372
     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 */
     378static 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);
    356390        }
    357391}
     
    370404        for (i=0;i < IPC_MAX_PHONES; i++)
    371405                ipc_phone_hangup(&task->phones[i]);
     406
     407        /* Disconnect all connected irqs */
     408        ipc_irq_cleanup(&task->answerbox);
    372409
    373410        /* Disconnect all phones connected to our answerbox */
     
    406443        }
    407444}
     445
     446/** Initialize table of interrupt handlers */
     447static 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
     459void 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 */
     473int 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 */
     498void 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
     521/** Initilize ipc subsystem */
     522void ipc_init(void)
     523{
     524        ipc_call_slab = slab_cache_create("ipc_call",
     525                                          sizeof(call_t),
     526                                          0,
     527                                          NULL, NULL, 0);
     528        ipc_irq_make_table(IRQ_COUNT);
     529}
     530
Note: See TracChangeset for help on using the changeset viewer.