PPC中断处理函数的入口地址
IVPR[32-47] | IVORn[48-59] | 0b'0000其中IPVR定义虚拟基址interrupt_base,描述如下:
interrupt_base: //head_fsl_booke.S (c:\linux\linux-2.6.23\arch\powerpc\kernel) 26851 2007/10/10
/* Critical Input Interrupt */
CRITICAL_EXCEPTION(0x0100, CriticalInput, unknown_exception)
/* Machine Check Interrupt */
#ifdef CONFIG_E200
/* no RFMCI, MCSRRs on E200 */
CRITICAL_EXCEPTION(0x0200, MachineCheck, machine_check_exception)
#else
MCHECK_EXCEPTION(0x0200, MachineCheck, machine_check_exception)
#endif
......
/* External Input Interrupt *///外部中断的定义和ExternalInput偏移地址
EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE)
IOVR定义偏移地址ExternalInput,描述如下:
/* Establish the interrupt vector offsets */
SET_IVOR(0, CriticalInput);
SET_IVOR(1, MachineCheck);
SET_IVOR(2, DataStorage);
SET_IVOR(3, InstructionStorage);
SET_IVOR(4, ExternalInput);
SET_IVOR(5, Alignment);
SET_IVOR(6, Program);
#define SET_IVOR(vector_number, vector_label) \
li r26,vector_label@l; \
mtspr SPRN_IVOR##vector_number,r26; \
sync
#define START_EXCEPTION(label) \
.align 5; //与cacheline对齐,提升性能,ppc32的cache是32 \
label:
cache的定义如下
#ifndef SMP_CACHE_BYTES
#define SMP_CACHE_BYTES L1_CACHE_BYTES
#endif
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
#define SMP_CACHE_BYTES L1_CACHE_BYTES
if defined(CONFIG_PPC32)
#define L1_CACHE_SHIFT 5
内核栈切换到中断栈
call_handle_irq(irq, desc, irqtp, desc->handle_irq);
/*
r3: irq
r4: desc
r5: irqtp
r6: handle_irq
*/
#ifdef CONFIG_IRQSTACKS
_GLOBAL(call_handle_irq)
mflr r0 //将被打断进程的下一条指令的地址保存到r0
stw r0,4(r1)//将r0保存到进程内核栈
mtctr r6 //将中断处理函数保存到ctr
stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r5) //将进程内核栈的栈顶指针保存到了中断栈里面
mr r1,r5 //栈顶指针切换成中断栈栈顶指针
bctrl //执行中断处理函数
lwz r1,0(r1)//恢复栈顶指针为进程内核态栈顶指针
lwz r0,4(r1)//恢复r0寄存器
mtlr r0 //将r0,也就是被打断进程的下一条指令放到lr寄存器
blr
#endif /* CONFIG_IRQSTACKS */
p4080ds的设备树
mpic: pic@40000 {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <2>;
reg = <0x40000 0x40000>;
compatible = "chrp,open-pic";
device_type = "open-pic";
};
init_IRQ
=>ppc_md.init_IRQ();//P4080_ds.c (arch\powerpc\platforms\85xx): .init_IRQ = corenet_ds_pic_init,
=>corenet_ds_pic_init
=>struct mpic *mpic;
struct resource r;
unsigned int flags = MPIC_PRIMARY | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU;
=>struct device_node *np = of_find_node_by_type(np, "open-pic");
=>of_address_to_resource(np, 0, &r)
=>mpic = mpic_alloc(np, r.start, flags, 0, 256, " OpenPIC ");
=>struct mpic *mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL);
=>mpic->name = name;
mpic->hc_irq = mpic_irq_chip;//mpic_irq_chip如下
=>static struct irq_chip mpic_irq_chip = {
.mask = mpic_mask_irq,
.unmask = mpic_unmask_irq,
.eoi = mpic_end_irq,
.set_type = mpic_set_irq_type,
};
mpic->hc_irq.name = name;
mpic->flags = flags;
mpic->isu_size = isu_size;
mpic->irq_count = irq_count;
mpic->num_sources = 0;
if (flags & MPIC_LARGE_VECTORS)
intvec_top = 2047;
else
intvec_top = 255;
mpic->timer_vecs[0] = intvec_top - 8;
mpic->timer_vecs[1] = intvec_top - 7;
mpic->timer_vecs[2] = intvec_top - 6;
mpic->timer_vecs[3] = intvec_top - 5;
mpic->ipi_vecs[0] = intvec_top - 4;
mpic->ipi_vecs[1] = intvec_top - 3;
mpic->ipi_vecs[2] = intvec_top - 2;
mpic->ipi_vecs[3] = intvec_top - 1;
mpic->spurious_vec = intvec_top;
=>mpic_init(mpic);
=>for (i = 0; i < mpic->num_sources; i++) {/*这段代码相当重要,芯片手册定义外部模块中断号0:15;而芯片定义内部模块的中断号0..63。在这里MPIC将其映射的硬件中断号统一排序为0..79,0..11=>0:11;而0..63=>16:79。*/
/* start with vector = source number, and masked */
u32 vecpri = MPIC_VECPRI_MASK | i |
(8 << MPIC_VECPRI_PRIORITY_SHIFT);
/* check if protected */
if (mpic->protected && test_bit(i, mpic->protected))
continue;
/* init hw */
mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);//写硬件中断号到配套的寄存器
mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu);
}
=>irq_ctx_init();//设置独立中断栈
=>struct thread_info *tp;
int i;
=>for_each_possible_cpu(i) {
memset((void *)softirq_ctx[i], 0, THREAD_SIZE);
tp = softirq_ctx[i];
tp->cpu = i;
tp->preempt_count = 0;
memset((void *)hardirq_ctx[i], 0, THREAD_SIZE);
tp = hardirq_ctx[i];
tp->cpu = i;
tp->preempt_count = HARDIRQ_OFFSET;
}
void do_IRQ(struct pt_regs *regs)
=>struct pt_regs *old_regs = set_irq_regs(regs);
=>irq_enter();
=>__irq_enter();
=>irq = ppc_md.get_irq();//P4080_ds.c (arch\powerpc\platforms\85xx): .get_irq = mpic_get_coreint_irq,
=>mpic_get_coreint_irq
=>struct mpic *mpic = mpic_primary;
=>src = mfspr(SPRN_EPR);//获取硬件中断号
=>return irq_linear_revmap(mpic->irqhost, src);//查表返回逻辑中断号
=>revmap = host->revmap_data.linear.revmap;
=>return revmap[hwirq];
=>handle_one_irq(irq);//根据逻辑中断号找ISR
=>generic_handle_irq(irq);
=>generic_handle_irq_desc(irq, irq_to_desc(irq));
=>handle_edge_irq //desc->handle_irq = handle_level_irq;
=>mask_ack_irq(desc, irq);
=>desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
=>action = desc->action;
=>desc->status |= IRQ_INPROGRESS;
=>action_ret = handle_IRQ_event(irq, action);
=>do {
ret = action->handler(irq, action->dev_id);
switch (ret) {
case IRQ_WAKE_THREAD:
ret = IRQ_HANDLED;
set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
wake_up_process(action->thread);
case IRQ_HANDLED:
status |= action->flags;
break;
}
retval |= ret;
action = action->next;
=>} while (action);
=>desc->status &= ~IRQ_INPROGRESS;
=>unmask_irq(desc, irq);
=>irq_exit();
=>set_irq_regs(old_regs);
POWERPC中断
https://blog.csdn.net/evenness/article/details/7594739
PowerPC构架应用程序二进制接口(ABI)及堆栈帧详解
http://blog.sina.com.cn/s/blog_70dd16910100ypf2.html
MPIC 与 PowerPC Linux 中断处理
https://blog.csdn.net/xxxl/article/details/47837757
Linux中PowerPC的中断原理分析
https://blog.csdn.net/JuanA1/article/details/6679920
MPIC 与 PowerPC Linux 中断处理
http://blog.chinaunix.net/uid-22898497-id-3892944.html
linux下 powerpc中断分析 好文
http://blog.chinaunix.net/uid-22898497-id-3892941.html