本文介绍了内核函数asm_do_IRQ()中的irq与我在模块中请求的irq不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用cortex-A9开发板做了一些实验.我使用gpio_to_irq()来获取一个irq num,然后我请求了irq并编写了一个小驱动程序,在syslog中为196.我在asm_do_IRQ中添加了一些printks.当我触发gpio中断时,驱动程序工作正常,但是asm_do_IRQ中的irq num为62.为什么irq号码与我要求的号码不同?驱动程序如下:

I did some experiment with a cortex-A9 development board. I used gpio_to_irq() to get an irq num and I requested the irq and wrote a small driver with it , it was 196 in syslog . And I added some printks in asm_do_IRQ. When I triggered the gpio interrupt , the driver works fine but the irq num in asm_do_IRQ was 62 .I can't understand. Why the irq number was different from the one I request? The driver is as follow:

    #include <linux/module.h>
    #include <linux/interrupt.h>
    #include <linux/irq.h>
    #include <linux/gpio.h>

    #define GPIO_N 36     //gpio number

    int flag = 0;

    static irqreturn_t handler(int irq,void *dev_id)
    {
            printk("hello world hahahahahhahahah \n\n");
            return 0;
    }

    static int __init gpio_test_init(void)
    {
            if(gpio_request_one(GPIO_N,GPIOF_DIR_IN,"some test")<0)
            {
                    printk(KERN_ERR "Oops! BAD! BAD! BAD!\n\n");
                    return 0;
            }

            int irq,irq2;
            irq = OMAP_GPIO_IRQ(TEST_GPIO);
            printk("irq : %d \n",irq,irq2);
            // ..................
            // irq : 196 in dmesg 
            //......................
            set_irq_type(irq,IRQ_TYPE_EDGE_FALLING);
            enable_irq(gpio_to_irq(GPIO_N));
            int err;
            // request the irq ...
            if((err = request_irq(irq,&handler,0,NULL,NULL))<0)
            {
                    printk("err : %d\n",err);
                    return 0;
            }
            printk("gpio test init success!\n");
            flag = 1;
            return 0;
    }
    static void __exit gpio_test_exit(void)
    {
            int irq = gpio_to_irq(TEST_GPIO);
            if(flag == 1)free_irq(irq,NULL);
            gpio_free(TEST_GPIO);
            printk("gpio test exit byebye!\n");
    }

    module_init(gpio_test_init);
    module_exit(gpio_test_exit);
    MODULE_LICENSE("GPL");

arch/arm/kernel/irq.c中的asm_do_IRQ

asm_do_IRQ in arch/arm/kernel/irq.c

    asmlinkage void __exception_irq_entry
    asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
    {
            struct pt_regs *old_regs = set_irq_regs(regs);
            printk("the irq : %d\n",irq);  
            //............... 
            // I get 62 here
            //...............
            irq_enter();

            /*
             * Some hardware gives randomly wrong interrupts.  Rather
             * than crashing, do something sensible.
             */
            if (unlikely(irq >= nr_irqs)) {
                    if (printk_ratelimit())
                            printk(KERN_WARNING "Bad IRQ%u\n", irq);
                    ack_bad_irq(irq);
            } else {
                    generic_handle_irq(irq);
            }

            /* AT91 specific workaround */
            irq_finish(irq);

            irq_exit();

            set_irq_regs(old_regs);

    }

推荐答案

此观察可能是由于物理和虚拟IRQ编号之间的映射所致.驱动程序中显示的数字是虚拟IRQ数字,仅在使用通用linux中断处理子系统时有效. asm_do_IRQ中的中断号将是内核中断结构提供的物理中断号.

This observation is likely due to the mapping between physical and virtual IRQ numbers. The numbers seen in your driver are virtual IRQ numbers, valid only when using the generic linux interrupt handling subsystem. The interrupt number in asm_do_IRQ will be the physical interrupt number provided by the interrupt fabric of the core.

我相信OMAP处理器支持GPIO引脚上的中断.通常的实现方式是为一组GPIO输入(例如32位)分配一条IRQ线.当任何GPIO发生中断时,该IRQ线将被激活.这可能是处理器上的数字62.如果您查看处理器的手册,则应该看到IRQ 62对应于GPIO组上的中断.

I believe the OMAP processors support interrupts on GPIO pins. The way this is usually implemented is to allocate a single IRQ line for a bank of GPIO inputs, say 32 bits. When an interrupt occurs on any of the GPIOs, that IRQ line will activate. This is likely the number 62 on your processor. If you look in the manual for your processor, you should see that IRQ 62 corresponds to an interrupt on a GPIO bank.

现在,Linux GPIO子系统将允许您将中断处理程序分配给任何GPIO,从而为您提供从linux irq编号到物理irq编号的映射.您的linux irq数是196.GPIO子系统配置为处理所有GPIO中断(例如中断62),读取GPIO寄存器以确定存储库中的哪些GPIO位可能已产生中断,然后调出用request_irq分配的中断处理程序.

Now, the linux GPIO subsystem will allow you to allocate an interrupt handler to any of the GPIOs, providing you with a mapping from a linux irq number to a physical irq number. The linux irq number in your case is 196. The GPIO subsystem is configured to handle all GPIO interrupts (say interrupt 62), read the GPIO register to determine which of the GPIO bits in a bank could have generated an interrupt, and then calls out the interrupt handler you've assigned with request_irq.

这是GPIO中断的基本控制流程:

Here's a basic flow of control for a GPIO interrupt:

  1. 在GPIO组中的中断发生更改. IRQ 62升高.
  2. asm_do_IRQ在IRQ 62上运行.平台子系统代码已注册GPIO子系统以处理IRQ 62.
  3. GPIO子系统读取GPIO寄存器,并确定GPIO位X引起了中断.它计算从X位到Linux虚拟IRQ编号的映射,在本例中为196.
  4. 然后GPIO中断处理程序使用196调用generic_handle_irq函数,该函数将调用您的中断处理程序.
  1. A change occurs on an interrupt in a GPIO bank. IRQ 62 is raised.
  2. asm_do_IRQ runs on IRQ 62. The GPIO subsystem has been registered to handle IRQ 62 by the platform init code.
  3. The GPIO subsystem reads the GPIO registers and determines that GPIO bit X has caused the interrupt. It calculates the mapping from bit X to the linux virtual IRQ number, in this case 196.
  4. The GPIO interrupt handler then calls the generic_handle_irq function with 196, which calls your interrupt handler.

平台通常在虚拟IRQ编号和物理IRQ编号之间定义一个静态映射.要查看此映射,

There is usually a static mapping defined by the platform between virtual IRQ numbers and physical IRQ numbers. To see this mapping,

    在低于linux-3.4的内核上
  • 启用CONFIG_VIRQ_DEBUG,或者
  • 在较新的内核上启用CONFIG_IRQ_DOMAIN_DEBUG.
  • enable CONFIG_VIRQ_DEBUG on kernels older than linux-3.4, or
  • enable CONFIG_IRQ_DOMAIN_DEBUG on newer kernels.

然后看一下irq_domain_mapping debugfs文件.例如.在PowerPC上:

Then have a look to irq_domain_mapping debugfs file. E.g. on PowerPC:

# mount -t debugfs none /sys/kernel/debug
# cat /sys/kernel/debug/irq_domain_mapping 
irq    hwirq    chip name        chip data   domain name
   16  0x00009  IPIC             0xcf801c80  /soc8347@e0000000/pic@700
   18  0x00012  IPIC             0xcf801c80  /soc8347@e0000000/pic@700
   19  0x0000e  IPIC             0xcf801c80  /soc8347@e0000000/pic@700
   20  0x0000f  IPIC             0xcf801c80  /soc8347@e0000000/pic@700
   21  0x00010  IPIC             0xcf801c80  /soc8347@e0000000/pic@700
   77  0x0004d  IPIC             0xcf801c80  /soc8347@e0000000/pic@700

这篇关于内核函数asm_do_IRQ()中的irq与我在模块中请求的irq不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-10 08:28