source: mainline/kernel/generic/src/ddi/irq.c@ a4e78743

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a4e78743 was 5e801dc, checked in by GitHub <noreply@…>, 6 years ago

Indicate and enforce constness of hash table key in certain functions (#158)

The assumption here is that modifying key in the hash/equal functions in something completely unexpected, and not something you would ever want to do intentionally, so it makes sense to disallow it entirely to get that extra level of checking.

  • Property mode set to 100644
File size: 6.6 KB
RevLine 
[0d107f31]1/*
[df4ed85]2 * Copyright (c) 2006 Jakub Jermar
[0d107f31]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[174156fd]29/** @addtogroup kernel_generic_ddi
[0d107f31]30 * @{
31 */
32/**
33 * @file
[4d76cfc]34 * @brief IRQ dispatcher
[0d107f31]35 *
[4d76cfc]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.
[0d107f31]39 */
40
[7dcf22a]41#include <ddi/irq.h>
[82cbf8c6]42#include <adt/hash.h>
[0d107f31]43#include <adt/hash_table.h>
[cecb0789]44#include <mm/slab.h>
[d99c1d2]45#include <typedefs.h>
[0d107f31]46#include <synch/spinlock.h>
[691eb52]47#include <console/console.h>
[3a2f8aa]48#include <interrupt.h>
[44a7ee5]49#include <mem.h>
[0d107f31]50#include <arch.h>
51
[82d515e9]52slab_cache_t *irq_cache = NULL;
[431c402]53
[4d76cfc]54/** Spinlock protecting the kernel IRQ hash table
[da1bafb]55 *
[0d107f31]56 * This lock must be taken only when interrupts are disabled.
[da1bafb]57 *
[0d107f31]58 */
[da1bafb]59IRQ_SPINLOCK_STATIC_INITIALIZE(irq_kernel_hash_table_lock);
60
[cecb0789]61/** The kernel IRQ hash table. */
62static hash_table_t irq_kernel_hash_table;
63
[4d76cfc]64/** Spinlock protecting the uspace IRQ hash table
[da1bafb]65 *
[cecb0789]66 * This lock must be taken only when interrupts are disabled.
[da1bafb]67 *
[cecb0789]68 */
[da1bafb]69IRQ_SPINLOCK_INITIALIZE(irq_uspace_hash_table_lock);
70
[4d76cfc]71/** The uspace IRQ hash table */
[cecb0789]72hash_table_t irq_uspace_hash_table;
[0d107f31]73
[82cbf8c6]74static size_t irq_ht_hash(const ht_link_t *);
[5e801dc]75static size_t irq_ht_key_hash(const void *);
[82cbf8c6]76static bool irq_ht_equal(const ht_link_t *, const ht_link_t *);
[5e801dc]77static bool irq_ht_key_equal(const void *, const ht_link_t *);
[0d107f31]78
[82cbf8c6]79static hash_table_ops_t irq_ht_ops = {
[0d107f31]80 .hash = irq_ht_hash,
[82cbf8c6]81 .key_hash = irq_ht_key_hash,
82 .equal = irq_ht_equal,
83 .key_equal = irq_ht_key_equal
[0d107f31]84};
85
[4d76cfc]86/** Last valid INR */
[78ffb70]87inr_t last_inr = 0;
88
[4d76cfc]89/** Initialize IRQ subsystem
[0d107f31]90 *
[4d76cfc]91 * @param inrs Numbers of unique IRQ numbers or INRs.
92 * @param chains Number of buckets in the hash table.
[da1bafb]93 *
[0d107f31]94 */
[98000fb]95void irq_init(size_t inrs, size_t chains)
[0d107f31]96{
[78ffb70]97 last_inr = inrs - 1;
98
[82d515e9]99 irq_cache = slab_cache_create("irq_t", sizeof(irq_t), 0, NULL, NULL,
[431c402]100 FRAME_ATOMIC);
[82d515e9]101 assert(irq_cache);
[431c402]102
[82cbf8c6]103 hash_table_create(&irq_uspace_hash_table, chains, 0, &irq_ht_ops);
104 hash_table_create(&irq_kernel_hash_table, chains, 0, &irq_ht_ops);
[0d107f31]105}
106
[4d76cfc]107/** Initialize one IRQ structure
[0d107f31]108 *
[4d76cfc]109 * @param irq Pointer to the IRQ structure to be initialized.
[0d107f31]110 *
111 */
112void irq_initialize(irq_t *irq)
113{
[f542825]114 memsetb(irq, sizeof(irq_t), 0);
[da1bafb]115 irq_spinlock_initialize(&irq->lock, "irq.lock");
[0d107f31]116 irq->inr = -1;
[a35b458]117
[3a2f8aa]118 irq_initialize_arch(irq);
[0d107f31]119}
120
[4d76cfc]121/** Register IRQ for device
[0d107f31]122 *
[ee50130]123 * The irq structure must be filled with information about the interrupt source
124 * and with the claim() function pointer and handler() function pointer.
[0d107f31]125 *
[4d76cfc]126 * @param irq IRQ structure belonging to a device.
[da1bafb]127 *
[0d107f31]128 */
129void irq_register(irq_t *irq)
130{
[da1bafb]131 irq_spinlock_lock(&irq_kernel_hash_table_lock, true);
132 irq_spinlock_lock(&irq->lock, false);
[82cbf8c6]133 hash_table_insert(&irq_kernel_hash_table, &irq->link);
[da1bafb]134 irq_spinlock_unlock(&irq->lock, false);
135 irq_spinlock_unlock(&irq_kernel_hash_table_lock, true);
[0d107f31]136}
137
[82cbf8c6]138/** Search and lock an IRQ hash table */
139static irq_t *
140irq_dispatch_and_lock_table(hash_table_t *h, irq_spinlock_t *l, inr_t inr)
[691eb52]141{
[82cbf8c6]142 irq_spinlock_lock(l, false);
[30f1a25]143 ht_link_t *first = hash_table_find(h, &inr);
144 for (ht_link_t *lnk = first; lnk;
145 lnk = hash_table_find_next(h, first, lnk)) {
[82cbf8c6]146 irq_t *irq = hash_table_get_inst(lnk, irq_t, link);
147 irq_spinlock_lock(&irq->lock, false);
148 if (irq->claim(irq) == IRQ_ACCEPT) {
149 /* leave irq locked */
150 irq_spinlock_unlock(l, false);
151 return irq;
152 }
153 irq_spinlock_unlock(&irq->lock, false);
[0d107f31]154 }
[82cbf8c6]155 irq_spinlock_unlock(l, false);
[a35b458]156
[691eb52]157 return NULL;
158}
[0d107f31]159
[4d76cfc]160/** Dispatch the IRQ
[691eb52]161 *
[ee50130]162 * We assume this function is only called from interrupt context (i.e. that
163 * interrupts are disabled prior to this call).
[691eb52]164 *
[ee50130]165 * This function attempts to lookup a fitting IRQ structure. In case of success,
166 * return with interrupts disabled and holding the respective structure.
[691eb52]167 *
[4d76cfc]168 * @param inr Interrupt number (aka inr or irq).
[691eb52]169 *
[ee50130]170 * @return IRQ structure of the respective device
171 * @return NULL if no IRQ structure found
[da1bafb]172 *
[691eb52]173 */
174irq_t *irq_dispatch_and_lock(inr_t inr)
175{
176 /*
[ee50130]177 * If the kernel console override is on, then try first the kernel
178 * handlers and eventually fall back to uspace handlers.
[691eb52]179 *
[ee50130]180 * In the usual case the uspace handlers have precedence.
[691eb52]181 */
[a35b458]182
[b366a6f4]183 if (console_override) {
[82cbf8c6]184 irq_t *irq = irq_dispatch_and_lock_table(&irq_kernel_hash_table,
185 &irq_kernel_hash_table_lock, inr);
[691eb52]186 if (irq)
187 return irq;
[a35b458]188
[82cbf8c6]189 return irq_dispatch_and_lock_table(&irq_uspace_hash_table,
190 &irq_uspace_hash_table_lock, inr);
[691eb52]191 }
[a35b458]192
[82cbf8c6]193 irq_t *irq = irq_dispatch_and_lock_table(&irq_uspace_hash_table,
194 &irq_uspace_hash_table_lock, inr);
[691eb52]195 if (irq)
196 return irq;
[a35b458]197
[82cbf8c6]198 return irq_dispatch_and_lock_table(&irq_kernel_hash_table,
199 &irq_kernel_hash_table_lock, inr);
[0d107f31]200}
201
[82cbf8c6]202/** Return the hash of the key stored in the item. */
203size_t irq_ht_hash(const ht_link_t *item)
[0d107f31]204{
[82cbf8c6]205 irq_t *irq = hash_table_get_inst(item, irq_t, link);
206 return hash_mix(irq->inr);
[0d107f31]207}
208
[82cbf8c6]209/** Return the hash of the key. */
[5e801dc]210size_t irq_ht_key_hash(const void *key)
[0d107f31]211{
[5e801dc]212 const inr_t *inr = key;
[82cbf8c6]213 return hash_mix(*inr);
[0d107f31]214}
215
[82cbf8c6]216/** Return true if the items have the same lookup key. */
217bool irq_ht_equal(const ht_link_t *item1, const ht_link_t *item2)
[2845930]218{
[82cbf8c6]219 irq_t *irq1 = hash_table_get_inst(item1, irq_t, link);
220 irq_t *irq2 = hash_table_get_inst(item2, irq_t, link);
221 return irq1->inr == irq2->inr;
222}
223
224/** Return true if the key is equal to the item's lookup key. */
[5e801dc]225bool irq_ht_key_equal(const void *key, const ht_link_t *item)
[82cbf8c6]226{
[5e801dc]227 const inr_t *inr = key;
[82cbf8c6]228 irq_t *irq = hash_table_get_inst(item, irq_t, link);
229 return irq->inr == *inr;
[2845930]230}
231
[0d107f31]232/** @}
233 */
Note: See TracBrowser for help on using the repository browser.