Changeset 4d76cfc in mainline for kernel/generic/src/ddi/irq.c


Ignore:
Timestamp:
2017-08-19T00:01:04Z (7 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
e7c4115d
Parents:
24abb85d
Message:

Remove the linear IRQ hash table optimization

File:
1 edited

Legend:

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

    r24abb85d r4d76cfc  
    3232/**
    3333 * @file
    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 mode.  However, the
    62  * hash index is computed only from inr. Moreover, if mode is IRQ_HT_MODE_CLAIM,
    63  * the match is based also on the return value of the claim(). Otherwise the
    64  * the keys do not match.
     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.
    6539 */
    6640
     
    7549#include <arch.h>
    7650
    77 /** Spinlock protecting the kernel IRQ hash table.
     51/** Spinlock protecting the kernel IRQ hash table
    7852 *
    7953 * This lock must be taken only when interrupts are disabled.
     
    8559static hash_table_t irq_kernel_hash_table;
    8660
    87 /** Spinlock protecting the uspace IRQ hash table.
     61/** Spinlock protecting the uspace IRQ hash table
    8862 *
    8963 * This lock must be taken only when interrupts are disabled.
     
    9266IRQ_SPINLOCK_INITIALIZE(irq_uspace_hash_table_lock);
    9367
    94 /** The uspace IRQ hash table. */
     68/** The uspace IRQ hash table */
    9569hash_table_t irq_uspace_hash_table;
    9670
    97 /**
    98  * Hash table operations for cases when we know that there will be collisions
    99  * between different keys.
    100  */
    10171static size_t irq_ht_hash(sysarg_t *key);
    10272static bool irq_ht_compare(sysarg_t *key, size_t keys, link_t *item);
     
    10979};
    11080
    111 /**
    112  * Hash table operations for cases when we know that there will be no collisions
    113  * between different keys.  However, there might be still collisions among
    114  * elements with single key (sharing of one IRQ).
    115  */
    116 static size_t irq_lin_hash(sysarg_t *key);
    117 static bool irq_lin_compare(sysarg_t *key, size_t keys, link_t *item);
    118 static void irq_lin_remove(link_t *item);
    119 
    120 static hash_table_operations_t irq_lin_ops = {
    121         .hash = irq_lin_hash,
    122         .compare = irq_lin_compare,
    123         .remove_callback = irq_lin_remove,
    124 };
    125 
    126 /** Number of buckets in either of the hash tables. */
     81/** Number of buckets in either of the hash tables */
    12782static size_t buckets;
    12883
    129 /** Last valid INR. */
     84/** Last valid INR */
    13085inr_t last_inr = 0;
    13186
    132 /** Initialize IRQ subsystem.
    133  *
    134  * @param inrs   Numbers of unique IRQ numbers or INRs.
    135  * @param chains Number of chains in the hash table.
     87/** Initialize IRQ subsystem
     88 *
     89 * @param inrs    Numbers of unique IRQ numbers or INRs.
     90 * @param chains  Number of buckets in the hash table.
    13691 *
    13792 */
     
    14196        last_inr = inrs - 1;
    14297
    143         /*
    144          * Be smart about the choice of the hash table operations.  In cases in
    145          * which inrs equals the requested number of chains (i.e. where there is
    146          * no collision between different keys), we can use optimized set of
    147          * operations.
    148          */
    149         if (inrs == chains) {
    150                 hash_table_create(&irq_uspace_hash_table, chains, 2,
    151                     &irq_lin_ops);
    152                 hash_table_create(&irq_kernel_hash_table, chains, 2,
    153                     &irq_lin_ops);
    154         } else {
    155                 hash_table_create(&irq_uspace_hash_table, chains, 2,
    156                     &irq_ht_ops);
    157                 hash_table_create(&irq_kernel_hash_table, chains, 2,
    158                     &irq_ht_ops);
    159         }
    160 }
    161 
    162 /** Initialize one IRQ structure.
    163  *
    164  * @param irq Pointer to the IRQ structure to be initialized.
     98        hash_table_create(&irq_uspace_hash_table, chains, 2, &irq_ht_ops);
     99        hash_table_create(&irq_kernel_hash_table, chains, 2, &irq_ht_ops);
     100}
     101
     102/** Initialize one IRQ structure
     103 *
     104 * @param irq  Pointer to the IRQ structure to be initialized.
    165105 *
    166106 */
     
    176116}
    177117
    178 /** Register IRQ for device.
     118/** Register IRQ for device
    179119 *
    180120 * The irq structure must be filled with information about the interrupt source
    181121 * and with the claim() function pointer and handler() function pointer.
    182122 *
    183  * @param irq IRQ structure belonging to a device.
     123 * @param irq  IRQ structure belonging to a device.
    184124 *
    185125 */
     
    198138}
    199139
    200 /** Search and lock the uspace IRQ hash table.
    201  *
    202  */
     140/** Search and lock the uspace IRQ hash table */
    203141static irq_t *irq_dispatch_and_lock_uspace(inr_t inr)
    204142{
     
    221159}
    222160
    223 /** Search and lock the kernel IRQ hash table.
    224  *
    225  */
     161/** Search and lock the kernel IRQ hash table */
    226162static irq_t *irq_dispatch_and_lock_kernel(inr_t inr)
    227163{
     
    244180}
    245181
    246 /** Dispatch the IRQ.
     182/** Dispatch the IRQ
    247183 *
    248184 * We assume this function is only called from interrupt context (i.e. that
     
    252188 * return with interrupts disabled and holding the respective structure.
    253189 *
    254  * @param inr Interrupt number (aka inr or irq).
     190 * @param inr  Interrupt number (aka inr or irq).
    255191 *
    256192 * @return IRQ structure of the respective device
     
    282218}
    283219
    284 /** Compute hash index for the key.
    285  *
    286  * This function computes hash index into the IRQ hash table for which there can
    287  * be collisions between different INRs.
    288  *
    289  * The mode is not used to compute the hash.
    290  *
    291  * @param key The first of the keys is inr and the second is mode.
     220/** Compute hash index for the key
     221 *
     222 * @param key  The first of the keys is inr and the second is mode. Only inr is
     223 *             used to compute the hash.
    292224 *
    293225 * @return Index into the hash table.
     
    300232}
    301233
    302 /** Compare hash table element with a key.
    303  *
    304  * There are two things to note about this function.  First, it is used for the
    305  * more complex architecture setup in which there are way too many interrupt
    306  * numbers (i.e. inr's) to arrange the hash table so that collisions occur only
    307  * among same inrs of different devices. So the explicit check for inr match
    308  * must be done.  Second, if mode is IRQ_HT_MODE_CLAIM, the result of the
    309  * claim() function is used for the match. Otherwise the key does not match.
     234/** Compare hash table element with a key
     235 *
     236 * If mode is IRQ_HT_MODE_CLAIM, the result of the claim() function is used for
     237 * the match. Otherwise the key does not match.
    310238 *
    311239 * This function assumes interrupts are already disabled.
    312240 *
    313  * @param key  Keys (i.e. inr and mode).
    314  * @param keys This is 2.
    315  * @param item The item to compare the key with.
    316  *
    317  * @return true on match
    318  * @return false on no match
     241 * @param key   Keys (i.e. inr and mode).
     242 * @param keys  This is 2.
     243 * @param item  The item to compare the key with.
     244 *
     245 * @return True on match
     246 * @return False on no match
    319247 *
    320248 */
     
    343271}
    344272
    345 /** Unlock IRQ structure after hash_table_remove().
    346  *
    347  * @param lnk Link in the removed and locked IRQ structure.
     273/** Unlock IRQ structure after hash_table_remove()
     274 *
     275 * @param lnk  Link in the removed and locked IRQ structure.
    348276 */
    349277void irq_ht_remove(link_t *lnk)
     
    354282}
    355283
    356 /** Compute hash index for the key.
    357  *
    358  * This function computes hash index into the IRQ hash table for which there are
    359  * no collisions between different INRs.
    360  *
    361  * @param key The first of the keys is inr and the second is mode.
    362  *
    363  * @return Index into the hash table.
    364  *
    365  */
    366 size_t irq_lin_hash(sysarg_t key[])
    367 {
    368         inr_t inr = (inr_t) key[IRQ_HT_KEY_INR];
    369         return inr;
    370 }
    371 
    372 /** Compare hash table element with a key.
    373  *
    374  * There are two things to note about this function.  First, it is used for the
    375  * less complex architecture setup in which there are not too many interrupt
    376  * numbers (i.e. inr's) to arrange the hash table so that collisions occur only
    377  * among same inrs of different devnos. So the explicit check for inr match is
    378  * not done.  Second, if devno is -1, the second key (i.e. devno) is not used
    379  * for the match and the result of the claim() function is used instead.
    380  *
    381  * This function assumes interrupts are already disabled.
    382  *
    383  * @param key  Keys (i.e. inr and mode).
    384  * @param keys This is 2.
    385  * @param item The item to compare the key with.
    386  *
    387  * @return true on match
    388  * @return false on no match
    389  *
    390  */
    391 bool irq_lin_compare(sysarg_t key[], size_t keys, link_t *item)
    392 {
    393         irq_t *irq = list_get_instance(item, irq_t, link);
    394         irq_ht_mode_t mode = (irq_ht_mode_t) key[IRQ_HT_KEY_MODE];
    395         bool rv;
    396        
    397         irq_spinlock_lock(&irq->lock, false);
    398         if (mode == IRQ_HT_MODE_CLAIM) {
    399                 /* Invoked by irq_dispatch_and_lock() */
    400                 rv = (irq->claim(irq) == IRQ_ACCEPT);
    401         } else {
    402                 /* Invoked by irq_find_and_lock() */
    403                 rv = false;
    404         }
    405        
    406         /* unlock only on non-match */
    407         if (!rv)
    408                 irq_spinlock_unlock(&irq->lock, false);
    409        
    410         return rv;
    411 }
    412 
    413 /** Unlock IRQ structure after hash_table_remove().
    414  *
    415  * @param lnk Link in the removed and locked IRQ structure.
    416  *
    417  */
    418 void irq_lin_remove(link_t *lnk)
    419 {
    420         irq_t *irq __attribute__((unused))
    421             = hash_table_get_instance(lnk, irq_t, link);
    422         irq_spinlock_unlock(&irq->lock, false);
    423 }
    424 
    425284/** @}
    426285 */
Note: See TracChangeset for help on using the changeset viewer.