Linux Device Driver Tutorial Part 13 – Interrupts Example Program in Linux Kernel

This article is a continuation of the  Series on Linux Device Driver and carries on the discussion on character drivers and their implementation. This is Part 13 of the Linux device driver tutorial. In our previous tutorial we have seen the What is an Interrupt and How it works through theory. Now we will see the Interrupt Example Program in Linux Kernel.

Interrupt Example Program in Linux Kernel

Before writing any interrupt program, you should keep these following points in mind.

  1. Interrupt handlers can not enter sleep, so to avoid calls to some functions which has sleep.
  2. When the interrupt handler has part of the code to enter the critical section, use spinlocks lock, rather than mutexes. Because if it couldn’t take mutex it will go to sleep until it takes the mute.
  3. Interrupt handlers can not exchange data with the userspace.
  4. The interrupt handlers must be executed as soon as possible. To ensure this, it is best to split the implementation into two parts, top half and bottom half. The top half of the handler will get the job done as soon as possible and then work late on the bottom half, which can be done with softirq or tasklet or workqueue.
  5. Interrupt handlers can not be called repeatedly. When a handler is already executing, its corresponding IRQ must be disabled until the handler is done.
  6. Interrupt handlers can be interrupted by higher authority handlers. If you want to avoid being interrupted by a highly qualified handler, you can mark the interrupt handler as a fast handler. However, if too many are marked as fast handlers, the performance of the system will be degraded, because the interrupt latency will be longer.

Functions Related to Interrupt

Before programming, we should know the basic functions which is useful for interrupts. This table explains the usage of all functions.

FunctionDescription
request_irq
(
unsigned int irq,
irq_handler_t handler,
unsigned long flags,
const char *name,
void *dev_id)
Register an IRQ, the parameters are as follows:

irq: IRQ number to allocate.

handler: This is Interrupt handler function.This function will be invoked whenever the operating system receives the interrupt.The data type of return is irq_handler_t, if its return value is IRQ_HANDLED, it indicates that the processing is completed successfully, but if the return value is IRQ_NONE, the processing fails.

flags: can be either zero or a bit mask of one or more of the flags defined in linux/interrupt.h. The most important of these flags are:
IRQF_DISABLED
IRQF_SAMPLE_RANDOM
IRQF_SHARED
IRQF_TIMER
(Explained after this table)

name: Used to identify the device name using this IRQ, for example, cat / proc / interrupts will list the IRQ number and device name.

dev_id: IRQ shared by many devices. When an interrupt handler is freed, dev provides a unique cookie to enable the removal of only the desired interrupt handler from the interrupt line. Without this parameter, it would be impossible for the kernel to know which handler to remove on a given interrupt line. You can pass NULL here if the line is not shared, but you must pass a unique cookie if your interrupt line is shared. This pointer is also passed into the interrupt handler on each invocation. A common practice is to pass the driver's device structure. This pointer is unique and might be useful to have within the handlers.

Return
returns zero on success and nonzero value indicates an error.

request_irq() cannot be called from interrupt context (other situations where code cannot block), because it can block.
free_irq(
unsigned int irq,
void *dev_id)
Release an IRQ registered by request_irq() with the following parameters:

irq: IRQ number.
dev_id: is the last parameter of request_irq.

If the specified interrupt line is not shared, this function removes the handler and disables the line.
If the interrupt line is shared, the handler identified via dev_id is removed, but the interrupt line is disabled only when the last handler is removed. With shared interrupt lines, a unique cookie is required to differentiate between the multiple handlers that can exist on a single line and enable free_irq() to remove only the correct handler.
In either case (shared or unshared), if dev_id is non-NULL, it must match the desired handler. A call to free_irq() must be made from process context.
enable_irq(unsigned int irq)Re-enable interrupt disabled by disable_irq or disable_irq_nosync.
disable_irq(unsigned int irq)Disable an IRQ from issuing an interrupt.
disable_irq_nosync(unsigned int irq)Disable an IRQ from issuing an interrupt, but wait until there is an interrupt handler being executed.
in_irq()returns true when in interrupt handler
in_interrupt()returns true when in interrupt handler or bottom half

Interrupts Flags

These are the second parameter of the function. It has several flags. Here I explained important flags.

  • IRQF_DISABLED.

    • When set, this flag instructs the kernel to disable all interrupts when executing this interrupt handler.
    • When unset, interrupt handlers run with all interrupts except their own enabled.

    Most interrupt handlers do not set this flag, as disabling all interrupts is bad form. Its use is reserved for performance-sensitive interrupts that execute quickly. This flag is the current manifestation of the SA_INTERRUPT flag, which in the past distinguished between “fast” and “slow” interrupts.

  • IRQF_SAMPLE_RANDOM. This flag specifies that interrupts generated by this device should contribute to the kernel entropy pool. The kernel entropy pool provides truly random numbers derived from various random events. If this flag is specified, the timing of interrupts from this device is fed to the pool as entropy. Do not set this if your device issues interrupt at a predictable rate (e.g. the system timer) or can be influenced by external attackers (e.g. a networking device). On the other hand, most other hardware generates interrupts at non-deterministic times and is, therefore, a good source of entropy.
  • IRQF_TIMER. This flag specifies that this handler process interrupts the system timer.
  • IRQF_SHARED. This flag specifies that the interrupt line can be shared among multiple interrupt handlers. Each handler registered on a given line must specify this flag; otherwise, only one handler can exist per line.

Registering an Interrupt Handler

Freeing an Interrupt Handler

Interrupt Handler

Programming

Interrupt can be coming from anywhere (any hardware) and anytime. In our tutorial we are not going to use any hardware. Here instead of using hardware, we are going to trigger interrupt by simulating. If you have only PC (without hardware), but you want to play around Interrupts in Linux you can follow our method.

Triggering Hardware Interrupt through Software

Intel processors handle interrupt using IDT (Interrupt Descriptor Table).  The IDT consists of 256 entries with each entry corresponding to a vector and of 8 bytes. All the entries are pointer to the interrupt handling function. The CPU uses IDTR to point to IDT. The relation between those two can be depicted as below,

Linux Device Driver Tutorial Part 13 – Interrupts Example Program in Linux Kernel

An interrupt can be programmatically raised using ‘int’ instruction. For example, the Linux system call was using int $0x80.

In Linux IRQ to vector mapping is done in arch/x86/include/asm/irq_vectors.h.The used vector range is as follows,

Linux Device Driver Tutorial Part 13 – Interrupts Example Program in Linux Kernel

Refer Here.

The IRQ0 is mapped to vector using the macro,

#define IRQ0_VECTOR (FIRST_EXTERNAL_VECTOR + 0x10)

where, FIRST_EXTERNAL_VECTOR = 0x20

So if we want to raise an interrupt IRQ11, programmatically we have to add 11 to a vector of IRQ0.

0x20 + 0x10 + 11 = 0x3B (59 in Decimal).

Hence executing “asm("int $0x3B")” will raise interrupt IRQ 11.

The instruction will be executed while reading device file of our driver (/dev/etx_device).

Driver Source Code

Here I took the old source code from the sysfs tutorial. In that source I have just added interrupt code like request_irq, free_irq along with interrupt handler.

In this program, interrupt will be triggered whenever we are reading device file of our driver (/dev/etx_device).

Whenever Interrupt triggers, it will print the “Shared IRQ: Interrupt Occurred” Text.

MakeFile

Building and Testing Driver

  • Build the driver by using Makefile (sudo make)
  • Load the driver using sudo insmod driver.ko
  • To trigger interrupt read device file (sudo cat /dev/etx_device)
  • Now see the Dmesg (dmesg)

  • We can able to see the print “Shared IRQ: Interrupt Occurred
  • Unload the module using sudo rmmod driver

This is the simple example using Interrupts in the device drivers. This is just a basic. You can also try using hardware. I hope this might helped you.

In our next tutorial, we will discuss one of the bottom half, which is workqueue.

0 0 vote
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

7 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
manoj
manoj
2 years ago

Also please add a tutorial on different ways to handle situations when critial region code is being accessed by cpu (such as spinlocks, mutexes, semaphones etc implementation in kernel space)

arun
arun
1 year ago

do_IRQ: 2.59 No irq handler for vector

im getting this error plz help me out.

EmbeTronicx India
EmbeTronicx India
Reply to  arun
1 year ago

Hi Arun,

Its looks like your hardware issue. Did you update the kernel recently? Please go through this below link.
https://unix.stackexchange.com/questions/367503/do-irq-0-163-no-irq-handler-for-vector-irq-1

EmbeTronicX
EmbeTronicX
Reply to  arun
1 month ago

Please refer this link.

nguyendang
nguyendang
1 year ago

do_IRQ: 2.59 No irq handler for vector

I have the same trouble as Arun but I cannot fix it so far, although following your instruction you replied to Arun.

Please help me, thank you!

EmbeTronicX
EmbeTronicX
Reply to  nguyendang
1 month ago

Hi,

Please refer this Link to fix.

Kalpesh
Kalpesh
9 months ago

What does IRQ 11 stands for(For which process is this IRQ number)

7
0
Would love your thoughts, please comment.x
()
x
%d bloggers like this: