内核函数 asm_do_IRQ() 中的 irq 与我在模块中请求的不同 [英] The irq in kernel function asm_do_IRQ() is different from the one I request in module
问题描述
我用 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:
- GPIO bank 中的中断发生了变化.引发 IRQ 62.
asm_do_IRQ
在 IRQ 62 上运行.GPIO 子系统已被平台初始化代码注册为处理 IRQ 62.- GPIO 子系统读取 GPIO 寄存器并确定 GPIO 位 X 已导致中断.它计算从位 X 到 linux 虚拟 IRQ 编号的映射,在本例中为 196.
- 然后 GPIO 中断处理程序使用 196 调用
generic_handle_irq
函数,该函数调用您的中断处理程序.
- A change occurs on an interrupt in a GPIO bank. IRQ 62 is raised.
asm_do_IRQ
runs on IRQ 62. The GPIO subsystem has been registered to handle IRQ 62 by the platform init code.- 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.
- 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屋!