Question

I'm learning interrupt handling in linux kernel and tried below code snippet to register a dummy irq handler on IRQ2. But it seems it is not getting registered as I'm seeing a negative return value and a message in kernel as below , arising from cleanup function which is trying to do free_irq():

[ 2203.989585] Trying to free already-free IRQ 2

below is the printk from kernel log which suggests that it hasn't got registered:

Here with registering IRQ handler on IRQ2 for flowTest...retval_irqreg= -22

Below is relevant part of my code which has four functions

1 the bottom half 
2. handler 
3. init function 
4. cleanup function

I'm not scheduling the bottom half yet , though it is present below. I'm working on kernel 3.5.0-17.

//Bottom half for the irq handler
static void bh_flowTest()
    {
        printk(KERN_INFO "Inside bottom half for flowTest.\n");
    }
// IRQ handler function
static irqreturn_t flow_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
                {
                printk(KERN_INFO "This is flowTest IRQ handler.\n");

        //static struct tq_struct task = {NULL, 0, bh_flowTest, NULL};
                /* Schedule bottom half to run */
        //queue_task(&task, &tq_immediate);

        // mark_bh(IMMEDIATE_BH);
    return IRQ_HANDLED;             
        }

static int flow_init(void)
    {
    printk(KERN_ALERT "Here with flowTest module ... loading...\n");
 int result=0;
 dev_t dev=0;
result = alloc_chrdev_region(&dev, minor_num,
num_devices,"mod_flowtest");                              // allocate major number dynamically.

i=MAJOR(dev);
printk(KERN_ALERT "Major allocated = %d",i);

cdev_init(&ms_flow_cd,&flow_fops);
cdev_add(&ms_flow_cd,dev,1);

//Registering interrupt handler on IRQ2 since IRQ2 is free as per /proc/interrupts
int retval_irqreg;
retval_irqreg=request_irq(2,(irq_handler_t)flow_irq_handler, /* our handler. It has been typecasted to remove warnings of incompatible pointer type , and enum irqreturn_t. Try removing the cast and see the warnings */
              IRQF_SHARED, 
              "test_flow_irq_handler", NULL);
printk(KERN_ALERT "Here with registering IRQ handler on IRQ2 for flowTest...retval_irqreg= %d\n",retval_irqreg);

return 0;
    }

static void flow_terminate(void)
    {
    dev_t devno=MKDEV(i,0);         // wrap major/minor numbers in a dev_t structure , to pass for deassigning.
    printk(KERN_ALERT "Going out... exiting...\n");
    unregister_chrdev_region(devno,num_devices);        //remove entry from the /proc/devices

    free_irq(2, NULL);
    }

I feel there is some basic mistake ,but if someone could point me to that please..!

Was it helpful?

Solution

It looks like IRQ 2 does NOT yet exist on your hardware. i.e. when you call request_irq() the Linux kernel does NOT yet know which interrrupt on which physical line from which peripheral hardware must be treated as the trigger for IRQ number "2" as it is just a number which is NOT yet associated with any actual physical interrupt yet).

Basically one first needs to associate a particular IRQ number with an actual physical hardware interrupt before attempting to register an ISR for that IRQ number. thsi is commonly done in the Linux kernel using irq_domain_add_linear().

In the past, IRQ numbers could be chosen so they matched the hardware IRQ line into the root interrupt controller (i.e. the component actually firing the interrupt line to the CPU) nowadays this number is just a number.

The irq_alloc_desc*() and irq_free_desc*() APIs provide allocation of irq numbers, but they don't provide any support for reverse mapping of the controller-local IRQ (hwirq) number into the Linux IRQ number space.

The current design of the Linux kernel uses a single large number space where each separate IRQ source is assigned a different number. This is simple when there is only one interrupt controller, but in systems with multiple interrupt controllers the kernel must ensure that each one gets assigned non-overlapping allocations of Linux IRQ numbers.

More details in the Linux-kernel Documentation/IRQ-domain.txt.

Also you may be interested in registering an ISR for an existing interrupt (say the keyboard IRQ?) When multiple ISRs are registered for a single IRQ, the Linux kernel will call each of the ISRs in each drivers that register a shared irq.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top