您的位置:首页 > 运维架构 > Linux

【转】linux中断流程详解

2017-05-21 20:05 281 查看

参考 :http://blog.csdn.net/yimu13/article/details/6803957

中断早期初始化

1. irq_desc[]

struct irq_desc {
struct irq_data     irq_data;
struct timer_rand_state *timer_rand_state;
unsigned int __percpu   *kstat_irqs;
irq_flow_handler_t  handle_irq;
#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
irq_preflow_handler_t   preflow_handler;
#endif
struct irqaction    *action;    /* IRQ action list */
unsigned int        status_use_accessors;
unsigned int        core_internal_state__do_not_mess_with_it;
unsigned int        depth;      /* nested irq disables */
unsigned int        wake_depth; /* nested wake enables */
unsigned int        irq_count;  /* For detecting broken IRQs */
unsigned long       last_unhandled; /* Aging timer for unhandled count */
unsigned int        irqs_unhandled;
raw_spinlock_t      lock;
#ifdef CONFIG_SMP
const struct cpumask    *affinity_hint;
struct irq_affinity_notify *affinity_notify;
#ifdef CONFIG_GENERIC_PENDING_IRQ
cpumask_var_t       pending_mask;
#endif
#endif
unsigned long       threads_oneshot;
atomic_t        threads_active;
wait_queue_head_t       wait_for_threads;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry   *dir;
#endif
const char      *name;
}
extern struct irq_desc irq_desc[NR_IRQS];
#define NR_IRQS         (GODNET_IRQ_START + 96)
#define GODNET_IRQ_START    (32)


GIC控制器,有PPI、SGI、SPI

SPI 共享外设中断号大于32.

2.

在内核早期初始化的时候,machine_desc会初始化gic_irq。

并且在别的函数(irq_set_handler)里设置irq_desc[]–>handle_irq。这个handle_irq后面会用得到。

==========================

下面是中断执行流程:

中断异常向量表:

1 在 arch/arm/kernel/entry-armv.S 中定义了宏 irq_handler

irq_handler里面会执行arch_irq_handler_default–》asm_do_IRQ

6         .macro  arch_irq_handler_default
7         get_irqnr_preamble r5, lr
8 1:      get_irqnr_and_base r0, r6, r5, lr
9         movne   r1, sp
10         @
11         @ routine called with r0 = irq number, r1 = struct pt_regs *
12         @
13         adrne   lr, BSYM(1b)
14         bne     asm_do_IRQ


无论是gic 控制器,还是别的中断控制器,都会执行到asm_do_IRQ

下面分析asm_do_IRQ 不

`asmlinkage void __exception_irq_entry

asm_do_IRQ(unsigned int irq, struct pt_regs *regs)

{

struct pt_regs *old_regs = set_irq_regs(regs);//18个寄存器,保存参数

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\n”, irq);

ack_bad_irq(irq);

} else {

generic_handle_irq(irq);

}

/* AT91 specific workaround */

irq_finish(irq);

irq_exit();

set_irq_regs(old_regs);

}`

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


static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
{
desc->handle_irq(irq, desc);
}


这里的desc_handle_rq就是内核早期初始化的时候设置的函数。

如有的平台是handle_level_irq

这函数会调用 handle_irq_event(desc);

irqreturn_t handle_irq_event(struct irq_desc *desc)
{
struct irqaction *action = desc->action;
irqreturn_t ret;

desc->istate &= ~IRQS_PENDING;
irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
raw_spin_unlock(&desc->lock);

ret = handle_irq_event_percpu(desc, action);

raw_spin_lock(&desc->lock);
irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
return ret;
}
irqreturn_t
handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
{
irqreturn_t retval = IRQ_NONE;
unsigned int random = 0, irq = desc->irq_data.irq;

do {
irqreturn_t res;

trace_irq_handler_entry(irq, action);
res = action->handler(irq, action->dev_id);
trace_irq_handler_exit(irq, action, res);

if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",
irq, action->handler))
local_irq_disable();

switch (res) {
case IRQ_WAKE_THREAD:
/*
* Catch drivers which return WAKE_THREAD but
* did not set up a thread function
*/
if (unlikely(!action->thread_fn)) {
warn_no_thread(irq, action);
break;
}

irq_wake_thread(desc, action);

/* Fall through to add to randomness */
case IRQ_HANDLED:
random |= action->flags;
break;

default:
break;
}

retval |= res;
action = action->next;
} while (action);

if (random & IRQF_SAMPLE_RANDOM)
add_interrupt_randomness(irq);

if (!noirqdebug)
note_interrupt(irq, desc, retval);
return retval;
}


由此找到了action->handler.

里面还会根据handler的返回值,如果是IRQ_WAKE_THREAD则唤醒中断线程。

那么这个handler是什么?

request_irq->request_threaded_irq-

if (!action)
return -ENOMEM;

action->handler = handler;
action->thread_fn = thread_fn;
action->flags = irqflags;
action->name = devname;
action->dev_id = dev_id;

chip_bus_lock(desc);
retval = __setup_irq(irq, desc, action);
chip_bus_sync_unlock(desc);


在__setup_irq里添加action到desc[]的action链表中。

然后遍历这个表,最终执行的就是中断申请的时候使用的handler。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: