리눅스 인터럽트 관리 (A)

첫째, 인터럽트 동작

리눅스 커널은 컴퓨터에 연결된 모든 하드웨어 장치를 관리 할 필요가있다. 당신은 무엇보다도 이러한 장치를 관리 할, 그들은 작업에 서로 통신합니다.
일반적으로이 기능을 달성하기 위해 두 가지 옵션이 있습니다 :

  • 정기적으로 장치의 상태를 조회하고 적절한 치료를 만들기 위해 설문 조사 (폴링) 커널;
  • 인터럽트 커널 하드웨어 신호는 (커널은 하드웨어 활성 구상된다)이 필요하므로 (인터럽트).

더 많은 CPU 시간과 낮은 효율을 차지하게됩니다 폴링 방법을 사용합니다. 예를 들어 프로세스가 키를 누르면되지 않은 쿼리를 계속 할 필요가, 버튼을 누르지있을 때 읽을 수 있습니다. 이 작업은 CPU 시간을 많이했다 그래서, CPU 낭비 많은 노력을합니다. 을 사용하면 이런 메커니즘을 제공 중단. 버튼이 눌러지지 않은 경우, 현재의 프로세스는 다른 프로세스로 제어를 중단. 운영 체제가 프로세스를 계속 할 수 있도록, 현재의 프로세스 활동로 설정되어있을 때 버튼을 누르면됩니다.

두 인터럽트 관리를 리눅스

리눅스 커널의 인터럽트 번호 모두 균일하는 이용 irq_desc구조 배열 중단 설명. (인터럽트 번호를 공유하거나 인터럽트의 세트) 배열 엔트리는 인터럽트를 사용한다.
struct irq_desc레코드 구조, 인터럽트는 인터럽트 상태의 이름은, 하부 하드웨어 인터페이스 (인터럽트 삭제 가능 인터럽트 마스크 가능 인터럽트) 입구의 인터럽트 핸들러에 액세스하는
사용자는 인터럽트 핸들러의 등록을 호출 할 수있는이.

1 구조체 irq_desc

struct irq_desc에서 include\linux\irq.h정의 파일의 내부

struct irq_desc {
    irq_flow_handler_t  handle_irq;    /* 当前中断的处理函数入口 */
    struct irq_chip     *chip;         /* 底层硬件访问 */
        ...
    struct irqaction    *action;    /* 用户注册的中断处理函数链表 */
    unsigned int        status;     /* IRQ状态 */

    ...

    const char      *name;         /* 中断函数名 */
} ____cacheline_internodealigned_in_smp;

에이. handle_irq

handle_irq이 아니면 인터럽트 핸들러 입구의 그룹입니다. 인터럽트가 발생하면, 그것은 호출 asm_do_IRQ기능을. 인터럽트 번호 안쪽이 대응 함수 호출 irq_desc어레이 제품 handle_irq.
에서 handle_irq내부 사용 chip실드를 활성화하는 인터페이스 멤버, 인터럽트를 취소합니다. 일레븐에 등록 된 사용자 호출 action핸들러 내부의 목록을.

비. 구조체 irq_chip

에 irq_chip 구조체 include\linux\irq.h정의 파일의 내부

struct irq_chip {
    const char  *name;
    /* 启动中断,如果不设置则缺省为 "enable" */
    unsigned int    (*startup)(unsigned int irq);       
    /* 关闭中断,如果不设置则缺省为 "disable" */
    void        (*shutdown)(unsigned int irq);      
    /* 使能中断,如果不设置则缺省为"unmask" */  
    void        (*enable)(unsigned int irq);
    /* 禁止中断,如果不设置则缺省为"mask" */  
    void        (*disable)(unsigned int irq);
    /* 响应中断,一般是清除当前的中断,使得可以接收下一个中断 */
    void        (*ack)(unsigned int irq);
    /* 屏蔽中断源 */
    void        (*mask)(unsigned int irq);
    /* 屏蔽和响应中断 */
    void        (*mask_ack)(unsigned int irq);
    /* 开启中断 */
    void        (*unmask)(unsigned int irq);
  ....
};

씨. 구조체 irqaction

struct irqaction구조에서 include\linux\interrupt.h정의 파일의 내부.
사용자에게 등록 된 인터럽트 핸들러 각 irqaction인터럽트 (예를 들어 공유 인터럽트)를 설명하기위한 구조는 복수의 핸들러가있다.
그들의 irqaction구조 action체인 헤더의 연결리스트로

struct irqaction {
    /* 用户注册的中断处理函数 */
    irq_handler_t handler;
    /* 中断的标志,是否是共享中断,中断的触发方式是电平触发,还是边沿触发 */
    unsigned long flags;

    cpumask_t mask;
    /* 用户注册时,给的中断的名字 */
    const char *name;
    /* handler 中断函数的参数,也可以用来区分共享中断 */
    void *dev_id;
    /* 链表的指针 */
    struct irqaction *next;
    /* 中断号 */
    int irq;
    struct proc_dir_entry *dir;
};

2. 요약

struct irq_desc어레이 struct irq_chip구조와 struct irqaction다음과 같이 세 가지의 관계 :

셋째, 인터럽트 핸들러 초기화

1 인터럽트 핸들러 초기화

에서 init\Main.c문서 start_kernel하는 기능을 호출 init_IRQ()이 인터럽트 초기화 아키텍처입니다 기능

2 init_IRQ 함수

init_IRQ그것은 인터럽트 처리 아키텍처를 초기화하는 데 사용의 arch\arm\kernel\irq.c파일 내부

void __init init_IRQ(void)
{
    int irq;
        /* 初始化irq_desc[] 每一项的中断状态 */
    for (irq = 0; irq < NR_IRQS; irq++)
        irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;
    ...
        /* 架构相关的中断初始化函数 */
    init_arch_irq();
}

3 init_arch_irq

init_arch_irq함수 포인터이며, arch\arm\kernel\setup.c파일 setup_arch()기능이 초기화됩니다

void __init setup_arch(char **cmdline_p)
{
    ...
    init_arch_irq = mdesc->init_irq;
    ...
}

mdesc->init_irq받는 포인트 arch\arm\plat-s3c24xx\irq.c파일 s3c24xx_init_irq()기능을합니다.
MACHINE_START(S3C2440, "SMDK2440")매크로는 정의하는 데 사용되는 struct machine_desc구조
의 구조 arch\arm\mach-s3c2440\Mach-smdk2440.c정의 파일을 내부 초기화 init_irq가리키는 s3c24xx_init_irq()함수

MACHINE_START(S3C2440, "SMDK2440")
    /* Maintainer: Ben Dooks <[email protected]> */
    .phys_io    = S3C2410_PA_UART,
    .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
    .boot_params    = S3C2410_SDRAM_PA + 0x100,
         /* init_irq成员在这里初始化 */
    .init_irq   = s3c24xx_init_irq,
    .map_io     = smdk2440_map_io,
    .init_machine   = smdk2440_machine_init,
    .timer      = &s3c24xx_timer,
MACHINE_END

4 s3c24xx_init_irq 함수

s3c24xx_init_irq()기능 arch\arm\plat-s3c24xx\irq.c모든 관련 데이터 구조를 조작 그의 칩 (코드의 코드 블록의 일부로서) 정의 (irq_desc [IRQ] .chip) ,, 및 초기화 처리기 입력 (irq_desc [IRQ] .handle_irq).
에서 IRQ_EINT0그리고 IRQ_EINT3예를 들어, set_irq_chip것이다 함수 irq_desc[irqno].chip = &s3c_irq_eint0t4는 수 후 irq_desc[irqno].chip인터럽트를 가능 터치 방식 함수 포인터 구조를 제공 인터럽트 마스크
set_irq_handler기능이 인터럽트 핸들러의 엔트리에 제공된다 irq_desc[irqno].handle_irq = handle_edge_irq발생한 인터럽트 handle_edge_irq는 핸들러 등록 된 사용자 특정 호출
irq_desc[irqno].falgs설정 이다IRQF_VALID

void __init s3c24xx_init_irq(void)
{
    ...
    /* external interrupts */
    for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
        irqdbf("registering irq %d (ext int)\n", irqno);
        set_irq_chip(irqno, &s3c_irq_eint0t4);
        set_irq_handler(irqno, handle_edge_irq);
        set_irq_flags(irqno, IRQF_VALID);
    }
    for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
        irqdbf("registering irq %d (extended s3c irq)\n", irqno);
        set_irq_chip(irqno, &s3c_irqext_chip);
        set_irq_handler(irqno, handle_edge_irq);
        set_irq_flags(irqno, IRQF_VALID);
    }
    ...
}

5 set_irq_chip 함수

int set_irq_chip(unsigned int irq, struct irq_chip *chip)
{
    struct irq_desc *desc;
    unsigned long flags;
        /* 判断是否超过最大的中断号 */
    if (irq >= NR_IRQS) {
        printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq);
        WARN_ON(1);
        return -EINVAL;
    }
         
    if (!chip)
        chip = &no_irq_chip;
        /* 通过中断号找到irq_desc数组对应的数组项 */
    desc = irq_desc + irq;
    spin_lock_irqsave(&desc->lock, flags);
        /* 判断 chip 的成员即&s3c_irq_eint0t4的成员是否为空,如果为空就设置为默认的操作函数 */
    irq_chip_set_defaults(chip);
        /* 设置irq_desc[].chip成员 */
    desc->chip = chip;
    spin_unlock_irqrestore(&desc->lock, flags);
    return 0;

5 set_irq_handler 함수

set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
{
    __set_irq_handler(irq, handle, 0, NULL);
}


/***************************************************************************************/


__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
          const char *name)
{
    struct irq_desc *desc;
    unsigned long flags;
    /* 通过中断号找到irq_desc数组对应的数组项 */
    desc = irq_desc + irq;
   
   ...
    /*  中间还会做一些判断 */
   ...
    /* 设置中断处理函数,名字*/
    desc->handle_irq = handle;
    desc->name = name;
    /* 设置中断的状态,开启中断 */
    if (handle != handle_bad_irq && is_chained) {
    desc->status &= ~IRQ_DISABLED;
    desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
    desc->depth = 0;
    desc->chip->unmask(irq);
    }

}

도 6은 작동 set_irq_flags

void set_irq_flags(unsigned int irq, unsigned int iflags)
{
    struct irq_desc *desc;
    unsigned long flags;

    if (irq >= NR_IRQS) {
        printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
        return;
    }
        /* 找到数组项 */
    desc = irq_desc + irq;
    spin_lock_irqsave(&desc->lock, flags);

       /* 设置中断状态 */
    desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
    if (iflags & IRQF_VALID)
        desc->status &= ~IRQ_NOREQUEST;
    if (iflags & IRQF_PROBE)
        desc->status &= ~IRQ_NOPROBE;
    if (!(iflags & IRQF_NOAUTOEN))
        desc->status &= ~IRQ_NOAUTOEN;
    spin_unlock_irqrestore(&desc->lock, flags);
}

IV 요약

대해 사실 아키텍처 인터럽트 처리 초기화 처리 irq_desc[]어레이의 초기화 각각 초기화된다.
브레이크 인터럽트에 의해 또는 일련의 irq_desc[]항목 배열하여 관리한다.
내부 항목 배열 handle_irq chip action세 가지 중요한 구조 부재.

  • handle_irq 현재 인터럽트 핸들러
  • 칩 연관된 기본 하드웨어 처리기 (트리거 인터럽트 모드, 마스크 가능한 인터럽트의 인터럽트 활성화)
  • 액션리스트 헤드리스트에 연결된 사용자 등록 처리 기능은, 인터럽트가 발생하면, 등록 된 사용자는 인터럽트 서비스 함수 내부에서 오는 호출

추천

출처www.cnblogs.com/gulan-zmc/p/11823660.html