拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PCIe协议入门:三层架构与核心概念解析

PCIe协议入门:三层架构与核心概念解析 PCIe 这个总线协议刚接触的时候很容易被它那一堆缩写和分层术语劝退。TLP、DLLP、LTSSM、RC、EP、Lane、Link……单看每一个词都认识连起来读就不知道在说什么。但如果你是从做驱动、做硬件、做 FPGA 或者做存储性能调优的角度切入绕不开它。因为今天几乎所有高带宽外设——NVMe SSD、独立网卡、GPU、采集卡、FPGA 加速卡——挂的都是 PCIe 这条总线。你调不通设备、测不到标称速率、枚举失败、链路降速最后追根溯源十有八九要回到 PCIe 协议本身。这篇是 PCIe 协议解析系列的第一篇目标很明确把 PCIe 的基本概念和三层架构讲清楚让你脑子里先有一张完整的地图。后面再去看枚举过程、LTSSM 状态机、配置空间、驱动子系统这些细节时才知道每一块拼图放在哪。我会尽量用从业者交流的方式来讲不堆砌手册原文重点解释“为什么这么设计”以及这些设计在实际调试中意味着什么。适合刚入行做硬件/驱动/固件的同学也适合做了几年但一直没系统梳理过 PCIe 的人。1. 先搞清楚 PCIe 到底解决的是什么问题1.1 从并行总线到串行点对点一次架构上的取舍要理解 PCIe得先知道它的前身 PCI 和 PCI-X 是什么样子。PCI 是并行总线32 位或 64 位数据线并排走多个设备共享同一组地址/数据/控制线靠仲裁决定谁占用总线。这种共享并行结构在低频时代没问题但频率一往上拉问题就来了多条线之间的时序偏移skew越来越难对齐串扰、反射、同步开关噪声全都冒出来布线难度和成本急剧上升。你想把频率从 33MHz 拉到几百 MHz物理层先扛不住。PCIe 的选择是彻底换思路改成串行、点对点、全双工。每个设备之间是独立的链路不再共享总线数据用差分信号对传输抗干扰能力强发送和接收各走各的通道可以同时收发。代价是每条链路需要独立的收发器但换来的是频率可以一路往上堆从最初的 2.5GT/s 一路走到今天的 32GT/s 甚至更高。这里有个关键点很多人一开始会混淆PCIe 的速率单位是 GT/s每秒传输次数不是 Gbps。因为 PCIe 用的是 8b/10b 或 128b/130b 编码实际有效带宽要打折扣。比如 Gen1 是 2.5GT/s用 8b/10b 编码每字节有效数据要传 10 位所以单 Lane 有效带宽是 2.5 × 0.8 2Gbps 250MB/s。Gen3 是 8GT/s改用 128b/130b 编码单 Lane 有效带宽约 8 × (128/130) / 8 ≈ 984MB/s接近 1GB/s。这个换算在做带宽预算的时候必须心里有数不然算出来的数字会差一大截。1.2 点对点链路带来的连锁好处点对点这个改动看着简单但它带来的连锁反应很深远。因为是独占链路每个设备都能拿到完整的带宽不存在“抢总线”的问题因为不共享也就不需要复杂的仲裁机制因为是差分串行PCB 布线可以用更少的层数、更长的走线距离。这些特性直接决定了 PCIe 能成为今天通用互连的事实标准。但点对点也带来一个新问题设备之间怎么互连如果每个设备都要和 CPU 直连引脚数根本不够。所以 PCIe 引入了Switch的概念用交换芯片把一条上行链路扩展成多条下行链路逻辑上还是一棵以 RCRoot Complex为根的树。这就解释了为什么你在系统里看到的 PCIe 拓扑永远是一棵树而不是一条总线。理解这棵树的结构对后面看枚举过程、看设备路径比如0000:00:1c.0非常关键。提示很多人第一次看lspci -t输出的树状结构会懵其实那就是 PCIe 拓扑的直接映射。RC 是根Switch 是中间节点EPEndpoint是叶子。1.3 PCIe 在系统中的位置它不只是“插槽”新手容易把 PCIe 理解成“主板上那个插显卡的槽”。这只是它的一种物理形态。实际上 PCIe 存在于很多你看不见的地方M.2 接口的 NVMe SSD 走的是 PCIe板载网卡走的是 PCIe很多嵌入式 SoC 内部的高速外设互连也是 PCIe。甚至在一些芯片内部不同模块之间也用 PCIe 做互连。所以 PCIe 的本质是一种通用的高速互连协议插槽只是它最直观的载体。你在调试一块 RK3588 或者 LS1028A 的板子时SPI NOR 存引导、PCIe NVMe 存系统这种混合存储方案本质上就是在用 PCIe 挂载高速存储设备。理解这一点你才不会把 PCIe 局限在“PC 硬件”的框框里。2. 三层架构PCIe 协议的分层设计逻辑2.1 为什么非要分层从“改一处动全身”说起PCIe 协议被划分为三层事务层Transaction Layer、数据链路层Data Link Layer、物理层Physical Layer。这个分层不是学术上的洁癖而是工程上的必然选择。想象一下不分层的后果如果传输逻辑、错误处理、信号编码全揉在一起那么你想把物理速率从 Gen3 升到 Gen4就得把整个协议栈重写一遍你想改一下错误重传策略又可能影响到信号编码。这种耦合度在工程上是灾难。分层之后每一层只关心自己的职责层与层之间通过明确定义的接口交互。物理层升级换代上层几乎不用动事务层增加一种新的事务类型下层也不关心。这跟软件里的 MVC 三层架构、物联网三层架构是同一个思路关注点分离。你在做 Java 后端时用三层架构而不是六边形架构很多时候也是因为团队熟悉、边界清晰、够用就好。PCIe 的分层也是同样的务实考量。2.2 三层各自的职责边界我用一个寄快递的类比来说明这三层这个类比我在带新人的时候反复用效果不错。事务层相当于“写信的人”。它负责决定这封信要寄给谁地址、信里写什么数据、是普通信件还是挂号信事务类型比如 Memory Read/Write、Configuration Read/Write、Message。它不关心信怎么运、路上会不会丢。数据链路层相当于“快递公司的分拣和追踪系统”。它给每封信加上序号Sequence Number收到后要回执确认ACK/NAK发现丢件就要求重发。它保证的是“相邻两站之间”的可靠传输注意是相邻两站不是端到端。物理层相当于“运输工具和道路”。它负责把包裹真正搬上车、沿着链路送过去处理信号的电平、编码、时钟恢复、链路训练这些底层的事。这个类比的关键在于可靠性是逐段保证的不是端到端保证的。这一点和 TCP 的端到端可靠性完全不同是理解 PCIe 的一个核心认知。后面讲 ACK/NAK 协议时会再展开。2.3 分层与数据包的对应关系每一层都会对数据做“包装”。事务层生成TLPTransaction Layer Packet数据链路层在 TLP 外面加上序列号和 CRC 生成DLLPData Link Layer Packet以及带链路 CRC 的 TLP物理层再把它们变成链路上的比特流。这里有个容易搞混的点DLLP 不是 TLP 加个头那么简单。DLLP 是数据链路层自己生成和消费的包用于 ACK/NAK、流控信用更新、电源管理握手等它不会传到事务层去。而 TLP 是承载实际事务的包会一路传到对端的事务层。两者是并列关系不是包含关系。层次生成/处理的包核心职责典型内容事务层TLP事务组装、地址路由、流控信用Memory/IO/Config 读写、Message数据链路层DLLP、带 LCRC 的 TLP可靠传输、ACK/NAK、错误检测Ack/Nak、Flow Control、电源管理物理层有序集、符号流链路训练、编码、电气信号TS1/TS2、SKP、电气空闲这张表建议记牢后面看任何 PCIe 抓包或者调试日志先判断你看到的是哪一层的包思路立刻就清晰了。3. 事务层TLP 是怎么组织一次访问的3.1 TLP 的头部结构决定了它能干什么TLP 的头部不是固定长度而是有3DW12 字节和 4DW16 字节两种。3DW 头用于 32 位地址4DW 头用于 64 位地址。头里包含的关键字段有Format、Type、TCTraffic Class、TD、EP、Attr、Length、Requester ID、Tag、Last DW BE、First DW BE以及地址字段。Format 和 Type 组合起来决定了这个 TLP 是什么事务。比如00000是 Memory Read00010是 Memory Write00100是 Config Read Type 000101是 Config Write Type 0。这些编码在调试配置空间访问问题时特别有用因为你能从抓包直接看出这次访问是读还是写、是配置空间还是内存空间。Length 字段表示这个 TLP 携带多少个 DW双字4 字节的数据范围是 1 到 1024。注意这个上限它意味着单个 TLP 最大只能传 4KB 数据。这也是为什么大块数据传输会被拆成多个 TLP理解这一点对分析带宽和延迟很重要。3.2 地址路由、ID 路由和隐式路由TLP 怎么找到目的地PCIe 定义了三种路由方式地址路由用于 Memory 和 IO 事务。TLP 头里带目标地址沿途的 Switch 根据自己配置空间里的 Base/Limit 寄存器判断这个地址归不归自己管归就往下转发不归就往上或往其他端口转发。ID 路由用于 Configuration 事务。TLP 头里带 Bus/Device/Function 号Switch 根据总线号范围来转发。这就是为什么配置空间访问必须知道设备的 BDFBus:Device:Function。隐式路由用于 Message 事务。消息不靠地址也不靠 ID而是靠消息码本身隐含的路径比如广播到所有设备、或者上报到 RC。这三种路由方式是理解 PCIe 拓扑和枚举过程的基础。你在看枚举日志时配置读写的 TLP 走的就是 ID 路由而 RC 发现下游设备靠的是地址路由和隐式路由的配合。3.3 流控信用为什么 PCIe 不会把接收端撑爆PCIe 用基于信用的流控Credit-Based Flow Control。发送端在发数据前必须先确认接收端有足够的缓冲区空间也就是有足够的“信用”。信用分类型Posted不需要响应的比如 Memory Write、Non-Posted需要响应的比如 Memory Read、Config Read、Completion响应包。每类又分 Header Credit 和 Data Credit。这个机制的好处是发送端永远不会发出超过接收端缓冲能力的数据从根本上避免了溢出。代价是链路初始化时必须先交换信用信息这就是为什么链路训练完成后还要有一段流控初始化的过程。注意流控信用不足是导致 PCIe 性能上不去的一个隐蔽原因。如果你发现带宽远低于理论值除了看链路速率和宽度也要怀疑是不是信用配置不合理或者接收端缓冲太小。3.4 Posted 与 Non-Posted一个影响性能的关键区分Memory Write 是 Posted 的意思是发送端发出去就不管了不需要等响应。Memory Read 是 Non-Posted 的发出去必须等 Completion 回来。这个区别对性能影响巨大。写操作可以流水线式地连续发吞吐高读操作必须等往返延迟敏感。这就是为什么在很多场景下写带宽能跑满而读带宽上不去。你在做 DMA 优化时如果能设计成以写为主的数据流往往能拿到更好的实际带宽。这个经验在做高速采集和存储写入时特别管用。4. 数据链路层可靠传输是怎么逐段保证的4.1 序列号与 ACK/NAK相邻两站之间的可靠性数据链路层给每个 TLP 分配一个 12 位的序列号循环使用。接收端收到 TLP 后检查 LCRC链路 CRC和序列号。如果都对就回一个 Ack DLLP如果 LCRC 错了或者序列号不连续就回 NAK发送端收到 NAK 后重传。这里的关键是这个可靠性只管相邻两个设备之间。A 发给 SwitchSwitch 确认收到了链路层的任务就完成了。至于 Switch 往下一跳转发时会不会丢那是下一段链路的事。所以 PCIe 的可靠性是逐段累积的每一段都可靠整体才可靠。这种设计和 TCP 的端到端重传完全不同。TCP 是发送端一直等到接收端确认才算完中间任何一段丢了都由发送端重传。PCIe 是每一段自己负责发送端把包交给下一站就卸责了。理解这个差异你才能明白为什么 PCIe 的 Switch 需要缓冲以及为什么链路错误会表现为局部重传而不是全局重传。4.2 LCRC 与 ECRC两层 CRC 的分工PCIe 有两层 CRCLCRC在数据链路层ECRC在事务层可选。LCRC 保护的是相邻链路之间的传输每一跳都会重新计算。ECRC 保护的是端到端的数据完整性从发起端一直带到目标端中间 Switch 不修改。ECRC 是可选的很多消费级设备不开。但在一些对数据完整性要求高的场景比如数据中心、存储阵列会打开 ECRC。打开 ECRC 会增加一点开销但能发现那些 LCRC 查不出、却在 Switch 内部转发时引入的错误。4.3 DLLP 的几种类型和它们的用途DLLP 主要有这几类Ack/Nak DLLP确认或否认收到 TLP。Flow Control DLLP更新信用信息包括 InitFC1、InitFC2、UpdateFC。Power Management DLLP电源管理握手比如 PM_Enter_L1、PM_Request_Ack。Vendor Specific DLLP厂商自定义。这些 DLLP 不携带事务数据只在链路层本地消费。你在抓包时如果看到大量 DLLP通常说明链路在频繁做流控更新或者电源管理切换这本身可能就是一个性能信号。4.4 重传机制的实际影响重传不是免费的。每次 NAK 触发重传都会引入延迟而且重传会占用链路带宽。如果链路质量差、误码率高重传频繁实际有效带宽会明显下降。这就是为什么 PCIe 对信号完整性要求那么高——不是为了好看是因为误码直接转化为性能损失。在实际调试中如果你怀疑链路有问题可以关注重传计数。很多 Root Complex 和 Switch 都提供错误计数器重传率异常升高往往指向信号完整性问题比如走线太长、连接器接触不良、参考时钟抖动过大。5. 物理层链路是怎么从无到有建立起来的5.1 Lane、Link 与链路宽度PCIe 的物理连接由Lane组成一条 Link 可以包含 1、2、4、8、16 条 Lane记作 x1、x2、x4、x8、x16。Lane 数量决定了理论带宽x16 的带宽是 x1 的 16 倍。但实际协商出来的宽度不一定等于物理宽度。比如一个 x16 的插槽插上一块 x4 的卡链路就协商成 x4。或者因为信号问题x16 只协商成功 x8。这就是为什么你在lspci里看到的LnkCap和LnkSta可能不一致——Cap 是能力Sta 是实际状态。提示排查性能问题时第一件事就是确认LnkSta里的速率和宽度是不是符合预期。很多“设备跑不满速”的问题根源就是链路降速或降宽。5.2 LTSSM链路训练状态机物理层最核心的机制是LTSSMLink Training and Status State Machine。链路从上电到可用要经历一系列状态Detect、Polling、Configuration、Recovery、L0、L1、L2 等。Detect检测对端是否存在靠接收端检测到的电气特性判断。Polling交换 TS1/TS2 有序集确认双方能通信。Configuration协商链路宽度和 Lane 编号确定哪个 Lane 是 Lane 0。L0正常工作状态TLP 和 DLLP 在这个状态下传输。Recovery链路出错或需要重新协商时进入重新训练。L1/L2低功耗状态。LTSSM 是 PCIe 调试的重灾区。链路起不来、反复进 Recovery、卡在 Configuration 阶段都是常见问题。理解这个状态机的流转逻辑你才能从日志里判断卡在哪一步。5.3 编码方式8b/10b 与 128b/130bGen1 和 Gen2 用8b/10b 编码每 8 位数据编码成 10 位传输开销 20%。Gen3 及以后改用128b/130b 编码每 128 位数据加 2 位同步头开销约 1.5%。这个改动是 Gen3 带宽大幅提升的重要原因之一。编码方式还影响直流平衡和时钟恢复。8b/10b 保证长期的 0/1 平衡便于接收端恢复时钟。128b/130b 用不同的机制达到类似效果。这些底层细节平时不用深究但当你看到“编码开销”这个词时要知道它指的是什么。5.4 有序集与 SKP维持链路同步的机制物理层传输的不只是数据还有有序集Ordered Set比如 TS1、TS2、SKP、EIEOS 等。TS1/TS2 用于链路训练SKP 用于补偿收发两端时钟频率的微小差异。SKP 有序集的机制值得一提因为发送端和接收端的时钟不可能完全同频时间长了缓冲会溢出或读空。SKP 就是定期插入的“填充”接收端可以丢弃或增加 SKP 来调整自己的缓冲深度。这个机制保证了长时间传输不会因为时钟漂移而失步。6. 配置空间与设备识别三层架构之上的管理平面6.1 配置空间的基本布局每个 PCIe 设备都有一个配置空间前 64 字节是标准头部包含 Vendor ID、Device ID、Command、Status、BARBase Address Register等。64 字节之后是能力结构Capability比如 Power Management、MSI、PCIe Capability、MSI-X 等。配置空间通过 BDF 寻址访问方式有两种MMIOMemory-Mapped IO和配置机制Configuration Mechanism。现代系统基本都用 ECAMEnhanced Configuration Access Mechanism把配置空间映射到一段内存地址通过内存读写来访问。6.2 BAR设备怎么“声明”自己要多少地址空间BAR 是设备告诉系统“我需要多大地址空间、是什么类型”的机制。系统在枚举时先往 BAR 写全 1再读回来根据哪些位是可写的来判断空间大小。然后分配一段物理地址写回 BAR。之后 CPU 访问这段地址就会被路由到对应设备。BAR 的坑很多。比如 64 位 BAR 要占用两个 BAR 位置BAR 大小必须是 2 的幂有些设备 BAR 没配好会导致地址冲突。你在调试设备识别问题时BAR 是必查项。6.3 枚举过程系统是怎么发现所有设备的枚举是 RC 从根开始逐级扫描总线、发现设备、分配总线号、配置 BAR 的过程。大致流程是RC 扫描 Bus 0发现设备后读 Vendor ID如果不是 0xFFFF 说明设备存在然后判断是桥还是 EP如果是桥就给它分配一个新的总线号继续往下扫描。这个过程解释了为什么设备路径是0000:00:1c.0这种形式——0000是域00是总线1c是设备号0是功能号。也解释了为什么热插拔需要重新枚举——新设备插入后系统要重新扫描才能发现它。注意枚举顺序和 RC 的实现强相关。有些平台上电后 EP 先启动还是 RC 先启动会影响枚举结果这也是为什么有些设计里要特别注意 PERST# 信号的时序。7. 把这些概念串起来一次内存读的完整旅程7.1 从 CPU 发起访问到数据返回假设 CPU 要读一个 PCIe 设备的内存空间。流程大致是CPU 发起读请求地址落在该设备 BAR 映射的范围内。RC 识别地址生成 Memory Read TLP通过事务层下发。TLP 经过数据链路层加上序列号和 LCRC。物理层把 TLP 编码成符号流通过 Lane 发出去。沿途 Switch 根据地址路由转发。目标设备收到 TLP事务层解析准备数据。设备生成 Completion TLP带上数据原路返回。RC 收到 Completion把数据交给 CPU。这个旅程里每一层都做了自己的事事务层管路由和事务类型数据链路层管可靠传输物理层管信号传输。任何一层出问题这次访问都会失败或变慢。7.2 每一层可能出的问题和对应的排查方向层次典型问题排查方向事务层路由错误、流控信用不足、Completion 超时看配置空间、看流控寄存器、看 RC 错误日志数据链路层重传频繁、LCRC 错误、序列号错乱看错误计数器、查信号完整性物理层链路起不来、降速降宽、反复 Recovery看 LTSSM 日志、查参考时钟、查走线这张表是我实际排查时的思路框架。遇到问题先定位在哪一层再往下钻比盲目试要高效得多。7.3 为什么理解三层架构能帮你少走弯路很多人调 PCIe 问题是“试错式”的换个驱动试试、改个配置试试、重启试试。这种方式偶尔能碰对但效率极低。理解三层架构之后你会先判断问题出在哪一层然后有针对性地查。比如设备识别不到先看物理层链路有没有起来LnkSta 有没有速率和宽度再看配置空间能不能读到 Vendor ID再看枚举有没有分配总线号。这个顺序是从底往上符合 PCIe 的实际工作流程。反过来从驱动往上查往往会绕远路。8. 几个新手最容易混淆的概念澄清8.1 RC、Switch、EP、Bridge 到底怎么区分RCRoot Complex是树的根连接 CPU 和 PCIe 拓扑负责发起事务、枚举设备。EPEndpoint是叶子设备比如 NVMe SSD、网卡。Switch是中间节点扩展链路。Bridge是 PCIe 到其他总线比如 PCI的转换桥现在比较少见。一个常见误解是把 RC 当成“一个设备”。实际上 RC 内部可能包含多个 Root Port每个 Root Port 下面挂一棵子树。你在系统里看到的多个00:01.0、00:1c.0就是不同的 Root Port。8.2 上游端口和下游端口的方向问题Switch 有上游端口Upstream Port和下游端口Downstream Port。上游端口朝向 RC下游端口朝向 EP。这个方向很重要因为很多寄存器和状态是分方向的。比如错误上报下游端口检测到的错误要往上游报。新手容易搞反方向导致看寄存器时理解错含义。记住一句话上游朝根下游朝叶。8.3 配置空间里的 Type 0 和 Type 1配置读写的 TLP 分 Type 0 和 Type 1。Type 0用于访问当前总线上的设备Type 1用于访问下游总线上的设备需要桥来转换。这个区分在枚举时很关键RC 访问自己总线上的设备用 Type 0访问桥下面的设备用 Type 1桥收到 Type 1 后转成 Type 0 再往下发。8.4 热插拔和 PERST# 的关系PERST#是 PCIe 的复位信号低有效。设备上电后PERST# 要保持有效一段时间等电源和时钟稳定后再释放设备才开始链路训练。如果 PERST# 时序不对链路可能起不来或者不稳定。热插拔场景下PERST# 的控制更复杂需要配合热插拔控制器。这也是为什么热插拔功能在消费级平台上支持得不好——硬件和软件都要配合缺一不可。9. 从协议理解到实际调试的衔接9.1 常用工具和它们能看到的层次调试 PCIe常用工具分几类lspci看配置空间、链路状态、能力结构。最基础也最常用。setpci直接读写配置空间寄存器适合精确定位。协议分析仪抓链路层和事务层的包能看到 TLP 和 DLLP。价格贵但问题复杂时无可替代。示波器/眼图仪看物理层信号质量排查信号完整性问题。大部分日常问题用 lspci 和 setpci 就能定位。协议分析仪用在链路层和事务层的疑难杂症上。物理层问题才需要示波器。9.2 看 lspci 输出时该关注什么lspci -vvv的输出信息量很大重点看这几块LnkCap 和 LnkSta链路能力和实际状态确认速率和宽度。DevSta设备状态有没有错误标志。Capabilities支持哪些能力比如 MSI-X、Power Management。BAR 信息地址空间分配情况。如果 LnkSta 的速率或宽度低于 LnkCap说明链路没协商到最佳状态要查物理层。如果 DevSta 有错误标志要查对应的错误类型。9.3 一个真实的排查思路示例假设你遇到“NVMe SSD 顺序读带宽只有标称的一半”。排查思路先看lspci -vvv里 SSD 的 LnkSta确认链路速率和宽度。如果协商成 x2 而不是 x4或者 Gen3 而不是 Gen4问题就在物理层。如果链路正常看 CPU 到 SSD 的路径上有没有瓶颈比如经过 Switch 时上行链路是不是共享的。如果链路和拓扑都正常看是不是读操作本身的特性导致——前面说过读是 Non-Posted延迟敏感如果队列深度不够带宽上不去。最后才怀疑驱动和文件系统层。这个顺序是从底层往上符合 PCIe 的工作逻辑能避免在错误的方向上浪费时间。9.4 协议理解对驱动开发的价值做驱动开发的人如果只照着现成的驱动改遇到问题会很被动。理解 PCIe 协议之后你能看懂驱动里那些pci_read_config_dword、pci_enable_device、pci_request_regions到底在干什么能判断是配置问题还是硬件问题能自己写探测和调试代码。比如你在做基于 LS1028A 的 PCIe 驱动时理解枚举过程和配置空间布局能帮你快速定位设备为什么没被识别、BAR 为什么分配失败。这些都不是靠试错能高效解决的。10. 写在最后的一点个人体会PCIe 协议内容很多但它的设计逻辑其实很一致分层解耦、逐段可靠、信用流控、状态机驱动。抓住这几条主线再看细节就不会迷路。我自己的经验是学 PCIe 不要一上来就啃手册。手册是查阅用的不是学习用的。先建立三层架构的整体认知知道每一层干什么、包长什么样、状态怎么流转然后再带着问题去查手册效率会高很多。遇到具体问题先判断在哪一层再往下钻这个思路比什么都重要。下一篇我会接着讲枚举过程和配置空间的细节包括 RC 怎么一步步发现设备、总线号怎么分配、BAR 怎么配置。这些内容是把三层架构落到实处的关键也是实际调试中最常打交道的部分。如果你在跟着调板子或者写驱动可以先把这篇的三层架构图在脑子里画熟后面会顺很多。
返回列表