标签: pci

如何确定PCI/PCIe BAR尺寸?

我知道PCI配置空间中的基地址寄存器(BAR)定义了PCI地址的起始位置,但该区域的大小是如何建立的?

当然这是硬件的属性,因为它只知道它可以处理的地址空间有多远.但是,我似乎无法在PCI配置结构中看到BAR大小字段.

pci pci-e

9
推荐指数
2
解决办法
2万
查看次数

Linux PCI驱动程序设置和拆解

看完这里的内核文档后:https://www.kernel.org/doc/Documentation/PCI/pci.txt关于设置和拆除PCI驱动程序的函数调用的顺序,我很遗憾.

我有两个问题:

  1. 对于设置,pci_enable_device()总是来之前 pci_request_regions()?文档似乎指出了这个事实,但确实说明:

    OS BUG:在启用这些资源之前,我们不会检查资源分配.如果我们pci_request_resources()在打电话之前打电话,序列会更有意义 pci_enable_device().目前,当两个设备分配了相同的范围时,设备驱动程序无法检测到错误.这不是常见问题,不太可能很快修复.这已经在之前讨论过,但在2.6.19之后没有改变:http://lkml.org/lkml/2006/3/2/194

    但是,在快速浏览了几个驱动程序的源代码之后,我们的共识是pci_enable_device()始终是第一位的.这些电话中的哪一个应该首先出现,为什么?

  2. 为了拆掉司机,我更加困惑.假设pci_enable_device()是第一个,我希望你在调用pci_release_regions()之前首先调用pci_disable_device()(即遵循一些对称性).但是,内核文档说这pci_release_regions()应该是最后的.让事情变得更复杂的是,我看了很多司机,而且几乎所有司机都有pci_release_regions()pci_disable_device(),就像我期望的那样.但是,我偶然发现了这个驱动程序:https://elixir.bootlin.com/linux/v4.12/source/drivers/infiniband/hw/hfi1/pcie.c(代码转载如下).

    void hfi1_pcie_cleanup(struct pci_dev *pdev)
    {
        pci_disable_device(pdev);
        /*
         * Release regions should be called after the disable. OK to
         * call if request regions has not been called or failed.
         */
        pci_release_regions(pdev);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    在拆除驱动程序时应该首先使用哪种功能?看来内核中的驱动程序本身无法达成一致.

c linux-device-driver linux-kernel pci pci-e

9
推荐指数
1
解决办法
443
查看次数

如何在Windows中获取PCI区域大小?

我需要扫描我的PCI总线并获取特定供应商的特定设备的信息.我的目标是找到AMD显卡的PCI区域大小,以便将该卡的PCI内存映射到用户空间,以便进行i2c传输并查看来自各种传感器的信息.

为了扫描PCI总线,我在大约一年前下载并编译了pciutils 3.1.7 for Windows x64.据说它使用DirectIO.

这是我的代码.

int scan_pci_bus()
{
    struct pci_access *pci;
    struct pci_dev *dev;
    int i;

    pci = pci_alloc();
    pci_init(pci);

    pci_scan_bus(pci);

    for(dev = pci->devices; dev; dev = dev->next) 
    {
        pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_PHYS_SLOT);
        if(dev->vendor_id == 0x1002 && dev->device_id == 0x6899)
        {
            //Vendor is AMD, Device ID is a AMD HD5850 GPU
            for(i = 0; i < 6; i++) 
            {
                printf("Region Size %d %x ID %x\n", dev->size[i], dev->base_addr[i], dev->device_id); …
Run Code Online (Sandbox Code Playgroud)

c windows size regions pci

8
推荐指数
1
解决办法
2750
查看次数

PCIe 64位非预取空间

我一直在阅读PCIe规范的恐怖,但仍无法对以下问题对得到任何解决方案.

  1. PCIe是否允许映射超过4GB边界的巨大(例如16GB)64位非预取内存空间?或者它们仍然与32位时的1GB相同,并且没有办法要求巨大的非预取空间?

  2. 假设规范允许它(以及我的读取它),广泛可用的BIOS支持它吗?或者它在理论上是允许的,但在实践中却没有完成?

pci pci-e

7
推荐指数
1
解决办法
8778
查看次数

如何为可缓存的PCIe BAR执行mmap

我正在尝试mmap()为PCIe BAR 编写一个带有自定义函数的驱动程序,目标是使这个BAR可以在处理器缓存中缓存.我知道这不是实现最高带宽的最佳方式,并且写入顺序是不可预测的(在这种情况下也不是问题).

这类似于如何阻止MMAP缓存值中描述的内容?

处理器是Sandy Bridge i7,PCIe器件是Altera Stratix IV dev.板.

首先,我尝试在CentOS 5(2.6.18)上进行.我改变了MTRR设置,以确保酒吧是不是不可缓存MTRR内,并使用io_remap_pfn_range()_PAGE_PCD_PAGE_PWT清除位.读取按预期工作:读取返回正确的值,第二次读取到同一地址不一定导致读取到PCIe(在FPGA中检查读取计数器).但是,写入导致系统冻结然后重新启动,而日志或屏幕上没有任何消息.

其次,我尝试在具有PAT支持的CentOS 6(2.6.32)上进行.结果是一样的:读取工作正常,写入会导致系统冻结并重新启动.有趣的是,非时间/写入组合完整高速缓存行写入(AVX/SSE)按预期工作,即它们总是进入FPGA并且FPGA观察完整的高速缓存行写入,读取之后返回正确的值.但是,简单的64位写入仍会导致系统冻结/重启.

我也尝试过ioremap_cache()然后iowrite32()在驱动程序代码中.结果是一样的.

我认为这是一个硬件问题,但如果有人可以分享有关正在发生的事情的任何想法,我将不胜感激.

编辑:我能够在CentOS 6上捕获MCE消息:机器检查异常:5 Bank 5:be2000000003110a.

我也尝试在2插槽Sandy Bridge(Romley)上使用相同的代码:读取和非临时写入行为是相同的,简单写入不会导致MCE /崩溃但对系统状态没有影响,即内存中的值不会改变.

此外,我在旧的2插槽Nehalem系统上尝试了相同的代码:简单的写入也会导致MCE,尽管代码不同.

caching mmap pci pci-e

7
推荐指数
1
解决办法
3576
查看次数

pci_enable_device和pcim_enable_device有什么区别?

本书PCI章节解释了:

int pci_enable_device(struct pci_dev *dev);
Run Code Online (Sandbox Code Playgroud)

但是还有:

int pcim_enable_device (struct pci_dev * pdev);
Run Code Online (Sandbox Code Playgroud)

但除了声明它是" 托管pci_enable_device "之外,它没有任何解释.

  1. 那么这两者之间的区别是什么?
  2. 这是什么意思,它是"管理"的?
  3. 我应该使用哪一个?

linux-device-driver linux-kernel pci pci-e

7
推荐指数
1
解决办法
1702
查看次数

检查linux上的IOMMU支持

我想在任何给定的Linux机器上验证是否支持PCI passthrough.经过一段谷歌搜索后,我发现我应该检查是否支持IOMMU,我这样做是通过运行:

dmesg | grep IOMMU   
Run Code Online (Sandbox Code Playgroud)

如果它支持IOMMU(而不是IOMMUv2),我会得到:

IOMMU                                                          
[    0.000000] DMAR: IOMMU enabled
[    0.049734] DMAR-IR: IOAPIC id 8 under DRHD base  0xfbffc000 IOMMU 0
[    0.049735] DMAR-IR: IOAPIC id 9 under DRHD base  0xfbffc000 IOMMU 0
[    1.286567] AMD IOMMUv2 driver by Joerg Roedel <jroedel@suse.de>
[    1.286568] AMD IOMMUv2 functionality not available on this system
Run Code Online (Sandbox Code Playgroud)

...... DMAR: IOMMU enabled我正在寻找的地方.

现在,如果计算机在没有重新启动的情况下运行了几天,那么[ 0.000000] DMAR: IOMMU enabled 使用上一个命令在日志中可能不再出现该第一条消息.

当该消息从日志中消失时,有没有办法检查IOMMU支持?

linux pci iommu

7
推荐指数
1
解决办法
2万
查看次数

在Linux上查找并行端口的内存地址

我正在尝试通过PCI Express卡找到我已连接到笔记本电脑的并行端口的基本(内存)地址.运行lspci -v显示我的计算机识别并行端口并提供I/O端口(1000和1008)但不提供内存地址(其他条目同时具有端口和内存位置......此卡是唯一没有内存地址的条目).此外,当我查看时,/proc/ioports我得到了lspci中给出的相同端口.但是,当我尝试在我正在运行的程序中使用这些地址中的任何一个(EMC2来控制步进电机)时,它在该地址处找不到并行端口.

如果有一个类似于Windows设备管理器 - >端口 - >资源的话,那真的很棒.在Ubuntu中有没有办法做到这一点?PCIe设备是否有标准内存位置?

编辑: 来自的输出lspci -v

04:00.0 Parallel controller: Oxford Semiconductor Ltd Device c110 (prog-if 02)
Subsystem: Oxford Semiconductor Ltd Device c110
Flags: bus master, fast devsel, latency 0, IRQ 18
I/O ports at 1000 [size=8]
I/O ports at 1008 [size=4]
Capabilities: [40] Power Management version 3
Capabilities: [50] Message Signalled Interrupts: Mask- 64bit+ Queue=0/0 Enable-
Capabilities: [70] Express Legacy Endpoint, MSI 00
Capabilities: [100] Device Serial Number 10-01-00-11-11-e0-30-00
Capabilities: …
Run Code Online (Sandbox Code Playgroud)

linux memory-address parallel-port pci

6
推荐指数
1
解决办法
1万
查看次数

Linux什么时候调用PCI驱动的probe函数?

在注册 PCI 驱动程序之前,我们必须对其进行初始化struct pci_driver并将其传递给 pci_register_driver. 该结构的字段之一是指向驱动程序probe函数的指针。

我的问题是 - 当内核调用驱动程序的探测例程时。是否保证在调用后立即pci_register_driver发生或可能发生在任何其他时间?是什么决定了这种行为?

UPDATE pci_register_driver是一个扩展为 的宏__pci_register_driver,它依次调用driver_registerdriver_register调用bus_add_driver.

中有以下代码bus_add_driver

if (drv->bus->p->drivers_autoprobe) {
        error = driver_attach(drv);
        if (error)
            goto out_unregister;
}
Run Code Online (Sandbox Code Playgroud)

driver_attachbus_for_each_dev使用参数__driver_attach调用,它将调用driver_probe_device

driver_probe_device最终调用really_probe

if (dev->bus->probe) {
    ret = dev->bus->probe(dev);
Run Code Online (Sandbox Code Playgroud)

我不确定的一件事是,是否drivers_autoprobe为 pci_bus 设置了标志。

linux linux-device-driver linux-kernel pci

6
推荐指数
2
解决办法
6820
查看次数

MSI 中断在 Linux 驱动程序中如何工作?

目前正在研究 PCI 设备驱动程序。设备的编程如下:
当 DMA 传输完成时,设备向 PC 发送 MSI 中断,其中包含 MSI 数据“001”二进制。

现在我正在为这个 pci 设备编写一个驱动程序,对于 MSI 部分,我有一些问题。

在维基百科中,它说:

MSI允许设备将少量中断描述数据写入特殊的内存映射I/O地址,然后芯片组将相应的中断传递给处理器。

Q1:那么就我而言,是small amount of interrupt-describing data"001"pci 设备发送到 PC 的吗?

在我的驱动程序代码中,MSI irq 的注册方式如下:

err = pci_enable_msi(my_pci_dev);  
err = request_irq(my_pci_dev->irq, irq_handler, 0, "PCI_FPGA_CARD", NULL);  
Run Code Online (Sandbox Code Playgroud)

irq_handler定义如下:

static irqreturn_t irq_handler(int irq, void *dev_id)  
{  
  printk(KERN_INFO "(irq_handler):  Called\n");  
  return IRQ_HANDLED;
}  
Run Code Online (Sandbox Code Playgroud)

Q2:有了上面的3个内核函数,我们如何获取消息呢"001"
Q3: PCI 设备最多支持 8 个 MSI 矢量,因此要使用所有这 8 个矢量,我应该使用下面的代码,否则都不正确:

err = pci_enable_msi_block(my_pci_dev,8);
err = request_irq(my_pci_dev->irq, irq_handler, 0, …
Run Code Online (Sandbox Code Playgroud)

linux interrupt linux-device-driver dma pci

6
推荐指数
1
解决办法
1万
查看次数