首页 > 解决方案 > Linux 内核如何设置 PCI BAR 以保证没有地址冲突?

问题描述

据我了解,(这很可能是错误的)每个 PCI 设备都知道它想要声明多少(大小)iomem/ioport 地址空间,但它不知道在哪里(偏移量)。只有 BIOS 或 OS 可以告诉设备该位置应该在哪里,因为有人必须与所有 PCI 设备通信并协调它们的 iomem/ioport 地址分配请求,以便分配的地址不会重叠,并且这种协调发生在启动时,或热插拔事件,或在pci 重新扫描期间。但是,在 Linux 内核代码中,我只找到了一个函数 ( pci_read_bases),它读取 BAR 信息,并相应地设置pci_dev& iomem_resource/ ioport_resource,而不是更改 BAR。所以问题是:

  1. 操作系统(Linux 内核)可以更改 BAR 吗?还是只有 BIOS 才能在加载操作系统之前做到这一点?
  2. 如果内核可以更改 BAR,那么协调地址分配的逻辑在哪里?(我确实看到了类似的函数pbus_assign_resources_sorted,但在我看来,该函数仅将现有的 BAR 映射到内核对象,例如iomem_resource,而不是更改 BAR)

标签: ciolinux-kernelpci

解决方案


对于正常的静态分配,BIOS 写入 BAR,内核在启动时读取它们。有趣的是动态分配的设备,例如 NVMe 卡的热插拔。在这种情况下,BIOS 必须保留一个范围,以防插入的设备在启动时不存在或大于移除的设备。内核收到一个中断,必须读取新的 BAR 值并将它们添加到地址空间。参见例如nvme_remap_bar https://elixir.bootlin.com/linux/v5.4/source/drivers/nvme/host/pci.c#L1649


推荐阅读