Bottom Half

TAEWOO HA·2023년 6월 26일
0

Top/Bottom half

● 대부분 디바이스 드라이버는 두 가지 문맥으로 동작

● Top half
– 인터럽트 컨텍스트에서 동작
– 인터럽트 핸들러
● 제한된 환경
● 일부 커널 함수 호출 불가
– Sleep 함수(예: mutex) 호출 불가

● Bottom half
– 보통 스레드(커널 스레드) 컨텍스트에서 동작
● sleep 함수 또는 blocking lock(mutex와 같은)호출 가능

Bottom half 사용 방법

● 일반적으로는 ISR은 아래와 같은 절차로 진행
● Acknowledge to device
– 다음 인터럽트를 받을 수 있도록
● 전반부 처리
– 레지스터 read/write
● wake_up_interruptible(&queue);
– 대기 중인 커널 스레드 wake_up

Bottom half의 다른 방법들

● Softirq/Tasklet
– TIMER, NET, BLOCK HRTIMER, RCU등 커널의 중요한 드라이버에서 사용
– 일반적으로 threaded irq, workqueue, kthread 이용

● Threaded IRQ
– 인터럽트 핸들러가 커널 스레드로 동작함
– Block/sleep 가능(I2C/SPI)에 필요
– 동적으로 priority 설정 가능
● 이유는 threaded irq에서 사용하는 thread는 real-time 클래스로 동작하고 있음.

● 워크큐(Workqueues)
– 대기중인 스레드 필요 없음
– Worker thread 이용
– 사용하기 편함
– 다음 시간에 실습 예정

Threaded IRQ

● 인터럽트 핸들러가 커널 스레드(Real-time)로 동작함
– Block/sleep 가능
– 동적으로 priority 설정 가능
– thread_fn은 real-time 클래스로 동작

int request_threaded_irq(struct device dev, unsigned int irq,
irq_handler_t handler, irq_handler_t thread_fn,
unsigned long flags, const char
name,
void *dev);
– handler: 인터럽트 핸들러(보통 NULL)
– thread_fn: 스레드로 동작하는 인터럽트 핸들러

Softirqs

● 인터럽트 컨텍스트
– Bottom half이지만 sleep 불가능
● 동적으로 등록 못함
● TIMER_SOFTIRQ, NET_TX/RX_SOFTIRQ, BLOCK_SOFTIRQ
● 가장 빠르게 실행
– 일반 디바이스 드라이버에서는 사용하지 않음.

태스크릿

● 동적으로 생성 가능
● 인터럽트 컨텍스트
– Bottom half이지만 sleep 불가능
● 빠르게 실행
– sleep이 불가능

워크큐

● 커널 스레드로 동작(워커 스레드)
● 사용하기 쉽다.

ISR/Softirq/Workqueue/Threaded IRQ

  • Bottom Half쪽으로 갈 때 irq가 켜진다. 인터럽트 컨텍스트가 Softirq와 태스크릿까지 처리,
  • 스레드 문맥으로 도는게 워크큐 , 스레디드 IRQ , 커널 스레드 ...

Kthread + Wait Queue 실험

GPIO 인터럽트

● GPIO input으로 설정하여 외부 인터럽트로 사용 가능
– 예) 버튼 입력, Door, Touch, Sensor interrupts
● Push 버튼 등 물리적인 문제
– 채터링 방지 처리 필요
– Debounce

채터링

  • 바운스가 발생 , 접지 문제 등등

커널 스레드를 이용한 Bottom Half 구현

● 인터럽트 기반으로 구현
– ISR에서 kthread wake-up
– ISR에서 user application에 signal 전송

  • 시그널 등록
  • 44~46에 슬리핑
  • 시그널이 걸리면 시그널 핸들러가 찍힘

  • 22 : task에게 시그널을 보낼 때 task_struct를 저장을 해놔야함
  • SIGNR : 시그널을 보내야해서 같은 번호가 있어야한다.
  • kdt_driver_read : wake up + user space = get_current()
  • get_current() : 현재 호출하는 task 상태를 알 수 있다.

  • gpio_to_irq : gpio번호를 알아낼 수 있음

실습

0개의 댓글

관련 채용 정보