Subversion Repositories HelenOS

Rev

Rev 1921 | Rev 1923 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1921 Rev 1922
Line 29... Line 29...
29
/** @addtogroup genericddi
29
/** @addtogroup genericddi
30
 * @{
30
 * @{
31
 */
31
 */
32
/**
32
/**
33
 * @file
33
 * @file
34
 * @brief   IRQ redirector.
34
 * @brief   IRQ dispatcher.
35
 *
35
 *
36
 * This file provides means of connecting IRQs with particular
36
 * This file provides means of connecting IRQs with particular
37
 * devices and logic for dispatching interrupts to IRQ handlers
37
 * devices and logic for dispatching interrupts to IRQ handlers
38
 * defined by those devices.
38
 * defined by those devices.
39
 *
39
 *
Line 54... Line 54...
54
 * architectures to use the hardware layout effectively.
54
 * architectures to use the hardware layout effectively.
55
 * For instance, on amd64 and ia32, where there is only 16
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
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)
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.
58
 * are unique, the claim functions can always return IRQ_ACCEPT.
-
 
59
 *
-
 
60
 *
-
 
61
 * Note about the irq_hash_table.
-
 
62
 *
-
 
63
 * The hash table is configured to use two keys: inr and devno.
-
 
64
 * However, the hash index is computed only from inr. Moreover,
-
 
65
 * if devno is -1, the match is based on the return value of
-
 
66
 * the claim() function instead of on devno.
59
 */
67
 */
60
 
68
 
61
#include <ddi/irq.h>
69
#include <ddi/irq.h>
62
#include <adt/hash_table.h>
70
#include <adt/hash_table.h>
63
#include <arch/types.h>
71
#include <arch/types.h>
64
#include <typedefs.h>
72
#include <typedefs.h>
65
#include <synch/spinlock.h>
73
#include <synch/spinlock.h>
66
#include <atomic.h>
74
#include <atomic.h>
67
#include <arch.h>
75
#include <arch.h>
68
 
76
 
-
 
77
#define KEY_INR     0
-
 
78
#define KEY_DEVNO   1
-
 
79
 
69
/**
80
/**
70
 * Spinlock protecting the hash table.
81
 * Spinlock protecting the hash table.
71
 * This lock must be taken only when interrupts are disabled.
82
 * This lock must be taken only when interrupts are disabled.
72
 */
83
 */
73
SPINLOCK_INITIALIZE(irq_hash_table_lock);
84
SPINLOCK_INITIALIZE(irq_hash_table_lock);
Line 113... Line 124...
113
     * In cases in which inrs equals the requested number of
124
     * In cases in which inrs equals the requested number of
114
     * chains (i.e. where there is no collision between
125
     * chains (i.e. where there is no collision between
115
     * different keys), we can use optimized set of operations.
126
     * different keys), we can use optimized set of operations.
116
     */
127
     */
117
    if (inrs == chains)
128
    if (inrs == chains)
118
        hash_table_create(&irq_hash_table, chains, 1, &irq_lin_ops);
129
        hash_table_create(&irq_hash_table, chains, 2, &irq_lin_ops);
119
    else
130
    else
120
        hash_table_create(&irq_hash_table, chains, 1, &irq_ht_ops);
131
        hash_table_create(&irq_hash_table, chains, 2, &irq_ht_ops);
121
}
132
}
122
 
133
 
123
/** Initialize one IRQ structure.
134
/** Initialize one IRQ structure.
124
 *
135
 *
125
 * @param irq Pointer to the IRQ structure to be initialized.
136
 * @param irq Pointer to the IRQ structure to be initialized.
Line 135... Line 146...
135
    irq->claim = NULL;
146
    irq->claim = NULL;
136
    irq->handler = NULL;
147
    irq->handler = NULL;
137
    irq->arg = NULL;
148
    irq->arg = NULL;
138
    irq->notif_answerbox = NULL;
149
    irq->notif_answerbox = NULL;
139
    irq->code = NULL;
150
    irq->code = NULL;
-
 
151
    irq->method = 0;
140
    atomic_set(&irq->counter, 0);
152
    atomic_set(&irq->counter, 0);
141
}
153
}
142
 
154
 
143
/** Register IRQ for device.
155
/** Register IRQ for device.
144
 *
156
 *
Line 149... Line 161...
149
 * @param irq IRQ structure belonging to a device.
161
 * @param irq IRQ structure belonging to a device.
150
 */
162
 */
151
void irq_register(irq_t *irq)
163
void irq_register(irq_t *irq)
152
{
164
{
153
    ipl_t ipl;
165
    ipl_t ipl;
-
 
166
    unative_t key[] = {
-
 
167
        (unative_t) irq->inr,
-
 
168
        (unative_t) irq->devno
-
 
169
    };
154
   
170
   
155
    ipl = interrupts_disable();
171
    ipl = interrupts_disable();
156
    spinlock_lock(&irq_hash_table_lock);
172
    spinlock_lock(&irq_hash_table_lock);
157
    hash_table_insert(&irq_hash_table, (void *) &irq->inr, &irq->link);
173
    hash_table_insert(&irq_hash_table, key, &irq->link);
158
    spinlock_unlock(&irq_hash_table_lock);
174
    spinlock_unlock(&irq_hash_table_lock);
159
    interrupts_restore(ipl);
175
    interrupts_restore(ipl);
160
}
176
}
161
 
177
 
162
/** Dispatch the IRQ.
178
/** Dispatch the IRQ.
163
 *
179
 *
-
 
180
 * We assume this function is only called from interrupt
-
 
181
 * context (i.e. that interrupts are disabled prior to
-
 
182
 * this call).
-
 
183
 *
-
 
184
 * This function attempts to lookup a fitting IRQ
-
 
185
 * structure. In case of success, return with interrupts
-
 
186
 * disabled and holding the respective structure.
-
 
187
 *
164
 * @param inr Interrupt number (aka inr or irq).
188
 * @param inr Interrupt number (aka inr or irq).
165
 *
189
 *
166
 * @return IRQ structure of the respective device or NULL.
190
 * @return IRQ structure of the respective device or NULL.
167
 */
191
 */
168
irq_t *irq_dispatch(inr_t inr)
192
irq_t *irq_dispatch_and_lock(inr_t inr)
169
{
193
{
170
    ipl_t ipl;
-
 
171
    link_t *lnk;
194
    link_t *lnk;
-
 
195
    unative_t key[] = {
-
 
196
        (unative_t) inr,
-
 
197
        (unative_t) -1      /* search will use claim() instead of devno */
-
 
198
    };
172
   
199
   
173
    ipl = interrupts_disable();
-
 
174
    spinlock_lock(&irq_hash_table_lock);
200
    spinlock_lock(&irq_hash_table_lock);
175
 
201
 
-
 
202
    lnk = hash_table_find(&irq_hash_table, key);
-
 
203
    if (lnk) {
-
 
204
        irq_t *irq;
-
 
205
       
-
 
206
        irq = hash_table_get_instance(lnk, irq_t, link);
-
 
207
 
-
 
208
        spinlock_unlock(&irq_hash_table_lock);
-
 
209
        return irq;
-
 
210
    }
-
 
211
   
-
 
212
    spinlock_unlock(&irq_hash_table_lock);
-
 
213
 
-
 
214
    return NULL;   
-
 
215
}
-
 
216
 
-
 
217
/** Find the IRQ structure corresponding to inr and devno.
-
 
218
 *
-
 
219
 * This functions attempts to lookup the IRQ structure
-
 
220
 * corresponding to its arguments. On success, this
-
 
221
 * function returns with interrups disabled, holding
-
 
222
 * the lock of the respective IRQ structure.
-
 
223
 *
-
 
224
 * This function assumes interrupts are already disabled.
-
 
225
 *
-
 
226
 * @param inr INR being looked up.
-
 
227
 * @param devno Devno being looked up.
-
 
228
 *
-
 
229
 * @return Locked IRQ structure on success or NULL on failure.
-
 
230
 */
-
 
231
irq_t *irq_find_and_lock(inr_t inr, devno_t devno)
-
 
232
{
-
 
233
    link_t *lnk;
-
 
234
    unative_t keys[] = {
-
 
235
        (unative_t) inr,
-
 
236
        (unative_t) devno
-
 
237
    };
-
 
238
   
-
 
239
    spinlock_lock(&irq_hash_table_lock);
-
 
240
 
176
    lnk = hash_table_find(&irq_hash_table, (void *) &inr);
241
    lnk = hash_table_find(&irq_hash_table, keys);
177
    if (lnk) {
242
    if (lnk) {
178
        irq_t *irq;
243
        irq_t *irq;
179
       
244
       
180
        irq = hash_table_get_instance(lnk, irq_t, link);
245
        irq = hash_table_get_instance(lnk, irq_t, link);
181
 
246
 
182
        spinlock_unlock(&irq_hash_table_lock);
247
        spinlock_unlock(&irq_hash_table_lock);
183
        interrupts_restore(ipl);
-
 
184
        return irq;
248
        return irq;
185
    }
249
    }
186
   
250
   
187
    spinlock_unlock(&irq_hash_table_lock);
251
    spinlock_unlock(&irq_hash_table_lock);
188
    interrupts_restore(ipl);
-
 
189
 
252
 
190
    return NULL;   
253
    return NULL;   
191
}
254
}
192
 
255
 
193
/** Compute hash index for the key.
256
/** Compute hash index for the key.
Line 195... Line 258...
195
 * This function computes hash index into
258
 * This function computes hash index into
196
 * the IRQ hash table for which there
259
 * the IRQ hash table for which there
197
 * can be collisions between different
260
 * can be collisions between different
198
 * INRs.
261
 * INRs.
199
 *
262
 *
200
 * @param key Pointer to INR.
263
 * The devno is not used to compute the hash.
-
 
264
 *
-
 
265
 * @param key The first of the keys is inr and the second is devno or -1.
201
 *
266
 *
202
 * @return Index into the hash table.
267
 * @return Index into the hash table.
203
 */
268
 */
204
index_t irq_ht_hash(unative_t *key)
269
index_t irq_ht_hash(unative_t key[])
205
{
270
{
206
    inr_t *inr = (inr_t *) key;
271
    inr_t inr = (inr_t) key[KEY_INR];
207
    return *inr % irq_hash_table.entries;
272
    return inr % irq_hash_table.entries;
208
}
273
}
209
 
274
 
210
/** Compare hash table element with a key.
275
/** Compare hash table element with a key.
211
 *
276
 *
-
 
277
 * There are two things to note about this function.
212
 * As usually, we do sort of a hack here.
278
 * First, it is used for the more complex architecture setup
-
 
279
 * in which there are way too many interrupt numbers (i.e. inr's)
213
 * Even when the key matches the inr member,
280
 * to arrange the hash table so that collisions occur only
-
 
281
 * among same inrs of different devnos. So the explicit check
214
 * we ask the device to either accept
282
 * for inr match must be done.
-
 
283
 * Second, if devno is -1, the second key (i.e. devno) is not
215
 * or decline to service the interrupt.
284
 * used for the match and the result of the claim() function
-
 
285
 * is used instead.
216
 *
286
 *
-
 
287
 * This function assumes interrupts are already disabled.
-
 
288
 *
217
 * @param key Pointer to key (i.e. inr).
289
 * @param key Keys (i.e. inr and devno).
218
 * @param keys This is 1.
290
 * @param keys This is 2.
219
 * @param item The item to compare the key with.
291
 * @param item The item to compare the key with.
220
 *
292
 *
221
 * @return True on match or false otherwise.
293
 * @return True on match or false otherwise.
222
 */
294
 */
223
bool irq_ht_compare(unative_t *key, count_t keys, link_t *item)
295
bool irq_ht_compare(unative_t key[], count_t keys, link_t *item)
224
{
296
{
225
    irq_t *irq = hash_table_get_instance(item, irq_t, link);
297
    irq_t *irq = hash_table_get_instance(item, irq_t, link);
226
    inr_t *inr = (inr_t *) key;
298
    inr_t inr = (inr_t) key[KEY_INR];
-
 
299
    devno_t devno = (devno_t) key[KEY_DEVNO];
-
 
300
 
227
    bool rv;
301
    bool rv;
228
   
302
   
229
    spinlock_lock(&irq->lock);
303
    spinlock_lock(&irq->lock);
-
 
304
    if (devno == -1) {
-
 
305
        /* Invoked by irq_dispatch(). */
230
    rv = ((irq->inr == *inr) && (irq->claim() == IRQ_ACCEPT));
306
        rv = ((irq->inr == inr) && (irq->claim() == IRQ_ACCEPT));
-
 
307
    } else {
-
 
308
        /* Invoked by irq_find(). */
-
 
309
        rv = ((irq->inr == inr) && (irq->devno == devno));
-
 
310
    }
-
 
311
   
-
 
312
    /* unlock only on non-match */
-
 
313
    if (!rv)
231
    spinlock_unlock(&irq->lock);
314
        spinlock_unlock(&irq->lock);
232
 
315
 
233
    return rv;
316
    return rv;
234
}
317
}
235
 
318
 
236
/** Compute hash index for the key.
319
/** Compute hash index for the key.
Line 238... Line 321...
238
 * This function computes hash index into
321
 * This function computes hash index into
239
 * the IRQ hash table for which there
322
 * the IRQ hash table for which there
240
 * are no collisions between different
323
 * are no collisions between different
241
 * INRs.
324
 * INRs.
242
 *
325
 *
243
 * @param key INR.
326
 * @param key The first of the keys is inr and the second is devno or -1.
244
 *
327
 *
245
 * @return Index into the hash table.
328
 * @return Index into the hash table.
246
 */
329
 */
247
index_t irq_lin_hash(unative_t *key)
330
index_t irq_lin_hash(unative_t key[])
248
{
331
{
249
    inr_t *inr = (inr_t *) key;
332
    inr_t inr = (inr_t) key[KEY_INR];
250
    return *inr;
333
    return inr;
251
}
334
}
252
 
335
 
253
/** Compare hash table element with a key.
336
/** Compare hash table element with a key.
254
 *
337
 *
-
 
338
 * There are two things to note about this function.
255
 * As usually, we do sort of a hack here.
339
 * First, it is used for the less complex architecture setup
256
 * We don't compare the inr member with
340
 * in which there are not too many interrupt numbers (i.e. inr's)
257
 * the key because we know that there are
341
 * to arrange the hash table so that collisions occur only
-
 
342
 * among same inrs of different devnos. So the explicit check
258
 * no collision between different keys.
343
 * for inr match is not done.
259
 * We only ask the device to either accept
344
 * Second, if devno is -1, the second key (i.e. devno) is not
260
 * or decline to service the interrupt.
345
 * used for the match and the result of the claim() function
-
 
346
 * is used instead.
-
 
347
 *
-
 
348
 * This function assumes interrupts are already disabled.
261
 *
349
 *
262
 * @param key Pointer to key (i.e. inr).
350
 * @param key Keys (i.e. inr and devno).
263
 * @param keys This is 1.
351
 * @param keys This is 2.
264
 * @param item The item to compare the key with.
352
 * @param item The item to compare the key with.
265
 *
353
 *
266
 * @return True on match or false otherwise.
354
 * @return True on match or false otherwise.
267
 */
355
 */
268
bool irq_lin_compare(unative_t *key, count_t keys, link_t *item)
356
bool irq_lin_compare(unative_t key[], count_t keys, link_t *item)
269
{
357
{
270
    irq_t *irq = list_get_instance(item, irq_t, link);
358
    irq_t *irq = list_get_instance(item, irq_t, link);
-
 
359
    devno_t devno = (devno_t) key[KEY_DEVNO];
271
    bool rv;
360
    bool rv;
272
   
361
   
273
    spinlock_lock(&irq->lock);
362
    spinlock_lock(&irq->lock);
-
 
363
    if (devno == -1) {
-
 
364
        /* Invoked by irq_dispatch() */
274
    rv = (irq->claim() == IRQ_ACCEPT);
365
        rv = (irq->claim() == IRQ_ACCEPT);
-
 
366
    } else {
-
 
367
        /* Invoked by irq_find() */
-
 
368
        rv = (irq->devno == devno);
-
 
369
    }
-
 
370
   
-
 
371
    /* unlock only on non-match */
-
 
372
    if (!rv)
275
    spinlock_unlock(&irq->lock);
373
        spinlock_unlock(&irq->lock);
276
   
374
   
277
    return rv;
375
    return rv;
278
}
376
}
279
 
377
 
280
/** @}
378
/** @}