🔥点击查看精选 CXL 系列文章🔥
🔥点击进入【芯片设计验证】社区,查看更多精彩内容🔥
📢 声明:
- 🥭 作者主页:【MangoPapa的CSDN主页】。
- ⚠️ 本文首发于CSDN,转载或引用请注明出处【https://mangopapa.blog.csdn.net/article/details/132129740】。
- ⚠️ 本文目的为 个人学习记录 及 知识分享。因个人能力受限,存在协议解读不正确的可能。若您参考本文进行产品设计或进行其他事项并造成了不良后果,本人不承担相关法律责任。
- ⚠️ 若本文所采用图片或相关引用侵犯了您的合法权益,请联系我进行删除。
- 😄 欢迎大家指出文章错误,欢迎同行与我交流 ~
- 📧 邮箱:mangopapa@yeah.net
- 💬 直达博主:loveic_lovelife 。(搜索或点击扫码)
文章目录
- 1. Bogus 是什么?
- 1.1 Bogus 概念
- 1.2 Bogus 应用场景
- 1.3 对 Host 和 Device 的要求
- 2. 为什么需要 Bogus?
- 2.1 Snoop & GO_WritePull 只响应其一?
- 3. Q&A
- 4. 参考
为便于表述,下述 Cacheline 均指 Device Cache 内归属于 Host Memory 的 Cacheline。
1. Bogus 是什么?
1.1 Bogus 概念
Bogus 是 CXL.cache D2H Data 中的一个字段,指示当前写的数据为伪数据,常用于 Host Snoop 与 Device Evict 相同 Cacheline 的场景,Host 收到该数据后应予以丢弃。
具体而言,在 Device 发出 Evict 请求之后、收到 GO_WritePull 响应之前收到了 Host 发来的针对该地址的 Snoop 请求,Device 先行对该 Snoop 进行响应并通过 D2H Data Channel 反馈该 Cacheline 的最新数据。紧接着,Device 收到 Host 发来的针对此前 Evict 请求的 GO_WritePull 响应,再次通过 D2H Data 反馈 Evict Cacheline 的数据,同时将 D2H Data Flit 中 Bogus 字段置一,提示 Host 当前数据此前已经发过一次,当前数据可能已经过期,Host 收到后直接丢弃数据。一次针对相同地址的 Evict+Snoop 的流程示意图如下图所示。
CXL 协议 Compliance 章节的算法 1b 中提到了 Bogus Write 的概念,笔者理解其并非 Bogus=1 的 Cache 写请求,而是常规的 Bogus=0 的写请求。
1.2 Bogus 应用场景
Bogus=1 仅适用于采用 Evict 原语进行写数据的场景。Device 可以采用 DirtyEvict、CleanEvict、CleanEvictNoData 等 D2H Evict 请求来释放 Device Cache 内归属于 Host Memory 的 Cacheline。发起 Evict 请求的前提是该 Cacheline 在 Device Cache 内的状态为 Modified 或 Shared/Exclusive,不能为 Invalid,这也意味着 Evict 请求在到达 Host 之前 Host Snoop Filter 仍然会 Track 该 Cacheline。
对于 WrInv、WoWrInv*、ItoMWr 及 WrCur 写数据,不存在需要 Bogus=1 的情况。笔者理解,有两大原因:
- 能够发起非 Evict 的写请求的前提是该 Cacheline 在 Device Cache 内的状态已经变为 Invalid,常规情况下其在 Host Snoop Filter 中的 Tracker 已经被释放了,Host SF 不应对其进行 Snoop 相关 Track,Device 也不应对一条 Invalid 的 Cacheline 进行 Evict 操作。
- 即便 Host SF 对齐进行 Snoop,Snoop 到的也是早已处于 Invalid 状态的 Cacheline,收到的响应只能是 RspIHitI,不涉及 Snoop 相关的 Data 反馈。再即便采用 Evict 该 Invalid 的 Cacheline,Evict 的数据也是第一次传输,为 Real Data,而非 Bogus Data。
1.3 对 Host 和 Device 的要求
为了实现有效的 Bogus 传输,协议对 Host 和 Device 有如下要求:
- 对于 Host,其内不能同时存在处于 Active 状态的针对同一 Cacheline 的 WritePull 和 Snoop Entry。也就是说,Host 在发出 Snoop 请求之后、收到 Snoop 对应的 Rsp 和/或 Data 之前,不能反馈相同地址的 WritePull 给 Device;反之亦然,Host 发出 WritePull 之后、收到 WritePull 对应的 Data 之前,不能发送相同地址的 Snoop 请求到 Device。
- 对于 Device,若其发出 Evict 请求之后收到了相同 Cacheline 的 Snoop 请求、Cacheline 状态变动并反馈了 Data 给 Host,接下来 Device 收到 WritePull 反馈 Data 的时候,必须设置 Bogus=1。
2. 为什么需要 Bogus?
我们抛开上边提到的约束,来探究下为什么要这么干——
我们知道,CXL 系统有两个场景会用到 D2H Data Channel:
- Device 主动发起 CXL.cache 写请求,在收到 Host 发来的 WritePull 响应后,Device 通过 D2H Data 发送写数据。
- Host 发起 Snoop 请求,Device 通过 D2H Data 来反馈数据。
假设允许在收齐 Rsp/Data 之前针对同一地址的 Cacheline 发送 GO_WritePull 和 Snoop 请求(协议不允许),我们分两种情况来讨论:
- 先发 GO_WritePull,再发 Snoop。这种情况显然没必要。Evict 请求是 Device 对 Host 的一种保证,保证 Device Cache 内已经没有该 Cacheline 的副本了,且 DirtyEvict/CleanEvict 接下来还会把数据反馈给 Host。要数据有数据,要状态有状态,还没提问,已有答案,Host 有什么想不开的非要再 Snoop 一次?直接执行就好了。
- 先发 Snoop,再发 GO_WritePull。我们知道,Snoop 走 H2D Req 通道,GO_WritePull 走 H2D Rsp 通道,两通道相互独立;我们还知道,根据排序规则,H2D Rsp 可以超过 H2D Req,即 GO_WritePull 可以超过 Snoop。这也就意味着,CXL 系统并不能保证 Snoop 和 GO_WritePull 哪个先到 Device。
针对上述第二种情况,不管 Snoop 先到还是 GO_WritePull 先到,接下来针对这两笔请求,D2H 上会先后出现两笔 Data。至于哪个先到 Host,并不确定。更要命的是两笔数据并不一定相同。
此外,笔者认为,Snoop 和 GO_WritePull 先后脚到达 Device,Device 同时处理起来容易造成混乱。Device 收到 Snoop 后,DCOH 在 Device Cache 之间进行 Cache 一致性相关处理,此间具体耗时并不明确。处理 Snoop 或许会改变 Cacheline 状态,处理 GO_WritePull 后 Invalid 相关 Cacheline,显然一方对 Cacheline 状态的修改均会影响另一方,导致另一方处理出错。
再考虑一种情况,虽然 Device 不知道其是否能收到 Snoop,但其知道其已经发出了 Evict 且还没收到 GO_WritePull,等待 GO_WritePull 期间,收到的 Snoop 先 Pending 在 Device 不就好了么?——不行。一来,即便先处理 GO_WritePull 再处理 Snoop,也不确保其 Data 就比 Snoop 对应的 Data 先到达。二来,笔者认为 Go_WritePull Pending 比 Snoop Rsp Pending@Device 代价更小一些——从发起请求方的重要性来看,Snoop 由 Host 发起,可能涉及到的组件更多,或许其他组件正在等待 Snoop 的 Rsp 以进行下一步运算处理;Evict 由 Device 发起,Pending 的组件只有 Device 自己,Device 本身不打算用这条 Cacheline 了才 Evict,对 Device 性能影响较小。
综合下来,为了解决以上各种问题,较好的方案便是协议提到的——Host 等待收齐 Snoop 的 Rsp/Data 之后再反馈相同地址的 GO_WritePull。对 Device 而言,若其发出 Evict 请求后在等待 GO_WritePull 期间收到相同 Cacheline 的 Snoop 请求则进行响应。待收到 GO_WritePull 之后,若 Evict 和 GO_WritePull 期间曾经反馈该地址的 Data,则再次反馈 Data 时标注 Bogus=1。通过这种方式,能够保证 Snoop 的 Data 一定比 GO_WritePull 的 Data 先到。如果此前处理 Snoop 时未反馈 Data,笔者理解接下来处理 GO_WritePull 时 Bogus 不应置一。
此外,如果从 Snoop 到 GO_WritePull 相关 Cacheline 的数据并未发送变动,似乎 Bogus=0 也讲得过去,但这样 Host 会重复更新该地址,似无必要。
2.1 Snoop & GO_WritePull 只响应其一?
Host 端发出 Snoop 和 GO_WritePull 后,相关 Entry 已经创建并等待 Rsp/Data,如果不回复,Host 会报错。
Host 发出 Snoop 后又收到了 Evict,Host 直接忽略该 Evict 不就好了么?显然也不应该,因为 Device 中 Evict 相关 Entry 也已创建,需要回复 GO_WritePull 来清除 Entry。当然,Device 等待 GO_WritePull 期间收到相关 Snoop,用这个 Snoop 替代 GO_WritePull 来消除 Evict 创建的 Entry,理论上似乎也讲得过去,但总感觉是个歪路子,而且会增加 Device 的设计复杂度。
3. Q&A
- H2D Data 支持 Bogus 吗?
对 CXL.cache 协议而言,不需要。CXL.mem 中的 BISnp、Evict 后边再说。 - Bogus 的意义是什么?
伪数据。该数据此前发送过一次,此时可能已过期,Host 不能使用。 - 如果 Snoop 没有 Data 返回,WritePull 的 Data 还需要 Bg=1 吗?
笔者理解不需要。
4. 参考
- CXL Base Spec, r3.0
|
🔥 精选往期 CXL 协议系列文章,请查看【 CXL 专栏】🔥
⬆️ 返回顶部 ⬆️