【问题标题】:Linux device driver handling multiple interrupt sources/vectors处理多个中断源/向量的 Linux 设备驱动程序
【发布时间】:2011-07-19 18:40:12
【问题描述】:

我正在编写一个设备驱动程序来处理 PCIe 卡的中断,该卡目前适用于 IRQ 线上引发的任何中断向量。

但它有一些可以被引发的类型,由向量寄存器标记。所以现在我需要阅读矢量信息并聪明一点...
那么,我是否:-

1/ 每种中断类型都有单独的开发节点/dev/int1/dev/int2 等,并且只需说明int1 用于向量类型 A 等?
1.1/ 由于每个文件/字符设备都有自己的minor 编号,打开时我会知道哪个是哪个。 我认为。
1.2/ ldd3 好像演示了这个方法。

2/ 有一个节点/dev/int (就像我现在所做的那样) 并且有多个进程挂在同一个read 方法上? 听起来更好?!
2.1/ 然后只唤醒正确的进程...?
2.2/ 我是否使用单独的wait_queue_head_t wait_queues?还是不同的flag/测试条件?

read 方法中:-

    wait_event_interruptible(wait_queue, flag);

在处理程序中不是真正的代码!:-

    int vector = read_vector();
    if vector = A then 
        wake_up_interruptible(wait_queue, flag)
        return IRQ_HANDLED;
    else
        return IRQ_NONE/IRQ_RETVAL?

编辑:来自人民 cmets 的笔记:-
1) 我的用户空间代码 mmap 的所有 PCIe 固件寄存器
2)用户空间代码有几个线程,每个线程在设备驱动设备节点上执行一个阻塞read,然后在发生中断时从固件返回数据。我需要根据中断类型唤醒正确的线程。

【问题讨论】:

    标签: linux device-driver linux-device-driver interrupt


    【解决方案1】:

    我不确定我是否正确理解了您对 Vector 寄存器的含义(指向某些文档的指针可以帮助我准确了解您的情况)。

    无论如何,任何 PCI 设备都会获得唯一的中断号(由 BIOS 或 x86 以外的其他架构上的某些固件提供)。您只需在驱动程序中注册此中断即可。

    priv->name = DRV_NAME;
    err = request_irq(pdev->irq, your_irqhandler, IRQF_SHARED, priv->name,
              pdev);
    if (err) {
        dev_err(&pdev->dev, "cannot request IRQ\n");
        goto err_out_unmap;
    }
    

    我不太明白的另一件事是为什么要将中断导出为开发节点:中断肯定是需要保留在驱动程序/内核代码中的东西。但我想在这里你想导出一个设备,然后在用户空间中访问。我只是觉得 /dev/int no 是一个好的命名。

    对于您关于多个开发节点的问题:如果您的不同中断源提供对不同硬件资源的访问(即使在同一个 PCI 板上),我会选择选项 1),每个设备都有一个 wait_queue。否则,我会选择选项 2)

    由于您的中断来自同一个物理设备,如果您选择选项 1) 或选项 2),则必须共享中断线,并且您必须读取中断处理程序来定义哪个硬件资源引发了中断。

    对于选项 1),它将是这样的:

    static irqreturn_t pex_irqhandler(int irq, void *dev) {
        struct pci_dev *pdev = dev;
        int result;
    
        result = pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &myirq);
    
        if (result) {
             int vector = read_vector();
             if (vector == A) {
                    set_flagA(flag);
             } else if (vector == B) {
                    set_flagB(flag);
             }
             wake_up_interruptible(wait_queue, flag);
             return IRQ_HANDLED;
        } else {
             return IRQ_NONE;
    }
    

    对于选项 2,它会是类似的,但是在您为每个节点请求的每个不同的中断处理程序中,您将只有一个 if 子句(用于相应的向量值)。

    【讨论】:

    • 抱歉文档是专有/定制固件。但是内存映射包含一个源向量,所以我知道哪个类型被提升了。谢谢,我的request_irq 代码位正在工作,我的驱动程序当前挂起这个单个 IRQ,但是 PCIe 卡引发了不同的中断,众所周知,它们都引发了相同的 IRQ 线。
    • 我没有导出 interrupts per-sa,我正在公开一个设备节点供用户空间使用,因为我可能不清楚,我已经更新了我的问,另请参阅我的其他评论回复。而名称int 只是这里的伪名称。是的,您有权阅读 vector(并没有侮辱的意思,但是您的选项 1 代码看起来非常像我 Q 中的伪代码!?(但是实际代码!))
    • 别担心,我不觉得受到侮辱,没有 10 种处理 irq 的方法。这个例子的意思是你可以有一个单独的 irq 处理程序来获取向量中所有可能的源,或者多个 irq 处理程序共享这个中断并且都寻址向量中的一个 irq 源。对于版本 1),您将拥有一台设备,其中包含许多队列;对于版本 2),您将拥有许多设备,每个设备都有一个队列。从您编辑的问题中,我会说选项 2 可能看起来更简单、更干净。
    【解决方案2】:

    如果你有不同的 chanel 可以read() ,那么你绝对应该使用不同的次要号码。想象一下,你有一张带四个串口的卡,你肯定想要四个/dev/ttySx
    但是你的设备适合这个型号吗?

    【讨论】:

    • 我喜欢串口的类比,我可能会走这条路,确保卡固件处理并发! 一罐蠕虫
    【解决方案3】:

    首先,我假设您没有尝试将代码放入主线内核。如果您是,请期待关于最佳方式的激烈讨论。如果您正在为主要由来自用户空间的mmap 驱动的卡编写一个简单的中断处理驱动程序,那么有很多方法可以解决这个问题。

    如果您使用多个设备节点(选项 1),您还可以实现poll,以便单个应用程序可以打开多个设备节点并等待选择的中断。次要号码足以区分它们。如果每个向量都有一个唤醒队列,则只能唤醒相关的侦听器。您需要在poll 成功后锁定向量,以确保read 成功。

    如果您使用单个设备节点(选项 2),则需要添加一些额外的魔法,以便线程可以注册它们对特定中断向量的兴趣。您可以使用 ioctl 执行此操作,或者让线程 write 将中断向量发送到设备。每个线程都应该打开设备节点以获取自己的文件描述符。然后,您可以将请求的向量列表与每个打开的文件描述符相关联。作为奖励,您可以让应用程序read 来自设备的中断向量,因此它知道发生了哪一个。

    您需要考虑如何清除中断。中断处理程序需要删除中断,然后存储结果,以便将其传递给用户空间。您可能会发现 kfifo 对此有用,而不是等待队列。如果每个打开的文件描述符都有一个 fifo,则可以将中断通知分发到每个侦听应用程序。

    【讨论】:

    • 不,不提交任何东西,只是为内部卡编写定制的 PCIe 驱动程序,是的,PCIe 卡上的所有寄存器在用户空间应用程序中都是mmaped。我喜欢带有write 的单个节点,我想我必须添加一个ioctl,正如你所说,非常漂亮。我不需要传递中断本身的结果,只需释放正确的阻塞read(我执行copy_to_user 并返回一些数据)。 (我更新了我的 Q 并进行了一些澄清)
    • 我认为我不需要poll,因为用户空间应用程序有一个线程用于每个节点opens 并在read 上挂起/阻塞。
    • 我在一些类似的设备上工作过。如果你想要单独的线程来监控不同的中断,你要么需要多个设备节点,要么每个线程打开单个设备节点并获取自己的文件描述符。您是否需要排队并计算中断,或者每个read 都应该阻塞直到下一个出现?
    • 我相信您的两个选项与我的 1 和 2 一致? (“多个设备......或......”)这是一个正确的假设吗?我不需要将它们排队或计数(每个线程将有 1 个阻塞read,它将由我的驱动程序激活,然后循环循环并再次阻塞。)
    • 我已经编辑了我的答案以参考您的第 1 点和第 2 点,并提到了线程。鉴于您的 cmets,我仍然留下了一些并不真正相关的点。
    猜你喜欢
    • 2012-12-13
    • 2018-05-19
    • 1970-01-01
    • 2023-03-02
    • 1970-01-01
    • 2013-10-29
    • 1970-01-01
    • 2021-12-27
    • 1970-01-01
    相关资源
    最近更新 更多