PCIE 区域未对齐,且不一致

Posted

技术标签:

【中文标题】PCIE 区域未对齐,且不一致【英文标题】:PCIE region not aligned, and not consistent 【发布时间】:2017-11-03 02:47:27 【问题描述】:

我正在为 openwrt 开发 PCIE 设备驱动程序,在尝试访问定时器中断中的 io-memory 时遇到数据总线错误,我在 last question 中提到过。经过大量研究,我想我可能找到了原因,但我无法解决它。以下是我的烦恼。

上周我发现 pcie 区域大小可能在系统启动期间发生了变化。我的驱动中 bar0 的区域大小为 4096(从pci_resource_len 返回),lspci -vv 中的区域大小为 4097,这打破了 linux 内核的页面大小。通过阅读pciutil的源码,我发现lspci命令从/sys/devices/pci0000:00/0000:00:00.0/resouce文件中获取pcie信息。所以我删除了我所有的自定义组件并在我的路由器上运行原来的 openwrt。通过cat /sys/devices/pci0000:00/0000:00:00.0/resouce,结果的第一行(bar0)是

0x0000000010008000 0x0000000010009000 0x0000000000040200

另外我还查了/proc/iomem的内容,和PCIE相关的内容是

10000000-13ffffff : mem_base
    10000000-13ffffff : PCI memory space
        10000000-10007fff : 0000:00:00.0
        10008000-10008fff : 0000:00:00.0

上面两个文件表示的bar0的区域大小不一样,超级奇怪!根据 PCIE 的机制,region size 应该是 2 的幂,region size 怎么会变成 4097?

【问题讨论】:

【参考方案1】:

花了几个星期阅读linux内核的源代码后,我发现这是linux kernel 4.4.14的一个bug。

/sys/devices/pci0000:00/0000:00:00.0/resouce 的内容是通过文件drivers/pci/pci-sysfs.c 中的函数resource_show 生成的。相关代码是

for (i = 0; i < max; i++) 
    struct resource *res =  &pci_dev->resource[i];
    pci_resource_to_user(pci_dev, i, res, &start, &end);
    str += sprintf(str, "0x%016llx 0x%016llx 0x%016llx\n",
               (unsigned long long)start,
               (unsigned long long)end,
               (unsigned long long)res->flags);

实际调用的函数pci_resource_to_user位于arch/mips/include/asm/pci.h

static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
        const struct resource *rsrc, resource_size_t *start,
        resource_size_t *end)

    phys_addr_t size = resource_size(rsrc);

    *start = fixup_bigphys_addr(rsrc->start, size);
    *end = rsrc->start + size;

*end的计算有误,应该替换为

*end = rsrc->start + size - (size ? 1 : 0)

【讨论】:

以上是关于PCIE 区域未对齐,且不一致的主要内容,如果未能解决你的问题,请参考以下文章

scikit-learn MLPRegressor 预测结果总是变化且不一致

Ubuntu 16.04.6 + Win10 双系统时间错误且不一致

UIcollectionView 标签如何向左对齐

PCIe Dma coherent

PCIe Dma coherent

ArcGIS处理每个栅格图行列号一致且上下对齐