[태그:] request_irq

  • 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 
  • 5장 인터럽트, p345 실습

    책이 dwc_otg_driver.c의 request_irq로 인터럽트를 등록을 설명했다. 그러나, 라즈베리 파이4가 dwc-otg_driver.c 함수를 사용하지 않는다. 있긴 있는데, 4로 오면서 의도적으로 사용하지 않는 듯 하다. 아무리 찾아봐도 request_irq를 dump_stack 메세지에서 찾을 수 없다. 내가 본 메세지는 다음과 같다.

    Jun 14 07:38:24 raspberrypi kernel: [    0.547246] xhci_hcd 0000:01:00.0: hcc params 0x002841eb hci version 0x100 quirks 0x0000001000000890
    Jun 14 07:38:24 raspberrypi kernel: [    0.550250] [+][irq_debug] irq_num: 53, func: request_threaded_irq, line: 1888, caller: xhci_run+0x240/0x670
    Jun 14 07:38:24 raspberrypi kernel: [    0.552941] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.19.127-v7l+ #78
    Jun 14 07:38:24 raspberrypi kernel: [    0.555588] Hardware name: BCM2835
    Jun 14 07:38:24 raspberrypi kernel: [    0.558290] [<c0212dd8>] (unwind_backtrace) from [<c020d3ec>] (show_stack+0x20/0x24)
    Jun 14 07:38:24 raspberrypi kernel: [    0.561023] [<c020d3ec>] (show_stack) from [<c09c01dc>] (dump_stack+0xd8/0x11c)
    Jun 14 07:38:24 raspberrypi kernel: [    0.563706] [<c09c01dc>] (dump_stack) from [<c0285ae0>] (request_threaded_irq+0x1b4/0x1b8)
    Jun 14 07:38:24 raspberrypi kernel: [    0.566425] [<c0285ae0>] (request_threaded_irq) from [<c07b4530>] (xhci_run+0x240/0x670)
    Jun 14 07:38:24 raspberrypi kernel: [    0.569178] [<c07b4530>] (xhci_run) from [<c079bd6c>] (usb_add_hcd+0x324/0x7ac)
    Jun 14 07:38:24 raspberrypi kernel: [    0.571892] [<c079bd6c>] (usb_add_hcd) from [<c07afa84>] (usb_hcd_pci_probe+0x278/0x398)
    Jun 14 07:38:24 raspberrypi kernel: [    0.574625] [<c07afa84>] (usb_hcd_pci_probe) from [<c07cc760>] (xhci_pci_probe+0x3c/0x180)
    Jun 14 07:38:24 raspberrypi kernel: [    0.577382] [<c07cc760>] (xhci_pci_probe) from [<c067d008>] (pci_device_probe+0xb0/0x138)
    Jun 14 07:38:24 raspberrypi kernel: [    0.580118] [<c067d008>] (pci_device_probe) from [<c0718f3c>] (really_probe+0x20c/0x2cc)
    Jun 14 07:38:24 raspberrypi kernel: [    0.582911] [<c0718f3c>] (really_probe) from [<c07191d0>] (driver_probe_device+0x70/0x188)
    Jun 14 07:38:24 raspberrypi kernel: [    0.585734] [<c07191d0>] (driver_probe_device) from [<c07193e4>] (__driver_attach+0xfc/0x100)
    Jun 14 07:38:24 raspberrypi kernel: [    0.588587] [<c07193e4>] (__driver_attach) from [<c0716e48>] (bus_for_each_dev+0x84/0xc4)
    Jun 14 07:38:24 raspberrypi kernel: [    0.591438] [<c0716e48>] (bus_for_each_dev) from [<c07187c8>] (driver_attach+0x2c/0x30)
    Jun 14 07:38:24 raspberrypi kernel: [    0.594277] [<c07187c8>] (driver_attach) from [<c0718248>] (bus_add_driver+0x1d0/0x214)
    Jun 14 07:38:24 raspberrypi kernel: [    0.597086] [<c0718248>] (bus_add_driver) from [<c0719bc4>] (driver_register+0x84/0x118)
    Jun 14 07:38:24 raspberrypi kernel: [    0.599945] [<c0719bc4>] (driver_register) from [<c067c2e0>] (__pci_register_driver+0x58/0x5c)
    Jun 14 07:38:24 raspberrypi kernel: [    0.602852] [<c067c2e0>] (__pci_register_driver) from [<c0e3f6cc>] (xhci_pci_init+0x68/0x6c)
    Jun 14 07:38:24 raspberrypi kernel: [    0.605785] [<c0e3f6cc>] (xhci_pci_init) from [<c0203004>] (do_one_initcall+0x50/0x220)
    Jun 14 07:38:24 raspberrypi kernel: [    0.608748] [<c0203004>] (do_one_initcall) from [<c0e01374>] (kernel_init_freeable+0x340/0x3e0)
    Jun 14 07:38:24 raspberrypi kernel: [    0.611723] [<c0e01374>] (kernel_init_freeable) from [<c09d5590>] (kernel_init+0x18/0x128)
    Jun 14 07:38:24 raspberrypi kernel: [    0.614684] [<c09d5590>] (kernel_init) from [<c02010ac>] (ret_from_fork+0x14/0x28)
    Jun 14 07:38:24 raspberrypi kernel: [    0.617678] Exception stack(0xefa61fb0 to 0xefa61ff8)
    • 일단 request_threaded_irq가 request_irq임은 확실하다.
    • xhci_run이 request_threaded_irq를 호출한다.
    • usb_add_hcd가 xhci_run을 호출한다.
    • … 이런 식으로 kernel_init로 간다.
    • 결국 시스템 시작할 때 인터럽트를 등록한다.

    문제가 책 예시와 다르게, 누가 request_irq를 실행하는지 모르는 점이다. dump_stack이 미리 정의되지 않은 함수는 보여주지 않는 듯 하다. 찾아보면 알겠지만 msi가 드라이버를 만들었다. xhci_run, usb_add_hcd, usb_hcd_pci_probe 등 여러 함수 중 request_irq를 콜하는 부분을 쉽게 찾을 수 없었다. 그러나 시간이 많은 나는 결국 xhci_run의 xhci_setup_msi가 requset_irq를 함을 찾아냈다.

    /*
     * Set up MSI
     */
    static int xhci_setup_msi(struct xhci_hcd *xhci)
    {
        int ret; 
        /*   
         * TODO:Check with MSI Soc for sysdev
         */
        struct pci_dev  *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
    
        ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
        if (ret < 0) { 
            xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                    "failed to allocate MSI entry");
            return ret; 
        }    
    
        ret = request_irq(pdev->irq, xhci_msi_irq,
                    0, "xhci_hcd", xhci_to_hcd(xhci));
        //210611 irq 추가...
        interrupt_debug_irq_desc(pdev->irq);
    
    
        if (ret) {
            xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                    "disable MSI interrupt");
            pci_free_irq_vectors(pdev);
        }    
    
        return ret; 
    }

    이렇게 설정 후 컴파일 하면, 메세지가 제대로 출력된다. 교재와 다르게 인터럽트 53번으로 설정한다.

    Jun 14 07:38:24 raspberrypi kernel: [    0.626769] 1fe0: 00000000 00000000 00000000 00000000 00000013 00000000
    Jun 14 07:38:24 raspberrypi kernel: [    0.629855] genirq: irq_chip Brcm_MSI did not update eff. affinity mask of irq 53
    Jun 14 07:38:24 raspberrypi kernel: [    0.632884] [+] irq_desc debug start
    Jun 14 07:38:24 raspberrypi kernel: [    0.635920] irq num: 53 name: xhci_hcd
    Jun 14 07:38:24 raspberrypi kernel: [    0.638938] dev_id:0xefa55000
    Jun 14 07:38:24 raspberrypi kernel: [    0.641924] interrupt handler: xhci_msi_irq+0x0/0x20
    Jun 14 07:38:24 raspberrypi kernel: [    0.644914] [-] irq_desc debug end

    몇 번 해보면서 느꼈는데, 꼬리에 꼬리를 물어 원하는 부분을 찾아내는 능력이 필요해 보인다. 그래야 그 부분을 수정하여 원하는 기능을 구현할 수 있으니까.