欢迎光临
我们一直在努力

【Linux驱动学习PCIE篇】PCIE学习(rk356x系列)

Rockchip AXI PCIe 主机控制器驱动 —— 学习笔记

源码文件:pcie-rockchip.c 平台:Rockchip RK3399 及同系列(rk35xx) 作者:Shawn Lin, Wenrui Li (Rockchip) 基础框架参考:Synopsys Designware Host Controller + ARM PCI Host Generic Driver


目录

  • 整体架构概览
  • 核心数据结构
  • 寄存器布局与定义
  • 配置空间访问
  • 设备树解析 —— 硬件资源获取
  • 硬件初始化流程
  • 中断处理体系
  • ATU 地址转换单元
  • Probe 主流程
  • 面试高频考点

  • 1. 整体架构概览

    ┌─────────────────────────────────────────────────┐
    │ CPU (AXI Bus) │
    └────────────────────┬────────────────────────────┘

    ┌──────────▼──────────┐
    │ PCIe Controller │
    │ (Rockchip AXI) │
    │ │
    │ ┌──────────────┐ │
    │ │ ATU (地址 │ │ ← Outbound: CPU→PCIe
    │ │ 转换单元) │ │ ← Inbound: PCIe→CPU
    │ └──────────────┘ │
    │ ┌──────────────┐ │
    │ │ Config Space │ │ ← ECAM 方式访问
    │ └──────────────┘ │
    │ ┌──────────────┐ │
    │ │ Interrupt │ │ ← INTx/MSI 中断管理
    │ │ Controller │ │
    │ └──────────────┘ │
    └─────────┬──────────┘

    ┌─────────▼──────────┐
    │ PCIe PHY │ ← 物理层 (SerDes)
    └─────────┬──────────┘

    ┌─────────▼──────────┐
    │ PCIe Endpoint │ ← 下游设备 (网卡/NVMe等)
    └────────────────────┘

    关键设计特点:

    • 基于 Designware IP 核,复用其寄存器布局
    • 采用 ECAM (Enhanced Configuration Access Mechanism) 访问配置空间
    • 双寄存器基址:axi-base(数据传输/配置空间) 和 apb-base(内部控制寄存器)
    • 支持 1/2/4 lane,Gen1(2.5GT/s) 和 Gen2(5GT/s)

    2. 核心数据结构

    struct rockchip_pcie {
    // ===== 寄存器基址 =====
    void __iomem *reg_base; // AXI 总线接口 (配置空间访问、数据传输)
    void __iomem *apb_base; // APB 总线接口 (控制器内部寄存器)

    // ===== PHY =====
    struct phy *phy; // PCIe 物理层 (SerDes PHY)

    // ===== 复位信号 (共7个) =====
    struct reset_control *core_rst; // 核心复位
    struct reset_control *mgmt_rst; // 管理接口复位
    struct reset_control *mgmt_sticky_rst; // 粘性管理复位 (热复位时保持状态)
    struct reset_control *pipe_rst; // PIPE 接口复位 (连接 PHY)
    struct reset_control *pm_rst; // 电源管理复位
    struct reset_control *aclk_rst; // ACLK 时钟域复位
    struct reset_control *pclk_rst; // PCLK 时钟域复位

    // ===== 时钟 (共4个) =====
    struct clk *aclk_pcie; // AXI 主时钟
    struct clk *aclk_perf_pcie; // AXI 性能监控时钟
    struct clk *hclk_pcie; // AHB 总线时钟
    struct clk *clk_pcie_pm; // 电源管理模块时钟

    // ===== 电源管理 =====
    struct regulator *vpcie3v3; // 3.3V (可选)
    struct regulator *vpcie1v8; // 1.8V (可选)
    struct regulator *vpcie0v9; // 0.9V (可选)

    // ===== GPIO =====
    struct gpio_desc *ep_gpio; // PERST# — 控制 EP 设备复位

    // ===== 配置信息 =====
    u32 lanes; // 通道数 (1/2/4)
    u8 root_bus_nr; // 根总线编号 (通常为 0)
    struct device *dev; // 所属 device
    struct irq_domain *irq_domain; // INTx 中断域
    };

    学习要点:

    • reg_base vs apb_base:两个基址分别对应 AXI 和 APB 总线,AXI 用于高速配置空间访问,APB 用于慢速控制寄存器的读写。
    • 7 个复位信号反映了硬件复杂度:核心、管理、PIPE、电源管理、两个时钟域各有独立复位。
    • 3 个 regulator 都是 optional,部分硬件上这些电压域可能由 PMIC 常供电。

    3. 寄存器布局与定义

    3.1 Client 寄存器区 (基址 0x0)

    这是面向"用户/驱动"的控制接口区。

    偏移寄存器名功能
    0x00 CLIENT_CONFIG 核心配置:使能、链路训练、ARI、通道数、RC模式、Gen2选择
    0x48 CLIENT_BASIC_STATUS1 链路状态(Link Up 标志位在 bit[21:20])
    0x4c CLIENT_INT_MASK 中断屏蔽
    0x50 CLIENT_INT_STATUS 中断状态

    CLIENT_CONFIG 位域:

    [0] – Enable : 控制器使能
    [1] – Link Train Enable: 链路训练使能
    [3] – ARI Enable : Alternative Routing-ID
    [5:4]- Lane Num : 通道数编码 ((lane>>1)&3)<<4
    [6] – Mode RC : 1=Root Complex, 0=Endpoint
    [7] – Gen Select 2 : 1=Gen2(5GT/s), 0=Gen1(2.5GT/s)

    HIWORD_UPDATE 机制(值得注意的设计):

    #define HIWORD_UPDATE(mask, val) (((mask) << 16) | (val))
    #define HIWORD_UPDATE_BIT(val) HIWORD_UPDATE(val, val)

    高 16 位是写掩码,低 16 位是实际值。一次 32 位写入即可实现 “读-改-写” 的原子操作,无需额外的锁保护。

    3.2 Core Control / Management 寄存器区 (基址 0x900000)

    偏移寄存器名功能
    0x000 CORE_CTRL 链路速度/宽度状态(只读/状态)
    0x004 CORE_CTRL_PLC1 FTS (Fast Training Sequence) 计数配置
    0x020 TXCREDIT_CFG1 发送信用更新间隔
    0x20c CORE_INT_STATUS 核心中断状态
    0x210 CORE_INT_MASK 核心中断屏蔽

    3.3 RC 配置空间 (基址 0x800000 / 0xa00000)

    偏移寄存器名功能
    0xa00000 RC_CONFIG_VENDOR Vendor ID (写为 0x1d87 — Rockchip)
    0xa00008 RC_CONFIG_RID_CCR Revision ID + Class Code (PCI Bridge)
    0xa000d0 RC_CONFIG_LCS Link Control/Status(链路重训练、带宽管理中断)
    0x800000 RC_CONFIG_NORMAL_BASE RC 自身 Type0 配置空间基址
    0xc00000 AXI_CONF_BASE Outbound ATU 区域
    0xc00800 AXI_INBOUND_BASE Inbound ATU 区域

    3.4 ECAM 地址计算

    #define PCIE_ECAM_ADDR(bus, dev, func, reg) \\
    (PCIE_ECAM_BUS(bus) | PCIE_ECAM_DEV(dev) | \\
    PCIE_ECAM_FUNC(func) | PCIE_ECAM_REG(reg))

    // bus<<20 | dev<<15 | func<<12 | reg<<0

    ECAM 将 PCIe 的 BDF (Bus/Device/Function) + Register 映射到 MMIO 地址空间,这是 PCIe 的标准做法。


    4. 配置空间访问

    4.1 读写体系

    pci_ops {
    .read = rockchip_pcie_rd_conf
    .write = rockchip_pcie_wr_conf
    }

    ├── 判断设备是否有效 (rockchip_pcie_valid_device)
    │ – bus == root_bus → 只允许 dev=0(只有一个slot)
    │ – bus->primary == root_bus → 只允许 dev=0(直连设备)

    ├── bus == root_bus ?
    │ YES → rd_own_conf / wr_own_conf (Type0 — RC 自身)
    │ NO → rd_other_conf / wr_other_conf (Type1 — 下游设备 ECAM)

    └── 返回 PCIBIOS_SUCCESSFUL / PCIBIOS_DEVICE_NOT_FOUND

    4.2 关键区别

    rd_own_confrd_other_conf
    基址 apb_base + 0x800000 reg_base + ECAM_ADDR
    对象 RC 自身 Type0 配置头 下游设备 Type0/Type1 配置头
    范围 仅 root bus 非 root bus

    4.3 重要限制

    驱动在 probe 末尾有一行警告:

    only 32-bit config accesses supported; smaller writes may corrupt adjacent RW1C fields

    这意味着:写配置空间时,非 4 字节对齐的小写入会先读 4 字节、修改、再写回,可能损坏相邻的 RW1C (Read-Write-1-to-Clear) 位。这是该硬件的一个已知限制。


    5. 设备树解析 —— 硬件资源获取

    函数 rockchip_pcie_parse_dt() 是驱动中"时间优先级最高"的部分,在 probe 中第一个被调用。

    获取的资源清单

    Category | Resource Name | Method
    ─────────────────────────────────────────────────────
    寄存器映射 | "axi-base" | devm_ioremap_resource
    | "apb-base" | devm_ioremap_resource
    ─────────────────────────────────────────────────────
    PHY | "pcie-phy" | devm_phy_get
    ─────────────────────────────────────────────────────
    复位 (7个) | core, mgmt, | devm_reset_control_get
    | mgmt-sticky, |
    | pipe, pm, pclk, |
    | aclk |
    ─────────────────────────────────────────────────────
    GPIO | "ep" (PERST#) | devm_gpiod_get (默认 HIGH)
    ─────────────────────────────────────────────────────
    时钟 (4个) | aclk, aclk-perf, | devm_clk_get
    | hclk, pm |
    ─────────────────────────────────────────────────────
    中断 (3条线) | "sys" | devm_request_irq (子系统/错误)
    | "legacy" | irq_set_chained_handler (INTx)
    | "client" | devm_request_irq (逻辑层/事件)
    ─────────────────────────────────────────────────────
    电源 (3个, 可选) | vpcie3v3, | devm_regulator_get_optional
    | vpcie1v8, |
    | vpcie0v9 |
    ─────────────────────────────────────────────────────
    通道数 | "num-lanes" | of_property_read_u32 (默认1)

    EPROBE_DEFER 的处理

    多处使用了此模式:

    if (PTR_ERR(phy) != EPROBE_DEFER)
    dev_err(dev, "missing phy\\n");
    return PTR_ERR(phy);

    含义: 如果依赖的资源驱动(如 PHY、复位控制器)尚未加载,返回 -EPROBE_DEFER 通知内核稍后重新尝试 probe,且不打印错误(因为这不是真正的错误,只是时序问题)。

    三条中断线的职责

    "sys" → 控制器内部错误/事件(FIFO溢出、TLP错误、PHY错误等)
    "legacy" → 下游设备的 INTx (INTA~INTD) 传统中断 ← 级联中断处理
    "client" → 高层逻辑事件(热复位、DPA、错误上报、PHY变化等)


    6. 硬件初始化流程

    rockchip_pcie_init_port() 是核心初始化函数,流程如下:

    Step-by-Step

    1. GPIO: PERST# 拉低 (复位 EP)

    2. 复位序列 assert:
    aclk_rst → pclk_rst → pm_rst


    3. udelay(10) ← 等 10μs 确保复位生效

    4. 复位序列 deassert (按特定顺序!):
    pm_rst → aclk_rst → pclk_rst

    5. phy_init() ← 初始化 PHY

    6. 核心复位 assert:
    core_rst → mgmt_rst → mgmt_sticky_rst → pipe_rst

    7. 写 CLIENT_CONFIG:
    Enable | LinkTrain | ARI | LaneNum | ModeRC | Gen2

    8. phy_power_on() ← PHY 上电

    9. 核心复位 deassert (严格顺序!):
    mgmt_sticky_rst → core_rst → mgmt_rst → pipe_rst

    10. 工作区 (Controller bug workaround):
    读写 L1_SUBSTATE_CTRL2 → 配置 FTS count

    11. 使能 Gen1 链路训练

    12. 轮询等 Link Up (每 20ms, 超时 500ms):
    检查 BASIC_STATUS1[21:20] == 2'b11 → 成功

    13. 触发 Gen2 重训练 (写 LCS.Retrain_Link)

    14. 轮询等 Gen2 (每 20ms, 超时 500ms):
    检查 CORE_CTRL[4:3] → 若超时则回退 Gen1

    15. 读最终链路宽度 (x1/x2/x4)

    16. 写 RC 配置头:
    Vendor ID → Class Code → BAR → ATU Region0

    复位顺序的重要性

    /* 注释原文:Please don't reorder the deassert sequence */

    复位解除 (deassert) 的顺序为:

    mgmt_sticky_rst → core_rst → mgmt_rst → pipe_rst

    这是由硬件设计决定的——内部状态机要求先释放粘性复位,再依次释放核心、管理、PIPE。随意调整顺序会导致控制器无法正常工作。

    链路训练两阶段

    Gen1 训练 (必须成功) Gen2 训练 (可降级)
    ┌──────────────────┐ ┌──────────────────┐
    │ 2.5 GT/s 建立链接 │ ───► │ 尝试升级到 5 GT/s │
    │ 超时则整体失败 │ │ 超时 → 保持 Gen1 │
    │ │ │ │ │
    │ 500ms timeout │ │ 500ms timeout │
    └──────────────────┘ └──────────────────┘


    7. 中断处理体系

    三层中断结构

    硬件中断线

    ├─ "sys" ──► rockchip_pcie_subsys_irq_handler()
    │ ├─ INT_LOCAL: 检查 CORE_INT_STATUS
    │ │ ├─ PRFPE/CRFPE/RRPE → FIFO RAM 奇偶校验错
    │ │ ├─ PRFO/CRFO → FIFO 溢出
    │ │ ├─ RT/RTR → 重放超时
    │ │ ├─ PE → PHY 接收错误
    │ │ ├─ MTR/UCR/FCE → TLP 畸形/流控错
    │ │ ├─ CT → 请求完成超时
    │ │ ├─ UTC → TC 映射错误
    │ │ └─ MMVC → MSI 掩码变化
    │ └─ INT_PHY: PHY 链路变化
    │ └─ 更新 Tx Credit + 清除带宽中断

    ├─ "legacy" ─► rockchip_pcie_legacy_int_handler() [chained]
    │ ├─ chained_irq_enter/exit
    │ ├─ 读 INT_STATUS[8:5] (INTA~INTD)
    │ ├─ 用 ffs() 逐位查找
    │ └─ irq_find_mapping → generic_handle_irq

    └─ "client" ─► rockchip_pcie_client_irq_handler()
    ├─ LEGACY_DONE / MSG → 传统/MSI 完成
    ├─ HOT_RST → 热复位
    ├─ DPA → 动态功率分配
    ├─ FATAL_ERR / NFATAL_ERR → AER 致命/非致命错
    ├─ CORR_ERR → 可纠正错误
    └─ PHY → PHY 事件

    级联中断 (Chained IRQ)

    irq_set_chained_handler_and_data(irq, rockchip_pcie_legacy_int_handler, rockchip);

    这告诉内核:当 “legacy” 中断触发时,先调用 rockchip_pcie_legacy_int_handler,它负责:

  • 读取状态寄存器找到具体是哪根 INTx
  • 通过 irq_find_mapping 将硬件中断号映射到 Linux IRQ 号
  • 调用 generic_handle_irq 分发给对应的设备驱动
  • 中断使能

    rockchip_pcie_enable_interrupts():
    1. CLIENT_INT_MASK → 只使能 CLI (Correctable/Fatal/NonFatal/DPA/HotRst/MSG/Legacy/PHY)
    2. CORE_INT_MASK → 使能所有核心中断
    3. 使能带宽变化中断 (LCS.LBMIE | LCS.LABIE)


    8. ATU 地址转换单元

    ATU (Address Translation Unit) 是 PCIe 控制器的关键模块,负责 CPU AXI 地址和 PCIe 总线地址之间的转换。

    Outbound ATU (CPU → PCIe)

    rockchip_pcie_prog_ob_atu(rockchip, region_no, type, num_pass_bits, lower_addr, upper_addr);

    作用: CPU 发出的 AXI 读写请求 → 转换为 PCIe 总线上的 TLP 包。

    参数说明:

    • region_no: 区域编号 (1~32),Region 0 保留给默认映射
    • type: AXI_WRAPPER_MEM_WRITE(0x2) 或 AXI_WRAPPER_IO_WRITE(0x6)
    • num_pass_bits: 地址直通位数(决定地址窗口大小),20-1 表示 1MB
    • lower_addr / upper_addr: PCI 总线侧的物理地址

    硬件寄存器布局 (每个 Region 4个寄存器):

    ADDR0: [5:0]=num_pass_bits, [31:8]=lower_addr[31:8]
    ADDR1: upper_addr (高32位)
    DESC0: [23]=enable, [2:0]=type
    DESC1: 保留 (写0)

    Inbound ATU (PCIe → CPU)

    rockchip_pcie_prog_ib_atu(rockchip, region_no, num_pass_bits, lower_addr, upper_addr);

    作用: 下游 EP 设备的 DMA 请求 → 转换为 AXI 地址,访问系统内存。

    当前配置:

    rockchip_pcie_prog_ib_atu(rockchip, 2, 32 1, 0x0, 0);
    // region=2, 直通32位, CPU端地址=0x0

    表示允许 EP 通过 DMA 访问整个低 4GB 的 CPU 内存空间。

    地址映射图解

    Outbound (CPU → PCIe)
    ┌─────────────────┐ ┌─────────────────┐
    │ CPU AXI Address │────────►│ PCIe Mem Space │
    │ 0xFA000000 │ ATU │ 0x00000000 │
    │ 窗口: 1MB×N │ │ (总线侧地址) │
    └─────────────────┘ └─────────────────┘

    Inbound (PCIe → CPU)
    ┌─────────────────┐ ┌─────────────────┐
    │ EP DMA Request │────────►│ System DRAM │
    │ (PCIe TLP) │ ATU │ 0x00000000 │
    │ │ │ (4GB 窗口) │
    └─────────────────┘ └─────────────────┘


    9. Probe 主流程

    rockchip_pcie_probe() 是驱动入口,完整流程:

    Probe 被调用 (设备树匹配 "rockchip,rk3399-pcie")

    ├─ 1. 解析 DT (rockchip_pcie_parse_dt)
    │ 获取:寄存器、PHY、复位、GPIO、时钟、中断、电源、通道数

    ├─ 2. 使能时钟
    │ aclk_pcie → aclk_perf_pcie → hclk_pcie → clk_pcie_pm

    ├─ 3. 使能电源 (rockchip_pcie_set_vpcie)
    │ vpcie3v3 → vpcie1v8 → vpcie0v9 (链式回滚)

    ├─ 4. 初始化端口 (rockchip_pcie_init_port)
    │ 复位序列 → PHY初始化 → Gen1训练 → Gen2训练 → RC配置

    ├─ 5. 使能中断 (rockchip_pcie_enable_interrupts)

    ├─ 6. 初始化 INTx IRQ Domain
    │ 创建线性中断域 (irq_domain_add_linear, 大小=4)

    ├─ 7. 获取 Host Bridge 资源 (of_pci_get_host_bridge_resources)
    │ 解析 DT 中 "ranges" 属性 → I/O / MEM / BUS 三种资源

    ├─ 8. 申请总线资源 (devm_request_pci_bus_resources)

    ├─ 9. 遍历资源链表
    │ IORESOURCE_IO → pci_remap_iospace, 记录 io_bus_addr
    │ IORESOURCE_MEM → 记录 mem_bus_addr, mem_size
    │ IORESOURCE_BUS → 记录 root_bus_nr

    ├─ 10. 配置 Outbound ATU (MEM 窗口)
    │ 按 1MB 步长循环配置 (非 Region 0)

    ├─ 11. 配置 Inbound ATU (DMA 窗口)
    │ Region 2, 32-bit 直通, CPU地址=0

    ├─ 12. 配置 Outbound ATU (I/O 窗口)
    │ Offset 偏移防止覆盖 MEM 区域

    ├─ 13. 扫描 PCI 总线 (pci_scan_root_bus)
    │ 这是最核心的一步:枚举所有 PCIe 设备

    ├─ 14. 资源分配与配置
    │ pci_bus_size_bridges → pci_bus_assign_resources
    │ → pcie_bus_configure_settings (每个子总线)

    ├─ 15. 添加设备 (pci_bus_add_devices)
    │ 触发设备驱动 probe,设备可用

    └─ 16. 打印硬件限制警告 (32-bit only)

    错误回滚路径

    err_vpcie:
    disable vpcie0v9 → vpcie1v8 → vpcie3v3
    err_set_vpcie:
    clk_disable_unprepare(pm)
    err_pcie_pm:
    clk_disable_unprepare(hclk)
    err_hclk_pcie:
    clk_disable_unprepare(aclk_perf)
    err_aclk_perf_pcie:
    clk_disable_unprepare(aclk)
    err_aclk_pcie:
    return err;

    遵循 “先开后关,后开先关” 的原则。


    10. 面试高频考点

    Q1: ECAM 是什么?本驱动中如何实现?

    ECAM (Enhanced Configuration Access Mechanism) 是 PCIe 规范定义的标准配置空间访问方式。每个 BDF (Bus/Device/Function) 占用 4KB MMIO 空间,公式为:

    Address = Base + (Bus<<20 | Dev<<15 | Func<<12 | Reg<<0)

    本驱动中 PCIE_ECAM_ADDR 宏实现了这个映射。

    Q2: ATU 的作用是什么?Outbound 和 Inbound 有什么区别?

    • Outbound ATU: CPU 访问 PCIe 总线地址空间(如设备 BAR 空间),将 CPU 物理地址翻译为 PCIe 总线地址
    • Inbound ATU: PCIe 设备 DMA 访问系统内存,将 PCIe 总线地址翻译为 CPU 物理地址

    Q3: 链路训练 (Link Training) 的过程是怎样的?

  • 先以 Gen1 (2.5GT/s) 进行训练→成功则链路建立
  • 再触发 Gen2 (5GT/s) 重训练→成功则升级,失败则保持 Gen1
  • 最终协商出链路宽度 (x1/x2/x4) 和速度
  • Q4: 为什么需要 7 个独立的复位信号?

    反映了 SoC 内部 PCIe 控制器的硬件分区设计:

    • core/mgmt/mgmt-sticky: 控制器核心逻辑和管理模块需要分步复位
    • pipe: PIPE 是连接 PHY 的标准接口,需要独立复位
    • pm: 电源管理状态机独立复位
    • aclk/pclk: 不同时钟域需要各自的复位,避免跨时钟域问题

    Q5: EPROBE_DEFER 是什么?为什么在这个驱动中反复出现?

    Linux 内核的设备模型机制。当驱动依赖的资源(如 PHY、复位控制器、时钟)尚未准备好时,返回 -EPROBE_DEFER 告诉设备模型"稍后重新调用我的 probe"。这个驱动依赖大量资源,因此对每个资源都需要处理这种情况。

    Q6: 为什么寄存器写入使用 HIWORD_UPDATE 宏?

    #define HIWORD_UPDATE(mask, val) (((mask) << 16) | (val))

    这是一种硬件支持的原子读-改-写机制。高 16 位作为字节掩码指示要修改哪些低 16 位,一次 32 位写入即可修改特定位段,无需软件层面的 read-modify-write 序列,避免了竞态条件。

    Q7: 传统中断 (INTx) 和 MSI 中断的区别?

    • INTx (Legacy): 基于物理引脚的边带信号 (INTA~INTD),4 条共享线,通过级联中断处理
    • MSI (Message Signaled Interrupt): 通过 PCIe 带内 TLP 报文发送中断,无需额外引脚,支持更多中断向量

    本驱动通过 irq_domain + chained_irq 实现了对 INTx 的支持。

    Q8: devm_* 系列函数有什么优势?

    devm_ (device managed) 函数会自动管理资源的生命周期:

    • probe 失败时自动释放所有已申请的资源
    • driver remove 时自动释放
    • 减少手动错误处理代码

    本驱动大量使用 devm_kzalloc、devm_ioremap_resource、devm_request_irq 等。


    附录:关键常量速查表

    常量值含义
    ROCKCHIP_VENDOR_ID 0x1d87 Rockchip 的 PCI-SIG Vendor ID
    AXI_REGION_SIZE 1MB 单个 ATU region 大小
    AXI_REGION_0_SIZE 32MB Region 0 的大小
    MAX_AXI_WRAPPER_REGION_NUM 33 最大 OB ATU Region 数
    MAX_AXI_IB_ROOTPORT_REGION_NUM 3 最大 IB ATU Region 数
    RC_REGION_0_PASS_BITS 24 Region 0 的地址直通位
    Link Training Timeout 500ms Gen1/Gen2 各自的超时时间
    Training Poll Interval 20ms 链路状态轮询间隔
    赞(0)
    未经允许不得转载:171主机测评 » 【Linux驱动学习PCIE篇】PCIE学习(rk356x系列)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址