Chapter 7 - Interrupts and Interrupt Handlers

Hardware와 통신 → polling, Interrupt의 두 가지 방법

polling은 비효율적, Interrupt를 이용해 Hardware가 일하는 동안 cpu는 다른 일 가능

Interrupt는 Interrupt Handler에 담겨있는 동작을 하게 됨

Interrupts

  • Hardware가 processor에 물리적 전기 신호를 보내는 것을 허용
  • Clock과는 무관하게 보내짐 (비동기적 신호)
  • 각각의 Device들 마다 고유의 interrupt value를 가지고 있어서 processor가 interrupt 발생 시 해당 value를 확인하는 것으로 어떤 Device에서 interrupt가 발생했는지를 파악할 수 있음
    • IRQ(Interrupt request) line
  • 기본적으로 IRQ line은 정적으로 배정되어있지만, 동적으로 배정되는 경우도 있음
    • PCI bus
  • Exception은 clock에 맞춰서 발생하는 동기적 신호
    • software interrupt

Interrupt Handlers

  • Interrupt Service Routine이라고도 함
  • Interrupt가 발생했을 때 해당 Interrupt를 어떻게 처리할 것인지에 대한 코드
  • Interrupt context를 수행하며 이는 atomic하게 이루어진다
  • Performance를 위해 Interrupt발생 시 최대한 빨리, 짧게 수행되어야 함

Top Halves VS Bottom Halves

  • Top half에서는 Interrupt의 발생을 확인하고 Interrupt context를 포함한 Interrupt발생 후 즉각적으로 cpu가 처리해주어야 할 일들을 처리한다
  • Bottom Half에서는 Device가 실제적으로 하는 일들을 한다

Registering an Interrupt Handler

  • Device driver가 Interrupt handler와 IRQ line을 등록한다

    /include/linux/interrupt.h
    request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
                    const char *name, void *dev)
    
    • irq - Interrupt number

    • handler - 실제로 동작할 Interrupt handler (함수포인터)

    • flags - handler의 특성을 나타내주는 flag들

      /include/linux/interrupt.h
      #define IRQF_SHARED        0x00000080
      #define IRQF_PROBE_SHARED    0x00000100
      #define __IRQF_TIMER        0x00000200
      #define IRQF_PERCPU        0x00000400
      #define IRQF_NOBALANCING    0x00000800
      #define IRQF_IRQPOLL        0x00001000
      #define IRQF_ONESHOT        0x00002000
      #define IRQF_NO_SUSPEND        0x00004000
      #define IRQF_FORCE_RESUME    0x00008000
      #define IRQF_NO_THREAD        0x00010000
      #define IRQF_EARLY_RESUME    0x00020000
      #define IRQF_COND_SUSPEND    0x00040000
      
      • IRQF_DISABLED - 해당 irq가 동작할때 다른 interrupt들을 disable한다
      • IRQF_SAMPLE_RANDOM - 해당 irq를 커널 엔트로피 풀의 일부로 참여시킨다. 주기적 동작을 막는다.(실행주기를 예측할 수 없게 만든다 -- 4.11에서 사라짐)
      • IRQF_TIMER - 타이머 인터럽트용 플래그
      • IRQF_SHARED - 하나의 interrupt line을 공유할 수 있게 한다 (Shared handler)
    • name - 해당 irq를 사용하는 device의 이름

    • dev - Shared handler에서 식별자로 쓰이는 기기 고유값 (주로 기기의 generic pointer 사용)

  • sleep하지 않는다는게 보장될 때 call해야한다

  • 해당 irq를 더이상 사용하지 않을 때 free할 수 있다.

    /kernel/irq/manage.c
    free_irq(unsigned int irq, void *dev)
    
    • 해당 interrupt line이 공유되고 있지 않다면 handler를 지우고 interrupt line도 disable시킨다.
    • 해당 interrupt line이 공유되고 있다면 handler만 지우고, 해당 line을 공유하는 handler들이 모두 삭제되었을 때 interrupt line을 disable시킨다.

Writing an Interrupt Handler

/drivers/net/ethernet/adaptec/starfire.c
static irqreturn_t intr_handler(int irq, void *dev_instance)
  • return type이 irqreturn_t
  • 만약 불려온 interrupt handler가 해당 device가 등록한 handler가 아니라면 IRQ_NONE을 반환, 맞다면 IRQ_HANDLED 반환

Shared Handler

  • 하나의 Interrupt line을 여러 개의 Interrupt handler들이 사용하고 있는 경우를 말함
  • Shared handler가 되려고 하는 handler들이 모두 등록 시 IRQF_SHARED flag가 set되어있을 때만 가능

Interrupt Context

  • process와 연관되어있지 않다.
  • sleep할 수 없다.
  • 짧고 단순해야한다.
  • 2-page kernel stack을 사용했을 때는 interrupt handler들이 커널스택을 공유하여 사용했지만, single page kernel stack을 사용할 때는 handler마다 각각의 스택을 가지고 있다.

Implementing Interrupt handlers

do_IRQ()handle_irq_event()handle_irq_event_percpu()__handle_irq_event_percpu()

  • Interrupt 발생 시 cpu는 do_IRQ()를 call -- architecture dependent
  • 해당 Interrupt line이 enable되어있다면 handle_irq_event()를 call
  • 2.6 버전에서는 IRQF_SAMPLE_RANDOM flag가 set되어있을 때만 add_interrupt_randomness() 함수를 수행했지만, 4.11버전 기준으로 무조건 해당 함수를 안정성 차원에서 실행시킨다.
  • 4.11버전 기준으로 irq와 irqaction 대신 descriptor를 이용해 묶어서 한번에 인자를 보내준다.
    /kernel/irq/handle.c
    handle_irq_event(struct irq_desc *desc)
    

Interrupt Control

results matching ""

    No results matching ""