This used to be a fair API comparison. Today it is also a version trap: setup_irq() appears in old BSPs, but it is absent from current mainline. That changes what a driver author should copy.

The difference at a glance

  • setup_irq(): older kernels accepted a caller-owned struct irqaction for static setup.

  • request_irq(): the public driver API accepts a handler, flags, name, and identity cookie.

  • Ownership: setup_irq callers supplied persistent action storage; request APIs allocate and manage it internally.

  • Cleanup: pair request_irq() with free_irq(); device-managed requests follow device lifetime.

  • Current status: mainline documents request_irq but no longer contains setup_irq.

Why old kernels had setup_irq

historical kernel code (simplified)c
static struct irqaction timer_action = {
    .handler = timer_interrupt,
    .flags = IRQF_TIMER,
    .name = "platform-timer",
};
 
ret = setup_irq(timer_irq, &timer_action);

Historical context—not a template for a new driver.

What the static action implied

  • struct irqaction is the IRQ core action descriptor, not merely a callback.

  • Static storage remains valid for the registration lifetime; stack storage would be invalid.

  • IRQF_TIMER carries timer-specific behavior in kernels that define it.

  • Linux 4.9 GPL-exported setup_irq, but ordinary drivers were still expected to use request APIs.

What request_irq does today

include/linux/interrupt.h (call path)c
request_irq(irq, handler, flags, name, dev_id)
    -> request_threaded_irq(irq, handler, NULL,
                            flags | IRQF_COND_ONESHOT,
                            name, dev_id);

The wrapper carries real semantics

  • irq is a Linux IRQ number resolved through bus or firmware resources.

  • handler runs in hard-interrupt context and must not sleep.

  • dev_id returns to the handler and identifies an action on a shared line.

  • Handling may begin immediately after success, so driver state must already be safe.

A current platform-driver pattern

drivers/example/example.cc
static irqreturn_t example_irq(int irq, void *data)
{
    struct example_dev *priv = data;
    u32 status = readl(priv->base + STATUS_REG);
 
    if (!(status & IRQ_PENDING))
        return IRQ_NONE;
    writel(status, priv->base + STATUS_REG);
    return IRQ_HANDLED;
}
 
irq = platform_get_irq(pdev, 0);
if (irq < 0)
    return irq;
return devm_request_irq(&pdev->dev, irq, example_irq, 0,
                        dev_name(&pdev->dev), priv);

Why this fits probe lifetime

  • platform_get_irq() resolves the resource and propagates errors.

  • devm_request_irq() releases registration during probe rollback or detach.

  • IRQ_NONE matters when the device did not raise a shared interrupt.

  • Acknowledgement order is hardware-specific and must follow the datasheet.

When the handler needs to sleep

drivers/example/threaded.cc
ret = devm_request_threaded_irq(dev, irq,
        example_irq_top, example_irq_thread,
        IRQF_ONESHOT, dev_name(dev), priv);
 
static irqreturn_t example_irq_top(int irq, void *data)
{
    return IRQ_WAKE_THREAD;
}

Separate the execution contexts

  • The primary handler runs in hard-IRQ context and returns IRQ_WAKE_THREAD.

  • The threaded function runs in process context and may use sleepable operations.

  • IRQF_ONESHOT keeps the line masked while the thread runs when required.

  • A NULL primary is supported when a thread function is supplied.

Manual ownership and teardown

manual-lifetime.cc
ret = request_irq(irq, example_irq, IRQF_SHARED,
                  "example", priv);
if (ret)
    return ret;
 
/* Quiesce the device first, then: */
free_irq(irq, priv);
  • Shared IRQ actions require a unique, non-NULL dev_id.

  • Pass the identical cookie to free_irq().

  • free_irq() waits for active handlers and cannot run in interrupt context.

  • Disable the device interrupt source before freeing its handler.

Mistakes that survive code review

  • Copying setup_irq: it may be absent or unexported in the target kernel.

  • Sleeping in a hard handler: move blocking work to a threaded IRQ.

  • Enabling hardware too early: an interrupt can arrive immediately after registration.

  • Freeing before quiescing: hardware can call into released state.

  • Confusing IRQs with vectors: irqdomains translate hardware specifiers into Linux IRQs.

Verify the exact source tree

Linux kernel source treebash
git grep -n setup_irq -- include kernel arch drivers
git grep -n 'request_irq(' -- include/linux/interrupt.h
git log -Ssetup_irq -- kernel/irq/manage.c include/linux/interrupt.h
include/linux/interrupt.h:... request_irq(...)
# Current mainline may return no setup_irq matches.

Source history beats memory

  • git grep checks the selected kernel, including vendor changes.

  • git log -S traces addition or removal of the exact token.

  • A vendor tree can retain an API after upstream removal.

  • These commands are read-only.

References