Changeset 91b60499 in mainline for kernel/generic/src/ddi/irq.c


Ignore:
Timestamp:
2017-09-30T06:29:42Z (7 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
300f4c4
Parents:
d076f16 (diff), 6636fb19 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge support for capabilities from lp:~jakub/helenos/caps

This commit introduces capabilities as task-local names for references to kernel
objects. Kernel objects are reference-counted wrappers for a select group of
objects allocated in and by the kernel that can be made accessible to userspace
in a controlled way via integer handles.

So far, a kernel object encapsulates either an irq_t or a phone_t.

Support for the former lead to the removal of kernel-assigned devnos and
unsecure deregistration of IRQs in which a random task was able to unregister
some other task's IRQ.

File:
1 edited

Legend:

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

    rd076f16 r91b60499  
    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 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.
     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.
    6439 */
    6540
     
    7449#include <arch.h>
    7550
    76 #define KEY_INR    0
    77 #define KEY_DEVNO  1
    78 
    79 /** Spinlock protecting the kernel IRQ hash table.
     51slab_cache_t *irq_slab = NULL;
     52
     53/** Spinlock protecting the kernel IRQ hash table
    8054 *
    8155 * This lock must be taken only when interrupts are disabled.
     
    8761static hash_table_t irq_kernel_hash_table;
    8862
    89 /** Spinlock protecting the uspace IRQ hash table.
     63/** Spinlock protecting the uspace IRQ hash table
    9064 *
    9165 * This lock must be taken only when interrupts are disabled.
     
    9468IRQ_SPINLOCK_INITIALIZE(irq_uspace_hash_table_lock);
    9569
    96 /** The uspace IRQ hash table. */
     70/** The uspace IRQ hash table */
    9771hash_table_t irq_uspace_hash_table;
    9872
    99 /**
    100  * Hash table operations for cases when we know that there will be collisions
    101  * between different keys.
    102  */
    10373static size_t irq_ht_hash(sysarg_t *key);
    10474static bool irq_ht_compare(sysarg_t *key, size_t keys, link_t *item);
     
    11181};
    11282
    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  */
    118 static size_t irq_lin_hash(sysarg_t *key);
    119 static bool irq_lin_compare(sysarg_t *key, size_t keys, link_t *item);
    120 static void irq_lin_remove(link_t *item);
    121 
    122 static 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. */
     83/** Number of buckets in either of the hash tables */
    12984static size_t buckets;
    13085
    131 /** Last valid INR. */
     86/** Last valid INR */
    13287inr_t last_inr = 0;
    13388
    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.
     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.
    13893 *
    13994 */
     
    14398        last_inr = inrs - 1;
    14499
    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.
     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.
    167111 *
    168112 */
     
    172116        link_initialize(&irq->link);
    173117        irq_spinlock_initialize(&irq->lock, "irq.lock");
    174         link_initialize(&irq->notif_cfg.link);
    175118        irq->inr = -1;
    176         irq->devno = -1;
    177119       
    178120        irq_initialize_arch(irq);
    179121}
    180122
    181 /** Register IRQ for device.
     123/** Register IRQ for device
    182124 *
    183125 * The irq structure must be filled with information about the interrupt source
    184126 * and with the claim() function pointer and handler() function pointer.
    185127 *
    186  * @param irq IRQ structure belonging to a device.
     128 * @param irq  IRQ structure belonging to a device.
    187129 *
    188130 */
     
    190132{
    191133        sysarg_t key[] = {
    192                 (sysarg_t) irq->inr,
    193                 (sysarg_t) irq->devno
     134                [IRQ_HT_KEY_INR] = (sysarg_t) irq->inr,
     135                [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_NO_CLAIM
    194136        };
    195137       
     
    201143}
    202144
    203 /** Search and lock the uspace IRQ hash table.
    204  *
    205  */
     145/** Search and lock the uspace IRQ hash table */
    206146static irq_t *irq_dispatch_and_lock_uspace(inr_t inr)
    207147{
    208148        link_t *lnk;
    209149        sysarg_t key[] = {
    210                 (sysarg_t) inr,
    211                 (sysarg_t) -1    /* Search will use claim() instead of devno */
     150                [IRQ_HT_KEY_INR] = (sysarg_t) inr,
     151                [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_CLAIM
    212152        };
    213153       
     
    224164}
    225165
    226 /** Search and lock the kernel IRQ hash table.
    227  *
    228  */
     166/** Search and lock the kernel IRQ hash table */
    229167static irq_t *irq_dispatch_and_lock_kernel(inr_t inr)
    230168{
    231169        link_t *lnk;
    232170        sysarg_t key[] = {
    233                 (sysarg_t) inr,
    234                 (sysarg_t) -1    /* Search will use claim() instead of devno */
     171                [IRQ_HT_KEY_INR] = (sysarg_t) inr,
     172                [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_CLAIM
    235173        };
    236174       
     
    247185}
    248186
    249 /** Dispatch the IRQ.
     187/** Dispatch the IRQ
    250188 *
    251189 * We assume this function is only called from interrupt context (i.e. that
     
    255193 * return with interrupts disabled and holding the respective structure.
    256194 *
    257  * @param inr Interrupt number (aka inr or irq).
     195 * @param inr  Interrupt number (aka inr or irq).
    258196 *
    259197 * @return IRQ structure of the respective device
     
    285223}
    286224
    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.
     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.
    295229 *
    296230 * @return Index into the hash table.
     
    299233size_t irq_ht_hash(sysarg_t key[])
    300234{
    301         inr_t inr = (inr_t) key[KEY_INR];
     235        inr_t inr = (inr_t) key[IRQ_HT_KEY_INR];
    302236        return inr % buckets;
    303237}
    304238
    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.
     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.
    313243 *
    314244 * This function assumes interrupts are already disabled.
    315245 *
    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
     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
    322252 *
    323253 */
     
    325255{
    326256        irq_t *irq = hash_table_get_instance(item, irq_t, link);
    327         inr_t inr = (inr_t) key[KEY_INR];
    328         devno_t devno = (devno_t) key[KEY_DEVNO];
     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];
    329259       
    330260        bool rv;
    331261       
    332262        irq_spinlock_lock(&irq->lock, false);
    333         if (devno == -1) {
     263        if (mode == IRQ_HT_MODE_CLAIM) {
    334264                /* Invoked by irq_dispatch_and_lock(). */
    335                 rv = ((irq->inr == inr) &&
    336                     (irq->claim(irq) == IRQ_ACCEPT));
     265                rv = ((irq->inr == inr) && (irq->claim(irq) == IRQ_ACCEPT));
    337266        } else {
    338267                /* Invoked by irq_find_and_lock(). */
    339                 rv = ((irq->inr == inr) && (irq->devno == devno));
     268                rv = false;
    340269        }
    341270       
     
    347276}
    348277
    349 /** Unlock IRQ structure after hash_table_remove().
    350  *
    351  * @param lnk Link in the removed and locked IRQ structure.
     278/** Unlock IRQ structure after hash_table_remove()
     279 *
     280 * @param lnk  Link in the removed and locked IRQ structure.
    352281 */
    353282void irq_ht_remove(link_t *lnk)
     
    358287}
    359288
    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  */
    370 size_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  */
    395 bool 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  */
    422 void 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 
    429289/** @}
    430290 */
Note: See TracChangeset for help on using the changeset viewer.