Files
codezero/src/generic/irq.c
Bahadir Balban 1ee5cc9c2b Fixed a task suspend/resume scheduler issue.
- Scheduler was increasing total priorities only when resuming tasks had 0 ticks.
This caused forked tasks that have parent's share of ticks to finish their jobs,
if these tasks exited quick enough, they would cause the total priorities to deduce
without increasing it in the first place. This is now fixed.

- Also strengthened rq locking, now both queues are locked before touching any.
- Also removed task suspends in irq, this would cause a race condition on ticks and
  runqueues, since neither is protected against irqs.
2008-10-22 13:00:28 +03:00

93 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()) {
/* This is buggy, races on prio_total */
if (in_user()) {
if (current->flags & TASK_SUSPENDING)
sched_suspend_async();
}
}
#endif
}