Ignore:
File:
1 edited

Legend:

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

    r431c402 ree50130  
    3232/**
    3333 * @file
    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.
     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.
    3964 */
    4065
     
    4974#include <arch.h>
    5075
    51 slab_cache_t *irq_slab = NULL;
    52 
    53 /** Spinlock protecting the kernel IRQ hash table
     76#define KEY_INR    0
     77#define KEY_DEVNO  1
     78
     79/** Spinlock protecting the kernel IRQ hash table.
    5480 *
    5581 * This lock must be taken only when interrupts are disabled.
     
    6187static hash_table_t irq_kernel_hash_table;
    6288
    63 /** Spinlock protecting the uspace IRQ hash table
     89/** Spinlock protecting the uspace IRQ hash table.
    6490 *
    6591 * This lock must be taken only when interrupts are disabled.
     
    6894IRQ_SPINLOCK_INITIALIZE(irq_uspace_hash_table_lock);
    6995
    70 /** The uspace IRQ hash table */
     96/** The uspace IRQ hash table. */
    7197hash_table_t irq_uspace_hash_table;
    7298
     99/**
     100 * Hash table operations for cases when we know that there will be collisions
     101 * between different keys.
     102 */
    73103static size_t irq_ht_hash(sysarg_t *key);
    74104static bool irq_ht_compare(sysarg_t *key, size_t keys, link_t *item);
     
    81111};
    82112
    83 /** Number of buckets in either of the hash tables */
     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 */
     118static size_t irq_lin_hash(sysarg_t *key);
     119static bool irq_lin_compare(sysarg_t *key, size_t keys, link_t *item);
     120static void irq_lin_remove(link_t *item);
     121
     122static 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. */
    84129static size_t buckets;
    85130
    86 /** Last valid INR */
     131/** Last valid INR. */
    87132inr_t last_inr = 0;
    88133
    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.
     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.
    93138 *
    94139 */
     
    98143        last_inr = inrs - 1;
    99144
    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.
     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.
    111167 *
    112168 */
     
    116172        link_initialize(&irq->link);
    117173        irq_spinlock_initialize(&irq->lock, "irq.lock");
     174        link_initialize(&irq->notif_cfg.link);
    118175        irq->inr = -1;
     176        irq->devno = -1;
    119177       
    120178        irq_initialize_arch(irq);
    121179}
    122180
    123 /** Register IRQ for device
     181/** Register IRQ for device.
    124182 *
    125183 * The irq structure must be filled with information about the interrupt source
    126184 * and with the claim() function pointer and handler() function pointer.
    127185 *
    128  * @param irq  IRQ structure belonging to a device.
     186 * @param irq IRQ structure belonging to a device.
    129187 *
    130188 */
     
    132190{
    133191        sysarg_t key[] = {
    134                 [IRQ_HT_KEY_INR] = (sysarg_t) irq->inr,
    135                 [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_NO_CLAIM
     192                (sysarg_t) irq->inr,
     193                (sysarg_t) irq->devno
    136194        };
    137195       
     
    143201}
    144202
    145 /** Search and lock the uspace IRQ hash table */
     203/** Search and lock the uspace IRQ hash table.
     204 *
     205 */
    146206static irq_t *irq_dispatch_and_lock_uspace(inr_t inr)
    147207{
    148208        link_t *lnk;
    149209        sysarg_t key[] = {
    150                 [IRQ_HT_KEY_INR] = (sysarg_t) inr,
    151                 [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_CLAIM
     210                (sysarg_t) inr,
     211                (sysarg_t) -1    /* Search will use claim() instead of devno */
    152212        };
    153213       
     
    164224}
    165225
    166 /** Search and lock the kernel IRQ hash table */
     226/** Search and lock the kernel IRQ hash table.
     227 *
     228 */
    167229static irq_t *irq_dispatch_and_lock_kernel(inr_t inr)
    168230{
    169231        link_t *lnk;
    170232        sysarg_t key[] = {
    171                 [IRQ_HT_KEY_INR] = (sysarg_t) inr,
    172                 [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_CLAIM
     233                (sysarg_t) inr,
     234                (sysarg_t) -1    /* Search will use claim() instead of devno */
    173235        };
    174236       
     
    185247}
    186248
    187 /** Dispatch the IRQ
     249/** Dispatch the IRQ.
    188250 *
    189251 * We assume this function is only called from interrupt context (i.e. that
     
    193255 * return with interrupts disabled and holding the respective structure.
    194256 *
    195  * @param inr  Interrupt number (aka inr or irq).
     257 * @param inr Interrupt number (aka inr or irq).
    196258 *
    197259 * @return IRQ structure of the respective device
     
    223285}
    224286
    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.
     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.
    229295 *
    230296 * @return Index into the hash table.
     
    233299size_t irq_ht_hash(sysarg_t key[])
    234300{
    235         inr_t inr = (inr_t) key[IRQ_HT_KEY_INR];
     301        inr_t inr = (inr_t) key[KEY_INR];
    236302        return inr % buckets;
    237303}
    238304
    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.
     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.
    243313 *
    244314 * This function assumes interrupts are already disabled.
    245315 *
    246  * @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
     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 match
     321 * @return false on no match
    252322 *
    253323 */
     
    255325{
    256326        irq_t *irq = hash_table_get_instance(item, irq_t, link);
    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];
     327        inr_t inr = (inr_t) key[KEY_INR];
     328        devno_t devno = (devno_t) key[KEY_DEVNO];
    259329       
    260330        bool rv;
    261331       
    262332        irq_spinlock_lock(&irq->lock, false);
    263         if (mode == IRQ_HT_MODE_CLAIM) {
     333        if (devno == -1) {
    264334                /* Invoked by irq_dispatch_and_lock(). */
    265                 rv = ((irq->inr == inr) && (irq->claim(irq) == IRQ_ACCEPT));
     335                rv = ((irq->inr == inr) &&
     336                    (irq->claim(irq) == IRQ_ACCEPT));
    266337        } else {
    267338                /* Invoked by irq_find_and_lock(). */
    268                 rv = false;
     339                rv = ((irq->inr == inr) && (irq->devno == devno));
    269340        }
    270341       
     
    276347}
    277348
    278 /** Unlock IRQ structure after hash_table_remove()
    279  *
    280  * @param lnk  Link in the removed and locked IRQ structure.
     349/** Unlock IRQ structure after hash_table_remove().
     350 *
     351 * @param lnk Link in the removed and locked IRQ structure.
    281352 */
    282353void irq_ht_remove(link_t *lnk)
     
    287358}
    288359
     360/** Compute hash index for the key.
     361 *
     362 * This function computes hash index into the IRQ hash table for which there are
     363 * 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 */
     370size_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 the
     379 * less complex architecture setup in which there are not too many interrupt
     380 * numbers (i.e. inr's) to arrange the hash table so that collisions occur only
     381 * among same inrs of different devnos. So the explicit check for inr match is
     382 * not done.  Second, if devno is -1, the second key (i.e. devno) is not used
     383 * 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 match
     392 * @return false on no match
     393 *
     394 */
     395bool 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 */
     422void 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
    289429/** @}
    290430 */
Note: See TracChangeset for help on using the changeset viewer.