如何枚举PCIE capability

1.      Capability 的组织结构

根据PCIE SPEC 3.0,PCIEcapability的布局如下:落在offset0x00~0xff之间的属于PCIE capability structure对应于PCI配置空间;而落在offset0x100~0x1000之间的属于extendedPCIE capability, 对应于PCIEextended 配置空间。

2.      Capability的检索

根据PCIE规范,每个capability结构包括如下两个部分:

·        Capability ID: 用来标示属于哪类的capabiliy

·        Next capability pointer:  是一个从0算起的offset,制定了下一个capability的位置,其为0 表示最后一个capability.

根据规范,下面代码include/linux/pci_regs.h归纳了capabilityID和各个capability名称的对应关系:

/* Capability lists */

#define PCI_CAP_LIST_ID   0 /* Capability ID */

#define  PCI_CAP_ID_PM    0x01 /* Power Management */

#define  PCI_CAP_ID_AGP   0x02 /* Accelerated Graphics Port */

#define  PCI_CAP_ID_VPD   0x03 /* Vital Product Data */

#define  PCI_CAP_ID_SLOTID  0x04 /* Slot Identification */

#define  PCI_CAP_ID_MSI   0x05 /* Message Signalled Interrupts */

#define  PCI_CAP_ID_CHSWP 0x06  /* CompactPCI HotSwap */

#define  PCI_CAP_ID_PCIX  0x07 /* PCI-X */

#define  PCI_CAP_ID_HT    0x08 /* HyperTransport */

#define  PCI_CAP_ID_VNDR  0x09 /* Vendor specific */

#define  PCI_CAP_ID_DBG   0x0A /* Debug port */

#define  PCI_CAP_ID_CCRC  0x0B /* CompactPCI Central Resource Control */

#define  PCI_CAP_ID_SHPC  0x0C /* PCI Standard Hot-Plug Controller */

#define  PCI_CAP_ID_SSVID 0x0D  /* Bridge subsystem vendor/device ID */

#define  PCI_CAP_ID_AGP3  0x0E /* AGP Target PCI-PCI bridge */

#define  PCI_CAP_ID_EXP   0x10 /* PCI Express */

#define  PCI_CAP_ID_MSIX  0x11 /* MSI-X */

#define  PCI_CAP_ID_AF    0x13 /* PCI Advanced Features */

#define PCI_CAP_LIST_NEXT 1 /*Next capability in the list */

#define PCI_CAP_FLAGS   2 /* Capability defined flags (16 bits) */

#define PCI_CAP_SIZEOF    4

 

利用上面next capability pointer, 一旦找到第一个capability,就能顺藤摸瓜找到挂在链子上的所有capability.那么问题来了,第一个capability是如何定位到的呢?秘密就在driver/pci/pci.c中的函数:

static int__pci_bus_find_cap_start(struct pci_bus *bus, unsigned int devfn, u8 hdr_type)

它根据不同的hdr_type来返回不同的起始位置:

static int__pci_bus_find_cap_start(struct pci_bus *bus,

unsigned int devfn, u8 hdr_type)

{

u16 status;

 

pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);

if (!(status & PCI_STATUS_CAP_LIST))

return 0;

 

switch (hdr_type) {

case PCI_HEADER_TYPE_NORMAL:

case PCI_HEADER_TYPE_BRIDGE:

return PCI_CAPABILITY_LIST;

case PCI_HEADER_TYPE_CARDBUS:

return PCI_CB_CAPABILITY_LIST;

default:

return 0;

}

 

return 0;

}

3.      内核中和capability的相关代码:

主要的代码在driver/pci/pci.c,相关的函数有很多,下面列出很少的一部分:

int pci_find_capability(struct pci_dev*dev, int cap);

intpci_find_next_capability(struct pci_dev *dev, u8 pos, int cap);

int pci_find_ext_capability(struct pci_dev*dev, int cap)