Linux Modules Character drivers IO & Memory Linux Kernel Process Management Process Address space Linux Scheduler Memory Management Interrupts Signals 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 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): PID 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.
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 otherwise return IRQ_HANDLED 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; save_flags(flags); cli(); /* this code runs with
interrupts disabled */ restore_flags(flags); 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 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> structsoftirq_action{ 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 raise_softirq(NET_TX_SOFTIRQ); Tasklets 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 & workqueue 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 */ schedule_work(&short_wq); Workqueue have a type of struct workqueue_struct
defined in <linux/workqueue.h> |