Ignore:
File:
1 edited

Legend:

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

    r8add9ca5 rc822026  
    3131 * @{
    3232 */
    33 
    3433/**
    3534 * @file
     
    4241 *
    4342 * The structure of a notification message is as follows:
    44  * - IMETHOD: interface and method as registered by the SYS_REGISTER_IRQ
    45  *            syscall
     43 * - METHOD: method as registered by the SYS_IPC_REGISTER_IRQ syscall
    4644 * - ARG1: payload modified by a 'top-half' handler
    4745 * - ARG2: payload modified by a 'top-half' handler
     
    5048 * - ARG5: payload modified by a 'top-half' handler
    5149 * - in_phone_hash: interrupt counter (may be needed to assure correct order
    52  *                  in multithreaded drivers)
     50 *         in multithreaded drivers)
    5351 *
    5452 * Note on synchronization for ipc_irq_register(), ipc_irq_unregister(),
     
    6967 *   structure are finished. Because we hold the hash table lock, we prevent new
    7068 *   IRQs from taking new references to the IRQ structure.
    71  *
    7269 */
    7370
     
    8481/** Free the top-half pseudocode.
    8582 *
    86  * @param code Pointer to the top-half pseudocode.
    87  *
     83 * @param code          Pointer to the top-half pseudocode.
    8884 */
    8985static void code_free(irq_code_t *code)
     
    9793/** Copy the top-half pseudocode from userspace into the kernel.
    9894 *
    99  * @param ucode Userspace address of the top-half pseudocode.
    100  *
    101  * @return Kernel address of the copied pseudocode.
    102  *
     95 * @param ucode         Userspace address of the top-half pseudocode.
     96 *
     97 * @return              Kernel address of the copied pseudocode.
    10398 */
    10499static irq_code_t *code_from_uspace(irq_code_t *ucode)
    105100{
    106         irq_code_t *code = malloc(sizeof(*code), 0);
    107         int rc = copy_from_uspace(code, ucode, sizeof(*code));
     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));
    108107        if (rc != 0) {
    109108                free(code);
     
    115114                return NULL;
    116115        }
    117        
    118         irq_cmd_t *ucmds = code->cmds;
     116        ucmds = code->cmds;
    119117        code->cmds = malloc(sizeof(code->cmds[0]) * code->cmdcount, 0);
    120118        rc = copy_from_uspace(code->cmds, ucmds,
     
    125123                return NULL;
    126124        }
    127        
     125
    128126        return code;
    129127}
     
    131129/** Register an answerbox as a receiving end for IRQ notifications.
    132130 *
    133  * @param box           Receiving answerbox.
    134  * @param inr           IRQ number.
    135  * @param devno         Device number.
    136  * @param imethod       Interface and method to be associated with the
    137  *                      notification.
    138  * @param ucode         Uspace pointer to top-half pseudocode.
    139  * @return              EOK on success or a negative error code.
     131 * @param box    Receiving answerbox.
     132 * @param inr    IRQ number.
     133 * @param devno  Device number.
     134 * @param method Method to be associated with the notification.
     135 * @param ucode  Uspace pointer to top-half pseudocode.
     136 *
     137 * @return EBADMEM, ENOENT or EEXISTS on failure or 0 on success.
    140138 *
    141139 */
    142140int ipc_irq_register(answerbox_t *box, inr_t inr, devno_t devno,
    143     sysarg_t imethod, irq_code_t *ucode)
    144 {
    145         sysarg_t key[] = {
    146                 (sysarg_t) inr,
    147                 (sysarg_t) devno
     141    unative_t method, irq_code_t *ucode)
     142{
     143        ipl_t ipl;
     144        irq_code_t *code;
     145        irq_t *irq;
     146        link_t *hlp;
     147        unative_t key[] = {
     148                (unative_t) inr,
     149                (unative_t) devno
    148150        };
    149 
    150         if ((inr < 0) || (inr > last_inr))
    151                 return ELIMIT;
    152        
    153         irq_code_t *code;
     151       
    154152        if (ucode) {
    155153                code = code_from_uspace(ucode);
    156154                if (!code)
    157155                        return EBADMEM;
    158         } else
     156        } else {
    159157                code = NULL;
     158        }
    160159       
    161160        /*
    162161         * Allocate and populate the IRQ structure.
    163162         */
    164         irq_t *irq = malloc(sizeof(irq_t), 0);
    165        
     163        irq = malloc(sizeof(irq_t), 0);
    166164        irq_initialize(irq);
    167165        irq->devno = devno;
     
    171169        irq->notif_cfg.notify = true;
    172170        irq->notif_cfg.answerbox = box;
    173         irq->notif_cfg.imethod = imethod;
     171        irq->notif_cfg.method = method;
    174172        irq->notif_cfg.code = code;
    175173        irq->notif_cfg.counter = 0;
     
    179177         * answerbox's list.
    180178         */
    181         irq_spinlock_lock(&irq_uspace_hash_table_lock, true);
    182        
    183         link_t *hlp = hash_table_find(&irq_uspace_hash_table, key);
     179        ipl = interrupts_disable();
     180        spinlock_lock(&irq_uspace_hash_table_lock);
     181        hlp = hash_table_find(&irq_uspace_hash_table, key);
    184182        if (hlp) {
    185                 irq_t *hirq = hash_table_get_instance(hlp, irq_t, link);
     183                irq_t *hirq __attribute__((unused))
     184                    = hash_table_get_instance(hlp, irq_t, link);
    186185               
    187186                /* hirq is locked */
    188                 irq_spinlock_unlock(&hirq->lock, false);
     187                spinlock_unlock(&hirq->lock);
    189188                code_free(code);
    190                 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
    191                
     189                spinlock_unlock(&irq_uspace_hash_table_lock);
    192190                free(irq);
     191                interrupts_restore(ipl);
    193192                return EEXISTS;
    194193        }
    195194       
    196         /* Locking is not really necessary, but paranoid */
    197         irq_spinlock_lock(&irq->lock, false);
    198         irq_spinlock_lock(&box->irq_lock, false);
    199        
     195        spinlock_lock(&irq->lock);  /* Not really necessary, but paranoid */
     196        spinlock_lock(&box->irq_lock);
    200197        hash_table_insert(&irq_uspace_hash_table, key, &irq->link);
    201198        list_append(&irq->notif_cfg.link, &box->irq_head);
    202        
    203         irq_spinlock_unlock(&box->irq_lock, false);
    204         irq_spinlock_unlock(&irq->lock, false);
    205         irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
    206        
     199        spinlock_unlock(&box->irq_lock);
     200        spinlock_unlock(&irq->lock);
     201        spinlock_unlock(&irq_uspace_hash_table_lock);
     202       
     203        interrupts_restore(ipl);
    207204        return EOK;
    208205}
     
    213210 * @param inr           IRQ number.
    214211 * @param devno         Device number.
    215  * @return              EOK on success or a negative error code.
    216212 */
    217213int ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno)
    218214{
    219         sysarg_t key[] = {
    220                 (sysarg_t) inr,
    221                 (sysarg_t) devno
     215        ipl_t ipl;
     216        unative_t key[] = {
     217                (unative_t) inr,
     218                (unative_t) devno
    222219        };
    223 
    224         if ((inr < 0) || (inr > last_inr))
    225                 return ELIMIT;
    226        
    227         irq_spinlock_lock(&irq_uspace_hash_table_lock, true);
    228         link_t *lnk = hash_table_find(&irq_uspace_hash_table, key);
     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);
    229226        if (!lnk) {
    230                 irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
     227                spinlock_unlock(&irq_uspace_hash_table_lock);
     228                interrupts_restore(ipl);
    231229                return ENOENT;
    232230        }
    233        
    234         irq_t *irq = hash_table_get_instance(lnk, irq_t, link);
    235        
     231        irq = hash_table_get_instance(lnk, irq_t, link);
    236232        /* irq is locked */
    237         irq_spinlock_lock(&box->irq_lock, false);
     233        spinlock_lock(&box->irq_lock);
    238234       
    239235        ASSERT(irq->notif_cfg.answerbox == box);
     
    241237        /* Free up the pseudo code and associated structures. */
    242238        code_free(irq->notif_cfg.code);
    243        
    244         /* Remove the IRQ from the answerbox's list. */
     239
     240        /* Remove the IRQ from the answerbox's list. */ 
    245241        list_remove(&irq->notif_cfg.link);
    246        
     242
    247243        /*
    248244         * We need to drop the IRQ lock now because hash_table_remove() will try
     
    252248         * the meantime.
    253249         */
    254         irq_spinlock_unlock(&irq->lock, false);
    255        
     250        spinlock_unlock(&irq->lock);
     251
    256252        /* Remove the IRQ from the uspace IRQ hash table. */
    257253        hash_table_remove(&irq_uspace_hash_table, key, 2);
    258254       
    259         irq_spinlock_unlock(&box->irq_lock, false);
    260         irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
     255        spinlock_unlock(&irq_uspace_hash_table_lock);
     256        spinlock_unlock(&box->irq_lock);
    261257       
    262258        /* Free up the IRQ structure. */
    263259        free(irq);
    264260       
     261        interrupts_restore(ipl);
    265262        return EOK;
    266263}
     264
    267265
    268266/** Disconnect all IRQ notifications from an answerbox.
     
    272270 * send notifications to it.
    273271 *
    274  * @param box Answerbox for which we want to carry out the cleanup.
    275  *
     272 * @param box           Answerbox for which we want to carry out the cleanup.
    276273 */
    277274void ipc_irq_cleanup(answerbox_t *box)
    278275{
     276        ipl_t ipl;
     277       
    279278loop:
    280         irq_spinlock_lock(&irq_uspace_hash_table_lock, true);
    281         irq_spinlock_lock(&box->irq_lock, false);
     279        ipl = interrupts_disable();
     280        spinlock_lock(&irq_uspace_hash_table_lock);
     281        spinlock_lock(&box->irq_lock);
    282282       
    283283        while (box->irq_head.next != &box->irq_head) {
     284                link_t *cur = box->irq_head.next;
     285                irq_t *irq;
    284286                DEADLOCK_PROBE_INIT(p_irqlock);
    285                
    286                 irq_t *irq = list_get_instance(box->irq_head.next, irq_t,
    287                     notif_cfg.link);
    288                
    289                 if (!irq_spinlock_trylock(&irq->lock)) {
     287                unative_t key[2];
     288               
     289                irq = list_get_instance(cur, irq_t, notif_cfg.link);
     290                if (!spinlock_trylock(&irq->lock)) {
    290291                        /*
    291292                         * Avoid deadlock by trying again.
    292293                         */
    293                         irq_spinlock_unlock(&box->irq_lock, false);
    294                         irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
     294                        spinlock_unlock(&box->irq_lock);
     295                        spinlock_unlock(&irq_uspace_hash_table_lock);
     296                        interrupts_restore(ipl);
    295297                        DEADLOCK_PROBE(p_irqlock, DEADLOCK_THRESHOLD);
    296298                        goto loop;
    297299                }
    298                
    299                 sysarg_t key[2];
    300300                key[0] = irq->inr;
    301301                key[1] = irq->devno;
     302               
    302303               
    303304                ASSERT(irq->notif_cfg.answerbox == box);
     
    316317                 * didn't drop the hash table lock in the meantime.
    317318                 */
    318                 irq_spinlock_unlock(&irq->lock, false);
     319                spinlock_unlock(&irq->lock);
    319320               
    320321                /* Remove from the hash table. */
     
    324325        }
    325326       
    326         irq_spinlock_unlock(&box->irq_lock, false);
    327         irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
     327        spinlock_unlock(&box->irq_lock);
     328        spinlock_unlock(&irq_uspace_hash_table_lock);
     329        interrupts_restore(ipl);
    328330}
    329331
    330332/** Add a call to the proper answerbox queue.
    331333 *
    332  * Assume irq->lock is locked and interrupts disabled.
    333  *
    334  * @param irq  IRQ structure referencing the target answerbox.
    335  * @param call IRQ notification call.
    336  *
     334 * Assume irq->lock is locked.
     335 *
     336 * @param irq           IRQ structure referencing the target answerbox.
     337 * @param call          IRQ notification call.
    337338 */
    338339static void send_call(irq_t *irq, call_t *call)
    339340{
    340         irq_spinlock_lock(&irq->notif_cfg.answerbox->irq_lock, false);
     341        spinlock_lock(&irq->notif_cfg.answerbox->irq_lock);
    341342        list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs);
    342         irq_spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock, false);
    343        
     343        spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock);
     344               
    344345        waitq_wakeup(&irq->notif_cfg.answerbox->wq, WAKEUP_FIRST);
    345346}
     
    347348/** Apply the top-half pseudo code to find out whether to accept the IRQ or not.
    348349 *
    349  * @param irq IRQ structure.
    350  *
    351  * @return IRQ_ACCEPT if the interrupt is accepted by the
    352  *         pseudocode, IRQ_DECLINE otherwise.
    353  *
     350 * @param irq           IRQ structure.
     351 *
     352 * @return              IRQ_ACCEPT if the interrupt is accepted by the
     353 *                      pseudocode. IRQ_DECLINE otherwise.
    354354 */
    355355irq_ownership_t ipc_irq_top_half_claim(irq_t *irq)
    356356{
     357        unsigned int i;
     358        unative_t dstval;
    357359        irq_code_t *code = irq->notif_cfg.code;
    358         uint32_t *scratch = irq->notif_cfg.scratch;
     360        unative_t *scratch = irq->notif_cfg.scratch;
     361
    359362       
    360363        if (!irq->notif_cfg.notify)
     
    364367                return IRQ_DECLINE;
    365368       
    366         size_t i;
    367369        for (i = 0; i < code->cmdcount; i++) {
    368                 uint32_t dstval;
    369                 uintptr_t srcarg = code->cmds[i].srcarg;
    370                 uintptr_t dstarg = code->cmds[i].dstarg;
     370                unsigned int srcarg = code->cmds[i].srcarg;
     371                unsigned int dstarg = code->cmds[i].dstarg;
    371372               
    372373                if (srcarg >= IPC_CALL_LEN)
    373374                        break;
    374                
    375375                if (dstarg >= IPC_CALL_LEN)
    376376                        break;
     
    404404                            (uint32_t) code->cmds[i].value);
    405405                        break;
    406                 case CMD_PIO_WRITE_A_8:
    407                         if (srcarg) {
    408                                 pio_write_8((ioport8_t *) code->cmds[i].addr,
    409                                     (uint8_t) scratch[srcarg]);
    410                         }
    411                         break;
    412                 case CMD_PIO_WRITE_A_16:
    413                         if (srcarg) {
    414                                 pio_write_16((ioport16_t *) code->cmds[i].addr,
    415                                     (uint16_t) scratch[srcarg]);
    416                         }
    417                         break;
    418                 case CMD_PIO_WRITE_A_32:
    419                         if (srcarg) {
    420                                 pio_write_32((ioport32_t *) code->cmds[i].addr,
    421                                     (uint32_t) scratch[srcarg]);
    422                         }
    423                         break;
    424406                case CMD_BTEST:
    425                         if ((srcarg) && (dstarg)) {
     407                        if (srcarg && dstarg) {
    426408                                dstval = scratch[srcarg] & code->cmds[i].value;
    427409                                scratch[dstarg] = dstval;
     
    429411                        break;
    430412                case CMD_PREDICATE:
    431                         if ((srcarg) && (!scratch[srcarg])) {
     413                        if (srcarg && !scratch[srcarg]) {
    432414                                i += code->cmds[i].value;
    433415                                continue;
     
    436418                case CMD_ACCEPT:
    437419                        return IRQ_ACCEPT;
     420                        break;
    438421                case CMD_DECLINE:
    439422                default:
     
    445428}
    446429
     430
    447431/* IRQ top-half handler.
    448432 *
    449433 * We expect interrupts to be disabled and the irq->lock already held.
    450434 *
    451  * @param irq IRQ structure.
    452  *
     435 * @param irq           IRQ structure.
    453436 */
    454437void ipc_irq_top_half_handler(irq_t *irq)
     
    456439        ASSERT(irq);
    457440
    458         ASSERT(interrupts_disabled());
    459         ASSERT(irq_spinlock_locked(&irq->lock));
    460        
    461441        if (irq->notif_cfg.answerbox) {
    462                 call_t *call = ipc_call_alloc(FRAME_ATOMIC);
     442                call_t *call;
     443
     444                call = ipc_call_alloc(FRAME_ATOMIC);
    463445                if (!call)
    464446                        return;
     
    467449                /* Put a counter to the message */
    468450                call->priv = ++irq->notif_cfg.counter;
    469                
     451
    470452                /* Set up args */
    471                 IPC_SET_IMETHOD(call->data, irq->notif_cfg.imethod);
     453                IPC_SET_METHOD(call->data, irq->notif_cfg.method);
    472454                IPC_SET_ARG1(call->data, irq->notif_cfg.scratch[1]);
    473455                IPC_SET_ARG2(call->data, irq->notif_cfg.scratch[2]);
     
    475457                IPC_SET_ARG4(call->data, irq->notif_cfg.scratch[4]);
    476458                IPC_SET_ARG5(call->data, irq->notif_cfg.scratch[5]);
    477                
     459
    478460                send_call(irq, call);
    479461        }
     
    482464/** Send notification message.
    483465 *
    484  * @param irq IRQ structure.
    485  * @param a1  Driver-specific payload argument.
    486  * @param a2  Driver-specific payload argument.
    487  * @param a3  Driver-specific payload argument.
    488  * @param a4  Driver-specific payload argument.
    489  * @param a5  Driver-specific payload argument.
    490  *
    491  */
    492 void ipc_irq_send_msg(irq_t *irq, sysarg_t a1, sysarg_t a2, sysarg_t a3,
    493     sysarg_t a4, sysarg_t a5)
    494 {
    495         irq_spinlock_lock(&irq->lock, true);
    496        
     466 * @param irq           IRQ structure.
     467 * @param a1            Driver-specific payload argument.
     468 * @param a2            Driver-specific payload argument.
     469 * @param a3            Driver-specific payload argument.
     470 * @param a4            Driver-specific payload argument.
     471 * @param a5            Driver-specific payload argument.
     472 */
     473void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2, unative_t a3,
     474    unative_t a4, unative_t a5)
     475{
     476        call_t *call;
     477
     478        spinlock_lock(&irq->lock);
     479
    497480        if (irq->notif_cfg.answerbox) {
    498                 call_t *call = ipc_call_alloc(FRAME_ATOMIC);
     481                call = ipc_call_alloc(FRAME_ATOMIC);
    499482                if (!call) {
    500                         irq_spinlock_unlock(&irq->lock, true);
     483                        spinlock_unlock(&irq->lock);
    501484                        return;
    502485                }
    503                
    504486                call->flags |= IPC_CALL_NOTIF;
    505487                /* Put a counter to the message */
    506488                call->priv = ++irq->notif_cfg.counter;
    507                
    508                 IPC_SET_IMETHOD(call->data, irq->notif_cfg.imethod);
     489
     490                IPC_SET_METHOD(call->data, irq->notif_cfg.method);
    509491                IPC_SET_ARG1(call->data, a1);
    510492                IPC_SET_ARG2(call->data, a2);
     
    515497                send_call(irq, call);
    516498        }
    517        
    518         irq_spinlock_unlock(&irq->lock, true);
     499        spinlock_unlock(&irq->lock);
    519500}
    520501
Note: See TracChangeset for help on using the changeset viewer.