对 CXL.cache 伪数据(Bogus Data)的解读



点击查看精选 CXL 系列文章
点击进入【芯片设计验证】社区,查看更多精彩内容


声明

  • 作者主页:【MangoPapa的CSDN主页】。
  • ⚠️ 本文首发于CSDN,转载或引用请注明出处【https://mangopapa.blog.csdn.net/article/details/132129740】。
  • ⚠️ 本文目的为 个人学习记录知识分享。因个人能力受限,存在协议解读不正确的可能。若您参考本文进行产品设计或进行其他事项并造成了不良后果,本人不承担相关法律责任。
  • ⚠️ 若本文所采用图片或相关引用侵犯了您的合法权益,请联系我进行删除。
  • 欢迎大家指出文章错误,欢迎同行与我交流 ~
  • 邮箱:[email protected]
  • 直达博主: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.cache 伪数据(Bogus Data)的解读_第1张图片

  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

  1. H2D Data 支持 Bogus 吗?
    对 CXL.cache 协议而言,不需要。CXL.mem 中的 BISnp、Evict 后边再说。
  2. Bogus 的意义是什么?
    伪数据。该数据此前发送过一次,此时可能已过期,Host 不能使用。
  3. 如果 Snoop 没有 Data 返回,WritePull 的 Data 还需要 Bg=1 吗?
    笔者理解不需要。


4. 参考

  1. CXL Base Spec, r3.0

— END —


精选往期 CXL 协议系列文章,请查看【 CXL 专栏】

⬆️ 返回顶部 ⬆️

你可能感兴趣的:(CXL,协议,CXL)