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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3422fb6 was 3422fb6, checked in by Jakub Jermar <jakub@…>, 9 years ago

Do not register IRQs inside of answerboxes

  • Property mode set to 100644
File size: 7.7 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
[7dcf22a]29/** @addtogroup genericddi
[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>
[0d107f31]42#include <adt/hash_table.h>
[cecb0789]43#include <mm/slab.h>
[d99c1d2]44#include <typedefs.h>
[0d107f31]45#include <synch/spinlock.h>
[691eb52]46#include <console/console.h>
[3a2f8aa]47#include <interrupt.h>
[44a7ee5]48#include <mem.h>
[0d107f31]49#include <arch.h>
50
[4d76cfc]51/** Spinlock protecting the kernel IRQ hash table
[da1bafb]52 *
[0d107f31]53 * This lock must be taken only when interrupts are disabled.
[da1bafb]54 *
[0d107f31]55 */
[da1bafb]56IRQ_SPINLOCK_STATIC_INITIALIZE(irq_kernel_hash_table_lock);
57
[cecb0789]58/** The kernel IRQ hash table. */
59static hash_table_t irq_kernel_hash_table;
60
[4d76cfc]61/** Spinlock protecting the uspace IRQ hash table
[da1bafb]62 *
[cecb0789]63 * This lock must be taken only when interrupts are disabled.
[da1bafb]64 *
[cecb0789]65 */
[da1bafb]66IRQ_SPINLOCK_INITIALIZE(irq_uspace_hash_table_lock);
67
[4d76cfc]68/** The uspace IRQ hash table */
[cecb0789]69hash_table_t irq_uspace_hash_table;
[0d107f31]70
[96b02eb9]71static size_t irq_ht_hash(sysarg_t *key);
72static bool irq_ht_compare(sysarg_t *key, size_t keys, link_t *item);
[2845930]73static void irq_ht_remove(link_t *item);
[0d107f31]74
75static hash_table_operations_t irq_ht_ops = {
76 .hash = irq_ht_hash,
77 .compare = irq_ht_compare,
[2845930]78 .remove_callback = irq_ht_remove,
[0d107f31]79};
80
[4d76cfc]81/** Number of buckets in either of the hash tables */
[98000fb]82static size_t buckets;
[cecb0789]83
[4d76cfc]84/** Last valid INR */
[78ffb70]85inr_t last_inr = 0;
86
[4d76cfc]87/** Initialize IRQ subsystem
[0d107f31]88 *
[4d76cfc]89 * @param inrs Numbers of unique IRQ numbers or INRs.
90 * @param chains Number of buckets in the hash table.
[da1bafb]91 *
[0d107f31]92 */
[98000fb]93void irq_init(size_t inrs, size_t chains)
[0d107f31]94{
[cecb0789]95 buckets = chains;
[78ffb70]96 last_inr = inrs - 1;
97
[4d76cfc]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);
[0d107f31]100}
101
[4d76cfc]102/** Initialize one IRQ structure
[0d107f31]103 *
[4d76cfc]104 * @param irq Pointer to the IRQ structure to be initialized.
[0d107f31]105 *
106 */
107void irq_initialize(irq_t *irq)
108{
[f542825]109 memsetb(irq, sizeof(irq_t), 0);
[0d107f31]110 link_initialize(&irq->link);
[da1bafb]111 irq_spinlock_initialize(&irq->lock, "irq.lock");
[0d107f31]112 irq->inr = -1;
[da1bafb]113
[3a2f8aa]114 irq_initialize_arch(irq);
[0d107f31]115}
116
[4d76cfc]117/** Register IRQ for device
[0d107f31]118 *
[ee50130]119 * The irq structure must be filled with information about the interrupt source
120 * and with the claim() function pointer and handler() function pointer.
[0d107f31]121 *
[4d76cfc]122 * @param irq IRQ structure belonging to a device.
[da1bafb]123 *
[0d107f31]124 */
125void irq_register(irq_t *irq)
126{
[96b02eb9]127 sysarg_t key[] = {
[24abb85d]128 [IRQ_HT_KEY_INR] = (sysarg_t) irq->inr,
129 [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_NO_CLAIM
[e3890b3f]130 };
[0d107f31]131
[da1bafb]132 irq_spinlock_lock(&irq_kernel_hash_table_lock, true);
133 irq_spinlock_lock(&irq->lock, false);
[00eace3]134 hash_table_insert(&irq_kernel_hash_table, key, &irq->link);
[da1bafb]135 irq_spinlock_unlock(&irq->lock, false);
136 irq_spinlock_unlock(&irq_kernel_hash_table_lock, true);
[0d107f31]137}
138
[4d76cfc]139/** Search and lock the uspace IRQ hash table */
[691eb52]140static irq_t *irq_dispatch_and_lock_uspace(inr_t inr)
[0d107f31]141{
142 link_t *lnk;
[96b02eb9]143 sysarg_t key[] = {
[24abb85d]144 [IRQ_HT_KEY_INR] = (sysarg_t) inr,
145 [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_CLAIM
[e3890b3f]146 };
[0d107f31]147
[da1bafb]148 irq_spinlock_lock(&irq_uspace_hash_table_lock, false);
[cecb0789]149 lnk = hash_table_find(&irq_uspace_hash_table, key);
[e3890b3f]150 if (lnk) {
[da1bafb]151 irq_t *irq = hash_table_get_instance(lnk, irq_t, link);
152 irq_spinlock_unlock(&irq_uspace_hash_table_lock, false);
[e3890b3f]153 return irq;
154 }
[da1bafb]155 irq_spinlock_unlock(&irq_uspace_hash_table_lock, false);
[691eb52]156
157 return NULL;
158}
[e3890b3f]159
[4d76cfc]160/** Search and lock the kernel IRQ hash table */
[691eb52]161static irq_t *irq_dispatch_and_lock_kernel(inr_t inr)
162{
163 link_t *lnk;
[96b02eb9]164 sysarg_t key[] = {
[24abb85d]165 [IRQ_HT_KEY_INR] = (sysarg_t) inr,
166 [IRQ_HT_KEY_MODE] = (sysarg_t) IRQ_HT_MODE_CLAIM
[691eb52]167 };
168
[da1bafb]169 irq_spinlock_lock(&irq_kernel_hash_table_lock, false);
[cecb0789]170 lnk = hash_table_find(&irq_kernel_hash_table, key);
[0d107f31]171 if (lnk) {
[da1bafb]172 irq_t *irq = hash_table_get_instance(lnk, irq_t, link);
173 irq_spinlock_unlock(&irq_kernel_hash_table_lock, false);
[0d107f31]174 return irq;
175 }
[da1bafb]176 irq_spinlock_unlock(&irq_kernel_hash_table_lock, false);
[691eb52]177
178 return NULL;
179}
[0d107f31]180
[4d76cfc]181/** Dispatch the IRQ
[691eb52]182 *
[ee50130]183 * We assume this function is only called from interrupt context (i.e. that
184 * interrupts are disabled prior to this call).
[691eb52]185 *
[ee50130]186 * This function attempts to lookup a fitting IRQ structure. In case of success,
187 * return with interrupts disabled and holding the respective structure.
[691eb52]188 *
[4d76cfc]189 * @param inr Interrupt number (aka inr or irq).
[691eb52]190 *
[ee50130]191 * @return IRQ structure of the respective device
192 * @return NULL if no IRQ structure found
[da1bafb]193 *
[691eb52]194 */
195irq_t *irq_dispatch_and_lock(inr_t inr)
196{
197 /*
[ee50130]198 * If the kernel console override is on, then try first the kernel
199 * handlers and eventually fall back to uspace handlers.
[691eb52]200 *
[ee50130]201 * In the usual case the uspace handlers have precedence.
[691eb52]202 */
[b366a6f4]203
204 if (console_override) {
205 irq_t *irq = irq_dispatch_and_lock_kernel(inr);
[691eb52]206 if (irq)
207 return irq;
[da1bafb]208
[b366a6f4]209 return irq_dispatch_and_lock_uspace(inr);
[691eb52]210 }
211
[b366a6f4]212 irq_t *irq = irq_dispatch_and_lock_uspace(inr);
[691eb52]213 if (irq)
214 return irq;
[da1bafb]215
[b366a6f4]216 return irq_dispatch_and_lock_kernel(inr);
[0d107f31]217}
218
[4d76cfc]219/** Compute hash index for the key
[0d107f31]220 *
[4d76cfc]221 * @param key The first of the keys is inr and the second is mode. Only inr is
222 * used to compute the hash.
[0d107f31]223 *
224 * @return Index into the hash table.
[da1bafb]225 *
[0d107f31]226 */
[96b02eb9]227size_t irq_ht_hash(sysarg_t key[])
[0d107f31]228{
[24abb85d]229 inr_t inr = (inr_t) key[IRQ_HT_KEY_INR];
[cecb0789]230 return inr % buckets;
[0d107f31]231}
232
[4d76cfc]233/** Compare hash table element with a key
[0d107f31]234 *
[4d76cfc]235 * If mode is IRQ_HT_MODE_CLAIM, the result of the claim() function is used for
236 * the match. Otherwise the key does not match.
[0d107f31]237 *
[e3890b3f]238 * This function assumes interrupts are already disabled.
239 *
[4d76cfc]240 * @param key Keys (i.e. inr and mode).
241 * @param keys This is 2.
242 * @param item The item to compare the key with.
[0d107f31]243 *
[4d76cfc]244 * @return True on match
245 * @return False on no match
[da1bafb]246 *
[0d107f31]247 */
[96b02eb9]248bool irq_ht_compare(sysarg_t key[], size_t keys, link_t *item)
[0d107f31]249{
250 irq_t *irq = hash_table_get_instance(item, irq_t, link);
[24abb85d]251 inr_t inr = (inr_t) key[IRQ_HT_KEY_INR];
252 irq_ht_mode_t mode = (irq_ht_mode_t) key[IRQ_HT_KEY_MODE];
[da1bafb]253
[63530c62]254 bool rv;
[0d107f31]255
[da1bafb]256 irq_spinlock_lock(&irq->lock, false);
[24abb85d]257 if (mode == IRQ_HT_MODE_CLAIM) {
[f619ec11]258 /* Invoked by irq_dispatch_and_lock(). */
[24abb85d]259 rv = ((irq->inr == inr) && (irq->claim(irq) == IRQ_ACCEPT));
[e3890b3f]260 } else {
[f619ec11]261 /* Invoked by irq_find_and_lock(). */
[24abb85d]262 rv = false;
[e3890b3f]263 }
264
265 /* unlock only on non-match */
266 if (!rv)
[da1bafb]267 irq_spinlock_unlock(&irq->lock, false);
268
[63530c62]269 return rv;
[0d107f31]270}
271
[4d76cfc]272/** Unlock IRQ structure after hash_table_remove()
[2845930]273 *
[4d76cfc]274 * @param lnk Link in the removed and locked IRQ structure.
[2845930]275 */
276void irq_ht_remove(link_t *lnk)
277{
[c822026]278 irq_t *irq __attribute__((unused))
279 = hash_table_get_instance(lnk, irq_t, link);
[da1bafb]280 irq_spinlock_unlock(&irq->lock, false);
[2845930]281}
282
[0d107f31]283/** @}
284 */
Note: See TracBrowser for help on using the repository browser.