ARM Linux中断机制分析
2.2.6 get_irqnr_preamble
get_irqnr_preamble用于获得中断状态寄存器基地址,特定于CPU,这里CPU用的是tegra,其定义如下
/* arch/arm/mach-tegra/include/mach/entry-macro.S /* Uses the GIC interrupt controller built into the cpu */ #define ICTRL_BASE (IO_CPU_VIRT + 0x40100)// #define IO_CPU_VIRT 0xFE000000 .macroget_irqnr_preamble, base, tmp movw \base, #(ICTRL_BASE & 0x0000ffff) movt \base, #((ICTRL_BASE & 0xffff0000) >> 16) .endm |
2.2.7 get_irqnr_and_base
get_irqnr_and_base用来获取中断号。
/* arch/arm/mach-tegra/include/mach/entry-macro.S .macro get_irqnr_and_base, irqnr, irqstat, base, tmp ldr \irqnr, [\base, #0x20] @ EVT_IRQ_STS cmp \irqnr, #0x80 .endm |
get_irqnr_preamble和get_irqnr_and_base两个宏由machine级的代码定义,目的就是从中断控制器中获得IRQ编号,紧接着就调用asm_do_IRQ,从这个函数开始,中断程序进入C代码中,传入的参数是IRQ编号和寄存器结构指针,
2.2.8 asm_do_IRQ
图4 asm_do_IRQ流程图
asm_do_IRQ是ARM处理硬件中断的核心函数,第一个参数指定了硬中断的中断号,第二个参数是寄存器备份组成的一个结构体,保存了中断发生时的模式对应的寄存器的值,在中断返回时使用。
linux/arch/arm/kernel/irq.c asmlinkage void __exception_irq_entry asm_do_IRQ(unsigned int irq, struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs);//获得寄存器值 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); } |
2.2.9 irq_enter
irq_enter是更新一些系统的统计信息,同时在__irq_enter宏中禁止了进程的抢占。虽然在产生IRQ时,ARM会自动把CPSR中的I位置位,禁止新的IRQ请求,直到中断控制转到相应的流控层后才通过local_irq_enable()打开。那为何还要禁止抢占?这是因为要考虑中断嵌套的问题,一旦流控层或驱动程序主动通过local_irq_enable打开了IRQ,而此时该中断还没处理完成,新的irq请求到达,这时代码会再次进入irq_enter,在本次嵌套中断返回时,内核不希望进行抢占调度,而是要等到最外层的中断处理完成后才做出调度动作,所以才有了禁止抢占这一处理。
linux/kernel/softirq.c voidirq_enter(void) { int cpu = smp_processor_id(); rcu_irq_enter(); if (idle_cpu(cpu) && !in_interrupt()) { /* Prevent raise_softirq from needlessly waking up ksoftirqd * here, as softirq will be serviced on return from interrupt.*/ local_bh_disable(); tick_check_idle(cpu); _local_bh_enable(); } __irq_enter(); } #define __irq_enter() \ do { \ account_system_vtime(current); \ add_preempt_count(HARDIRQ_OFFSET); \ trace_hardirq_enter(); \ } while (0) |
2.2.10 generic_handle_irq
~/include /linux/Irqdesc.h /* * Architectures call this to let the generic IRQ layer * handle an interrupt. If the descriptor is attached to an * irqchip-style controller then we call the ->handle_irq() handler, * and it calls __do_IRQ() if its attached to an irqtype-style controller. */ static inline void generic_handle_irq_desc(unsigned int irq,struct irq_desc *desc) { desc->handle_irq(irq, desc);//调用该irq注册的函数处理,该函数在注册中断时填写irq_desc结构体时指定。 }// handle_irq是 |
ARMLinux中断机 相关文章:
- ARM Linux中断机制之中断的初始化(11-10)
- ARM Linux中断机制之中断的申请(11-10)
- ARM Linux中断机制之中断处理(11-09)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)