5

我和我的同事正在使用我们的一种基于 PCIe 的产品,我们发现某种平台/芯片组依赖性正在阻止将中断传递到我们的 linux 内核驱动程序 (rapafp)。我们必须在现场继续支持的一个旧版本的产品是对旧 PCI 设计的改造。所以我们有一些 FPGA,其中一个有一个 66MHz PCI-32 接口,并连接到德州仪器 XIO PCI-to-PCIe 桥接器。我应该注意,我已经不知疲倦地研究了好几天,但我没有得到任何结果。我们确实考虑过我们自己设备的硬件问题,但是我们换了多张卡,这并没有什么区别。

有效的参考系统

我们有一个运行 RHEL6.5 的系统运行良好,因此我们将其用作参考。以下是有关该平台的一些信息。我不知道您需要什么级别的详细信息,而且我不想写垃圾邮件问题。请让我知道还有什么有用的以及如何提供(问题中的内联、pastebin 等)。

来自uname -a

Linux DL-2-107.localdomain 2.6.32-431.el6.i686 #1 SMP Fri Nov 22 00:26:36 UTC 2013 i686 i686 i386 GNU/Linux

从 /proc/interrupts:

           CPU0       CPU1       
...
 16:  609672457 1344098703   IO-APIC-fasteoi   uhci_hcd:usb3, pata_jmicron, rapafp    

来自 dmesg 的信息:

rapafp driver version 3.3.0.5
rapafp: Requesting IRQ 16
TSI: rapafp0 (BusID 2:0:0) is RAPTOR 4000 @ 2048x2048
TSI: rapafp1 (BusID 2:0:0) is RAPTOR 4000 @ 1280x1024

来自 lspci:

# lspci -t
-[0000:00]-+-00.0
           +-01.0-[01-02]----00.0-[02]----00.0

00:01.0 PCI bridge: Intel Corporation 82Q35 Express PCI Express Root Port (rev 02) (prog-if 00 [Normal decode])
01:00.0 PCI bridge: Texas Instruments XIO2000(A)/XIO2200A PCI Express-to-PCI Bridge (rev 03) (prog-if 00 [Normal decode])
02:00.0 Display controller: Tech-Source Device 0042

安装的 CPU 是:型号名称:Intel(R) Core(TM)2 CPU E8400 @ 3.00GHz

来自 dmidecode 的一些 BIOS 信息:

Vendor: Phoenix Technologies, LTD
Version: 6.00 PG
Release Date: 12/12/2008

请注意,驱动程序在编写时从未考虑过 fasteoi,因此它永远不会进行任何结束中断调用。然而,它在该机器上完美运行。

无法对我们的驱动程序产生任何中断的系统

我们有两个系统在接收中断时出现问题。一个是运行RHEL6.5(2.6.32-431.el6.i686),另一个是RHEL7.4(3.10.0-693.17.1.el7.x86_64)。

RHEL6 系统能够中断我们的驱动程序,但只是间歇性的。这可能是由于内核将设备连接到边缘触发的中断线(尽管驱动程序另有请求!)并且驱动程序没有被写入与边缘触发兼容。

RHEL7 系统根本无法中断我们的驱动程序 我们当前的目标是将驱动程序移植到 RHEL7,所以我将专注于那台机器。主机与参考系统有很多相似之处和不同之处。重要的主要区别是内核版本、32 位与 64 位,可能还有 BIOS。首先,以下是一些系统信息。

来自uname -a

Linux rhel74.techsource.com 3.10.0-693.17.1.el7.x86_64 #1 SMP Thu Jan 25 20:13:58 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

/proc/中断:

10:          0          0   IO-APIC-edge      rapafp

来自 dmesg:

[321790.744110] raptor_attach: irq_set_irq_type(10,8) succeeded!
[321790.744111] raptor_attach: calling request_irq.
[321790.744239] raptor_attach: request_irq(10) succeeded!
[321790.744240] raptor_attach: done
[321790.744342] TSI: rapafp0 (BusID 2:0:0) is RAPTOR 4000 @ 2048x2048
...
[321807.840300] PCI Config Register dump:
[321807.840405]  vendor id              0x1227  
[321807.840508]  device id              0x43
[321807.840611]  command register       0x202   
[321807.840715]  status register        0x2a0
[321807.840818]  revision id            0x0     
[321807.840921]  programming class code 0x0
[321807.841025]  sub-class code         0x80    
[321807.841129]  basic class code       0x3
[321807.841232]  header type            0x0     
[321807.841335]  base register 0        0xbfff0008
[321807.841439]  base register 1        0xa0000008      
[321807.841542]  base register 2        0xb8000008
[321807.841645]  base register 3        0x0     
[321807.841749]  base register 4        0xbffc0008
[321807.841852]  base register 5        0x0     
[321807.841955]  Cardbus CIS Pointer    0x0
[321807.842059]  Subsystem Vendor ID    0x1227  
[321807.842162]  Subsystem ID           0x43
[321807.842266]  ROM base register      0x0     
[321807.842369]  interrupt line         0xa
[321807.842472]  interrupt pin          0x1     
[321807.842576]  minimum grant          0x0
[321807.842679]  maximum grant          0x0

来自 lspci 的信息:

# lspci -t
-[0000:00]-+-00.0
           +-01.0-[01-02]----00.0-[02]----00.0

00:00.0 Host bridge: Intel Corporation 82X38/X48 Express DRAM Controller (rev 01)
        Subsystem: Holco Enterprise Co, Ltd/Shuttle Computer Device 3111
        Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort+ >SERR- <PERR- INTx-
...
00:01.0 PCI bridge: Intel Corporation 82X38/X48 Express Host-Primary PCI Express Bridge (rev 01) (prog-if 00 [Normal decode])
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0, Cache Line Size: 64 bytes
        Interrupt: pin A routed to IRQ 24
...
01:00.0 PCI bridge: Texas Instruments XIO2000(A)/XIO2200A PCI Express-to-PCI Bridge (rev 03) (prog-if 00 [Normal decode])
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
...
02:00.0 Display controller: Tech-Source Device 0043
        Subsystem: Tech-Source Device 0043
        Control: I/O- Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B+ DisINTx-
        Status: Cap- 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Interrupt: pin A routed to IRQ 10

尝试的解决方案

我尝试了一系列修复。我做的第一件事是检查中断处理代码并重写它,以便它对边缘触发的中断线更友好,但这没有效果。我做的其他事情包括:

  • 没有调用 pci_enable_device,所以我添加了它。没有效果。
  • 我注意到我们对 request_irq 的调用使用以 开头的旧标志SA_,因此我将它们替换为以 开头的较新标志IRQF_。我尝试了各种标志组合。IRQF_TRIGGER_RISING, IRQF_TRIGGER_FALLING, IRQF_TRIGGER_HIGH, IRQF_TRIGGER_LOW, 这些的组合,有和没有 IRQF_SHARED 等等。这些都对 IRQ 传递、/proc/interrupts 报告的内容或 lspci 报告的桥配置没有任何影响。然而,request_irq 从未返回任何错误代码。
  • 我尝试调用 enable_irq 和 set_irq_type。无论我传递给他们什么,都没有效果。没有返回错误代码。

最后我注意到 PCI 桥 00:01.0 有遗留中断 (DisINTx+)。我四处寻找某种预先存在的功能,它可以遍历网桥层次结构并修复所有它们的中断,但我找不到任何东西。所以我决定尝试一下。

首先,我编写了自己的函数来提升桥接层次结构:

static int raptor_enable_intx(struct pci_dev *dev, TspciPtr pTspci) {
    int num_en = 0;
    int result;
    u16 cmd, old_cmd;

    while (dev) {
        pci_read_config_word(dev, PCI_COMMAND, &old_cmd);
        pci_intx(dev, true);
        pci_read_config_word(dev, PCI_COMMAND, &cmd);
        if (cmd & PCI_COMMAND_INTX_DISABLE) {
            printk (KERN_INFO "raptor_enable_intx: Could not clear DisINTx for device %s\n", pci_name(dev));
        } else {
            printk (KERN_INFO "raptor_enable_intx: Successfully cleared DisINTx for device %s\n", pci_name(dev));
            if ((old_cmd & PCI_COMMAND_INTX_DISABLE)) num_en++;
        }

        dev = pci_upstream_bridge(dev);
    }
    return num_en;
}

这样做的主要影响是导致机器挂起,尽管不是马上。我尝试在 raptor_enable_intx 之前或之后调用 request_irq。IIRC,一个没有效果,而另一个导致系统挂起,尽管不是立即。

我还发现 pci_common_swizzle 有一些关于 PCI 标准要求它的评论,所以我在上述函数之后调用它。在我做完这些事情之后,我会调用 request_irq。通过这些更改,系统会立即在 insmod 上挂起。

当然,我意识到遍历网桥并强制关闭 PCI_COMMAND_INTX_DISABLE 是一种令人作呕的黑客行为,如果是这种情况或导致系统挂起的混乱,我不会感到惊讶。

无论如何,所以我在这里迷路和困惑。有谁知道我做错了什么?我应该如何获得该系统桥以允许遗留中断通过?

在此先感谢您的帮助!

4

0 回答 0