在基于 Linux 的 OS 中管理中断

Managing interrupt in Linux-based OS

上下文

我有一个设备树,其中一个节点是:

    gpio@41210000 {
        #gpio-cells = <0x2>;
        #interrupt-cells = <0x2>;
        compatible = "xlnx,xps-gpio-1.00.a,generic-uio,BTandSW";
        gpio-controller;
        interrupt-controller;
        interrupt-parent = <0x4>;
        //interrupt-parent =<&gic>;
        interrupts = <0x0 0x1d 0x4>;
        reg = <0x41210000 0x10000>;
        xlnx,all-inputs = <0x1>;
        xlnx,all-inputs-2 = <0x1>;
        xlnx,all-outputs = <0x0>;
        xlnx,all-outputs-2 = <0x0>;
        xlnx,dout-default = <0x0>;
        xlnx,dout-default-2 = <0x0>;
        xlnx,gpio-width = <0x4>;
        xlnx,gpio2-width = <0x2>;
        xlnx,interrupt-present = <0x1>;
        xlnx,is-dual = <0x1>;
        xlnx,tri-default = <0xffffffff>;
        xlnx,tri-default-2 = <0xffffffff>;
    };

一旦内核运行,执行

cat /proc/interrupts

结果是:

root@linaro-developer:~# cat /proc/interrupts
           CPU0       CPU1
 16:          0          0     GIC-0  27 Edge      gt
 17:          0          0     GIC-0  43 Level     ttc_clockevent
 18:       1588       1064     GIC-0  29 Edge      twd
 21:         43          0     GIC-0  39 Level     f8007100.adc
 24:          0          0     GIC-0  35 Level     f800c000.ocmc
 25:        506          0     GIC-0  59 Level     xuartps
 26:          0          0     GIC-0  51 Level     e000d000.spi
 27:          0          0     GIC-0  54 Level     eth5
 28:       4444          0     GIC-0  56 Level     mmc0
 29:          0          0     GIC-0  45 Level     f8003000.dmac
 30:          0          0     GIC-0  46 Level     f8003000.dmac
 31:          0          0     GIC-0  47 Level     f8003000.dmac
 32:          0          0     GIC-0  48 Level     f8003000.dmac
 33:          0          0     GIC-0  49 Level     f8003000.dmac
 34:          0          0     GIC-0  72 Level     f8003000.dmac
 35:          0          0     GIC-0  73 Level     f8003000.dmac
 36:          0          0     GIC-0  74 Level     f8003000.dmac
 37:          0          0     GIC-0  75 Level     f8003000.dmac
 38:          0          0     GIC-0  40 Level     f8007000.devcfg
 45:          0          0     GIC-0  41 Edge      f8005000.watchdog
IPI1:          0          0  Timer broadcast interrupts
IPI2:       1731       2206  Rescheduling interrupts
IPI3:         29         36  Function call interrupts
IPI4:          0          0  CPU stop interrupts
IPI5:          0          0  IRQ work interrupts
IPI6:          0          0  completion interrupts
Err:          0

问题

  1. 一旦内核是运行,它是否应该自动识别并更新文件/proc/interrupt中的数据?

  2. 但是我写了一个.probe函数是这样的:

     static int SWITCH_of_probe(struct platform_device *pdev)
    {
        int ret=0;
        struct irq_data data_tmp;
        SWITCH_01_devices->temp_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!(SWITCH_01_devices->temp_res)) {
            dev_err(&pdev->dev, "TRY could not get IO memory\n");
            return -ENXIO;
        }
    
     PDEBUG("resource : regs.start=%#x,regs.end=%#x\n",SWITCH_01_devices->temp_res->start,SWITCH_01_devices->temp_res->end);
    
     //SWITCH_01_devices->irq_line = platform_get_irq(pdev, 0);
     SWITCH_01_devices->irq_line = irq_of_parse_and_map(pdev->dev.of_node, 0);
       if (SWITCH_01_devices->irq_line < 0) {
           dev_err(&pdev->dev, "could not get IRQ\n");
         printk(KERN_ALERT "could not get IRQ\n");
           return SWITCH_01_devices->irq_line;
       }
    
     PDEBUG(" resource VIRTUAL IRQ NUMBER : irq=%#x\n",SWITCH_01_devices->irq_line);
     ret = request_irq((SWITCH_01_devices->irq_line), SWITCH_01_interrupt, IRQF_SHARED  , DRIVER_NAME, NULL);
     if (ret) {
        printk(KERN_ALERT "NEW SWITCH_01: can't get assigned irq, ret= %d\n", SWITCH_01_devices->irq_line, ret);
        SWITCH_01_devices->irq_line = -1;
    }
    
    
     SWITCH_01_devices->mem_region_requested = request_mem_region((SWITCH_01_devices->temp_res->start),resource_size(SWITCH_01_devices->temp_res),"SWITCH_01");
     if(SWITCH_01_devices->mem_region_requested == NULL){
         printk(KERN_WARNING "[LEO] SWITCH: FaiSWITCH request_mem_region(res.start,resource_size(&(SWITCH_01_devices->res)),...);\n");
     }
     else
         PDEBUG(" [+] request_mem_region\n");
    
     return 0; /* Success */
     }
    

在内核中插入模块时,我从 dmesg 得到以下输出:

[ 1249.777189] SWITCH_01: loading out-of-tree module taints kernel.
[ 1249.777787] [LEO] SWITCH_01: dinamic allocation of major number
[ 1249.777801] [LEO]  cdev initialized
[ 1249.777988] [LEO] resource : regs.start=0x41210000,regs.end=0x4121ffff
[ 1249.777994] [LEO]  resource : irq=0x2e
[ 1249.778000] NEW SWITCH_01: can't get assigned irq, ret= -22
[ 1249.782531] [LEO]  [+] request_mem_region

我做错了什么?为什么我无法执行正确的 request_irq?

注意:设备树的interrupts = <0x0 0x1d 0x4>字段和检测到的irq_number不一样。正如指出 ,我将 platform_get_irq(pdev, 0); 更改为 irq_of_parse_and_map(pdev->dev.of_node, 0); 但结果是一样的。

Once the kernel is running, should it recognize, automatically, and update the data in the file /proc/interrupt?

是的,一旦中断被注册,它就会更新。

[ 1249.777189] SWITCH_01: loading out-of-tree module taints kernel.
[ 1249.777787] [LEO] SWITCH_01: dinamic allocation of major number
[ 1249.777801] [LEO]  cdev initialized
[ 1249.777988] [LEO] resource : regs.start=0x41210000,regs.end=0x4121ffff
[ 1249.777994] [LEO]  resource : irq=0x2e
[ 1249.778000] NEW SWITCH_01: can't get assigned irq, ret= -22
[ 1249.782531] [LEO]  [+] request_mem_region

What am I doing wrong? Why I cannot perform a correct request_irq?

共享中断(IRQF_SHARED)必须传递dev_id(你在request_irq()中传递NULL),如果NULL-EINVAL是已返回,因此请确保您传递了一个非空的有效 dev_id