事由: 当我写irq chip的驱动的时候,我发现irq alloc descs这个函数可以不用,我就很奇怪,如果不分配空间创建irqdesc,哪接下来的irq set chip 以及irq set chip data等函数向哪里填充数据。
我继续查看irq set chip等函数,kernel/kernel/irq
struct irq_desc *desc=irq_get_desc_lock(irq,&flags)//通过irq来查找desc
desc->irq_Data.chip=chip;
那么这个desc肯定是有什么地方创建了
initIRQ->machine_descinit_irq->rkxx_init_irq->gic_init->gic_dist_init->
early_irq_init-> early_irq_init通过arch_probe_nr_irqs获得NR_IRQS,然后分配irq descs
首先站在系统的最高层来看看,系统中申请了那些中断。
/proc# cat interrupts
CPU0
2: 0 dummy_cctv wifi0
3: 537 MIPS ehci_hcd:usb1
4: 534 MIPS eth0
6: 0 MIPS cascade_cctv
7: 27152 MIPS timer
18: 0 ath_misc_cctv_suiyuan cascade_cctv
19: 1189 ath_misc_cctv_suiyuan serial
64: 0 ath_pci_cctv wifi1
第一列显示的是中断号,
第二列显示的是中断的次数,
第三列为:此中断对应的structirq_chip结构中的name,因为每一个irq于一个特定的structirq_chip相联系。
第四列为:申请此中断时的名称。
重要的一个数据结构,硬件中断描述符。
struct irq_chip {
const char *name;
unsignedint (*startup)(unsigned int irq);
void (*shutdown)(unsigned int irq);
void (*enable)(unsigned int irq);
void (*disable)(unsigned int irq);
void (*ack)(unsigned int irq);
void (*mask)(unsigned int irq);
void (*mask_ack)(unsigned int irq);
void (*unmask)(unsigned int irq);
void (*eoi)(unsigned int irq);
void (*end)(unsigned int irq);
int (*set_affinity)(unsigned int irq,
const struct cpumask *dest);
int (*retrigger)(unsigned int irq);
int (*set_type)(unsigned int irq, unsigned int flow_type);
int (*set_wake)(unsigned int irq, unsigned int on);
#ifdefCONFIG_IRQ_RELEASE_METHOD
void (*release)(unsigned int irq, void *dev_id);
#endif
const char *typename;
};
Handle.c(z:\wlan\src\linux\kernels\mips-linux-2.6.31\kernel\irq)
Irq.c(z:\wlan\src\linux\kernels\mips-linux-2.6.31\arch\mips\kernel)
asmlinkage void __initstart_kernel(void)
{
early_irq_init();
init_IRQ();//用来初始化中断相关的代码。
}
struct irq_desc irq_desc[NR_IRQS]__cacheline_aligned_in_smp = {
[0 ... NR_IRQS-1] = {
.status = IRQ_DISABLED,
.chip = &no_irq_chip,
.handle_irq = handle_bad_irq,
.depth = 1,
.lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),
}
};
static unsigned intkstat_irqs_all[NR_IRQS][NR_CPUS];
int __initearly_irq_init(void)
{
struct irq_desc *desc;
int count;
int i;
init_irq_default_affinity();
printk(KERN_INFO "NR_IRQS:%d\n", NR_IRQS); //NR_IRQS:128
desc = irq_desc;
count = ARRAY_SIZE(irq_desc);
for (i = 0; i < count; i++) {
desc[i].irq = i;
alloc_desc_masks(&desc[i], 0, true);
init_desc_masks(&desc[i]);
desc[i].kstat_irqs = kstat_irqs_all[i];
}
return arch_early_irq_init();
}
void __initinit_IRQ(void)
{
int i;
#ifdef CONFIG_KGDB
if (kgdb_early_setup)
return;
#endif
for (i = 0; i < NR_IRQS; i++){
set_irq_noprobe(i);
}
printk("cctv: %s: line:%d\n", __FUNCTION__,__LINE__);
arch_init_irq();
#ifdef CONFIG_KGDB
if (!kgdb_early_setup)
kgdb_early_setup = 1;
#endif
}
Irq.c(z:\wlan\src\linux\kernels\mips-linux-2.6.31\arch\mips\atheros)
void__init arch_init_irq(void) //主要对AR9344平台的中断进行初始化。
{
printk("cctv: %s: line:%d\n", __FUNCTION__,__LINE__);
mips_cpu_irq_init();
ath_misc_irq_init(ATH_MISC_IRQ_BASE);
ath_gpio_irq_init(ATH_GPIO_IRQ_BASE);
#ifdef CONFIG_PCI
ath_pci_irq_init(ATH_PCI_IRQ_BASE);
#endif
setup_irq(ATH_CPU_IRQ_MISC, &cascade);
setup_irq(ATH_MISC_IRQ_GPIO, &cascade);
#ifdef CONFIG_PCI
setup_irq(ATH_CPU_IRQ_PCI, &cascade);
#endif
ath_arch_init_irq();
set_c0_status(ST0_IM);
}
//先看看下面这个函数:给特定的中断号建立起一个特定的中断处理函数
Void set_irq_chip_and_handler(unsignedint irq, struct irq_chip *chip,
irq_flow_handler_t handle)
{//下面这俩个函数主要就是对irq对应的structirq_desc的成员进行赋值。
set_irq_chip(irq, chip);
__set_irq_handler(irq, handle, 0, NULL);
}
//下面这个函数是将一个特定的中断号于数据结构structirq_chip建立其联系,我们可以从函数的俩个参数看出来。
int set_irq_chip(unsigned int irq,struct irq_chip *chip)
{
struct irq_desc *desc =irq_to_desc(irq);//根据irq号,取出irq_desc。
unsigned long flags;
if (!desc) {
WARN(1, KERN_ERR "Trying to install chip for IRQ%d\n",irq);
return -EINVAL;
}
if (!chip)
chip = &no_irq_chip;
spin_lock_irqsave(&desc->lock, flags);
irq_chip_set_defaults(chip);
desc->chip = chip; //将参数赋值给特定中断对应的chip。
spin_unlock_irqrestore(&desc->lock, flags);
return 0;
}
voidirq_chip_set_defaults(struct irq_chip *chip)
{//给struct irq_chip结构成员赋初始值。
if(!chip->enable)
chip->enable = default_enable;
if (!chip->disable)
chip->disable = default_disable;
if (!chip->startup)
chip->startup = default_startup;
if (!chip->shutdown)
chip->shutdown = chip->disable != default_disable?
chip->disable : default_shutdown;
if (!chip->name)
chip->name = chip->typename;
if (!chip->end)
chip->end = dummy_irq_chip.end;
}
#defineATH_CPU_IRQ_BASE 0x00
#defineATH_MISC_IRQ_BASE 0x10
#defineATH_GPIO_IRQ_BASE 0x20
#defineATH_MISC_IRQ_COUNT 14
下面的函数主要也就是对特定的中断号关联特定的handler。
static void ath_misc_irq_init(intirq_base)
{
int i;
for (i = irq_base; i < irq_base + ATH_MISC_IRQ_COUNT; i++){
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = NULL;
irq_desc[i].depth = 1;
set_irq_chip_and_handler(i,&ath_misc_irq_controller,
handle_percpu_irq);
}
}
int setup_irq(unsigned int irq,struct irqaction *act)
{
struct irq_desc *desc = irq_to_desc(irq);
return __setup_irq(irq, desc, act);
}
///
下面来看看驱动中对注册到系统的中断是如何申请和处理的。
static inline int__must_check
request_irq(unsigned int irq,irq_handler_t handler, unsigned long flags,
const char*name, void *dev)
{//中断申请函数。
return request_threaded_irq(irq, handler, NULL, flags, name,dev);
}
ret =request_irq(ATH_GPIO_IRQn(BUTTON_GPIO), ar9344buttons_interrupt,0,"ar9344 button", NULL);
函数中的主要完成的事情为:
desc= irq_to_desc(irq);和retval =__setup_irq(irq, desc, action);
int request_threaded_irq(unsignedint irq, irq_handler_t handler,
irq_handler_t thread_fn, unsigned longirqflags,
const char *devname, void *dev_id){
struct irqaction *action;
struct irq_desc *desc;
int retval;
desc = irq_to_desc(irq);
if (!desc)
return -EINVAL;
if (desc->status & IRQ_NOREQUEST)
return -EINVAL;
if (!handler)
return -EINVAL;
action = kzalloc(sizeof(structirqaction), GFP_KERNEL);
if (!action)
return -ENOMEM;
action->handler = handler;
action->thread_fn = thread_fn;
action->flags = irqflags;
action->name = devname;
action->dev_id = dev_id;
retval = __setup_irq(irq, desc, action);
}
原文:http://blog.csdn.net/suiyuan19840208/article/details/7654265