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

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

Replace the old hash table implementation in the kernel with the newer one

This replaces the original hash table implementation with the resizable one
already used in uspace. Along the way, the IRQ hash table code was streamlined
and cleaned up.

  • Property mode set to 100644
File size: 6.6 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 genericddi
30 * @{
31 */
32/**
33 * @file
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.
39 */
40
41#include <ddi/irq.h>
42#include <adt/hash.h>
43#include <adt/hash_table.h>
44#include <mm/slab.h>
45#include <typedefs.h>
46#include <synch/spinlock.h>
47#include <console/console.h>
48#include <interrupt.h>
49#include <mem.h>
50#include <arch.h>
51
52slab_cache_t *irq_slab = NULL;
53
54/** Spinlock protecting the kernel IRQ hash table
55 *
56 * This lock must be taken only when interrupts are disabled.
57 *
58 */
59IRQ_SPINLOCK_STATIC_INITIALIZE(irq_kernel_hash_table_lock);
60
61/** The kernel IRQ hash table. */
62static hash_table_t irq_kernel_hash_table;
63
64/** Spinlock protecting the uspace IRQ hash table
65 *
66 * This lock must be taken only when interrupts are disabled.
67 *
68 */
69IRQ_SPINLOCK_INITIALIZE(irq_uspace_hash_table_lock);
70
71/** The uspace IRQ hash table */
72hash_table_t irq_uspace_hash_table;
73
74static size_t irq_ht_hash(const ht_link_t *);
75static size_t irq_ht_key_hash(void *);
76static bool irq_ht_equal(const ht_link_t *, const ht_link_t *);
77static bool irq_ht_key_equal(void *, const ht_link_t *);
78
79static hash_table_ops_t irq_ht_ops = {
80 .hash = irq_ht_hash,
81 .key_hash = irq_ht_key_hash,
82 .equal = irq_ht_equal,
83 .key_equal = irq_ht_key_equal
84};
85
86/** Last valid INR */
87inr_t last_inr = 0;
88
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.
93 *
94 */
95void irq_init(size_t inrs, size_t chains)
96{
97 last_inr = inrs - 1;
98
99 irq_slab = slab_cache_create("irq_t", sizeof(irq_t), 0, NULL, NULL,
100 FRAME_ATOMIC);
101 assert(irq_slab);
102
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);
105}
106
107/** Initialize one IRQ structure
108 *
109 * @param irq Pointer to the IRQ structure to be initialized.
110 *
111 */
112void irq_initialize(irq_t *irq)
113{
114 memsetb(irq, sizeof(irq_t), 0);
115 irq_spinlock_initialize(&irq->lock, "irq.lock");
116 irq->inr = -1;
117
118 irq_initialize_arch(irq);
119}
120
121/** Register IRQ for device
122 *
123 * The irq structure must be filled with information about the interrupt source
124 * and with the claim() function pointer and handler() function pointer.
125 *
126 * @param irq IRQ structure belonging to a device.
127 *
128 */
129void irq_register(irq_t *irq)
130{
131 irq_spinlock_lock(&irq_kernel_hash_table_lock, true);
132 irq_spinlock_lock(&irq->lock, false);
133 hash_table_insert(&irq_kernel_hash_table, &irq->link);
134 irq_spinlock_unlock(&irq->lock, false);
135 irq_spinlock_unlock(&irq_kernel_hash_table_lock, true);
136}
137
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)
141{
142 irq_spinlock_lock(l, false);
143 for (ht_link_t *lnk = hash_table_find(h, &inr); lnk;
144 lnk = hash_table_find_next(h, lnk)) {
145 irq_t *irq = hash_table_get_inst(lnk, irq_t, link);
146 irq_spinlock_lock(&irq->lock, false);
147 if (irq->claim(irq) == IRQ_ACCEPT) {
148 /* leave irq locked */
149 irq_spinlock_unlock(l, false);
150 return irq;
151 }
152 irq_spinlock_unlock(&irq->lock, false);
153 }
154 irq_spinlock_unlock(l, false);
155
156 return NULL;
157}
158
159/** Dispatch the IRQ
160 *
161 * We assume this function is only called from interrupt context (i.e. that
162 * interrupts are disabled prior to this call).
163 *
164 * This function attempts to lookup a fitting IRQ structure. In case of success,
165 * return with interrupts disabled and holding the respective structure.
166 *
167 * @param inr Interrupt number (aka inr or irq).
168 *
169 * @return IRQ structure of the respective device
170 * @return NULL if no IRQ structure found
171 *
172 */
173irq_t *irq_dispatch_and_lock(inr_t inr)
174{
175 /*
176 * If the kernel console override is on, then try first the kernel
177 * handlers and eventually fall back to uspace handlers.
178 *
179 * In the usual case the uspace handlers have precedence.
180 */
181
182 if (console_override) {
183 irq_t *irq = irq_dispatch_and_lock_table(&irq_kernel_hash_table,
184 &irq_kernel_hash_table_lock, inr);
185 if (irq)
186 return irq;
187
188 return irq_dispatch_and_lock_table(&irq_uspace_hash_table,
189 &irq_uspace_hash_table_lock, inr);
190 }
191
192 irq_t *irq = irq_dispatch_and_lock_table(&irq_uspace_hash_table,
193 &irq_uspace_hash_table_lock, inr);
194 if (irq)
195 return irq;
196
197 return irq_dispatch_and_lock_table(&irq_kernel_hash_table,
198 &irq_kernel_hash_table_lock, inr);
199}
200
201/** Return the hash of the key stored in the item. */
202size_t irq_ht_hash(const ht_link_t *item)
203{
204 irq_t *irq = hash_table_get_inst(item, irq_t, link);
205 return hash_mix(irq->inr);
206}
207
208/** Return the hash of the key. */
209size_t irq_ht_key_hash(void *key)
210{
211 inr_t *inr = (inr_t *) key;
212 return hash_mix(*inr);
213}
214
215/** Return true if the items have the same lookup key. */
216bool irq_ht_equal(const ht_link_t *item1, const ht_link_t *item2)
217{
218 irq_t *irq1 = hash_table_get_inst(item1, irq_t, link);
219 irq_t *irq2 = hash_table_get_inst(item2, irq_t, link);
220 return irq1->inr == irq2->inr;
221}
222
223/** Return true if the key is equal to the item's lookup key. */
224bool irq_ht_key_equal(void *key, const ht_link_t *item)
225{
226 inr_t *inr = (inr_t *) key;
227 irq_t *irq = hash_table_get_inst(item, irq_t, link);
228 return irq->inr == *inr;
229}
230
231/** @}
232 */
Note: See TracBrowser for help on using the repository browser.