中断学习之外部中断 powerpc实现

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

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值