Skip to main content
PCIe 使用双向连接同时发送和接收信息,如下图所示。
PCIe 设备连接链路

图:PCIe 设备连接链路

设备之间的路径称为链路(Link)。它由一个或多个发送和接收对组成。链路中的一对称为通道(Lane)。Qualcomm Linux 设备中的 PCIe 设备连接支持 16 个通道。通道数或链路宽度为 x16。 下表列出了设备的 PCIe 连接类型。

表:PCIe 连接

PCIe 类型说明
根复合体(RC)将 CPU 连接到 PCIe 拓扑
交换机连接 2 个以上的端口并充当数据包路由器
桥连接不同的总线:例如,PCIe 到 PCIe,或 PCIe 到外设组件互连(PCI)
端点(EP)位于 PCIe 拓扑树结构的底部,只有一个上游端口
传统端点使用较旧的 PCI 总线操作以支持向后兼容

PCIe 主机模式枚举功能

系统首次上电时,在系统主机处理器上运行的配置软件只知道 Bus 0 的存在(如果支持 PCIe)。软件不了解总线拓扑或连接到总线的任何设备。枚举过程会发现系统中存在的各种总线、设备和功能。 枚举完成后,系统中的每条总线编号如下:
  • 主总线号表示直接连接到桥的主接口(朝向根复合体)的总线。
  • 次总线号表示直接连接到桥的次接口(远离根复合体)的总线。
  • 从属总线号表示存在于桥下游侧的编号最高的总线。
BDF 编号唯一标识每个设备。事务层数据包(TLP)的基于 ID 的路由方法使用此编号。PCIe 主机模式枚举过程包括以下步骤:
  1. 链路训练
  2. 扫描总线上的设备
  3. 注册
有关 PCIe 设备初始化、枚举过程的更多信息,请参阅 https://www.kernel.org/doc/html/latest/PCI/index.html。

PCIe 分层架构

下图展示了 PCIe 软件架构。
PCIe 软件架构

图:PCIe 软件架构

下图展示了 PCIe 的分层架构模型。
PCIe 分层架构

图:PCIe 分层架构

交换的传输单元如下。
  • 物理层实体之间的有序集(Ordered set)。
  • 数据链路层实体之间的数据链路层数据包(DLLP)。
  • 事务层实体之间的事务层数据包(TLP)。
下表列出了 PCIe 架构中的三个层及其各自的功能。

表:PCIe 架构中的层

层特性
物理层逻辑子块:链路训练、初始化和维护。
物理子块:8b/10b 编码和解码,以及并串和串并转换。
数据链路层DLLP 数据包的组装和拆卸。
链路层 CRC(LCRC)的生成和验证。
确认和否定确认协议(重传出错的 TLP)。
事务层TLP 数据包的组装和拆卸。
端到端 CRC(ECRC)的生成和验证。
流量控制:接收实体使用 DLLP 通告可用接收缓冲区大小信息。
服务质量(QoS):流量类别(TC)到虚拟通道(VC)的映射。
事务排序:在 VC 内实现事务排序规则。
PCI 为每个功能定义了一个专用的配置地址空间块,如下图所示。软件确定功能的存在、对其进行配置,并检查和控制其状态。
PCIe 配置地址空间

图:PCIe 配置地址空间

PCIe 软件驱动程序配置

PCIe 控制器驱动程序初始化 PCIe 资源并执行链路训练。训练成功后,控制器驱动程序调用 PCIe 框架进行链路枚举,例如端点发现、识别客户端驱动程序并探测这些驱动程序。有关 PCIe 框架和客户端驱动程序 PCIe 注册的更多信息,请参阅 https://www.kernel.org/doc/html/latest/PCI/index.html。

链路训练

链路训练包括以下操作:
  1. 位于 https://github.com/torvalds/linux/blob/master/drivers/pci/controller/dwc/pcie-qcom.c 的 PCIe 驱动程序 pcie-qcom.c 文件从设备树获取所需资源,例如稳压器、时钟。
  2. PCIe 驱动程序调用位于 https://github.com/torvalds/linux/blob/master/drivers/pci/controller/dwc/pcie-designware-host.c 的 Synopsys DesignWare® Core 主机驱动程序 pcie-designware-host.c 文件来初始化根复合体。
  3. Synopsys DesignWare Core 驱动程序执行所有必要的初始化。
  4. Synopsys DesignWare Core 驱动程序调用函数指针以执行主机初始化。
  5. Qualcomm PCIe 驱动程序执行 PHY 上电,启用所有稳压器、时钟。
  6. Synopsys DesignWare Core 驱动程序通过调用启动链路的函数指针来开始链路训练。

硬件初始化

驱动程序初始化并配置 PCIe 硬件模块并执行链路训练。初始化在调用 platform _probe() 驱动函数之后进行。
当 Synopsys DesignWare Core 驱动程序初始化时,它还会初始化 MSI、MSIx 和控制器。该驱动程序调用 Qualcomm 函数指针以开始链路训练。
Synopsys DesignWare Core 驱动程序等待链路激活后再枚举 PCI 框架。Qualcomm PCIe 驱动程序仅启用链路训练。
注意:PCIE_0 根复合体实例默认启用,用于 WLAN EP 连接。

为 Dragonwing IQ-9075(Lemans)启用 PCIe 端点(EP)模式

Dragonwing IQ-9075(Lemans)上的每个 PCIe 控制器实例都可以运行在根复合体(RC)或端点(EP)模式,但不能同时运行两种模式。设备树在同一基地址处为每种模式定义了单独的节点,并且每个 PCIe 实例每次只能启用其中一个。
注意:Monaco 也支持 PCIe EP 模式,但该支持尚未包含在当前内核代码树中,计划在后续版本中提供。

表:Lemans PCIe EP 节点

EP 节点RC 节点(互斥)Compatiblenum-laneslinux,pci-domain
pcie0_eppcie0qcom,sa8775p-pcie-ep20
pcie1_eppcie1qcom,sa8775p-pcie-ep41
pcie0_ep 和 pcie1_ep 均在 arch/arm64/boot/dts/qcom/lemans.dtsi 中定义,且默认 status = "disabled",因为对应的 RC 节点(pcie0、pcie1)已启用。绑定到这些节点的 Qualcomm PCIe EP 控制器驱动程序为 drivers/pci/controller/dwc/pcie-qcom-ep.c(驱动名称 qcom-pcie-ep)。

PCIe EP 模式内核配置

CONFIG_PCI_ENDPOINT 和 CONFIG_PCI_ENDPOINT_CONFIGFS 已在 Lemans defconfig 中启用。用于构建 Qualcomm EP 控制器驱动程序的 CONFIG_PCIE_QCOM_EP 默认未启用,必须开启才能启用 EP 模式。CONFIG_PCI_EPF_MHI 及其依赖项 CONFIG_MHI_BUS_EP 也默认未启用,必须开启才能使用 MHI 端点功能。 要启用这些配置,请将以下补丁应用到 arch/arm64/configs/defconfig 文件。
注意:CONFIG_PCIE_QCOM_EP 依赖 CONFIG_PCI_ENDPOINT,并选择 drivers/pci/controller/dwc/Kconfig 中定义的 CONFIG_PCIE_DW_EP 和 CONFIG_PCIE_QCOM_COMMON。CONFIG_PCI_EPF_MHI 定义于 drivers/pci/endpoint/functions/Kconfig,依赖 CONFIG_MHI_BUS_EP——即 drivers/bus/mhi/ep/Kconfig 中的 MHI 端点总线实现。

在设备树中启用 EP 节点

pcie1(RC)和 pcie1_ep(EP)都在 lemans.dtsi 中通过标签定义,且 pcie1 在其中默认 status = "disabled"。然而,lemans-evk.dts 又通过板载 M.2 E-key 连接器将 pcie1 重新启用为 RC 模式(&pcie1 { ... status = "okay"; };)。由于每个 PCIe 实例在同一时间只能处于 RC 或 EP 中的一种模式,因此在 Lemans EVK 上将 PCIE_1 切换为 EP 模式意味着禁用该 RC 覆盖,并改为启用 pcie1_ep。将以下更改应用到 arch/arm64/boot/dts/qcom/lemans-evk.dts:
pcie1_default_state(在 lemans-evk.dts 靠后位置的 &tlmm 节点中定义)为 GPIO 4 (PERST#) 和 GPIO 5 (WAKE#) 设置了引脚功能、驱动强度和偏置,但没有固定它们的方向,因此 EP 节点可以复用与 RC 模式相同的 pinctrl 组和物理 GPIO。但是,每个 GPIO 上的信号方向会在两种模式之间反转:
  • 在 RC 模式下,pcie-qcom.c 将 PERST# GPIO 请求为 GPIOD_OUT_HIGH——根复合体驱动 PERST# 以复位下行设备。RC 模式不驱动 WAKE# GPIO。
  • 在 EP 模式下,pcie-qcom-ep.c 将 reset-gpios 请求为 GPIOD_IN——端点将 PERST# 作为输入读取,由连接的根复合体驱动;并将 wake-gpios 请求为 GPIOD_OUT_LOW——端点将 WAKE# 作为输出驱动到主机。
GPIO 方向由驱动程序在 probe 时根据其匹配的模式绑定设置,而不是由 pinctrl 组设置,因此不需要为方向切换额外修改设备树。
注意:上游 qcom,pcie-ep.yaml 绑定要求提供 reset-gpios,即连接到由所连接根复合体驱动的 PERST# 输入的 GPIO。lemans.dtsi 中的 pcie1_ep 节点没有定义该属性,因为它是板卡相关的。
同样的步骤也适用于 PCIE_0:禁用 pcie0 RC 覆盖,改为启用 pcie0_ep,复用 pcie0_default_state pinctrl 组及其 PERST#/WAKE# GPIO。
注意:禁用 pcie0 也会同时禁用 M.2 E-key 连接器的 PCIe 链路(pcieport0),因为该连接器在 RC 模式下接线到 PCIE_0。仅当你不需要将 M.2 连接器用于 PCIe 卡时,才将 PCIE_0 切换到 EP 模式。
phys、iommus、interconnects、power-domains、clocks 和 resets 已在两个 EP 节点中填充完毕,标准 bring-up 时无需修改。

PCIe EP 驱动初始化

pcie-qcom-ep.c 中的 qcom_pcie_ep_probe() 会获取 parf、dbi、mmio 和 dma 寄存器区域、全部五个实例时钟、core 复位、reset(PERST#)和可选的 wake(WAKE#) GPIO,以及可选的 pciephy PHY,然后调用公共的 DesignWare dw_pcie_ep_init() 来初始化端点核心。Lemans 匹配 qcom,sa8775p-pcie-ep compatible 字符串,该字符串选择 cfg_1_34_0 配置(启用 HDMA 支持、NO_SNOOP 覆盖,并禁用 MHI RAM 奇偶校验)。 一个全局 IRQ 线程(qcom_pcie_ep_global_irq_thread())用于处理由连接的根复合体触发的链路建立/断开事件、总线主控使能(BME),以及 PM turn-off/D 状态通知。

使用 configfs 绑定 MHI 端点功能

pci-epf-mhi.c 驱动在 pci_epf_mhi_ids[] 中为每个 SoC 注册一个设备 ID,每个都有各自的 header(vendor/device ID)和 MHI 通道配置。Lemans 匹配 pci_epf_mhi_sa8775p 条目,该条目设置设备 ID 0x0116,使用 BAR_0、32 个 MSI 向量、MRU 为 0x8000,并启用 DMA 辅助传输(MHI_EPF_USE_DMA)。该条目还选择标准的 mhi_v1_channels 表(LOOPBACK、SAHARA、DIAG、SSR、QDSS、EFS、MBIM、QMI、IP-CTRL-1、IPCR、DUN、IP_SW0)。header 和通道配置由此条目固定,因此无需通过 configfs 写入 vendorid/deviceid。 内核在启用 pcie1_ep 的情况下启动后,使用 PCI 端点 configfs 接口将 MHI 端点功能绑定到 qcom-pcie-ep 控制器。functions 目录名称必须与 pci_epf_mhi_sa8775p 条目匹配,以便探测到正确的设备 ID 和通道表。
向 start 写入 1 会声明端点已就绪,允许链路与连接的根复合体进行训练。pci_epf_mhi_bind() 会从父 qcom-pcie-ep 平台设备中查找 mmio 寄存器区域和 doorbell 中断,而 pci_epf_mhi_link_up() 会在链路建立后注册 MHI 端点控制器。
注意:如果 mhi_bus_ep 和 pci_epf_mhi 构建为独立模块,请先加载 mhi_bus_ep,因为 CONFIG_PCI_EPF_MHI 依赖 CONFIG_MHI_BUS_EP。

验证 MHI EP 模式枚举

在连接到 Lemans EP 端口的主机上,确认设备已作为具有该 MHI 设备 ID 的 PCI 端点被枚举。
输出:
在目标端,确认 MHI 端点通道已注册。
有关基于 configfs 的端点 bring-up 流程的更多信息,请参阅 https://www.kernel.org/doc/html/latest/PCI/endpoint/pci-endpoint-cfs.html。

启用 QPS615 PCIe 交换机

本节介绍如何在 Qualcomm Linux 硬件 SoC 中启用 QPS615 PCIe 交换机。QPS615 交换机端点在 PCIe1 实例上受支持。下图展示了 QPS615 端点和连接。
QPS615 PCIe 交换机连接图

图:QPS615 PCIe 交换机连接图

可从以下位置访问 Qualcomm PCIe 驱动程序文档:

PCIe 相关配置

以下配置默认启用,以支持 QPS615 交换机。若要将其用于其他 PCIe 端点,请通过还原代码更改来禁用 QPS615 交换机的默认支持。 要启用 PCIe 相关的 configs,请将以下补丁应用到 /arch/arm64/configs/qcom_addons.config 文件。

消息信号中断(MSI)

当前的 MSI 映射并不包含所有向量。Qualcomm Linux 硬件 SoC 支持八个向量。每个向量又支持 32 个 MSI。因此,支持的 MSI 总数为 256。 有关为此 PCIe 实例添加所有受支持的 MSI 组的信息,请参阅 https://lore.kernel.org/linux-arm-msm/f1168212-bc6e-4570-869c-2870d6f248ad@linaro.org/T/。

PCIe 内核驱动程序日志示例

以下是来自 QPS615 设备枚举的 PCIe 内核驱动程序日志示例。

通过 QPS615 PCIe 交换机支持的以太网接口

QPS615 PCIe 交换机为设备启用以太网连接。当设备加载 QPS615 驱动程序并建立 PCIe 链路时,默认情况下会在设备启动期间自动激活受支持的以太网接口。 要自定义默认配置或启用 Qualcomm 硬件设置之外的额外 MAC/PHY 组件,请参阅 Qualcomm Linux Ethernet guide 中的 Bring up Ethernet 部分。

表:支持的以太网接口

接口类型速度连接器类型说明
QEP PHY (SGMII)2.5 GbEIX/RJ45 连接器(QEP8121)
  • 默认启用。
AQR PHY (USXGMII)10 GbEIX/RJ45 连接器(AQR113C)
  • 10 千兆以太网 AQR PHY 是 RB3 Gen 2 开发套件以及 Dragonwing IQ-8275 和 Dragonwing IQ-9075 评估套件(EVK)中的可选组件。 它已在 AQR113C 上通过验证。

启用替代硬件组件

您可以连接 Qualcomm 提供的硬件配置之外的 MAC/PHY 组件并将其启用。 要将 QPS615 替换为其他基于 PCIe 的 MAC/PHY,请参阅启用 QPS615 PCIe 交换机。
注意:您必须从相应的供应商处获取 MAC/PHY 驱动程序和固件。Qualcomm 对这些配置更改不承担责任。

通过 PCIe 交换机启用 USB 接口

本节介绍如何在 Qualcomm Linux 硬件 SoC 中通过 PCIe 交换机激活 USB 接口。PCIE1 实例连接到 QPS615 交换机的端点,QPS615 的下游端口连接到 PCIe 转 USB 端点。有关使用 QPS615 的 PCIe 转 USB 端点连接,请参阅位于 https://docs.qualcomm.com/bundle/publicresource/topics/80-80021-251/rb3_hardware_overview.html 的主板和转接板框图。
注意:Dragonwing IQ-9075 PCIe 软件不支持 USB。
USB 集线器的电源通过 pwrctrl 驱动程序启用,有关这些详细信息,请参阅以下上游链接。 https://elixir.bootlin.com/linux/v7.1/source/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts#L896 https://elixir.bootlin.com/linux/v7.1/source/Documentation/devicetree/bindings/usb/renesas,upd720201-pci.yaml https://elixir.bootlin.com/linux/v7.1/source/drivers/pci/pwrctrl/generic.c

下载 PCIe 转 USB 控制器固件

要从 https://www.renesas.com/us/en/products/interface/usb-switches-hubs/upd720201-usb-30-host-controller#design_development 下载固件,请注册并登录 https://www.renesas.com/。将下载的固件文件重命名为 renesas_usb_fw.mem。
注意:为防止命令失败,请在更新 Renesas 固件之前,按照 Set up the device 部分中的说明更新软件。
选项 1(Ubuntu):使用 SCP 或类似工具推送固件文件。例如,
选项 2(Yocto):
  1. 通过 USB 线缆将设备连接到主机 PC 以使用 adb。
  2. 将固件推送到设备。
  3. 要激活固件,请执行以下任一选项。
    • 选项 A:重启目标设备以启用 USB Type-A 端口。
    • 选项 B:手动绑定 Renesas xHCI 驱动程序。
  4. 验证固件枚举。

用于 PCIe 转 USB 设备枚举参考的 PCIe 内核驱动程序日志

您可以运行以下命令来查看设备信息:
  • 要显示 USB 中的设备信息,请运行以下命令。
    将显示以下消息。
  • 要显示 PCIe 中的设备信息,请运行以下命令。
    将显示以下消息。

级联连接 QPS615 交换机

以级联方式连接 QPS615 交换机,以启用额外的以太网、PCIe 和 USB 端口。
注意:此功能仅在 QCS6490 中受支持。
下图展示了以级联方式连接到 PCIE1 的两个 QPS615 交换机,以及连接到 PCIE2 的另一个 QPS615 交换机。
QPS615 级联连接

图:QPS615 交换机级联连接

要为所有端点启动链路训练和枚举,请执行以下操作:
  1. 要重置 QPS615 交换机,请切换 QPS615 #1 和 QPS615 #2 的 RESX GPIO。
  2. 要控制端点重置,请触发 PERST。两个交换机共享 PERST。
设备可以直接连接到 QPS615 交换机。PCIe RC0 连接到 WLAN 端点。由于 PCIe 节点层次结构,存在以下差异。
  • 连接到交换机的设备:
    • QPS615 PCIe 树节点层次结构是静态固定的。
    • 用于交换 USP 和 DSP 端口的所有节点都在 PCIe 初始化期间创建。
    • 其中一个交换机 DSP 端口代表 WLAN。
    • 如果禁用 WLAN 节点,将禁用 WLAN 设备,但 PCIe 下游端口仍保持启用状态,并返回默认的最大链路宽度。
  • 直接连接的 WLAN 设备:
    • 仅禁用单个节点。
    • 当 WLAN 被禁用时,返回 Invalid argument。

通过 PCIe 接口启用 NVMe

本节介绍如何使用 PCIe 启用 NVMe 以进行存储扩展。要验证 NVMe 是否通过 PCIe 接口连接,请执行以下操作:
  1. 要显示 PCIe 设备信息,请运行以下命令。
    输出:
  2. 找到 PCIe 日志。
    输出:
  3. 要找到 NVMe 目录,请运行以下命令。
    输出:

为 SMMUv2 目标更新 iommu-map 属性

对使用 SMMUv2 IOMMU 处理 PCIe 的目标(例如 Dragonwing IQ-9075 (Lemans)、Monaco 和 Kodiak)而言,每个 PCIe Requester ID (RID) 都会通过 PCIe host bridge 节点中的 iommu-map 属性转换为一个 Stream ID (SID)。在给 PCIe 根复合体下游添加设备、交换机或端点时,此属性配置错误是导致出现 no iommu-map translation for id 失败的常见原因。

iommu-map 的工作原理

每个 iommu-map 条目具有以下形式:
内核(drivers/of/base.c: of_map_id())按以下规则处理:
多个条目按顺序检查,首个匹配项生效。当 count = 1 时,映射简化为 RID == rid_base -> SID = sid_base。每个条目使用 count = 1(稀疏点映射)可将一个 RID 精确固定到一个 SID,无论 RID 值有多大,并可避免耗尽 SMMU 实现的 SID 范围。
注意:简单的单一 range 条目,例如 iommu-map = <0x0 &pcie_smmu 0x0000 0x500>;,会将 count 个连续的 RID 映射到 count 个连续的 SID,因此 SID 偏移会随 RID 值成比例增长。一旦来自下游交换机或额外端点的 RID 超出 SMMU 可用的 SID 范围,这种映射就会失败。

PCIe RID 与 SID 基础

PCIe RID 是一个 16 位值,编码了总线、设备和功能:

表:常见 RID 值

BusDevFnRID (hex)说明
0000x0000根复合体,始终存在
1000x0100RC 下行的第一个设备(端点或交换机上行)
2100x0208交换机下行端口,设备 1
21610x0281lspci 地址 02:10.1

lemans.dtsi 参考示例

Lemans 定义了两个 PCIe 控制器,每个都映射到共享 pcie_smmu(qcom,sa8775p-smmu-500,一个 SMMUv2 系列 IOMMU)中各自的 SID 子范围。pcie0 使用 SID 基址 0x0000,pcie1 使用 SID 基址 0x0080,因此它们的 SID 空间不会重叠。
RID 0x0000(bus 0, dev 0, fn 0)在 pcie0 上映射到 SID 0x0000,在 pcie1 上映射到 SID 0x0080。RID 0x0100(bus 1, dev 0, fn 0)在 pcie0 上映射到 SID 0x0001,在 pcie1 上映射到 SID 0x0081。Monaco 使用其自身的 pcie_smmu 实例遵循相同模式;Kodiak 也遵循相同模式,只是使用 apps_smmu(qcom,sc7280-smmu-500)而不是专用的 pcie_smmu。
注意:lemans-ride-common.dtsi 在 pcieport0(bus 1, dev 0, fn 0 — RID 0x0100)上挂载了一个 WiFi 芯片,并从 lemans.dtsi 继承 iommu-map 而未覆盖,因为基础文件已经涵盖了该 RID。

为交换机拓扑扩展 iommu-map

如果在控制器下游安装了 PCIe 交换机(例如,通过两个交换机端口在 bus 4 上添加 NVMe SSD),请在条目列表中为每个 RID 增加一行,并对每一项保持 count = 1:
这总共只使用了 5 个 SID(0x0000 到 0x0004),全部位于 pcie0 的子范围之内;而不是使用一个 count = 0x500 的单一 range 条目,后者可能超出 SMMU 实现的 SID 范围。
注意:分配给每个 RID 的 SID 值不必是连续的,也不必按 RID 顺序排列。它们只需在该控制器的 iommu-map 内唯一,并且位于 SMMU 实现的 SID 范围内。

诊断缺失的 iommu-map 条目

当设备的 RID 没有匹配的 iommu-map 条目时,内核日志会记录类似如下的错误:
  1. 从日志中读取 RID。在此示例中,RID 为 0x0281。
  2. 将 RID 解码为总线、设备和功能。
    与同一日志行中的 lspci 地址交叉核对(0001:02:10.1 → bus 2, device 0x10, function 1)。字段一致,确认 RID 解码正确。
  3. 为该设备选择一个空闲 SID。查看现有的 iommu-map 条目,选一个尚未被此控制器映射中其他条目使用、并且在 SMMU 实现的 SID 范围内的 SID。
  4. 使用 count = 1 添加条目。
    如果 fn0 和 fn1 连续且都还没有 SID,可以用一个 count = 2 的条目同时覆盖两者:<0x0280 &apps_smmu 0x1403 0x2> 会将 RID 0x0280 映射到 SID 0x1403,将 RID 0x0281 映射到 SID 0x1404。
  5. 重新构建 DTB、刷写并重启,然后确认修复效果。
    错误行必须不再出现。
注意:无论是否存在 iommu-map 条目,lspci 都会显示设备,因为 lspci 直接读取 PCI 配置空间,不受 IOMMU 映射影响。请使用 dmesg,而不是 lspci,来确认缺失的条目已被修复。
有关内核 RID 到 SID 的转换,请参阅 drivers/of/base.c: of_map_id()。

PCIe 客户端驱动程序示例

客户端驱动程序定义 device-id 表和 pci_driver 结构,并向 PCIe 框架注册。以下是一些 PCIe 客户端驱动程序示例,供参考。
  • 用于保存客户端特定私有数据的数据结构示例。
  • 驱动程序示例:您可以根据驱动程序特定的数据结构提供数据。
  • 带有驱动程序特定数据的设备 ID 表示例。客户端驱动程序使用 0x306 设备 ID 进行注册。
注意:MODULE_DEVICE_TABLE(pci, sample_pci_id_table); 是强制性的。
  • 带有客户端驱动程序名称、pci-id 表和回调的 pci_driver 数据结构示例。在向 PCI 框架注册时会传递指向此结构的指针。
  • 要向 PCI 固件注册,请从 module_init() 中调用 pci_register_driver(&sample_pci_driver)。

PCIe 启用(bringup)

有关 PCIe 启用的信息,请参阅 PCIe-related configurations 和 QPS615 switch support。

PCIe 功耗优化

PCIe 定义了两种类型的电源管理方法。
  • 电源管理软件,用于确定每个设备的电源管理能力并单独管理每个设备
  • 无需软件干预的系统,例如活动状态电源管理(ASPM)
在链路上没有数据包传输的时间段内,设备会将链路置于省电状态。

PCIe L0 链路状态

PCIe 电源管理定义了以下 L0 链路状态:
  • L0:活动状态,所有 PCIe 事务和其他操作均已启用
  • L0s:具有低恢复延迟的 ASPM 状态(节能待机状态)

PCIe 设备状态

PCIe 电源管理定义了以下设备状态:
  • D0(强制):设备处于完全开启状态,其中有两个子状态
    • D0uninitialized:设备复位后,功能处于 D0uninitialized 状态,等待被枚举和配置。
    • D0active
      • 枚举和配置过程完成后,功能处于 D0active 状态。
      • 当系统软件启用一个或多个(任意组合)功能参数(例如内存空间使能、I/O 空间使能或 BME 位)时,功能进入 D0active 状态。
  • D1(可选):浅睡眠状态
    • 除 PME 消息外,功能不能发起 TLP
    • 除配置事务外,功能不能作为事务的目标。
    • 功能通过对 PM 控制和状态寄存器进行编程来发出进入 D1 状态的软件命令。
  • D2(可选):深睡眠状态
    • 除 PME 消息外,功能不能发起 TLP
    • 除配置事务外,功能不能作为事务的目标。
    • 功能通过对 PM 控制和状态寄存器进行编程来发出进入 D2 状态的软件命令。
  • D3(强制):设备处于最低功耗状态,功能必须支持两种 D3 状态
  • D3hot
    • 除 PME 消息外,功能不能发起 TLP。
    • 除配置事务外,功能不能作为事务的目标。
    • 功能通过对电源状态字段进行编程来发出进入 D3hot 状态的软件命令。
  • D3cold:设备进入 D3cold 状态并断电;电源恢复后,设备进入 D0uninitialized 状态。

PCIe 验证

有关 PCIe 验证的信息,请参阅 PCIe-related configurations 和 QPS615 switch support。

调试 PCIe 问题

lspci 和 setpci 命令是 Linux 发行版的原生命令。这些命令具有不同级别的输出。这些命令还可以提供对 PCI 总线上训练的不同组件的能力和状态的有用的即时快照。这些能力大多是 PCIe 基础规范所要求的配置空间寄存器的反映。有关更多详细信息,请参阅 https://pcisig.com/specifications。要查看使用说明,请运行以下命令。
以下功能对排查 PCIe 问题很有用。
  • 显示设备信息
    将显示以下消息。
  • 显示设备控制寄存器中的 PCIe 设备和供应商 ID。
    将显示以下消息。
有关 PCIe 调试的更多信息,请参阅 https://www.kernel.org/doc/html/v4.17/driver-api/pci.html。

PCIe 示例

有关上游设备树参考的信息,请参阅以下文件。 有关 Qualcomm Linux 硬件 SoC 的设备树节点信息,请参阅以下 DTSI 文件。

客户端与 PCI 驱动程序操作流程示例

下图展示了 PCIe 客户端驱动程序为客户端配置 PCIe 驱动程序所遵循的顺序。
PCIe 设备连接链路

客户端与 PCI 驱动程序高层调用流程示例

下图展示了 PCIe 客户端驱动程序与 PCIe 驱动程序之间的高层调用流程和调用详细信息。
PCIe 设备连接链路