int generic_handle_irq(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
if (!desc)
return -EINVAL;
generic_handle_irq_desc(irq, desc);
return 0;
}
该函数通过软中断号来索引数组irq_desc,得到一个struct irq_desc类型的指针变量desc,然后调用其成员函数handle_irq对当前中断进行实际的处理。
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp =
{
[0 ... NR_IRQS-1] =
{
.handle_irq = handle_bad_irq,
.depth = 1,
.lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
}
};
int __init early_irq_init(void)
{
int count, i, node = first_online_node;
struct irq_desc *desc;
init_irq_default_affinity();
printk(KERN_INFO "NR_IRQS:%d\n", NR_IRQS);
desc = irq_desc;
count = ARRAY_SIZE(irq_desc);
for (i = 0; i < count; i++)
{
desc[i].kstat_irqs = alloc_percpu(unsigned int);
alloc_masks(&desc[i], GFP_KERNEL, node);
raw_spin_lock_init(&desc[i].lock);
lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
desc_set_defaults(i, &desc[i], node, NULL);
}
return arch_early_irq_init();
}
linux操作系统在系统初始化期间通过调用early_irq_init函数来初始化irq_desc数组。
struct irq_data
{
u32 mask;
unsigned int irq;
unsigned long hwirq;
unsigned int node;
unsigned int state_use_accessors;
struct irq_chip *chip;
struct irq_domain *domain;
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
struct irq_data *parent_data;
#endif
void *handler_data;
void *chip_data;
struct msi_desc *msi_desc;
cpumask_var_t affinity;
};
结构体成员的irq表示软中断号,chip表示当前中断来自的PIC,linux通过封装在struct irq_data中的chip来屏蔽各种不同硬件平台上PIC的差异,给上层的软件提供统一的对PIC操作的接口。利用PIC中封装的函数,可以屏蔽或启用当前中断,设定外部设备中断触发电信号的类型。
irq_desc中的action是针对某一具体设备的中断处理的抽象。设备驱动程序会通过request_irq来向其中挂载设备特定的中断处理函数。从通用中断处理函数发起的对某一中断处理,实际上被分成了两个层次,第一层是handle_irq函数,它与软中断号irq一一对应,代表了对IRQ line上的处理动作,而action则代表与具体设备相关的中断处理,也是设备驱动程序开发者要直接与之打交道的对象,通过action成员,可以在一条IRQ line上挂载多个设备。
阅读(718) | 评论(0) | 转发(0) |