我知道PCI配置空间中的基地址寄存器(BAR)定义了PCI地址的起始位置,但该区域的大小是如何建立的?
当然这是硬件的属性,因为它只知道它可以处理的地址空间有多远.但是,我似乎无法在PCI配置结构中看到BAR大小字段.
看完这里的内核文档后:https://www.kernel.org/doc/Documentation/PCI/pci.txt关于设置和拆除PCI驱动程序的函数调用的顺序,我很遗憾.
我有两个问题:
对于设置,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()始终是第一位的.这些电话中的哪一个应该首先出现,为什么?
为了拆掉司机,我更加困惑.假设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)
在拆除驱动程序时应该首先使用哪种功能?看来内核中的驱动程序本身无法达成一致.
我需要扫描我的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) 我一直在阅读PCIe规范的恐怖,但仍无法对以下问题对得到任何解决方案.
PCIe是否允许映射超过4GB边界的巨大(例如16GB)64位非预取内存空间?或者它们仍然与32位时的1GB相同,并且没有办法要求巨大的非预取空间?
假设规范允许它(以及我的读取它),广泛可用的BIOS支持它吗?或者它在理论上是允许的,但在实践中却没有完成?
我正在尝试mmap()为PCIe BAR 编写一个带有自定义函数的驱动程序,目标是使这个BAR可以在处理器缓存中缓存.我知道这不是实现最高带宽的最佳方式,并且写入顺序是不可预测的(在这种情况下也不是问题).
处理器是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,尽管代码不同.
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 "之外,它没有任何解释.
我想在任何给定的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支持?
我正在尝试通过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) 在注册 PCI 驱动程序之前,我们必须对其进行初始化struct pci_driver并将其传递给 pci_register_driver. 该结构的字段之一是指向驱动程序probe函数的指针。
我的问题是 - 当内核调用驱动程序的探测例程时。是否保证在调用后立即pci_register_driver发生或可能发生在任何其他时间?是什么决定了这种行为?
UPDATE
pci_register_driver是一个扩展为 的宏__pci_register_driver,它依次调用driver_register和driver_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_attach将bus_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 设置了标志。
目前正在研究 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)