内核函数 asm_do_IRQ() 中的 irq 与我在模块中请求的不同 [英] The irq in kernel function asm_do_IRQ() is different from the one I request in module

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

问题描述

我用 cortex-A9 开发板做了一些实验.我使用 gpio_to_irq() 来获取 irq num,我请求了 irq 并用它编写了一个小驱动程序,它在 syslog 中是 196.我在 asm_do_IRQ 中添加了一些印刷品.当我触发 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 

");
            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!

");
                    return 0;
            }

            int irq,irq2;
            irq = OMAP_GPIO_IRQ(TEST_GPIO);
            printk("irq : %d 
",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
",err);
                    return 0;
            }
            printk("gpio test init success!
");
            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!
");
    }

    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
",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
", 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 输入分配一条 IRQ 线,比如 32 位.当任何 GPIO 上发生中断时,该 IRQ 线将激活.这可能是您处理器上的数字 62.如果您查看处理器手册,您应该会看到 IRQ 62 对应于 GPIO bank 上的中断.

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 寄存器以确定 bank 中的哪些 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 bank 中的中断发生了变化.引发 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.

然后查看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 与我在模块中请求的不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆