Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

87258
1323
114589


[리눅스커널] IRQ 스레드 생성 예제 코드 분석 - 라즈베리파이 6. Bottom-Half

6.3.2 라즈비안 92번 인터럽트 IRQ 스레드 생성 예제 코드 분석해보기

IRQ 스레드를 생성하는 함수 흐름을 알아봤으니 IRQ 스레드를 생성하는 예제 코드를 살펴보겠습니다.

분석할 소스 코드는 다음과 같습니다.
[https://github.com/raspberrypi/linux/blob/rpi-4.19.y/drivers/mmc/host/bcm2835-mmc.c]
1 static int bcm2835_mmc_add_host(struct bcm2835_host *host)
2 {
3 struct mmc_host *mmc = host->mmc;
4 struct device *dev = mmc->parent;
...
5 bcm2835_mmc_init(host, 0);
6 ret = devm_request_threaded_irq(dev, host->irq, bcm2835_mmc_irq,
7 bcm2835_mmc_thread_irq, IRQF_SHARED,
8 mmc_hostname(mmc), host); 

bcm2835_mmc_add_host() 함수에서 라즈베리파이에서 92번 인터럽트 핸들러와 해당 IRQ 스레드를 설정하는 코드입니다.

위 코드를 보면 request_threaded_irq() 함수 대신 devm_request_threaded_irq() 함수를 써서 IRQ 스레드를 설정합니다. 함수 이름이 다르니 다른 동작을 하는 함수로 보입니다. 하지만 devm_request_threaded_irq() 함수를 열어 보면 request_threaded_irq() 함수를 호출합니다.
[[https://elixir.bootlin.com/linux/v4.19.30/source/kernel/irq/devres.c]]
1 int devm_request_threaded_irq(struct device *dev, unsigned int irq,
2       irq_handler_t handler, irq_handler_t thread_fn,
3       unsigned long irqflags, const char *devname,
4       void *dev_id)
5 {
6 struct irq_devres *dr;
7 int rc;
8
...
9
10 rc = request_threaded_irq(irq, handler, thread_fn, irqflags, devname,
11   dev_id);

10 번째 줄과 같이 devm_request_threaded_irq() 함수에서 request_threaded_irq() 함수를 호출합니다.

IRQ 스레드 생성 관점으로만 보면 devm_request_threaded_irq() 함수는 request_threaded_irq() 함수와 같은 기능입니다. 인터럽트를 struct device 구조체로 관리하는 방식만 다를 뿐입니다.

이번에 request_threaded_irq() 함수에 전달하는 인자가 약간 다른 것 같습니다.
6 ret = devm_request_threaded_irq(dev, host->irq, bcm2835_mmc_irq,
7 bcm2835_mmc_thread_irq, IRQF_SHARED,
8 mmc_hostname(mmc), host); 

6번째 줄을 보면 bcm2835_mmc_irq() 함수를 인터럽트 핸들러로 등록합니다. 이 함수는 92번 “mmc1” 인터럽트가 발생하면 호출되는 인터럽트 핸들러 함수입니다. 

7번째 줄 코드를 보면 request_threaded_irq() 함수 세 번째 인자로 bcm2835_mmc_thread_irq() 함수를 지정합니다. 이 함수를 IRQ 스레드 핸들러라고 합니다. IRQ 스레드가 실행될 때 호출되는 핸들러 함수입니다.  

조금 더 이해를 돕기 위해 request_threaded_irq() 함수의 선언부를 보면 세 번째 인자로 irq_handler_t thread_fn가 선언돼 있습니다. 두 번째 인자는 인터럽트 핸들러 함수입니다.
[https://elixir.bootlin.com/linux/v4.19.30/source/include/linux/interrupt.h] 
extern int __must_check
request_threaded_irq(unsigned int irq, irq_handler_t handler,
     irq_handler_t thread_fn,
     unsigned long flags, const char *name, void *dev);

thread_fn 이란 함수 포인터에 bcm2835_mmc_thread_irq() 이란 IRQ Thread 핸들러 함수를 등록하는 것입니다.

이를 알기 쉬운 코드 형식으로 표현하면 각 인자를 다음과 같이 등록합니다.
인터럽트 번호: irq:  host->irq
인터럽트 핸들러 handler bcm2835_mmc_irq
IRQ Thread 핸들러thread_fn bcm2835_mmc_thread_irq

인터럽트가 발생했을 때 인터럽트 컨택스트에서 수행하는 인터럽트 핸들러는 bcm2835_mmc_irq() 함수이고 “irq/92-mmc1” IRQ 스레드가 실행하는 스레드 핸들 함수는 bcm2835_mmc_thread_irq() 함수입니다. 

IRQ 스레드 이름을 정하는 규칙은 무엇일까

다음은 IRQ 스레드를 생성하는 코드를 보면서 92번 인터럽트에 대한 IRQ 스레드 이름을 어떤 규칙으로 생성하는지 알아봅시다.
[https://elixir.bootlin.com/linux/v4.19.30/source/kernel/irq/manage.c]
1 static int
2 setup_irq_thread(struct irqaction *new, unsigned int irq, bool secondary)
3 {
4 struct task_struct *t;
5 struct sched_param param = {
6 .sched_priority = MAX_USER_RT_PRIO/2,
7 };
8
9 if (!secondary) {
10 t = kthread_create(irq_thread, new, "irq/%d-%s", irq,   
11    new->name);
12 } else {
13 t = kthread_create(irq_thread, new, "irq/%d-s-%s", irq,
14    new->name);
15 param.sched_priority -= 1;
16 }

이 정보를 참고하면 “irq=92 name=mmc1” 인터럽트의 IRQ 스레드 이름은 “irq/92-mmc1”라는 점을 유추할 수 있습니다. 

“irq/92-mmc1” IRQ 스레드는 언제 실행될까요? 92번 인터럽트가 발생하면 호출되는 인터럽트 핸들러가 IRQ 스레드 실행 여부를 결정합니다. 만약 92번 인터럽트가 발생하지 않으면 IRQ 스레드는 실행하지 않습니다.



     "혹시 글을 읽고 궁금한 점이 있으면 댓글로 질문 남겨주세요. 아는 한 성실하게 답변 올려 드리겠습니다!"


# Reference 인터럽트 후반부 처리








6.9 Soft IRQ 서비스는 누가 언제 처리하나?




6.13 Soft IRQ 디버깅
6.13.1 ftrace Soft IRQ 이벤트 분석 방법
6.13.2 /proc/softirqs로 Soft IRQ 서비스 실행 횟수 확인




핑백

덧글

댓글 입력 영역