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

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
    0---------------------------------------------------------------------------------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函数),它会处理更多内部事务并将控制转交给hdlr(do_IRQ)。
注意,transfer_to_handler通 过链接寄存器加载处理程序的地址,因此您看到的是.long do_IRQ,而不是bldo_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
}
 
暂时写这么多,有新发现在继续添加(呵呵, 有点晕!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值