如何编写Linux PCIe设备驱动器 之二
功能(capability)集
功能(capability)APIs
int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val);
int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val);
int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val);
int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val);
int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos, u16 clear, u16 set);
int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos, u32 clear, u32 set);
读PCIe读请求大小代码
/**
* pcie_get_readrq - get PCI Express read request size
* @dev: PCI device to query
*
* Returns maximum memory read request in bytes or appropriate error value.
*/
int pcie_get_readrq(struct pci_dev *dev)
{
u16 ctl;
pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &ctl);
return 128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12);
}
通过pci_bus_read_config完成功能存取
int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val)
{
if (pci_dev_is_disconnected(dev)) {
PCI_SET_ERROR_RESPONSE(val);
return PCIBIOS_DEVICE_NOT_FOUND;
}
return pci_bus_read_config_word(dev->bus, dev->devfn, where, val);
}
static inline int pci_pcie_cap(struct pci_dev *dev)
{
return dev->pcie_cap;
}
int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val)
{
int ret;
*val = 0;
if (pos & 1)
return PCIBIOS_BAD_REGISTER_NUMBER;
if (pcie_capability_reg_implemented(dev, pos)) {
ret = pci_read_config_word(dev, pci_pcie_cap(dev) + pos, val);
if (ret)
*val = 0;
return ret;
}
if (pci_is_pcie(dev) && pcie_downstream_port(dev) &&
pos == PCI_EXP_SLTSTA)
*val = PCI_EXP_SLTSTA_PDS;
return 0;
}
功能APIs参数pos常量值
#define PCI_EXP_FLAGS 0x02 /* Capabilities register */
#define PCI_EXP_DEVCAP 0x04 /* Device capabilities */
#define PCI_EXP_DEVCTL 0x08 /* Device Control */
#define PCI_EXP_DEVSTA 0x0a /* Device Status */
#define PCI_EXP_LNKCAP 0x0c /* Link Capabilities */
#define PCI_EXP_LNKCTL 0x10 /* Link Control */
#define PCI_EXP_LNKSTA 0x12 /* Link Status */
#define PCI_EXP_SLTCAP 0x14 /* Slot Capabilities */
#define PCI_EXP_SLTCTL 0x18 /* Slot Control */
#define PCI_EXP_SLTSTA 0x1a /* Slot Status */
#define PCI_EXP_RTCTL 0x1c /* Root Control */
#define PCI_EXP_RTCAP 0x1e /* Root Capabilities */
#define PCI_EXP_RTSTA 0x20 /* Root Status */
下列的代码段读取PCIe的功能数据, 并存储在存储器中。
static int pci_save_pcie_state(struct pci_dev *dev)
{
int i = 0;
struct pci_cap_saved_state *save_state;
u16 *cap;
if (!pci_is_pcie(dev))
return 0;
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
if (!save_state) {
pci_err(dev, "buffer not found in %s\n", __func__);
return -ENOMEM;
}
cap = (u16 *)&save_state->cap.data[0];
pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &cap[i++]);
pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &cap[i++]);
pcie_capability_read_word(dev, PCI_EXP_SLTCTL, &cap[i++]);
pcie_capability_read_word(dev, PCI_EXP_RTCTL, &cap[i++]);
pcie_capability_read_word(dev, PCI_EXP_DEVCTL2, &cap[i++]);
pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &cap[i++]);
pcie_capability_read_word(dev, PCI_EXP_SLTCTL2, &cap[i++]);
return 0;
}
PCI功能结构
PCI功能ID
在PCI功能结构的PCIe功能ID具有下列的值
/* 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_SECDEV 0x0F /* Secure Device */
#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
#define PCI_CAP_ID_SATA 0x12 /* SATA Data/Index Conf. */
#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */
#define PCI_CAP_ID_EA 0x14 /* PCI Enhanced Allocation */
MSI功能
功能ID为PCI_CAP_ID_MS (0x05)。
PCIe设备需要 MSI中断支持。所有能够生成中断的 PCIe设备功能必须支持 MSI。 MSI 机制通过执行内存写入事务来传递中断。 MSI和MSI-X是边沿触发中断机制。
某些 PCI 设备及其驱动程序依赖于 INTx 类型电平触发中断行为。为了利用 MSI功能,以及边沿触发中断语义,这些设备及其驱动程序可能需要重新设计。
实现 MSI 的传统端点需要支持 MSI 功能结构的 32 位或 64 位消息地址版本。实现 MSI 的 PCIe端点需要支持 MSI 功能结构的 64 位消息地址版本。
MSI事务的请求者必须将事务描述符的 No Snoop 和 Relaxed Ordering 属性设置为 0b。如果启用了 IDO 属性的使用,则允许 MSI事务的请求者设置基于 ID 的排序(IDO)属性。
电源功率管理功能
功能ID为 PCI_CAP_ID_PM (0x01)。