本文共 1213 字,大约阅读时间需要 4 分钟。
PCI/PCIE协议还是很完美的,所以目前很是流行。所以linux内核主线代码是严格按照协议来的,例如pci_read_bases(dev, 6, PCI_ROM_ADDRESS);轮流获取6个MEM空间大小。
但是由于开发是存在BUG,或者开发者没有彻底理解PCI/PCIE或是别的原因,很多设备并没有严格按照PCI/PCIE协议来实现。
例如,有的设备实际上只有一个有效的BASE_ADDRESS地址,但是实际探测有N个地址,部分无效的地址空间还特别大,导致地址空间不够,后面别的PCI设备无法获取地址。
针对这种情况,linux内核做了妥协,允许驱动初始化流程在某个阶段可以修改前面阶段的一些资源,也就是数据结构。
enum pci_fixup_pass { pci_fixup_early, /* Before probing BARs */ pci_fixup_header, /* After reading configuration header */ pci_fixup_final, /* Final phase of device fixups */ pci_fixup_enable, /* pci_enable_device() time */ pci_fixup_resume, /* pci_device_resume() */ pci_fixup_suspend, /* pci_device_suspend */ pci_fixup_resume_early, /* pci_device_resume_early() */};
刚才讲的那种情况,可以在pci_fixup_header阶段修正,方法如下:
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_XXX, PCI_DEVICE_ID_IBM_XXX, fixup_xxx_pci_bar);//只保留BASE_ADDRESS0的资源信息,其它5个BAR的资源信息全部清除static void fixup_xxx_pci_bar(struct pci_dev *dev) for (i = 1; i < DEVICE_COUNT_RESOURCE; i++) { dev->resource[i].start = dev->resource[i].end = 0; dev->resource[i].flags = 0; }
生效的位置:获取BASE_ADDREESS大小之后,分配PCI/PCIE域到BASE_ADDREESS里面之前
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) /* Fix up broken headers */ pci_fixup_device(pci_fixup_header, dev);
转载地址:http://uvlji.baihongyu.com/