source: mainline/kernel/generic/src/interrupt/irq.c@ 0d107f31

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

Prototypical implementation of new IRQ redirector in sparc64.
The new code can support shared IRQs in kernel (and multiple IRQs per device).
Userspace support is yet to be written.
The only architecture that uses this code is actually sparc64 only.

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2 * Copyright (C) 2006 Jakub Jermar
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
29/** @addtogroup genericinterrupt
30 * @{
31 */
32/**
33 * @file
34 * @brief IRQ redirector.
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
42 * - multiple IRQs per signle device
43 *
44 *
45 * Note about architectures.
46 *
47 * Some architectures has the term IRQ well defined. Examples
48 * of such architectures include amd64, ia32 and mips32. Some
49 * other architectures, such as sparc64, don't use the term
50 * at all. In those cases, we boldly step forward and define what
51 * an IRQ is.
52 *
53 * The implementation is generic enough and still allows the
54 * architectures to use the hardware layout effectively.
55 * For instance, on amd64 and ia32, where there is only 16
56 * IRQs, the irq_hash_table can be optimized to a one-dimensional
57 * array. Next, when it is known that the IRQ numbers (aka INR's)
58 * are unique, the claim functions can always return IRQ_ACCEPT.
59 */
60
61#include <irq.h>
62#include <adt/hash_table.h>
63#include <arch/types.h>
64#include <typedefs.h>
65#include <synch/spinlock.h>
66#include <arch.h>
67
68/**
69 * Spinlock protecting the hash table.
70 * This lock must be taken only when interrupts are disabled.
71 */
72SPINLOCK_INITIALIZE(irq_hash_table_lock);
73static hash_table_t irq_hash_table;
74
75/**
76 * Hash table operations for cases when we know that
77 * there will be collisions between different keys.
78 */
79static index_t irq_ht_hash(unative_t *key);
80static bool irq_ht_compare(unative_t *key, count_t keys, link_t *item);
81
82static hash_table_operations_t irq_ht_ops = {
83 .hash = irq_ht_hash,
84 .compare = irq_ht_compare,
85 .remove_callback = NULL /* not used */
86};
87
88/**
89 * Hash table operations for cases when we know that
90 * there will be no collisions between different keys.
91 * However, there might be still collisions among
92 * elements with single key (sharing of one IRQ).
93 */
94static index_t irq_lin_hash(unative_t *key);
95static bool irq_lin_compare(unative_t *key, count_t keys, link_t *item);
96
97static hash_table_operations_t irq_lin_ops = {
98 .hash = irq_lin_hash,
99 .compare = irq_lin_compare,
100 .remove_callback = NULL /* not used */
101};
102
103/** Initialize IRQ subsystem.
104 *
105 * @param inrs Numbers of unique IRQ numbers or INRs.
106 * @param chains Number of chains in the hash table.
107 */
108void irq_init(count_t inrs, count_t chains)
109{
110 /*
111 * Be smart about the choice of the hash table operations.
112 * In cases in which inrs equals the requested number of
113 * chains (i.e. where there is no collision between
114 * different keys), we can use optimized set of operations.
115 */
116 if (inrs == chains)
117 hash_table_create(&irq_hash_table, chains, 1, &irq_lin_ops);
118 else
119 hash_table_create(&irq_hash_table, chains, 1, &irq_ht_ops);
120}
121
122/** Initialize one IRQ structure.
123 *
124 * @param irq Pointer to the IRQ structure to be initialized.
125 *
126 */
127void irq_initialize(irq_t *irq)
128{
129 link_initialize(&irq->link);
130 irq->inr = -1;
131 irq->devno = -1;
132 irq->notif = 0;
133 irq->trigger = 0;
134 irq->claim = NULL;
135 irq->handler = NULL;
136 irq->arg = NULL;
137}
138
139/** Register IRQ for device.
140 *
141 * The irq structure must be filled with information
142 * about the interrupt source and with the claim()
143 * function pointer and irq_handler() function pointer.
144 *
145 * @param irq IRQ structure belonging to a device.
146 */
147void irq_register(irq_t *irq)
148{
149 ipl_t ipl;
150
151 ipl = interrupts_disable();
152 spinlock_lock(&irq_hash_table_lock);
153 hash_table_insert(&irq_hash_table, (void *) &irq->inr, &irq->link);
154 spinlock_unlock(&irq_hash_table_lock);
155 interrupts_restore(ipl);
156}
157
158/** Dispatch the IRQ.
159 *
160 * @param inr Interrupt number (aka inr or irq).
161 *
162 * @return IRQ structure of the respective device or NULL.
163 */
164irq_t *irq_dispatch(inr_t inr)
165{
166 ipl_t ipl;
167 link_t *lnk;
168
169 ipl = interrupts_disable();
170 spinlock_lock(&irq_hash_table_lock);
171
172 lnk = hash_table_find(&irq_hash_table, (void *) &inr);
173 if (lnk) {
174 irq_t *irq;
175
176 irq = hash_table_get_instance(lnk, irq_t, link);
177
178 spinlock_unlock(&irq_hash_table_lock);
179 interrupts_restore(ipl);
180 return irq;
181 }
182
183 spinlock_unlock(&irq_hash_table_lock);
184 interrupts_restore(ipl);
185
186 return NULL;
187}
188
189/** Compute hash index for the key.
190 *
191 * This function computes hash index into
192 * the IRQ hash table for which there
193 * can be collisions between different
194 * INRs.
195 *
196 * @param key Pointer to INR.
197 *
198 * @return Index into the hash table.
199 */
200index_t irq_ht_hash(unative_t *key)
201{
202 inr_t *inr = (inr_t *) key;
203 return *inr % irq_hash_table.entries;
204}
205
206/** Compare hash table element with a key.
207 *
208 * As usually, we do sort of a hack here.
209 * Even when the key matches the inr member,
210 * we ask the device to either accept
211 * or decline to service the interrupt.
212 *
213 * @param key Pointer to key (i.e. inr).
214 * @param keys This is 1.
215 * @param item The item to compare the key with.
216 *
217 * @return True on match or false otherwise.
218 */
219bool irq_ht_compare(unative_t *key, count_t keys, link_t *item)
220{
221 irq_t *irq = hash_table_get_instance(item, irq_t, link);
222 inr_t *inr = (inr_t *) key;
223
224 return ((irq->inr == *inr) && (irq->claim() == IRQ_ACCEPT));
225}
226
227/** Compute hash index for the key.
228 *
229 * This function computes hash index into
230 * the IRQ hash table for which there
231 * are no collisions between different
232 * INRs.
233 *
234 * @param key INR.
235 *
236 * @return Index into the hash table.
237 */
238index_t irq_lin_hash(unative_t *key)
239{
240 inr_t *inr = (inr_t *) key;
241 return *inr;
242}
243
244/** Compare hash table element with a key.
245 *
246 * As usually, we do sort of a hack here.
247 * We don't compare the inr member with
248 * the key because we know that there are
249 * no collision between different keys.
250 * We only ask the device to either accept
251 * or decline to service the interrupt.
252 *
253 * @param key Pointer to key (i.e. inr).
254 * @param keys This is 1.
255 * @param item The item to compare the key with.
256 *
257 * @return True on match or false otherwise.
258 */
259bool irq_lin_compare(unative_t *key, count_t keys, link_t *item)
260{
261 irq_t *irq = list_get_instance(item, irq_t, link);
262
263 return (irq->claim() == IRQ_ACCEPT);
264}
265
266/** @}
267 */
Note: See TracBrowser for help on using the repository browser.