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

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

IRQ handlers are using one superfluous argument and an unused elipsis.
On the other hand, IRQ claim functions would need to be passed the instance
argument.

  • Property mode set to 100644
File size: 10.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
[e3890b3f]34 * @brief IRQ dispatcher.
[0d107f31]35 *
36 * This file provides means of connecting IRQs with particular
37 * devices and logic for dispatching interrupts to IRQ handlers
38 * defined by those devices.
39 *
40 * This code is designed to support:
41 * - multiple devices sharing single IRQ
[6cd9aa6]42 * - multiple IRQs per single device
43 * - multiple instances of the same device
[0d107f31]44 *
45 *
46 * Note about architectures.
47 *
48 * Some architectures has the term IRQ well defined. Examples
49 * of such architectures include amd64, ia32 and mips32. Some
50 * other architectures, such as sparc64, don't use the term
51 * at all. In those cases, we boldly step forward and define what
52 * an IRQ is.
53 *
54 * The implementation is generic enough and still allows the
55 * architectures to use the hardware layout effectively.
56 * For instance, on amd64 and ia32, where there is only 16
57 * IRQs, the irq_hash_table can be optimized to a one-dimensional
58 * array. Next, when it is known that the IRQ numbers (aka INR's)
59 * are unique, the claim functions can always return IRQ_ACCEPT.
[e3890b3f]60 *
61 *
62 * Note about the irq_hash_table.
63 *
64 * The hash table is configured to use two keys: inr and devno.
65 * However, the hash index is computed only from inr. Moreover,
66 * if devno is -1, the match is based on the return value of
67 * the claim() function instead of on devno.
[0d107f31]68 */
69
[7dcf22a]70#include <ddi/irq.h>
[0d107f31]71#include <adt/hash_table.h>
72#include <arch/types.h>
73#include <synch/spinlock.h>
74#include <arch.h>
75
[e3890b3f]76#define KEY_INR 0
77#define KEY_DEVNO 1
78
[0d107f31]79/**
80 * Spinlock protecting the hash table.
81 * This lock must be taken only when interrupts are disabled.
82 */
83SPINLOCK_INITIALIZE(irq_hash_table_lock);
84static hash_table_t irq_hash_table;
85
86/**
87 * Hash table operations for cases when we know that
88 * there will be collisions between different keys.
89 */
90static index_t irq_ht_hash(unative_t *key);
91static bool irq_ht_compare(unative_t *key, count_t keys, link_t *item);
92
93static hash_table_operations_t irq_ht_ops = {
94 .hash = irq_ht_hash,
95 .compare = irq_ht_compare,
96 .remove_callback = NULL /* not used */
97};
98
99/**
100 * Hash table operations for cases when we know that
101 * there will be no collisions between different keys.
102 * However, there might be still collisions among
103 * elements with single key (sharing of one IRQ).
104 */
105static index_t irq_lin_hash(unative_t *key);
106static bool irq_lin_compare(unative_t *key, count_t keys, link_t *item);
107
108static hash_table_operations_t irq_lin_ops = {
109 .hash = irq_lin_hash,
110 .compare = irq_lin_compare,
111 .remove_callback = NULL /* not used */
112};
113
114/** Initialize IRQ subsystem.
115 *
116 * @param inrs Numbers of unique IRQ numbers or INRs.
117 * @param chains Number of chains in the hash table.
118 */
119void irq_init(count_t inrs, count_t chains)
120{
121 /*
122 * Be smart about the choice of the hash table operations.
123 * In cases in which inrs equals the requested number of
124 * chains (i.e. where there is no collision between
125 * different keys), we can use optimized set of operations.
126 */
127 if (inrs == chains)
[e3890b3f]128 hash_table_create(&irq_hash_table, chains, 2, &irq_lin_ops);
[0d107f31]129 else
[e3890b3f]130 hash_table_create(&irq_hash_table, chains, 2, &irq_ht_ops);
[0d107f31]131}
132
133/** Initialize one IRQ structure.
134 *
135 * @param irq Pointer to the IRQ structure to be initialized.
136 *
137 */
138void irq_initialize(irq_t *irq)
139{
140 link_initialize(&irq->link);
[63530c62]141 spinlock_initialize(&irq->lock, "irq.lock");
[7bcfbbc]142 irq->preack = false;
[0d107f31]143 irq->inr = -1;
144 irq->devno = -1;
[b513b3e]145 irq->trigger = (irq_trigger_t) 0;
[0d107f31]146 irq->claim = NULL;
147 irq->handler = NULL;
[6cd9aa6]148 irq->instance = NULL;
[8d2760f]149 irq->cir = NULL;
150 irq->cir_arg = NULL;
[b14e35f2]151 irq->notif_cfg.notify = false;
[2b017ba]152 irq->notif_cfg.answerbox = NULL;
153 irq->notif_cfg.code = NULL;
154 irq->notif_cfg.method = 0;
155 irq->notif_cfg.counter = 0;
[b14e35f2]156 link_initialize(&irq->notif_cfg.link);
[0d107f31]157}
158
159/** Register IRQ for device.
160 *
161 * The irq structure must be filled with information
162 * about the interrupt source and with the claim()
163 * function pointer and irq_handler() function pointer.
164 *
165 * @param irq IRQ structure belonging to a device.
166 */
167void irq_register(irq_t *irq)
168{
169 ipl_t ipl;
[e3890b3f]170 unative_t key[] = {
171 (unative_t) irq->inr,
172 (unative_t) irq->devno
173 };
[0d107f31]174
175 ipl = interrupts_disable();
176 spinlock_lock(&irq_hash_table_lock);
[e3890b3f]177 hash_table_insert(&irq_hash_table, key, &irq->link);
[0d107f31]178 spinlock_unlock(&irq_hash_table_lock);
179 interrupts_restore(ipl);
180}
181
182/** Dispatch the IRQ.
[e3890b3f]183 *
184 * We assume this function is only called from interrupt
185 * context (i.e. that interrupts are disabled prior to
186 * this call).
187 *
188 * This function attempts to lookup a fitting IRQ
189 * structure. In case of success, return with interrupts
190 * disabled and holding the respective structure.
[0d107f31]191 *
192 * @param inr Interrupt number (aka inr or irq).
193 *
194 * @return IRQ structure of the respective device or NULL.
195 */
[e3890b3f]196irq_t *irq_dispatch_and_lock(inr_t inr)
[0d107f31]197{
198 link_t *lnk;
[e3890b3f]199 unative_t key[] = {
200 (unative_t) inr,
201 (unative_t) -1 /* search will use claim() instead of devno */
202 };
[0d107f31]203
204 spinlock_lock(&irq_hash_table_lock);
205
[e3890b3f]206 lnk = hash_table_find(&irq_hash_table, key);
207 if (lnk) {
208 irq_t *irq;
209
210 irq = hash_table_get_instance(lnk, irq_t, link);
211
212 spinlock_unlock(&irq_hash_table_lock);
213 return irq;
214 }
215
216 spinlock_unlock(&irq_hash_table_lock);
217
218 return NULL;
219}
220
221/** Find the IRQ structure corresponding to inr and devno.
222 *
223 * This functions attempts to lookup the IRQ structure
224 * corresponding to its arguments. On success, this
225 * function returns with interrups disabled, holding
226 * the lock of the respective IRQ structure.
227 *
228 * This function assumes interrupts are already disabled.
229 *
230 * @param inr INR being looked up.
231 * @param devno Devno being looked up.
232 *
233 * @return Locked IRQ structure on success or NULL on failure.
234 */
235irq_t *irq_find_and_lock(inr_t inr, devno_t devno)
236{
237 link_t *lnk;
238 unative_t keys[] = {
239 (unative_t) inr,
240 (unative_t) devno
241 };
242
243 spinlock_lock(&irq_hash_table_lock);
244
245 lnk = hash_table_find(&irq_hash_table, keys);
[0d107f31]246 if (lnk) {
247 irq_t *irq;
248
249 irq = hash_table_get_instance(lnk, irq_t, link);
250
251 spinlock_unlock(&irq_hash_table_lock);
252 return irq;
253 }
254
255 spinlock_unlock(&irq_hash_table_lock);
256
257 return NULL;
258}
259
260/** Compute hash index for the key.
261 *
262 * This function computes hash index into
263 * the IRQ hash table for which there
264 * can be collisions between different
265 * INRs.
266 *
[e3890b3f]267 * The devno is not used to compute the hash.
268 *
269 * @param key The first of the keys is inr and the second is devno or -1.
[0d107f31]270 *
271 * @return Index into the hash table.
272 */
[e3890b3f]273index_t irq_ht_hash(unative_t key[])
[0d107f31]274{
[e3890b3f]275 inr_t inr = (inr_t) key[KEY_INR];
276 return inr % irq_hash_table.entries;
[0d107f31]277}
278
279/** Compare hash table element with a key.
280 *
[e3890b3f]281 * There are two things to note about this function.
282 * First, it is used for the more complex architecture setup
283 * in which there are way too many interrupt numbers (i.e. inr's)
284 * to arrange the hash table so that collisions occur only
285 * among same inrs of different devnos. So the explicit check
286 * for inr match must be done.
287 * Second, if devno is -1, the second key (i.e. devno) is not
288 * used for the match and the result of the claim() function
289 * is used instead.
[0d107f31]290 *
[e3890b3f]291 * This function assumes interrupts are already disabled.
292 *
293 * @param key Keys (i.e. inr and devno).
294 * @param keys This is 2.
[0d107f31]295 * @param item The item to compare the key with.
296 *
297 * @return True on match or false otherwise.
298 */
[e3890b3f]299bool irq_ht_compare(unative_t key[], count_t keys, link_t *item)
[0d107f31]300{
301 irq_t *irq = hash_table_get_instance(item, irq_t, link);
[e3890b3f]302 inr_t inr = (inr_t) key[KEY_INR];
303 devno_t devno = (devno_t) key[KEY_DEVNO];
304
[63530c62]305 bool rv;
[0d107f31]306
[63530c62]307 spinlock_lock(&irq->lock);
[e3890b3f]308 if (devno == -1) {
[f619ec11]309 /* Invoked by irq_dispatch_and_lock(). */
[6cd9aa6]310 rv = ((irq->inr == inr) &&
311 (irq->claim(irq->instance) == IRQ_ACCEPT));
[e3890b3f]312 } else {
[f619ec11]313 /* Invoked by irq_find_and_lock(). */
[e3890b3f]314 rv = ((irq->inr == inr) && (irq->devno == devno));
315 }
316
317 /* unlock only on non-match */
318 if (!rv)
319 spinlock_unlock(&irq->lock);
[63530c62]320
321 return rv;
[0d107f31]322}
323
324/** Compute hash index for the key.
325 *
326 * This function computes hash index into
327 * the IRQ hash table for which there
328 * are no collisions between different
329 * INRs.
330 *
[e3890b3f]331 * @param key The first of the keys is inr and the second is devno or -1.
[0d107f31]332 *
333 * @return Index into the hash table.
334 */
[e3890b3f]335index_t irq_lin_hash(unative_t key[])
[0d107f31]336{
[e3890b3f]337 inr_t inr = (inr_t) key[KEY_INR];
338 return inr;
[0d107f31]339}
340
341/** Compare hash table element with a key.
342 *
[e3890b3f]343 * There are two things to note about this function.
344 * First, it is used for the less complex architecture setup
345 * in which there are not too many interrupt numbers (i.e. inr's)
346 * to arrange the hash table so that collisions occur only
347 * among same inrs of different devnos. So the explicit check
348 * for inr match is not done.
349 * Second, if devno is -1, the second key (i.e. devno) is not
350 * used for the match and the result of the claim() function
351 * is used instead.
352 *
353 * This function assumes interrupts are already disabled.
[0d107f31]354 *
[e3890b3f]355 * @param key Keys (i.e. inr and devno).
356 * @param keys This is 2.
[0d107f31]357 * @param item The item to compare the key with.
358 *
359 * @return True on match or false otherwise.
360 */
[e3890b3f]361bool irq_lin_compare(unative_t key[], count_t keys, link_t *item)
[0d107f31]362{
363 irq_t *irq = list_get_instance(item, irq_t, link);
[e3890b3f]364 devno_t devno = (devno_t) key[KEY_DEVNO];
[63530c62]365 bool rv;
366
367 spinlock_lock(&irq->lock);
[e3890b3f]368 if (devno == -1) {
[f619ec11]369 /* Invoked by irq_dispatch_and_lock() */
[6cd9aa6]370 rv = (irq->claim(irq->instance) == IRQ_ACCEPT);
[e3890b3f]371 } else {
[f619ec11]372 /* Invoked by irq_find_and_lock() */
[e3890b3f]373 rv = (irq->devno == devno);
374 }
375
376 /* unlock only on non-match */
377 if (!rv)
378 spinlock_unlock(&irq->lock);
[0d107f31]379
[63530c62]380 return rv;
[0d107f31]381}
382
383/** @}
384 */
Note: See TracBrowser for help on using the repository browser.