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 预测结果总是变化且不一致