High-level IRQ flow handlers

Default flow implementations
Default flow handler implementations
Quirks and optimizations
Delayed interrupt disable

The generic layer provides a set of pre-defined irq-flow methods:

The interrupt flow handlers (either pre-defined or architecture specific) are assigned to specific interrupts by the architecture either during bootup or during device initialization.

Default flow implementations

Helper functions

The helper functions call the chip primitives and are used by the default flow implementations. The following helper functions are implemented (simplified excerpt):

default_enable(struct irq_data *data)
{
	desc->irq_data.chip->irq_unmask(data);
}

default_disable(struct irq_data *data)
{
	if (!delay_disable(data))
		desc->irq_data.chip->irq_mask(data);
}

default_ack(struct irq_data *data)
{
	chip->irq_ack(data);
}

default_mask_ack(struct irq_data *data)
{
	if (chip->irq_mask_ack) {
		chip->irq_mask_ack(data);
	} else {
		chip->irq_mask(data);
		chip->irq_ack(data);
	}
}

noop(struct irq_data *data))
{
}

		

Default flow handler implementations

Default Level IRQ flow handler

handle_level_irq provides a generic implementation for level-triggered interrupts.

The following control flow is implemented (simplified excerpt):

desc->irq_data.chip->irq_mask_ack();
handle_irq_event(desc->action);
desc->irq_data.chip->irq_unmask();
		

Default Fast EOI IRQ flow handler

handle_fasteoi_irq provides a generic implementation for interrupts, which only need an EOI at the end of the handler.

The following control flow is implemented (simplified excerpt):

handle_irq_event(desc->action);
desc->irq_data.chip->irq_eoi();
		

Default Edge IRQ flow handler

handle_edge_irq provides a generic implementation for edge-triggered interrupts.

The following control flow is implemented (simplified excerpt):

if (desc->status & running) {
	desc->irq_data.chip->irq_mask_ack();
	desc->status |= pending | masked;
	return;
}
desc->irq_data.chip->irq_ack();
desc->status |= running;
do {
	if (desc->status & masked)
		desc->irq_data.chip->irq_unmask();
	desc->status &= ~pending;
	handle_irq_event(desc->action);
} while (status & pending);
desc->status &= ~running;
		

Default simple IRQ flow handler

handle_simple_irq provides a generic implementation for simple interrupts.

Note: The simple flow handler does not call any handler/chip primitives.

The following control flow is implemented (simplified excerpt):

handle_irq_event(desc->action);
		

Default per CPU flow handler

handle_percpu_irq provides a generic implementation for per CPU interrupts.

Per CPU interrupts are only available on SMP and the handler provides a simplified version without locking.

The following control flow is implemented (simplified excerpt):

if (desc->irq_data.chip->irq_ack)
	desc->irq_data.chip->irq_ack();
handle_irq_event(desc->action);
if (desc->irq_data.chip->irq_eoi)
        desc->irq_data.chip->irq_eoi();
		

EOI Edge IRQ flow handler

handle_edge_eoi_irq provides an abnomination of the edge handler which is solely used to tame a badly wreckaged irq controller on powerpc/cell.

Bad IRQ flow handler

handle_bad_irq is used for spurious interrupts which have no real handler assigned..

Quirks and optimizations

The generic functions are intended for 'clean' architectures and chips, which have no platform-specific IRQ handling quirks. If an architecture needs to implement quirks on the 'flow' level then it can do so by overriding the high-level irq-flow handler.

Delayed interrupt disable

This per interrupt selectable feature, which was introduced by Russell King in the ARM interrupt implementation, does not mask an interrupt at the hardware level when disable_irq() is called. The interrupt is kept enabled and is masked in the flow handler when an interrupt event happens. This prevents losing edge interrupts on hardware which does not store an edge interrupt event while the interrupt is disabled at the hardware level. When an interrupt arrives while the IRQ_DISABLED flag is set, then the interrupt is masked at the hardware level and the IRQ_PENDING bit is set. When the interrupt is re-enabled by enable_irq() the pending bit is checked and if it is set, the interrupt is resent either via hardware or by a software resend mechanism. (It's necessary to enable CONFIG_HARDIRQS_SW_RESEND when you want to use the delayed interrupt disable feature and your hardware is not capable of retriggering an interrupt.) The delayed interrupt disable is not configurable.