msi가 xhci 드라이버를 잘못 만들었는지 인터럽트를 너무 많이 발생시킨다.
왼쪽부터 36: 인터럽트 번호, 40080: cpu0 발생 횟수, 0: cpu 1, 2, 3 발생횟수, mmc1, mmc0 인터럽트 이름 정도? 모든 인터럽트가 충분하게 많이 일어난다.
pi@raspberrypi:~ $ cat /proc/interrupts CPU0 CPU1 CPU2 CPU3 ... 36: 40080 0 0 0 GICv2 158 Level mmc1, mmc0 37: 11075 0 0 0 GICv2 144 Level vc4 firmware kms ... 51: 707 0 0 0 GICv2 66 Level VCHIQ doorbell 52: 0 0 0 0 GICv2 175 Level PCIe PME, aerdrv 53: 2927 0 0 0 Brcm_MSI 524288 Edge xhci_hcd
인터럽트 53이 524,288번 발생했다. 53번 인터럽트가 있을 때 printk로 메세지를 출력하려 했으나, 횟수가 많아서인지 부팅을 할 수 없다. 횟수가 적은 31번 인터럽트를 보기로 했고, sd카드 읽고 쓰는 이벤트로 짐작된다. dump_stack을 보면 __sdhci_add_host가 request_threaded_irq로 등록한다.
31번으로 바꾸면 잘 출력이 되는데, 아마 msi가 드라이버를 이상하게 만들어서 그런가 싶다. 인터럽트를 한번 등록하고 말아야 하는데, xhci_run으로 계속 등록하는 느낌이 든다.
[ 0.824266] [+][irq_debug] irq_num: 36, func: request_threaded_irq, line: 1888, caller: __sdhci_add_host+0xcc/0x354 [ 0.827401] CPU: 0 PID: 32 Comm: kworker/0:1 Not tainted 4.19.127-v7l+ #91 [ 0.830475] Hardware name: BCM2835 [ 0.833547] Workqueue: events deferred_probe_work_func [ 0.836652] [<c0212dd8>] (unwind_backtrace) from [<c020d3ec>] (show_stack+0x20/0x24) [ 0.839740] [<c020d3ec>] (show_stack) from [<c09c01dc>] (dump_stack+0xd8/0x11c) [ 0.842903] [<c09c01dc>] (dump_stack) from [<c0285ac8>] (request_threaded_irq+0x19c/0x1a0) [ 0.846078] [<c0285ac8>] (request_threaded_irq) from [<c0843ba0>] (__sdhci_add_host+0xcc/0x354) [ 0.849277] [<c0843ba0>] (__sdhci_add_host) from [<c0844a60>] (sdhci_add_host+0x34/0x48) [ 0.852508] [<c0844a60>] (sdhci_add_host) from [<c084e8e0>] (sdhci_iproc_probe+0x11c/0x150) [ 0.855711] [<c084e8e0>] (sdhci_iproc_probe) from [<c071ad64>] (platform_drv_probe+0x58/0xa8) [ 0.858963] [<c071ad64>] (platform_drv_probe) from [<c0718f24>] (really_probe+0x20c/0x2cc) [ 0.862234] [<c0718f24>] (really_probe) from [<c07191b8>] (driver_probe_device+0x70/0x188) [ 0.865503] [<c07191b8>] (driver_probe_device) from [<c071947c>] (__device_attach_driver+0xac/0xd0) [ 0.868788] [<c071947c>] (__device_attach_driver) from [<c0716f2c>] (bus_for_each_drv+0x90/0xd4) [ 0.872033] [<c0716f2c>] (bus_for_each_drv) from [<c0718c90>] (__device_attach+0xe0/0x148) [ 0.875327] [<c0718c90>] (__device_attach) from [<c07194fc>] (device_initial_probe+0x1c/0x20) [ 0.878644] [<c07194fc>] (device_initial_probe) from [<c0717f50>] (bus_probe_device+0x94/0x9c) [ 0.881988] [<c0717f50>] (bus_probe_device) from [<c07183e0>] (deferred_probe_work_func+0x70/0x9c) [ 0.885363] [<c07183e0>] (deferred_probe_work_func) from [<c023da28>] (process_one_work+0x23c/0x518) [ 0.888693] [<c023da28>] (process_one_work) from [<c023eb00>] (worker_thread+0x60/0x5b8) [ 0.892070] [<c023eb00>] (worker_thread) from [<c02445a4>] (kthread+0x16c/0x174) [ 0.895476] [<c02445a4>] (kthread) from [<c02010ac>] (ret_from_fork+0x14/0x28) [ 0.898876] Exception stack(0xef3e3fb0 to 0xef3e3ff8)
__sdhci_add_host 함수를 찾아 책 예제를 추가했다. linux/drivers/mmc/host/sdhci.c에 정의되어 있다. 함수를 추가하면, 에러난다. 어디에 정의되어 있는지 모르는 듯 하다.
/*210611, interrupt_debug_irq_desc 추가 */ static void interrupt_debug_irq_desc(int irq_num) { struct irqaction *action; struct irq_desc *desc; desc = irq_to_desc(irq_num); if (!desc ) { pr_err("invalid desc at %s line: %d\n", __func__, __LINE__); return; } action = desc->action; if (!action ) { pr_err("invalid action at %s line:%d \n", __func__, __LINE__); return; } printk("[+] irq_desc debug start \n"); printk("irq num: %d name: %8s \n", action->irq , action->name); printk("dev_id:0x%x \n", (unsigned int)action->dev_id); if (action->handler) { printk("interrupt handler: %pF \n", action->handler); } printk("[-] irq_desc debug end \n"); }
int __sdhci_add_host(struct sdhci_host *host) { struct mmc_host *mmc = host->mmc; int ret; /* * Init tasklets. */ tasklet_init(&host->finish_tasklet, sdhci_tasklet_finish, (unsigned long)host); timer_setup(&host->timer, sdhci_timeout_timer, 0); timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0); init_waitqueue_head(&host->buf_ready_int); sdhci_init(host, 0); ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq, IRQF_SHARED, mmc_hostname(mmc), host); if (ret) { pr_err("%s: Failed to request IRQ %d: %d\n", mmc_hostname(mmc), host->irq, ret); goto untasklet; } //210611 irq 실습 interrupt_debug_irq_desc(host->irq); ...
usb 드라이버는 irq_to_desc를 잘 사용했는데, sdhci가 에러내는게 이상하다. 헤더에 extern으로 다른 파일에서 쓸 수 있도록 했음을 알았고, 앞쪽에 통쨰로 복사하여 붙였다.
/* * linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver * * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * Thanks to the following companies for their support: * * - JMicron (hardware and technical support) */ ... //210618. irq_to_desc 실습 #include <linux/irq.h> #include <linux/slab.h> #include <linux/export.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> #include <linux/radix-tree.h> #include <linux/bitmap.h> #include <linux/irqdomain.h> #include <linux/sysfs.h> #include "../kernel/irq/internals.h"
부팅 메세지를 보면 정상적으로 출력된다.
[ 0.912941] [+] irq_desc debug start [ 0.918446] irq num: 36 name: mmc1 [ 0.921869] dev_id:0xef827b40 [ 0.925260] interrupt handler: bcm2835_mmc_irq+0x0/0x6e8 [ 0.928658] [-] irq_desc debug end