Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3946 → Rev 3947

/trunk/kernel/generic/src/ddi/irq.c
69,8 → 69,10
 
#include <ddi/irq.h>
#include <adt/hash_table.h>
#include <mm/slab.h>
#include <arch/types.h>
#include <synch/spinlock.h>
#include <memstr.h>
#include <arch.h>
 
#define KEY_INR 0
77,13 → 79,22
#define KEY_DEVNO 1
 
/**
* Spinlock protecting the hash table.
* Spinlock protecting the kernel IRQ hash table.
* This lock must be taken only when interrupts are disabled.
*/
SPINLOCK_INITIALIZE(irq_hash_table_lock);
static hash_table_t irq_hash_table;
static SPINLOCK_INITIALIZE(irq_kernel_hash_table_lock);
/** The kernel IRQ hash table. */
static hash_table_t irq_kernel_hash_table;
 
/**
* Spinlock protecting the uspace IRQ hash table.
* This lock must be taken only when interrupts are disabled.
*/
SPINLOCK_INITIALIZE(irq_uspace_hash_table_lock);
/** The uspace IRQ hash table. */
hash_table_t irq_uspace_hash_table;
 
/**
* Hash table operations for cases when we know that
* there will be collisions between different keys.
*/
111,6 → 122,9
.remove_callback = NULL /* not used */
};
 
/** Number of buckets in either of the hash tables. */
static count_t buckets;
 
/** Initialize IRQ subsystem.
*
* @param inrs Numbers of unique IRQ numbers or INRs.
118,6 → 132,7
*/
void irq_init(count_t inrs, count_t chains)
{
buckets = chains;
/*
* Be smart about the choice of the hash table operations.
* In cases in which inrs equals the requested number of
124,10 → 139,17
* chains (i.e. where there is no collision between
* different keys), we can use optimized set of operations.
*/
if (inrs == chains)
hash_table_create(&irq_hash_table, chains, 2, &irq_lin_ops);
else
hash_table_create(&irq_hash_table, chains, 2, &irq_ht_ops);
if (inrs == chains) {
hash_table_create(&irq_uspace_hash_table, chains, 2,
&irq_lin_ops);
hash_table_create(&irq_kernel_hash_table, chains, 2,
&irq_lin_ops);
} else {
hash_table_create(&irq_uspace_hash_table, chains, 2,
&irq_ht_ops);
hash_table_create(&irq_kernel_hash_table, chains, 2,
&irq_ht_ops);
}
}
 
/** Initialize one IRQ structure.
137,23 → 159,12
*/
void irq_initialize(irq_t *irq)
{
memsetb(irq, 0, sizeof(irq_t));
link_initialize(&irq->link);
spinlock_initialize(&irq->lock, "irq.lock");
irq->preack = false;
link_initialize(&irq->notif_cfg.link);
irq->inr = -1;
irq->devno = -1;
irq->trigger = (irq_trigger_t) 0;
irq->claim = NULL;
irq->handler = NULL;
irq->instance = NULL;
irq->cir = NULL;
irq->cir_arg = NULL;
irq->notif_cfg.notify = false;
irq->notif_cfg.answerbox = NULL;
irq->notif_cfg.code = NULL;
irq->notif_cfg.method = 0;
irq->notif_cfg.counter = 0;
link_initialize(&irq->notif_cfg.link);
}
 
/** Register IRQ for device.
160,12 → 171,15
*
* The irq structure must be filled with information
* about the interrupt source and with the claim()
* function pointer and irq_handler() function pointer.
* function pointer and handler() function pointer.
*
* @param irq IRQ structure belonging to a device.
* @param irq IRQ structure belonging to a device.
* @return True on success, false on failure.
*/
void irq_register(irq_t *irq)
{
spinlock_t *lock = &irq_kernel_hash_table_lock;
hash_table_t *table = &irq_kernel_hash_table;
ipl_t ipl;
unative_t key[] = {
(unative_t) irq->inr,
173,9 → 187,11
};
ipl = interrupts_disable();
spinlock_lock(&irq_hash_table_lock);
hash_table_insert(&irq_hash_table, key, &irq->link);
spinlock_unlock(&irq_hash_table_lock);
spinlock_lock(lock);
spinlock_lock(&irq->lock);
hash_table_insert(table, key, &irq->link);
spinlock_unlock(&irq->lock);
spinlock_unlock(lock);
interrupts_restore(ipl);
}
 
201,58 → 217,33
(unative_t) -1 /* search will use claim() instead of devno */
};
spinlock_lock(&irq_hash_table_lock);
 
lnk = hash_table_find(&irq_hash_table, key);
/*
* Try uspace handlers first.
*/
spinlock_lock(&irq_uspace_hash_table_lock);
lnk = hash_table_find(&irq_uspace_hash_table, key);
if (lnk) {
irq_t *irq;
irq = hash_table_get_instance(lnk, irq_t, link);
 
spinlock_unlock(&irq_hash_table_lock);
spinlock_unlock(&irq_uspace_hash_table_lock);
return irq;
}
spinlock_unlock(&irq_hash_table_lock);
spinlock_unlock(&irq_uspace_hash_table_lock);
 
return NULL;
}
 
/** Find the IRQ structure corresponding to inr and devno.
*
* This functions attempts to lookup the IRQ structure
* corresponding to its arguments. On success, this
* function returns with interrups disabled, holding
* the lock of the respective IRQ structure.
*
* This function assumes interrupts are already disabled.
*
* @param inr INR being looked up.
* @param devno Devno being looked up.
*
* @return Locked IRQ structure on success or NULL on failure.
*/
irq_t *irq_find_and_lock(inr_t inr, devno_t devno)
{
link_t *lnk;
unative_t keys[] = {
(unative_t) inr,
(unative_t) devno
};
spinlock_lock(&irq_hash_table_lock);
 
lnk = hash_table_find(&irq_hash_table, keys);
/*
* Fallback to kernel handlers.
*/
spinlock_lock(&irq_kernel_hash_table_lock);
lnk = hash_table_find(&irq_kernel_hash_table, key);
if (lnk) {
irq_t *irq;
irq = hash_table_get_instance(lnk, irq_t, link);
 
spinlock_unlock(&irq_hash_table_lock);
spinlock_unlock(&irq_kernel_hash_table_lock);
return irq;
}
spinlock_unlock(&irq_hash_table_lock);
spinlock_unlock(&irq_kernel_hash_table_lock);
 
return NULL;
}
273,7 → 264,7
index_t irq_ht_hash(unative_t key[])
{
inr_t inr = (inr_t) key[KEY_INR];
return inr % irq_hash_table.entries;
return inr % buckets;
}
 
/** Compare hash table element with a key.
308,7 → 299,7
if (devno == -1) {
/* Invoked by irq_dispatch_and_lock(). */
rv = ((irq->inr == inr) &&
(irq->claim(irq->instance) == IRQ_ACCEPT));
(irq->claim(irq) == IRQ_ACCEPT));
} else {
/* Invoked by irq_find_and_lock(). */
rv = ((irq->inr == inr) && (irq->devno == devno));
367,7 → 358,7
spinlock_lock(&irq->lock);
if (devno == -1) {
/* Invoked by irq_dispatch_and_lock() */
rv = (irq->claim(irq->instance) == IRQ_ACCEPT);
rv = (irq->claim(irq) == IRQ_ACCEPT);
} else {
/* Invoked by irq_find_and_lock() */
rv = (irq->devno == devno);