Preliminary irq registration call + irq capability checking

Need to add irqctrl capabilities and irq bits to device memory
caps.

Also need to initialize irq field of devmem caps.
This commit is contained in:
Bahadir Balban
2009-11-28 19:13:23 +02:00
parent b5e6c66426
commit 6e40a2b601
17 changed files with 380 additions and 110 deletions

View File

@@ -1,9 +1,8 @@
/*
* Kernel irq handling (core irqs like timer). Also hope to add thread-level
* irq handling in the future.
*
* Copyright (C) 2007 Bahadir Balban
* Kernel irq handling (core irqs like timer).
* Also thread-level irq handling.
*
* Copyright (C) 2007 - 2009 Bahadir Balban
*/
#include <l4/config.h>
#include <l4/macros.h>
@@ -16,7 +15,33 @@
#include INC_PLAT(irq.h)
#include INC_ARCH(exception.h)
/* This enables the lower chip on the current chip, if such chaining exists. */
/*
* Registers a userspace thread as an irq handler.
*/
int irq_register(struct ktcb *task, int notify_slot,
l4id_t irq_index, irq_handler_t handler)
{
struct irq_desc *this_desc = irq_desc_array + irq_index;
struct irq_chip *current_chip = irq_chip_array;
for (int i = 0; i < IRQ_CHIPS_MAX; i++) {
if (irq_index >= current_chip->start &&
irq_index < current_chip->end) {
this_desc->chip = current_chip;
break;
}
}
/* Setup the handler */
this_desc->handler = handler;
/* Setup the slot to notify the task */
this_desc->task_notify_slot = notify_slot;
return 0;
}
/* If there is cascading, enable it. */
static inline void cascade_irq_chip(struct irq_chip *this_chip)
{
if (this_chip->cascade >= 0) {
@@ -31,51 +56,86 @@ void irq_controllers_init(void)
for (int i = 0; i < IRQ_CHIPS_MAX; i++) {
this_chip = irq_chip_array + i;
/* Initialise the irq chips (e.g. reset all registers) */
/* Initialise the irq chip (e.g. reset all registers) */
this_chip->ops.init();
/* Enable cascaded irqs if needed */
/* Enable cascaded irq on this chip if it exists */
cascade_irq_chip(this_chip);
}
}
int global_irq_index(void)
/*
* Finds the global irq number by looping over irq chips.
*
* Global irq number =
* Unique irq chip_offset defined by us + irq number local to chip
*/
l4id_t global_irq_index(void)
{
struct irq_chip *this_chip;
int irq_index = 0;
l4id_t irq_index = 0;
/* Loop over irq chips from top to bottom until
* the actual irq on the lowest chip is found */
/*
* Loop over all chips, starting from the top
* (i.e. nearest to the cpu)
*/
for (int i = 0; i < IRQ_CHIPS_MAX; i++) {
/* Get the chip */
this_chip = irq_chip_array + i;
BUG_ON((irq_index = this_chip->ops.read_irq()) < 0);
if (irq_index != this_chip->cascade) {
irq_index += this_chip->offset;
/* Found the real irq, return */
break;
}
/* Hit the cascading irq. Continue on next irq chip. */
/* Find local irq that is triggered on this chip */
BUG_ON((irq_index =
this_chip->ops.read_irq()) == IRQ_NIL);
/* See if this irq is a cascaded irq */
if (irq_index == this_chip->cascade)
continue; /* Yes, continue to next chip */
/*
* Irq was initiated from this chip. Add this chip's
* global irq offset and return it
*/
irq_index += this_chip->start;
return irq_index;
}
return irq_index;
/*
* Cascaded irq detected, but no lower chips
* left to process. This should not happen
*/
BUG();
return IRQ_NIL;
}
void do_irq(void)
{
int irq_index = global_irq_index();
l4id_t irq_index = global_irq_index();
struct irq_desc *this_irq = irq_desc_array + irq_index;
/* TODO: This can be easily done few instructions quicker by some
* immediate read/disable/enable_all(). We stick with this clear
* implementation for now. */
/*
* Note, this can be easily done a few instructions
* quicker by some immediate read/disable/enable_all().
*
* We currently stick with it as it is clearer.
*/
irq_disable(irq_index);
/* Re-enable all irqs */
enable_irqs();
/* TODO: Call irq_thread_notify(irq_index) for threaded irqs. */
/* Handle the irq */
BUG_ON(!this_irq->handler);
if (this_irq->handler() != IRQ_HANDLED) {
printk("Spurious or broken irq\n"); BUG();
if (this_irq->handler(this_irq) != IRQ_HANDLED) {
printk("Spurious or broken irq\n");
BUG();
}
irq_enable(irq_index);
}