The kernel's handling of device interrupts has been massively reworked in
the 2.6 series. Fortunately, very few of those changes are visible to the
rest of the kernel; most well-written code should "just work" (almost) under 2.6.
There are, however, two important exceptions: the return type of interrupt
handlers has changed, and drivers which depend on
being able to globally disable interrupts will require some changes for
2.6.
Interrupt handler return values
Prior to 2.5.69, interrupt handlers returned void. There is,
however, one useful thing that interrupt handlers can tell the kernel:
whether the interrupt was something they could handle or not. If a device
starts generating spurious interrupts, the kernel would like to respond by
blocking interrupts from that device. If no interrupt handler for a given
IRQ has been registered, the kernel knows that any interrupt on that number
is spurious. When interrupt handlers exist, however, they must tell the
kernel about spurious interrupts.
So, interrupt handlers now return an irqreturn_t value;
void handlers will no longer compile. If your interrupt handler
recognizes and handles a given interrupt, it should return
IRQ_HANDLED. If it knows that the interrupt was not on a device
it manages, it can return IRQ_NONE instead. The macro:
IRQ_RETVAL(handled)
can also be used; handled should be nonzero if the handler could
deal with the interrupt. The "safe" value to return, if, for some reason
you are not sure, is IRQ_HANDLED.
Disabling interrupts
In the 2.6 kernel, it is no longer possible to globally disable
interrupts.
In particular, the cli(), sti(), save_flags(),
and restore_flags() functions are no longer available. Disabling
interrupts across all processors in the
system is simply no longer done. This behavior has been strongly
discouraged for some
time, so most code should have been converted by now.
The proper way to do this fixing, of course, is to figure out exactly which
resources were being protected by disabling interrupts. Those resources
can then be explicitly protected with spinlocks instead. The change is
usually fairly straightforward, but it does require an understanding of
what is really going on.
It is still possible to disable all interrupts locally with
local_save_flags() or local_irq_disable(). A single
interrupt can be disabled globally with disable_irq(). Some of the
spinlock operations also disable interrupts on the local processor, of
course. None of these functions are changed (at least, with regard to
their external interface) since 2.4.
Various small changes
One function that has changed is synchronize_irq(). In
2.6, this function takes an integer IRQ number as a parameter. It spins
until no interrupt handler is running for the given IRQ. If the IRQ is
disabled prior to calling synchronize_irq(), the caller will know
that no interrupt handler can be running after that call. The 2.6 version
of synchronize_irq() only waits for handlers for the given IRQ
number; it is no longer possible to wait until no interrupt handlers at all
are running.
If your code has post-interrupt logic which runs as a bottom half, or out
of a task queue, it will need to be changed for 2.6. Bottom halves are
deprecated, and the task queue mechanism has been removed altogether.
Post-interrupt processing should now be done using tasklets or work queues.
A new function was added in 2.6.1:
int can_request_irq(unsigned int irq, unsigned long flags);
This function returns a true value if the given interrupt allocation
request would succeed, but does not actually allocate anything. Potential
users should always be aware that the situation could change after calling
can_request_irq().
Finally, the declarations of request_irq() and free_irq() have
moved from <linux/sched.h> to
<linux/interrupt.h>. No comments have been posted.
Post one now
|