Files
codezero/src/generic/irq.c

91 lines
2.2 KiB
C

/*
* Kernel irq handling (core irqs like timer). Also hope to add thread-level
* irq handling in the future.
*
* Copyright (C) 2007 Bahadir Balban
*
*/
#include <l4/config.h>
#include <l4/macros.h>
#include <l4/generic/scheduler.h>
#include <l4/generic/platform.h>
#include <l4/generic/tcb.h>
#include <l4/generic/irq.h>
#include <l4/lib/mutex.h>
#include <l4/lib/printk.h>
#include INC_PLAT(irq.h)
#include INC_ARCH(exception.h)
/* This enables the lower chip on the current chip, if such chaining exists. */
static inline void cascade_irq_chip(struct irq_chip *this_chip)
{
if (this_chip->cascade >= 0) {
BUG_ON(IRQ_CHIPS_MAX == 1);
this_chip->ops.unmask(this_chip->cascade);
}
}
void irq_controllers_init(void)
{
struct irq_chip *this_chip;
for (int i = 0; i < IRQ_CHIPS_MAX; i++) {
this_chip = irq_chip_array + i;
/* Initialise the irq chips (e.g. reset all registers) */
this_chip->ops.init();
/* Enable cascaded irqs if needed */
cascade_irq_chip(this_chip);
}
}
int global_irq_index(void)
{
struct irq_chip *this_chip;
int irq_index = 0;
/* Loop over irq chips from top to bottom until
* the actual irq on the lowest chip is found */
for (int i = 0; i < IRQ_CHIPS_MAX; i++) {
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. */
}
return irq_index;
}
void do_irq(void)
{
int 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. */
irq_disable(irq_index);
enable_irqs();
/* TODO: Call irq_thread_notify(irq_index) for threaded irqs. */
BUG_ON(!this_irq->handler);
if (this_irq->handler() != IRQ_HANDLED) {
printk("Spurious or broken irq\n"); BUG();
}
irq_enable(irq_index);
#if 0
/* Process any pending flags for currently runnable task */
if (!in_nested_irq_context()) {
if (in_user()) {
if (current->flags & TASK_SUSPENDING)
sched_suspend_async();
}
}
#endif
}