5장 인터럽트 실습2

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 

코멘트

댓글 남기기

이 사이트는 Akismet을 사용하여 스팸을 줄입니다. 댓글 데이터가 어떻게 처리되는지 알아보세요.