Linux Device Drivers

Linux Device Drivers

Character drivers
IO & Memory
Linux Kernel
Process Management
Process Address space

Linux Scheduler
Memory Management
System Calls
Kernel Synchronization
Linux Inter Process Communications

Serial Ports
Parallel Ports
Introduction to Hardware
Linux Timers
DMA in Linux
Linux Threads
Linux Thread Synchronization

Linux Multi Threading
Debugging in Linux
GDB GNU Debugger
KDB Kernel Debugger
KGDB Kernel GNU Debugger
Example Ethernet Driver

Interrupt Handling

Interrupt Handling


The Kernel Contexts

There are two contexts (patterns of execution flow) in the Linux kernel: interrupt and user (space) contexts. User contexts are code which is entered from userspace: a system call. Unless the kernel code sleeps for some reason (explicitly allowing other code to run),

no other user context will run on that CPU; this is the non-preemptive part. They are always associated with a particular process.  However, an interrupt can occur at anytime, which halts the user context in its tracks and runs an interrupt context. This is not associated with any process; it is caused by a timer, an external hardware interrupt,

or a bottom-half (bottom halves may be run off the timer or other interrupts). When it is finished, the user context will resume.


Kernel Threads


ü     Even though Linux is a monolithic OS, a few ''kernel threads'' exist to do housekeeping work.

ü     These Tasks don't utilize USER memory; they share KERNEL memory.

ü     They also operate at the highest privilege (RING 0 on a i386 architecture) like any other kernel mode piece of code.

ü     Kernel threads are created by ''kernel_thread[arch/i386/kernel/process]'function, which calls ''clone'' [arch/i386/kernel/process.c] system callfrom assembler (which is a ''fork'' like system call):


A list of most common kernel threads (from ''ps x'' command):


1 init

2 keventd

3 kswapd

4 kreclaimd

5 bdflush

6 kupdated

7 kacpid

67 khubd


'init' kernel thread is the first process created, at boot time. It will call all other User Mode Tasks (from file /etc/inittab) like console daemons, tty daemons and network daemons (''rc'' scripts).


A very slow resource is used because we would have a task switching overhead otherwise.






Hardware Device









PIC cascading



Second serial port



First serial port



Floppy disk



Parallel port



System clock



Network interface



PS/2 mouse



Maths coprocessor I



IDE Controller First



IDE Controller Second



Interrupt Handling


ü     An interrupt is simply a signal that the hardware can send when it wants the processor's attention.

ü     A module is expected to request an interrupt channel before using it, and to release it when its done.



Freeing an interrupt handler


When your driver unloads, you need to unregister your interrupt  handler and disable the interrupt line. To do this call

void free_irq(unsigned intirq, void *dev_id);


If the specified interrupt line is not shared, this function removes the handler and disables the line.


Fast & Slow Handlers


Fast interrupts are those that could be handled very quickly,

Whereas handling slow interrupts take significantly longer.


ü     A Fast handler runs with interrupt reporting disabled in the microprocessor , and the interrupt being serviced is disabled in the interrupt controller.

ü     A slow handler runs with interrupt reporting enabled in the processor, and the interrupt being serviced is disabled in the interrupt controller.

ü     Fast handlers should not be used generally.


Implementing a Handler


ü     Its ordinary C code with some restrictions

§       Can’t transfer data to or from user space, because it does not execute in the context of process

§       Cannot do anything that would sleep

§       Cannot allocate memory with anything other than GFP_ATOMIC.

§       Cannot lock a semaphore

§       Cannot call schedule


ü     Give feedback to device about interrupt reception (by clearing a bit or byte on the interface board “Interrupt Pending”

ü     Write a routine that executes in a minimum of time

ü     If a long computation needs to be performed, use a tasklet.


Interrupt handling


#include <linux/interrupt.h>

In interrupt handler:


If interrupt for someone else

return IRQ_NONE




Control of Interrupts


The use of functions cli and sti to disable and enable interrupts has been used.


To disable interrupts, it is better to use the following calls:


unsigned long flags;



/* this code runs with interrupts disabled */




The macros save_flags() and restore_flags() must be called from the same function.


Bottom Half Processing


§       An interrupt handler should execute in a minimum of time and not to keep interrupts blocked for long.

§       Often a substantial amount of work must be done in response to device interrupt

§       This can be accomplished by splitting the interrupt handler into two halves

§       Top Half: is the routine that actually responds to the interrupt

§       Bottom Half: is a routine that is scheduled by the top half to be executed later, at a safer time

§       Difference : All interrupts are enabled during execution of bottom half –that’s why it runs at a “ Safer time”

§       Restrictions : All of the restrictions that apply to interrupt handlers also apply to bottom-halfs



Bottom half Status


Currently there are three methods for deferring work: softirq, tasklet and work queues. Taskletsare built on softirqsand work queues are entirely different.


Bottom half                                                    Status


BH                                                                   Removed in 2.5

Task Queues                                                   Removed in 2.5

Softirq                                                             Available since 2.3

Tasklet                                                                        Available since 2.3

Work queue                                                    Available since 2.5





Softirqs are rarely used, tasklets are much more common form of bottom half. Because tasklets are built on softirqs, it is required to be studied. The softirq code lives in kernel/softirq.c


Implementation of Softirqs


Softirqs are statically allocated at compile time. Unlike tasklets you can not dynamically register and destroy softirqs. Softirqs are represented by the softirq_action structure, which is defined in <linux/interrupt.h>



void (*action(structsoftirq_action*);/* function to run */

void *data;/* data to pass to function */



A 32-entry array of this structure is declared in kernel/softirq.c


static struct softirq_action softirq_vec[32];


Each registered softirq consumes one entry in the array. So there can be maximum of 32 registered softirqs.


Using Softirqs


Softirqs are reserved for the most timing-critical and important bottom half processing on the system. Currently, only two subsystems –networking and SCSI –directly use softirqs.

Additionally, kernel timers and taskletsare built on top of softirqs.


Assigning an Index


You declare softirqs statically at compile time via an enum in <linux/interrupt.h>. The kernel uses this index as relative priority.


Tasklet                                                priority                        Softirq Description


HI_SOFTIRQ                          0                      high priority tasklets

TIMER_SOFTIRQ                  1                      timer bottom half

NET_TX_SOFTIRQ               2                      send network packets

NET_RX_SOFTIRQ               3                      receive network packets

SCSI_SOFTIRQ                      4                      SCSI bottom half

TASKLET_SOFTIRQ 5                      Tasklets




Registering Your Handler


The softirq handler is assigned at run-time via open_softirq(), which takes three parameters: the softirq.sindex, its handler and a value for the data field.


open_softirq (NET_TX_SOFTIRQ, netx_tx_action, NULL);


The softirq handlers runs with interrupts enabled and cannot sleep.


Raising Your Softirq


After a handler is added to the enumlist and registered via open_softirq(), it is ready to run. To mark it pending, so that it is run at the next invocation of do_softirq(), call raise_softirq().


For example, the networking subsystem would call







A tasklet is a special function that may be scheduled to run, in interrupt context at a system defined safe time.


§       They may be scheduled to run multiple times , but will only run once

§       No tasklet will ever run in parallel with itself , since they only run once

§       Tasklet can run in parallel with other tasklets on SMP systems

§       They are guaranteed to run on the CPU that first schedules them


Linux Support


DECLARE_TASKLET ( name , function , data ) ;

DECLARE_TASKLET_DISABLED ( name, function, data);


It can be scheduled , but will not be executed until enabled at some future time


tasklet_schedule ( name ) ;


void tasklet_disable ( struct tasklet_struct &t ) ;


void tasklet_enable ( struct tasklet_struct &t ) ;


void tasklet_kill ( struct tasklet_struct &t ) ;



Work Queues


Work queues are different form of deferring work. Work queues defer work into a kernel thread –this bottom half always runs in a process context.

Work queues are schedulable and can therefore sleep

It is easy to decide between using work queue and softirqs/tasklets

If the deferred work needs to sleep, work queues are used.



Work Queue


Two mechanisms to implement bottom half processing:

tasklets            &



Tasklets are very fast, but all tasklet code must be atomic.


Workqueue higher latency, but allowed to sleep.


static struct work_struct short_wq;

INIT_WORK(&short_wq, (void (*) (void *))short_do_tasklet, NULL);


/* in interrupt handler */



Workqueue have a type of struct workqueue_struct defined in <linux/workqueue.h>