您的位置 首页 应用

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

一,认识几个重要结构体:1.中断描述符对于每一条中断线都由一个irq_desc结构来描述。//在include/linux/irq.h中structirq_desc{unsign…

一,知道几个重要结构体:

1.中止描绘符

关于每一条中止线都由一个irq_desc结构来描绘。

//在include/linux/irq.h中

struct irq_desc {
unsigned intirq;//中止号
struct timer_rand_state *timer_rand_state;
unsigned int *kstat_irqs;
#ifdef CONFIG_INTR_REMAP
struct irq_2_iommu *irq_2_iommu;
#endif

/*

在kernel/irq/chip.c中完结了5个函数:handle_simple_irq(),handle_level_irq(),
handle_edge_irq(),handle_fasteoi_irq()以及handle_percpu_irq()。 handle_irq指针可
以指向这5个函数中的一个, 挑选一种中止事情处理战略, 这是经过函数set_irq_handler()
完结的

*/
irq_flow_handler_thandle_irq;//上层中止处理函数,
struct irq_chip*chip;//底层硬件操作
struct msi_desc*msi_desc;
void*handler_data;//附加参数,用于handle_irq
void*chip_data;//渠道相关附加参数,用于chip
struct irqaction*action;/* IRQ action list*///中止服务例程链表
unsigned intstatus;/* IRQ status *///中止当时的状况

//中止封闭翻开层数调用一次disable_irq( ) ,depth加1;调用一次enable_irq( )该值减1,

//假如depth等于0就敞开这条中止线,假如depth大于0就封闭中止线。

unsigned intdepth;
unsigned intwake_depth;////* 唤醒次数 */
unsigned intirq_count;/* 发生的中止次数 */
unsigned longlast_unhandled;/* Aging timer for unhandled count */
unsigned intirqs_unhandled;
spinlock_tlock;
#ifdef CONFIG_SMP
cpumask_var_taffinity;
unsigned intcpu;
#ifdef CONFIG_GENERIC_PENDING_IRQ
cpumask_var_tpending_mask;
#endif
#endif
atomic_tthreads_active;
wait_queue_head_t wait_for_threads;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry*dir;///proc/irq/ 进口
#endif
const char*name;///proc/interrupts 中显现的中止称号
} ____cacheline_internodealigned_in_smp;

/*在kernel/irq/handle.c中有个大局irq_desc数组,描绘了体系中一切的中止线:

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

NR_IRQS为最大中止数关于s3c2410芯片,在文件arch/arm/mach-s3c2410/include/mach/irqs.h中界说如下:

#ifdef CONFIG_CPU_S3C2443
#define NR_IRQS (IRQ_S3C2443_AC97+1)
#else
#define NR_IRQS (IRQ_S3C2440_AC97+1)//每一个中止源都对应一个irq_desc结构体。
#endif

*/

2. 中止硬件操作函数集

//在include/linux/irq.h中界说

//该结构体中各函数在文件linux/arch/arm/plat-s3c24xx/irq.c中完结

struct irq_chip {
const char*name;//用于 /proc/interrupts
unsigned int(*startup)(unsigned int irq);//默以为 enable 假如为NULL
void(*shutdown)(unsigned int irq);//默以为 disable 假如为NULL
void(*enable)(unsigned int irq);//答应中止,默以为 unmask 假如为NULL
void(*disable)(unsigned int irq);//制止中止,默以为 mask假如为 NULL

void(*ack)(unsigned int irq);//呼应一个中止,铲除中止标志
void(*mask)(unsigned int irq);//mask 一个中止源,通常是封闭中止
void(*mask_ack)(unsigned int irq);//呼应并 mask 中止源
void(*unmask)(unsigned int irq);//unmask 中止源
void(*eoi)(unsigned int irq);

void(*end)(unsigned int irq);
void(*set_affinity)(unsigned int irq,
const struct cpumask *dest);
int(*retrigger)(unsigned int irq);
int(*set_type)(unsigned int irq, unsigned int flow_type);//设置中止触发方法 IRQ_TYPE_LEVEL
int(*set_wake)(unsigned int irq, unsigned int on);

/* Currently used only by UML, might disappear one day.*/
#ifdef CONFIG_IRQ_RELEASE_METHOD
void(*release)(unsigned int irq, void *dev_id);
#endif
/*
* For compatibility, ->typename is copied into ->name.
* Will disappear.
*/
const char*typename;
};

3.中止处理例程描绘符

//在include/linux/interrupt.h中

struct irqaction {
irq_handler_t handler;/* 详细的中止处理程序 */
unsigned long flags;//用一组标志描绘中止线与 I/O 设备之间的联系。
cpumask_t mask;
const char *name;/* 称号,会显现在/proc/interreupts中 */
void *dev_id;/* 设备ID,用于区别同享一条中止线的多个处理程序 ,以便从同享中止线的许多中止处理程序中删去指定的那一个*/
struct irqaction *next;/* 指向下一个irq_action结构 */
int irq;/* 中止通道号 */
struct proc_dir_entry *dir; /* procfs目录 */
irq_handler_t thread_fn;
struct task_struct *thread;
unsigned long thread_flags;
};

这三个结构体间的联系表明如下

二,中止初始化进程
中止机制的初始化经过 两个函数完结: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(unsigned int irq, struct irq_desc *desc)
{
#ifdef CONFIG_GENER%&&&&&%_HARDIRQS_NO__DO_IRQ
desc->handle_irq(irq, desc);//直接调用上层中止处理函数
#else
if (likely(desc->handle_irq))
desc->handle_irq(irq, desc);
else
__do_IRQ(irq);//通用中止处理函数,该函数终究调用desc->handle_irq(irq, desc);
#endif
}

上层中止处理函数

上层中止处理函数有5个分别为:handle_simple_irq(),handle_level_irq(),
handle_edge_irq(),handle_fasteoi_irq()以及handle_percpu_irq()。

这几个函数在文件kernel/irq/chip.c中完结。常用的有两个handle_level_irq(),和handle_edge_irq()。

这5个上层中止处理函数都是经过调用函数handle_IRQ_event()来做进一步处理。

irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
irqreturn_t ret, retval = IRQ_NONE;
unsigned int status = 0;

if (!(action->flags & IRQF_DISABLED))
local_irq_enable_in_hardirq();

do {

。。。。。。

ret = action->handler(irq, action->dev_id);//履行中止处理函数。

。。。。。。

retval |= ret;
action = action->next;
} while (action);//调用该中止线上的一切例程

if (status & IRQF_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
local_irq_disable();

return retval;
}

void
handle_level_irq(unsigned int irq, struct irq_desc *desc)
{
struct irqaction *action;
irqreturn_t action_ret;

。。。。。。

desc = irq_remap_to_desc(irq, desc);

。。。。。。

action = desc->action;

action_ret = handle_IRQ_event(irq, action);

。。。。。。

}

void
handle_edge_irq(unsigned int irq, struct irq_desc *desc)
{
spin_lock(&desc->lock);

。。。。。。
desc = irq_remap_to_desc(irq, desc);
。。。。。。
desc->status |= IRQ_INPROGRESS;

do {
struct irqaction *action = desc->action;
。。。。。。

desc->status &= ~IRQ_PENDING;
spin_unlock(&desc->lock);
action_ret = handle_IRQ_event(irq, action);
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);
spin_lock(&desc->lock);

//该函数与函数handle_level_irq不太相同的是,该函数多了一个循环。即假如在本次中止

//的处理进程中该中止线上又有中止发生,则再次履行该中止线上的处理例程

/*

以下是5个常用的中止线状况。

#define IRQ_INPROGRESS 1 /* 正在履行这个 IRQ 的一个处理程序 */
#define IRQ_DISABLED 2 /* 由设备驱动程序现已禁用了这条 IRQ 中止线 */

#define IRQ_PENDING 4 /* 一个 IRQ 现已出现在中止线上,且被应对,但还没有
为它供给服务 */
#define IRQ_REPLAY 8 /* 当 Linux 从头发送一个已被删去的 IRQ 时 */
#define IRQ_WAITING 32 /* 当对硬件设备进行探测时,设置这个状况以符号正在被
测验的 irq */

*/

} while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);

desc->status &= ~IRQ_INPROGRESS;
out_unlock:
spin_unlock(&desc->lock);
}

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/yingyong/275382.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部