资讯动态

024、PCIE完成事务:请求的回应

发布时间:2026/10/10 1:25:25 来源:尧图企业网站定制
024、PCIE完成事务请求的回应昨天调一块FPGA的PCIE板卡DMA连续读总是丢数据。逻辑分析仪抓链路层包发现主机发了一串Mem Read请求端点设备也回了Completion包但TLP头里的Byte Count字段竟然全是0xFFF。主机看到这个值直接放弃等待剩余数据DMA引擎就卡在半路了。这个问题让我意识到很多工程师只关心怎么发请求却对Completion的细节一知半解。完成事务是双向对话的闭环PCIE的完成事务Completion不是独立的它必须对应一个之前的非 posted 请求读请求或原子操作。主机发Mem Read TLP到端点端点必须用Completion with DataCpID回应。如果请求是配置读写或IO读写回的是CompletionCp。这个机制保证了请求方知道对方到底收没收到、执没执行。调试时最容易忽略的是Completion的标签匹配。每个非 posted 请求都带唯一的TagTC/Attr字段后面那8位回应包必须原样带回这个Tag。有一次我改FPGA代码时把Tag映射表搞乱了主机收到一堆Tag错位的Completion直接触发Uncorrectable Error。现在我的代码里一定会加个断言assert(comp_tag lookup_table(req_tag)) // 这里必须严丝合缝。那些藏在TLP头里的关键字段Completion TLP的头第三个DW是信息富矿。低12位是Byte Count表示还剩多少字节要传注意是“还剩”不是“本次”。比如主机要读256字节第一个CpID传128字节这里填128第二个CpID传剩下的128字节这里就填0。我开头说的那个bug就是硬件工程师误解了规范把Remaining Byte Count写成了Total Byte Count。第14位是BCMByte Count Modified这个位几乎没人用但某些PCI桥会用它做优化。我的建议是除非你在写桥片驱动否则永远把它设成0。第15位是Error位端点检测到错误就在这拉高同时状态码Status填对应值。状态码000是成功001是Unsupported RequestUR端点发现请求的地址根本不存在就回这个。完成状态码沉默的错误报告者状态码只有3位但信息量很大。除了UR还有CAConfiguration Abort、CRSConfiguration Retry Status。CA通常出现在访问保留的配置空间时。CRS更有意思它专用于主机读设备VID/DID时设备还没准备好。主机收到CRS后会等一会儿再试这个机制让热插拔和电源管理变得平滑。我遇到过一个坑设备启动时PCIE核还没初始化完主机来读配置空间我直接回了UR。结果主机认为设备故障直接禁用了功能。后来改成先回CRS等初始化完成再响应正常数据问题就解决了。关键点设备没准备好时别轻易回URCRS才是友好信号。数据负载与边界对齐Completion with Data的负载对齐规则和请求类型有关。Mem Read的数据必须按DW对齐但起始地址可以是任意字节。比如读从地址0x03开始的4字节第一个DW的高字节有效低字节填0xFF。硬件实现时很多人会忘记做这个移位结果数据对不上。我的代码里永远有这么一段// 根据lower_addr[1:0]移位数据总线 // 别偷懒直接用字节使能有些主机控制器不认 always (*) begin case(lower_addr) 2b00: data_aligned data_raw; // 自然对齐 2b01: data_aligned {data_raw[23:0], 8hFF}; // 右移1字节 // ... 这里踩过坑务必补全所有case endcase end原子操作的Completion也要带数据内容是操作后的原值。比如执行FetchAdd后回的是加法前的内存值。调试原子操作时我习惯在Completion数据里打时间戳这样能跟踪并发操作的顺序。调试经验抓包看三个点用协议分析仪抓Completion包时我必看三个地方一是Byte Count是否递减到0二是Tag是否和请求匹配三是状态码是不是000。如果看到一串Byte Count不变的Completion肯定是硬件状态机卡住了。如果Tag不匹配查地址路由表和Tag分配逻辑。状态码非零时结合请求地址分析——是访问了非法空间还是设备内部错误。有个隐蔽的坑PCI桥可能把大请求拆成多个小请求端点需要处理多个请求但回Completion时可能合并。这时Byte Count的计算容易出错。我的土办法是在FPGA里加个调试FIFO记录每个请求的起始地址、长度和Tag回包时逐个弹出核对。个人建议别把Completion当成简单应答。它携带的状态、剩余计数、数据对齐信息都是链路稳定的关键。硬件设计时Completion状态机应该独立于请求处理流水线避免背压导致的死锁。驱动开发时永远检查Completion状态码即使你认为不会出错。最后记住PCIE是可靠传输协议但可靠是靠正确实现Completion机制换来的——你糊弄它它就糊弄你。调PCIE问题就像破案Completion是现场留下的痕迹。痕迹乱了案子就破不了。把每个字段的来龙去脉想清楚链路层的很多问题会自己浮现出来。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑