微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM Linux中断机制之中断的初始化

ARM Linux中断机制之中断的初始化

时间:11-10 来源:互联网 点击:

这三个结构体间的关系表示如下

二,中断初始化过程

中断机制的初始化通过 两个函数完成:early_trap_init()和init_IRQ(),在此我们先讨论函数init_IRQ()。

//函数init_IRQ在文件linux/arch/arm/kernel/irq.c中实现。

void __init init_IRQ(void)
{
int irq;

/* 设置 irq_desc 数组的 status 为 IRQ_NOREQUEST | IRQ_NOPROBE(没有请求,没有检测) */

for (irq = 0; irq < NR_IRQS; irq++)
irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;

#ifdef CONFIG_SMP
cpumask_setall(bad_irq_desc.affinity);
bad_irq_desc.cpu = smp_processor_id();
#endif

/*

init_arch_irq在文件linux/arch/arm/kernel/irq.c中定义如下

void (*init_arch_irq)(void) __initdata = NULL;

该函数指针在 setup_arch()中被赋值,

init_arch_irq = mdesc->init_irq;

指向 machine_desc 中定义的 init_irq 函数。

在平台smdk2440中,该函数在文件linux/arch/arm/plat-s3c24xx/irq.c中实现。

*/
init_arch_irq();
}

//函数s3c24xx_init_irq在文件linux/arch/arm/plat-s3c24xx/irq.c中实现

void __init s3c24xx_init_irq(void)
{
unsigned long pend;
unsigned long last;
int irqno;
int i;

irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");

/* first, clear all interrupts pending... */

last = 0;
for (i = 0; i < 4; i++) {
pend = __raw_readl(S3C24XX_EINTPEND);

if (pend == 0 || pend == last)
break;

__raw_writel(pend, S3C24XX_EINTPEND);//清除外部中断寄存器EINTPEND中的请求标志,
printk("irq: clearing pending ext status %08x\n", (int)pend);
last = pend;
}

last = 0;

。。。。。。

//设置各中断的底层硬件操作函数集desc->chip,中断上层处理函数desc->handle_irq

for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
/* set all the s3c2410 internal irqs */

switch (irqno) {
/* deal with the special IRQs (cascaded) */

case IRQ_EINT4t7:
case IRQ_EINT8t23:
case IRQ_UART0:
case IRQ_UART1:
case IRQ_UART2:
case IRQ_ADCPARENT:
set_irq_chip(irqno, &s3c_irq_level_chip);
set_irq_handler(irqno, handle_level_irq);
break;

case IRQ_RESERVED6:
case IRQ_RESERVED24:
/* no IRQ here */
break;

default:
//irqdbf("registering irq %d (s3c irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_chip);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
}

//以下几个中断都有多个中断源,每一个中断源也都有各自的中断号,它们的多个中断源中任意一个产生中断

//该中断都会被触发,而不是直接出发子中断。这几个中断并不处理中断函数,它们的中作是计算子中断的中断号,

//并根据子中断的中断号在数组irq_desc[NR_IRQS]中去找出该中断号对应的irq_desc结构,并调用该结构中的中断处理函数。

set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);

set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);

。。。。。。

for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
irqdbf("registering irq %d (extended s3c irq)\n", irqno);
set_irq_chip(irqno, &s3c_irqext_chip);//设置子中断的硬件操作函数集
set_irq_handler(irqno, handle_edge_irq);//设置子中断的上层处理函数
set_irq_flags(irqno, IRQF_VALID);
}

。。。。。。

}

比如此时外部中断10产生了中断,中断号为IRQ_EINT8t23的中断被触发,执行函数s3c_irq_demux_extint8()。

static void
s3c_irq_demux_extint8(unsigned int irq,
struct irq_desc *desc)
{
unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);

eintpnd &= ~eintmsk;
eintpnd &= ~0xff;/* ignore lower irqs */

/* we may as well handle all the pending IRQs here */

while (eintpnd) {
irq = __ffs(eintpnd);//计算该中断在外部中断寄存器EINTPEND中的偏移量
eintpnd &= ~(1

irq += (IRQ_EINT4 - 4);//根据这个偏移量重新计算中断号
generic_handle_irq(irq);//根据重新计算的中断号获取对应的结构体irq_desc,并调用它的上层中断处理函数。
}

}

static inline void generic_handle_irq_desc(

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top