4

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

    #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

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

    }
4

1 回答 1

4

这种观察很可能是由于物理和虚拟 IRQ 编号之间的映射。您的驱动程序中看到的数字是虚拟 IRQ 编号,仅在使用通用 linux 中断处理子系统时有效。中的中断号asm_do_IRQ将是内核中断结构提供的物理中断号。

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

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

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

  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 中断处理程序generic_handle_irq使用 196 调用该函数,该函数调用您的中断处理程序。

虚拟IRQ号和物理IRQ号之间通常有一个由平台定义的静态映射。要查看此映射,

  • CONFIG_VIRQ_DEBUG在早于 linux-3.4 的内核上启用,或
  • CONFIG_IRQ_DOMAIN_DEBUG在较新的内核上启用。

然后看看irq_domain_mappingdebugfs 文件。例如在 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
于 2013-04-08T07:48:41.767 回答