Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2112779
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2013-09-24 16:36:34

有一个问题:
在datasheet中清楚的说明s3c6410一共有64个中断,
但是dm9000的驱动中request_irq()的中断号却是108.
如下图所示: cat   /proc/interrupts

为什么申请出来的中断号是108呢? ?
从中断引脚的定义可以看出:
  1. #define IRQ_EINT(x) S3C_EINT(x)
  2. #define S3C_EINT(x) ((x) + S3C_IRQ_EINT_BASE)
  3. #define S3C_IRQ_EINT_BASE S3C_IRQ(64+5)
  4. #define S3C_IRQ(x) ((x) + S3C_IRQ_OFFSET)
  5. #define S3C_IRQ_OFFSET (32)
EINT(7) = 7+EINT_BASE
EINT_BASE=64+5+32=101
7+64+5+32=108,里面各个数值都是什么意思呢?
要弄明白这个需要详细的了解一下arm中断的各个流程.
1. 系统中断的初始化.       
2. 中断产生并进入中断处理函数
一. 中断初始化
从start_kernel开始看起,下面有四个函数跟中断初始化有关系
  1. asmlinkage void __init start_kernel(void)
  2. {
  3.     setup_arch(); --> early_trap_init();  //1.中断向量表与中断函数的copy
  4.     trap_init();        //空函数,不管它
  5.     early_irq_init();   //2.初始化irq_desc数组
  6.     init_IRQ();         //3.s3c6410内部64个中断的初始化
  7.     rest_init();        //4. do_initcalls() --> s3c64xx_init_irq_eint();外部中断的初始化
  8. }

1. 中断向量与中断函数的拷贝
在arch/arm/kernel/traps.c中
  1. void __init early_trap_init(void)
  2. {
  3.     //这儿定义了CONFIG_CPU_USE_DOMAINS
  4.     unsigned long vectors = CONFIG_VECTORS_BASE;      //BASE=0xffff0000
  5.     extern char __stubs_start[], __stubs_end[];
  6.     extern char __vectors_start[], __vectors_end[];
  7.     extern char __kuser_helper_start[], __kuser_helper_end[];
  8.     int kuser_sz = __kuser_helper_end - __kuser_helper_start;
  9.     //copy中断向量表到0xffff000
  10.     memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
  11.     //copy中量函数到0xffff000+0x200
  12.     memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
  13.     //copy中断向量表到0xffff000
  14.     memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);

  15.     kuser_get_tls_init(vectors);

  16.     memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
  17.      sigreturn_codes, sizeof(sigreturn_codes));
  18.     memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE),
  19.      syscall_restart_code, sizeof(syscall_restart_code));

  20.     flush_icache_range(vectors, vectors + PAGE_SIZE);
  21.     modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
  22. }

2.初始化irq_desc结构体数组
在kernel/irq/irqdesc.c中,其中NR_IRQS=246
start_kernel
    --> early_irq_init
  1. struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
  2.     [0 ... NR_IRQS-1] = {
  3.         .handle_irq    = handle_bad_irq,
  4.         .depth        = 1,
  5.         .lock        = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
  6.     }
  7. };
  8. int __init early_irq_init(void)
  9. {
  10.     int count, i, node = first_online_node;
  11.     struct irq_desc *desc;
  12.     init_irq_default_affinity();
  13.     desc = irq_desc;
  14.     count = ARRAY_SIZE(irq_desc);
  15.     for (i = 0; i < count; i++) {
  16.         desc[i].kstat_irqs = alloc_percpu(unsigned int);
  17.         alloc_masks(&desc[i], GFP_KERNEL, node);
  18.         raw_spin_lock_init(&desc[i].lock);
  19.         lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
  20.         desc_set_defaults(i, &desc[i], node);
  21.     }
  22.     return arch_early_irq_init();
  23. }
#define ARCH_IRQ_INIT_FLAGS    (IRQ_NOREQUEST | IRQ_NOPROBE)

start_kernel
    --> early_irq_init
        --> desc_set_defaults
  1. static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node)
  2. {
  3.     int cpu;
  4.     desc->irq_data.irq = irq;
  5.     desc->irq_data.chip = &no_irq_chip;
  6.     desc->irq_data.chip_data = NULL;
  7.     desc->irq_data.handler_data = NULL;
  8.     desc->irq_data.msi_desc = NULL;
  9.     irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS); //初始化为IRQ_NOREQUEST | IRQ_NOPROBE
  10.     irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED);
  11.     desc->handle_irq = handle_bad_irq;
  12.     desc->depth = 1;
  13.     desc->irq_count = 0;
  14.     desc->irqs_unhandled = 0;
  15.     desc->name = NULL;
  16.     for_each_possible_cpu(cpu)
  17.         *per_cpu_ptr(desc->kstat_irqs, cpu) = 0;
  18.     desc_smp_init(desc, node);
  19. }

3. s3c6410内部64 个中断初始化
  1. 在arch/arm/kernel/iqr.c中
  2. void __init init_IRQ(void)
  3. {
  4.     machine_desc->init_irq();
  5. }

  6. 在arch/arm/mach-s3c64xx/mach-smdk6410.c中
  7. MACHINE_START(SMDK6410, "SMDK6410")
  8.     .boot_params    = S3C64XX_PA_SDRAM + 0x100,
  9.     .init_irq    = s3c6410_init_irq,
  10.     .map_io        = smdk6410_map_io,
  11.     .init_machine    = smdk6410_machine_init,
  12.     .timer        = &s3c24xx_timer,
  13. MACHINE_END

  14. 在arch/arm/mach-s3c64xx/s3c6410.c中
  15. void __init s3c6410_init_irq(void)
  16. {
  17.     /* VIC0 is missing IRQ7, VIC1 is fully populated. */
  18.     s3c64xx_init_irq(~0 & ~(1 << 7), ~0);
  19. }
  20. //VIC0中的第7号中断是保留的,

  21. 在arch/arm/mach-s3c64xx/iqr.c中
  22. void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
  23. {
  24.     /* initialise the pair of VICs */
  25.     vic_init(VA_VIC0, IRQ_VIC0_BASE, vic0_valid, 0);
  26.     vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, 0);

  27.     /* add the timer sub-irqs */
  28.     s3c_init_vic_timer_irq(5, IRQ_TIMER0);

  29.     s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));
  30. }
arch/arm/mach-s3c64xx/irq.c:s3c64xx_init_irq[55]: vic0_valid=0xffffff7f, vic1_valid=0xffffffff
arch/arm/mach-s3c64xx/irq.c:s3c64xx_init_irq[56]: VA_VIC0=0xf6000000, IRQ_VIC0_BASE=0x20
arch/arm/mach-s3c64xx/irq.c:s3c64xx_init_irq[57]: VA_VIC1=0xf6010000, IRQ_VIC1_BASE=0x40

#define VA_VIC0            (S3C_VA_IRQ + 0x00)
#define S3C_VA_IRQ    S3C_ADDR(0x00000000)    /* irq controller(s) */
#define S3C_ADDR(x)    (S3C_ADDR_BASE + (x))
#define S3C_ADDR_BASE    0xF6000000

  1. void __init vic_init(void __iomem *base, unsigned int irq_start,
  2.          u32 vic_sources, u32 resume_sources)
  3. {
  4.     //读取vid,没有找到0xfe0这个是代表什么,不知道也没有多大影响 
  5.     for (i = 0; i < 4; i++) {
  6.         u32 addr = ((u32)base & PAGE_MASK) + 0xfe0 + (i * 4);
  7.         cellid |= (readl(addr) & 0xff) << (8 * i);
  8.     }
  9.     //VIC @f6000000: id 0x00041192, vendor 0x41
  10.     vendor = (cellid >> 12) & 0xff;
  11.     switch(vendor) {
  12.     case AMBA_VENDOR_ST:
  13.         vic_init_st(base, irq_start, vic_sources);
  14.         return;
  15.     default:
  16.         printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");      
  17.     case AMBA_VENDOR_ARM:
  18.         break;
  19.     }
  20.     vic_disable(base);               //3.1 禁止所有的中断
  21.    
  22.     vic_clear_interrupts(base);      //PL190???这TMD是什么玩意?

  23.     vic_init2(base);                 //又有PL190?我准备放弃搞懂这个函数

  24.     vic_set_irq_sources(base, irq_start, vic_sources);  //3.2 设置irq_desc中标志为可用

  25.     vic_pm_register(base, irq_start, resume_sources);   //3.3
  26. }

3.1 禁止所有的中断
  1. static void __init vic_disable(void __iomem *base)
  2. {
  3.     //32位的寄存器,每一位代表一个中断
  4.     writel(0, base + VIC_INT_SELECT);         //将所有的中断都设为IRQ,不是FIQ
  5.     writel(0, base + VIC_INT_ENABLE);         //所有的中断都为disable状态
  6.     writel(~0, base + VIC_INT_ENABLE_CLEAR);  //写1是要清除VIC_INT_ENABLE的中断使能
  7.     writel(0, base + VIC_IRQ_STATUS);         //清除状态寄存器
  8.     writel(0, base + VIC_ITCR);               //TMD,VIC test control reg??
  9.     writel(~0, base + VIC_INT_SOFT_CLEAR);    //写1是要清除VICSOFTINT寄存器
  10. }
3.2 对64个内部中断的irq_desc重新设置其标志位
  1. static void __init vic_set_irq_sources(void __iomem *base, unsigned int irq_start, u32 vic_sources)
  2. {
  3.     //vic_source是32bit,其中每1位置1的代表启用一个中断源
  4.     //调用时vic0=~0 & ~(1 << 7),即不添加中断源7
  5.     for (i = 0; i < 32; i++) {
  6.         if (vic_sources & (1 << i)) {                 //只对置1的中断源进行处理
  7.             unsigned int irq = irq_start + i;         //vic的中断号是从iqr_start=32或64开始
  8.             //通过中断号找到irq_desc结构体,并设置irq_descirq_data.chip与handle_irq
  9.             irq_set_chip_and_handler(irq, &vic_chip, handle_level_irq);
  10.             irq_set_chip_data(irq, base);
  11.             set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); //1.2.1重新设置irq_desc中的标志位为IRQF_VALID
  12.         }
  13.     }
  14. }
vic0的中断号是32-64;
vic1的中断号是65-96;

3.2.1初始化irq_desc中的标志位state_use_accessors为IRQF_VALID|IRQF_PROBE
  1. void set_irq_flags(unsigned int irq, unsigned int iflags)
  2. {
  3.     unsigned long clr = 0, set = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;

  4.     if (irq >= nr_irqs) {
  5.         printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
  6.         return;
  7.     }
  8.     //清除在early_irq_init中设置的IRQ_NOREQUEST|IRQ_NOPROBE标志,重新设为
  9.     //IRQ_VALID|IRQ_PROBE
  10.     if (iflags & IRQF_VALID)
  11.         clr |= IRQ_NOREQUEST;
  12.     if (iflags & IRQF_PROBE)
  13.         clr |= IRQ_NOPROBE;
  14.     if (!(iflags & IRQF_NOAUTOEN))
  15.         clr |= IRQ_NOAUTOEN;
  16.     
  17.     irq_modify_status(irq, clr, set & ~clr);
  18. }
4. 外部中断的初始化
start_kernel
    --> do_initcalls()
        --> 
s3c64xx_init_irq_eint()
  1. static int __init s3c64xx_init_irq_eint(void)
  2. {
  3.     int irq;
  4.     //6410的外部中断号是从IRQ_EINT(0)=101 到 IRQ_EINT(27)=128
  5.     //对101-128的外部中断,初始化其irq_desc结构体,
  6.     //其中断处理函数是handle_level_irq
  7.     for (irq = IRQ_EINT(0); irq <= IRQ_EINT(27); irq++) {
  8.         irq_set_chip_and_handler(irq, &s3c_irq_eint, handle_level_irq);
  9.         irq_set_chip_data(irq, (void *)eint_irq_to_bit(irq));
  10.         set_irq_flags(irq, IRQF_VALID);
  11.     }
  12.     //对未映射之前的中断号为(0,1,32,33)-->现在的(32,33,64,65)
  13.    //对这四个中断注册其中断处理函数
  14.     irq_set_chained_handler(IRQ_EINT0_3, s3c_irq_demux_eint0_3);
  15.     irq_set_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11);
  16.     irq_set_chained_handler(IRQ_EINT12_19, s3c_irq_demux_eint12_19);
  17.     irq_set_chained_handler(IRQ_EINT20_27, s3c_irq_demux_eint20_27);

  18.     return 0;
  19. }
在include/linux/irq.h中
start_kernel
    --> do_initcalls()
        --> 
s3c64xx_init_irq_eint()
            --> irq_set_chained_handler
irq_set_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11);
  1. static inline void
  2. irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle)
  3. {
  4.     __irq_set_handler(irq, handle, 1, NULL);   //irq=33(33-32=1即INT_EINT1)
  5. }
start_kernel
    --> do_initcalls()
        --> 
s3c64xx_init_irq_eint()
            --> irq_set_handler
在kernel/irq/chip.c中
  1. void __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, const char *name)
  2. { 
  3.     //其它的省略只看办正事的地方
  4.     desc->handle_irq = handle;   //注册中断处理函数
  5.     desc->name = name;           //name=NULL
  6. }

二.以usr_irq为例分析中断调用过程
1. 中断向量表
中断向量表在arch/arm/kernel/entry-armv.S中
  1. .globl    __vectors_start
  2. __vectors_start:
  3.  ARM(    swi    SYS_ERROR0    )
  4.  THUMB(    svc    #0        )
  5.  THUMB(    nop            )
  6.     W(b)    vector_und + stubs_offset
  7.     W(ldr)    pc, .LCvswi + stubs_offset
  8.     W(b)    vector_pabt + stubs_offset
  9.     W(b)    vector_dabt + stubs_offset
  10.     W(b)    vector_addrexcptn + stubs_offset
  11.     W(b)    vector_irq + stubs_offset
  12.     W(b)    vector_fiq + stubs_offset

  13.     .globl    __vectors_end
  14. __vectors_end:
a. 当有irq中断发生时,就会调用vector_irq.但是vector_irq?
一下linux源代码也没有找到一个vector_irq,难道是弄错了?
际上vector_irq是通过vector_stub这个宏来定义的.
b. 跳转的地址是怎么确定的呢?
    以 b  vector_irq + stubs_offset 为例
    在entry-armv.S中有:
            .equ    stubs_offset, __vectors_start + 0x200 - __stubs_start
    所以 vector_irq + stubs_offset =
            vector_irq + __vectors_start + 0x200 - __stubs_start =
            (vecor_irq - __stubs_start) + (__vectors_start + 0x200)
          即:  相对于中断函数首地址的偏移  +  中断函数首地址
在arch/arm/kernel/entry-armv.S中有
  1. __stubs_start:
  2.     vector_stub    irq, IRQ_MODE, 4     ;马上分析这个宏的作用
  3.     .long    __irq_usr            @ 0 (USR_26 / USR_32)
  4.     .long    __irq_invalid        @ 1 (FIQ_26 / FIQ_32)
  5.     .long    __irq_invalid        @ 2 (IRQ_26 / IRQ_32)
  6.     .long    __irq_svc            @ 3 (SVC_26 / SVC_32)
  7.     .long    __irq_invalid        @ 4
  8.     .long    __irq_invalid        @ 5
2. 用vector_stub 产生中断函数
把vector_stub    irq, IRQ_MODE, 4展开后是:
在arch/arm/kernel/entry-armv.S中
  1. vector_stub    irq, IRQ_MODE, 4
  2. .macro    vector_stub, name, mode, correction=0    
  3. vector_irq:                  ;看到没有vector_irq,它老人家终于出来了
  4.     .if 4
  5.     sub    lr, lr, #4
  6.     .endif
  7.     
  8.     ;将r0,lr,spsr压栈
  9.     stmia    sp, {r0, lr}    ;将r0,lr寄存器压栈
  10.     mrs    lr, spsr          ;将spsr保存在lr中
  11.     str    lr, [sp, #8]      ;将lr压栈,即保存spsr
  12.    
  13.    ;将SVC_MODE保存到spsr中,准备切换到svc
  14.     mrs    r0, cpsr          ;读取cpsr到r0
  15.     eor    r0, r0, #(IRQ_MODE ^ SVC_MODE | PSR_ISETSTATE)   ;将r0设为SVC_MODE
  16.     msr    spsr_cxsf, r0     ;将r0中的SVC_MODE写到spsr中,通过movs就可以切换到SVC模式了

  17.     and    lr, lr, #0x0f                       ;usr模式(10000)的低4位==0,SVC模式(10011)的低4位==3,
  18.  THUMB(    adr    r0, 1f            )          ;这几句没有完全弄明白
  19.  THUMB(    ldr    lr, [r0, lr, lsl #2]    )    ;
  20.     mov    r0, sp                              ;
  21.  ARM(    ldr    lr, [pc, lr, lsl #2]    )      ;感觉是要跳到这个宏的下几句进行
  22.     movs    pc, lr            ;跳转到下一条指令,并cpsr会被spsr覆盖即切换到SVC模式
  23. ENDPROC(vector_irq)

  24.     .align    2    
  25. 1:
  26.     .endm
以spsr中的低四位为索引,对pc值进行调整:
如果上述是从user模式进入,则会跳到__irq_users处执行
如果上述是从svc模式进入,则会跳到 __irq_svc处执行

3. 进入irq_usr
从中断向量表中查找到中断函数,然后进入中断函数的处理过程__irq_usr
在arhc/arm/kernel/entry-armv.S中
  1. .align    5
  2. __irq_usr:
  3.     usr_entry
  4.     kuser_cmpxchg_check
  5.     get_thread_info tsk
  6.     irq_handler                 ;irq_handler继续调用
  7.     mov    why, #0
  8.     b    ret_to_user_from_irq
  9.  UNWIND(.fnend        )
  10. ENDPROC(__irq_usr)
__irq_usr
--> irq_handler
  1. 在arch/arm/kernel/entry-armv.S中
  2.     .macro    irq_handler
  3.     arch_irq_handler_default
  4. 9997:
  5.     .endm
__irq_usr
--> irq_handler
--> arch_irq_handler_default
  1. 在arm/include/asm/entry-macro-multi.S中
  2.     .macro    arch_irq_handler_default
  3.     get_irqnr_preamble r5, lr
  4. 1:    get_irqnr_and_base r0, r6, r5, lr     ;3.1获取中断号
  5.     movne    r1, sp    
  6.     adrne    lr, BSYM(1b)
  7.     bne    asm_do_IRQ                      ;3.2进入中断处理函数
  8. 9997:
  9.     .endm

3.1 获取中断号
从寄存器中读取的中断号的范围是(0-64),但是实际上这儿把中断号读取出来之后,都加了一个固定值32
所以真正的中断号的取值范围是(0-64)+32.
在arch/arm/include/asm/entry-macro-vic2.S中

 .macro    get_irqnr_preamble, base, tmp
  1.     ldr    \base, =VA_VIC0
  2.     .endm

  3. @base是VA_VIC0    
  4. .macro    get_irqnr_and_base, irqnr, irqstat, base, tmp
  5.     mov    \irqnr, #IRQ_VIC0_BASE + 31                  //为什么这儿要加上31呢?是因为clz这个指令
  6.     ldr    \irqstat, [ \base, # VIC_IRQ_STATUS ]        //读取VIC_IRQ_STATUS的值,也就是中断号的值(加上"的值"比较确切)
  7.     teq    \irqstat, #0                                  //看irqstat是不是0,如果是0,标志位Z=1

  8.     @ otherwise try vic1                                 //下面的一串eq执行说明vic0没有产生中断irqstat==0       
  9.     addeq    \tmp, \base, #(VA_VIC1 - VA_VIC0)           //              
  10.     addeq    \irqnr, \irqnr, #(IRQ_VIC1_BASE - IRQ_VIC0_BASE)
  11.     ldreq    \irqstat, [ \tmp, # VIC_IRQ_STATUS ]
  12.     teqeq    \irqstat, #0                               //看irqstat是不是0,如果是0,标志位Z=1
  13.                                          //下面两句ne执行说明Z=0, 即irqstat不为0,再即有中断产生      
  14.     clzne    \irqstat, \irqstat          //判断是哪一位产生了中断,但是clz是从高向低计数的,实际的中断号是(32-highnr)          
  15.     subne    \irqnr, \irqnr, \irqstat    //irqnr = (IRQ_BASE+31)-highnr = IRQ_BASE+(31-high_nr)也就是加上实际的中断号
  16.     .endm
注意:
   a.   teq   \irqstat, #0    判断irqstat是不是等于0,如果等于0,则cpsr中Z置位.
   后面的指令都代着eq,如果Z=1则执行,反之则不执行
   b.   clz {cond} Rd, Rm
         对Rm中leading zeros的个数进行计数,将结果存在Rd中 P { margin-bottom: 0.08in; direction: ltr; color: rgb(0, 0, 0); text-align: justify; }P.western { font-family: "細明體","MingLiU",monospace; font-size: 12pt; }P.cjk { font-family: "細明體","MingLiU",monospace; font-size: 12pt; }P.ctl { font-family: "細明體","MingLiU",monospace; font-size: 12pt; }
         (leading zeros: Rm中从高位向低位进行查找,直至遇到1为止,将0的个数统计出来)
        例: 0x0000 0000  --> 32;
             0x0000 000F --> 24; 
             0x0F00 0000 --> 4 ;
             0x8000 0000 -->  0;
   c. 总结一下上面的代码: 
       如果vic0产生了中断,  读取中断号的值,判断中断号是不是0,不是0,则跳到clz句判断中断号;

3.2 进入c语言的中断处理函数asm_do_IRQ
在arch/arm/kernel/irq.c中
__irq_usr
--> irq_handler
--> arch_irq_handler_default
    --> asm_do_IRQ
  1. asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
  2. {
  3.     struct pt_regs *old_regs = set_irq_regs(regs);
  4.     irq_enter();

  5.     if (unlikely(irq >= nr_irqs)) {    //判断中断号是否超出范围
  6.         if (printk_ratelimit())
  7.             printk(KERN_WARNING "Bad IRQ%u\n", irq);
  8.         ack_bad_irq(irq);
  9.     } else {
  10.         generic_handle_irq(irq);     //封装,继续调用
  11.     }

  12.     /* AT91 specific workaround */
  13.     irq_finish(irq);

  14.     irq_exit();
  15.     set_irq_regs(old_regs);
  16. }

__irq_usr
--> irq_handler
--> arch_irq_handler_default
    --> asm_do_IRQ
        --> generic_handler_irq
  1. int generic_handle_irq(unsigned int irq)
  2. {
  3.     struct irq_desc *desc = irq_to_desc(irq);

  4.     if (!desc)
  5.         return -EINVAL;
  6.     generic_handle_irq_desc(irq, desc);   //封装,继续调用
  7.     return 0;
  8. }
  9. EXPORT_SYMBOL_GPL(generic_handle_irq);
--> asm_do_IRQ
  --> generic_handler_irq
   -->  generic_handler_irq_desc
  1. static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
  2. {
  3.     desc->handle_irq(irq, desc);       //调用每个中断的中断处理函数
  4. }
注意,上面的desc->handle_irq是在 s3c64xx_init_irq_eint() 中注册的,
以dm9000的eint(7)为例说明一下:
irq_set_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11);
注册 desc->handle_irq= s3c_irq_demux_eint4_11
3.3 分发外部中断
--> asm_do_IRQ
  --> generic_handler_irq
   -->  generic_handler_irq_desc
    --> s3c_irq_demux_eint4_11
在arch/arm/mach-s3c64xx/irq-eint.c中
  1. static void s3c_irq_demux_eint4_11(unsigned int irq, struct irq_desc *desc)
  2. {
  3.     s3c_irq_demux_eint(4, 11);
  4. }
--> asm_do_IRQ
  --> generic_handler_irq
   -->  generic_handler_irq_desc
    --> s3c_irq_demux_eint4_11
            --> s3c_irq_demux_eint
在arch/arm/mach-s3c64xx/irq-eint.c中
  1. static inline void s3c_irq_demux_eint(unsigned int start, unsigned int end)
  2. {
  3.     u32 status = __raw_readl(S3C64XX_EINT0PEND);
  4.     u32 mask = __raw_readl(S3C64XX_EINT0MASK);
  5.     unsigned int irq;
  6.     status &= ~mask;
  7.     status >>= start;
  8.     status &= (1 << (end - start + 1)) - 1;       
  9.     //当dm9000发生中断时,这儿的status=8=1000b,start=4,end=11
  10.     for (irq = IRQ_EINT(start); irq <= IRQ_EINT(end); irq++) {
  11.         if (status & 1)
  12.             generic_handle_irq(irq)//irq=IRQ_EINT(7)
  13.         status >>= 1;
  14.     }
  15. }
从IRQ_EINT(4)开始stauts向右移1位,当status==1时,正好是IRQ_EINT(7)
IRQ_EINT(7)正好是在dm9000注册的中断号

3.4 第二次调用generic_handle_irq
  1. int generic_handle_irq(unsigned int irq)
  2. {
  3.     struct irq_desc *desc = irq_to_desc(irq);

  4.     if (!desc)
  5.         return -EINVAL;
  6.     generic_handle_irq_desc(irq, desc);
  7.     return 0;
  8. }

  1. static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
  2. {
  3.     desc->handle_irq(irq, desc);
  4. }
这次的desc->handle_irq是谁呢?
注意,上面的desc->handle_irq也是在 s3c64xx_init_irq_eint() 中注册的,
但这次不一样的,要不成死循环了,这次是 desc->handle_irq= handle_level_irq


三.驱动调用request_irq申请中断
dm9000申请中断:
    request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev);
    其中: dev->irq=EINT(7)=108,   irqflags=0x84=IRQF_SAMPLE_RANDOM|IRQF_SHARED

在include/linux/interrupt.h中
  1. static inline int __must_check
  2. request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
  3.      const char *name, void *dev)
  4. {
  5.     return request_threaded_irq(irq, handler, NULL, flags, name, dev);
  6. }


在kernel/irq/maage.c中
  1. int request_threaded_irq(unsigned int irq, irq_handler_t handler,
  2.              irq_handler_t thread_fn, unsigned long irqflags,
  3.              const char *devname, void *dev_id)
  4. {
  5.     struct irqaction *action;
  6.     struct irq_desc *desc;
  7.     int retval;

  8.     if ((irqflags & IRQF_SHARED) && !dev_id)   //如果是共享中断,缺没有定义dev_id返回错误
  9.         return -EINVAL;

  10.     desc = irq_to_desc(irq);                  //根据中断号在irq_desc数组中找到对应的irq_desc结构体
  11.    
  12.     //这个东东在哪初始化的呢?
  13.     if (!irq_settings_can_request(desc))      //!(status_use_accessors & _IRQ_NOREQUEST)
  14.         return -EINVAL;

  15.     if (!handler) {                           //检查有没有指定中断处理函数
  16.         if (!thread_fn)
  17.             return -EINVAL;
  18.         handler = irq_default_primary_handler;
  19.     }

  20.     action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);

  21.     action->handler = handler;
  22.     action->thread_fn = thread_fn;
  23.     action->flags = irqflags;
  24.     action->name = devname;
  25.     action->dev_id = dev_id;

  26.     chip_bus_lock(desc);
  27.     retval = __setup_irq(irq, desc, action);
  28.     chip_bus_sync_unlock(desc);

  29.     if (retval)
  30.         kfree(action);
  31.     return retval;
  32. }


附录:
1. s3c6410的外部中断
section 12.3
s3c6410的外部中断eint0-4,共5个
  1. NO  SOURCES     Description                   Group
  2. 0   INT_EINT0   External interrupt 0-3         VIC0
  3. 1   INT_EINT1   External interrupt 4-11        VIC0
  4. 32  INT_EINT2   External interrupt 12-19       VIC1
  5. 33  INT_EINT3   External interrupt 20-27       VIC1
  6. 53  INT_EINT4   External interrupt Group 1-9   VIC1
外部中断0-3会触发0号中断
外部中断4-11会触发1号中断
外部中断12-19会触发32号中断
外部中断20-27会触发33号中断

  1. XEINT0/GPN0    XEINT1/GPN1    XEINT2/GPN2    XEINT3/GPN3
  2. XEINT4/GPN4    XEINT5/GPN5    XEINT6/GPN6    XEINT7/GPN7
  3. XINT8/GPN8     XINT9/GPN9     XEINT10/GPN10  XINT11/GPN11
  4. XEINT12/GPN12  XEINT13/GPN13  XEINT14/GPN14  XEINT15/GPN15
  5. EINT16/GPL8    EINT17/GPL9    EINT18/GPL10   EINT19/GPL11
  6. EINT20/GPL12   EINT21/GPL13   EINT22/GPL14   EINT23/GPM0
  7. EINT24/GPM1    EINT25/GPM2    EINT26/GPM3    EINT27/GPM4

2. 总结一下s3c6410的中断
  1. 以IRQ_EINT(7)为例:
  2.     7+64+5+32 = 108
  3. 32: 起始偏移
  4. 64: s3c6410的中断号顺次排列
  5. 5: 时钟中断
  6. 7: 外部中断





阅读(5691) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~