linux powerpc e500内核外部中断,PIC,PPC,设备驱动

http://blog.chinaunix.net/u2/71164/showart_2038214.html

 

powerpc e500内核中断系统有两部分组成一个是e500 的内核,一个是中断异常控制器programmable interrupt controller (PIC) interrupt protocol

e500内核有些特殊之处是:在e500内核进入中断和异常处理程序时不能关闭mmu 也就是说e500内核所看到的是虚拟地址。E500内核的解决办法是利用IVPR  IVOR寄存器来共同决定中断程序的入口地址,IVPR保存中断入口程序的0~15 IVOR保存16~27 28~31位为0;(每一个IVOR对应一种中断, 如:IVOR4 对应着外部中断)。此外PIC控制器还有Interrupt Source Configuration Registers 用来区分是具体的中断如外部中断一有EIVPR1 EIDR1共同决定

0---------------------------------------------------------------------------------à31

MSK           A      RSV1    P      S             PRIORITY    VECTIOR

0               1        2~7    8      9               12~`15       16~`31

其中vector 位为硬件中断号(不同于datasheet种的中断号)。其他个相关位见datasheet

e500 int信号有效是期铜外部中断处理,外部中断处理根据具体的硬件中断号执行具体本中断的处理程序。俺也不知道处于啥原因linux又弄了个软中断号这样你在申请中断(request_irq是应该使用的是软中断号)。为此系统必须建立软中断号与硬中断号之间的联系。建立联系之后你就可以通过硬件中断号向系统要软件中断号了然后request_irq了。参见irq_of_parse_and_map函数或者干脆就直接调用irq_create_mapping(不知道会不会有问题)

与之相关的中断调用如下(arch/powerpc/kernel/head_fsl_booke.S)

      

#define SET_IVOR(vector_number, vector_label)              /

              li      r26,vector_label@l;              /

              mtspr      SPRN_IVOR##vector_number,r26;      /

              sync

 

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

       SET_IVOR(7,  FloatingPointUnavailable);

       SET_IVOR(8,  SystemCall);

       SET_IVOR(9,  AuxillaryProcessorUnavailable);

       SET_IVOR(10, Decrementer);

       SET_IVOR(11, FixedIntervalTimer);

       SET_IVOR(12, WatchdogTimer);

       SET_IVOR(13, DataTLBError);

       SET_IVOR(14, InstructionTLBError);

       SET_IVOR(15, DebugCrit);

以外部中断处理为例:SET_IVOR(4,  ExternalInput);

当外部中断发生时根据 IVOR4 IVPR中的地址会导致调用ExternalInput

arch/powerpc/kernel/head_fs_booke.S-à

/* External Input Interrupt */

       EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE)

 

#define EXCEPTION(n, label, hdlr, xfer)                          /

       START_EXCEPTION(label);                             /

       NORMAL_EXCEPTION_PROLOG;                         /

       addi r3,r1,STACK_FRAME_OVERHEAD;                 /

       xfer(n, hdlr)

 

#define EXC_XFER_LITE(n, hdlr)              /

       EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, /

                       ret_from_except)

 

#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret)    /

       li      r10,trap;                              /

       stw  r10,_TRAP(r11);                                /

       lis    r10,msr@h;                                /

       ori   r10,r10,msr@l;                                  /

       copyee(r10, r9);                                 /

       bl     tfer;                                  /

       .long       hdlr;                                    /

       .long       ret

 

 

首先,trap 加载到寄存器 r10 中。在接下来的一行中,那个值存储在由 TRAP(r11) 给出的地址中。TRAP(r11) 以及接下来两行去做一些硬件相关的位操作。然后,我们调用 tfer 函数(transfer_to_handler 函数),它会处理更多内部事务并将控制转交给 hdlrdo_IRQ)。注意, transfer_to_handler 通过链接寄存器加载处理程序的地址,因此您看到的是.long do_IRQ,而不是 bl do_IRQ

这个宏完成一些必要的设置后导致do_IRQ的调用!

 (transfer_to_handler 参见arch/powerpc/kernel/entry_32.S )

void do_IRQ(struct pt_regs *regs)

{

       struct pt_regs *old_regs = set_irq_regs(regs);

       unsigned int irq;

 

       irq_enter();

 

       check_stack_overflow();

 

       irq = ppc_md.get_irq();/*这个东西返回传说中的软件中断号,可见申请中断要用   软件中断号而你在寄存器EIPVRn里读出来的是硬件中断号,呵呵,终于给irq_create_mapping   找个说法了*/

 

       if (irq != NO_IRQ && irq != NO_IRQ_IGNORE)

              handle_one_irq(irq);

       else if (irq != NO_IRQ_IGNORE)

              /* That's not SMP safe ... but who cares ? */

              ppc_spurious_interrupts++;

 

       irq_exit();

       set_irq_regs(old_regs);

 

#ifdef CONFIG_PPC_ISERIES

       if (firmware_has_feature(FW_FEATURE_ISERIES) &&

                     get_lppaca()->int_dword.fields.decr_int) {

              get_lppaca()->int_dword.fields.decr_int = 0;

              /* Signal a fake decrementer interrupt */

              timer_interrupt(regs);

       }

#endif

}

暂时写这么多,有新发现在继续添加(呵呵, 有点晕!)

你可能感兴趣的:(exception,linux,struct,vector,alignment)