Linux 64 位 BAR 编程

标签 linux pci-e

PCI 桥支持 32/64 pref/no pref:

pci_bus 0000:00: root bus resource [bus 00-ff]
pci_bus 0000:00: root bus resource [io  0x0000-0xffff] 
pci_bus 0000:00: root bus resource [mem 0x1000000000-0x10ffffffff] (bus address [0x00000000-0xffffffff])
pci_bus 0000:00: root bus resource [mem 0x1100000000-0x11ffffffff pref] (bus address [0x00000000-0xffffffff])
pci_bus 0000:00: root bus resource [mem 0x2000000000-0x2fffffffff] (bus address [0x00000000-0xfffffffff])
pci_bus 0000:00: root bus resource [mem 0x3000000000-0x3fffffffff pref] (bus  address [0x00000000-0xfffffffff])

使用 2 个 BAR 扫描端点:

pci 0000:01:00.0: BAR 2: assigned [mem 0x2100000000-0x211fffffff 64bit pref]
pci 0000:01:00.0: BAR 0: assigned [mem 0x1000000000-0x100007ffff]

桥上有 window :

pci 0000:00:00.0: PCI bridge to [bus 01]
pci 0000:00:00.0:   bridge window [mem 0x1000000000-0x10000fffff]
pci 0000:00:00.0:   bridge window [mem 0x2100000000-0x211fffffff 64bit pref]

端点总结了 BAR:

endpoint: BAR 0 addr = 0x1000000000, size = 524287
endpoint: BAR 1 addr = 0x2100000000, size = 536870911

BAR1 的高 32 位将被编程为什么?我期望 0x21,但找到 0x1。

这是因为 pcibios_bus_to_resource/pcibios_resource_to_bus。 它标识了 3 个窗口偏移量:

window->res->start = 1000000000 window->offset = 1000000000 window->res->end = 10FFFFFFFF
window->res->start = 1100000000 window->offset = 1100000000 window->res->end = 11FFFFFFFF
window->res->start = 2000000000 window->offset = 2000000000 window->res->end = 2FFFFFFFFF

显示上面地址时加上偏移量,编程BAR时减去偏移量 在端点注册。所以 0x2100000000 变成 0x100000000。

这对于 64 位地址和 32 位 BAR 可能有意义,但为什么对于 64 位 BAR 就正确呢?

最佳答案

据此(取自问题):

    pci_bus 0000:00: root bus resource [mem 0x1000000000-0x10ffffffff] (bus address [0x00000000-0xffffffff])
    pci_bus 0000:00: root bus resource [mem 0x1100000000-0x11ffffffff pref] (bus address [0x00000000-0xffffffff])
    pci_bus 0000:00: root bus resource [mem 0x2000000000-0x2fffffffff] (bus address [0x00000000-0xfffffffff])
    pci_bus 0000:00: root bus resource [mem 0x3000000000-0x3fffffffff pref] (bus  address [0x00000000-0xfffffffff])

内存地址0x20'0000'0000对应总线地址0。

因此如果要使用内存地址 0x21'0000'0000 访问设备中的 BAR,则需要将其编程为 0x1'0000'0000。

类似地,内存地址0x10'0000'0000对应总线地址0。因此设备中的BAR被编程为0,以使用内存地址0x10'0000'0000访问。

关于Linux 64 位 BAR 编程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50244684/

相关文章:

linux - Freepbx自定义上下文出站路由

dma - DMA 和 PCIe 如何一起玩?

dma - PCIe卡如何将数据DMA到CPU RAM中?

linux - 每 245 分钟运行一次 cron

linux - 将多个变量从本地 bash 传递到远程 bash 脚本而无需吞噬

linux - 如何在行号处拆分文件

linux - struts2 Web 应用程序在 suse linux 中安装的 tomcat 7 中无法运行

Linux 网络驱动程序 MSI 中断问题

linux - ISR 内的 PCIe 读写

arm - PCIe 总线上的写入是原子的吗?