OS 在 NUMA 系统中如何路由和处理 MMIO、IO 和 PCI 配置请求?

How are MMIO, IO and PCI configuration request routed and handled by the OS in a NUMA system?

TL;DR

MMIO、IO 和 PCI 配置请求如何路由到 NUMA 系统中的正确节点?
每个节点都有一个“路由 table”,但我的印象是 OS 应该不知道它。
如果 OS 无法更改“路由 table”,它如何重新映射设备?


要正确介绍“路由 table”,即源地址解码器 (SAD),请参阅 Intel Xeon 中的物理地址解码 v3/v4 CPUs:补充数据表

我将首先尝试回顾一下我从论文和几乎没有记录的数据表中收集到的内容。不幸的是,这会使问题变长,并且可能不会包含所有部分。

当请求离开 LLC1 uncore 需要知道将它路由到哪里。

工作站CPUs上,目标是DRAM、PCIe根port/integrated设备或DMI接口。
由于 iMC 寄存器 2 或 PCIe 根端口之一 3/integrated,uncore 可以轻松判断内存请求是否属于 DRAM设备,最终将回退到 DMI。
当然,这也包括 MMIO,并且与端口映射 IO 几乎相同(仅跳过 DRAM 检查)。
PCI 配置请求 (CFG) 按照规范进行路由,唯一需要注意的是,总线 0 上的 CFG 请求不是针对集成设备,而是沿着 DMI 接口发送 4.

服务器上CPU物理地址的目标可以是off-socket。
一个table用于查找节点id(NID)5。这个table叫做SAD。

实际上,SAD 由两个解码器组成:DRAM 解码器(使用 table)和 IO 解码器6(主要由固定的范围和启用位,而且 应该 包含 tables).
如果需要,IO 解码器会覆盖 DRAM 解码器。

DRAM 解码器使用范围列表,每个范围都与目标 NID 列表相关联7。 如果内存、MMIO 或 PCIe 内存映射配置请求 (MMCFG) 匹配某个范围,uncore 将沿着 QPI/UPI 路径将请求发送到所选目标(尚不清楚 SAD 是否可以针对请求者节点本身) .
IO 解码器可以使用固定目标的固定范围的启用位(例如,将遗留 BIOS windows 回收到“BIOS NID”)或使用可变范围,其中部分地址用于索引目标列表。

端口映射 IO 目标在描述为 IO[yyy] 的 table 中查找。
在名为 PCI[zzz].
的 table 中查找 MMCFG IO 目标 CFG 目的地重用 PCI[zzz] table.
这里yyyzzz表示索引函数,即请求地址的一部分(zzz是CFG的总线号)。

所有这些对我来说都很有意义,但是这些 table 没有记录在数据表中,所以像 PCI[zzz] 这样的符号实际上可能意味着完全不同的东西。


虽然关于这些解码器的文档很少甚至没有,但对于原始心智模型来说已经足够了。

我仍然不清楚 SAD 是否用于针对本地资源的请求,或者它们是否仅用于出口请求。
这在以后很重要。

假设当一个请求离开 LLC 时,SAD 用于将其路由到一个组件(最终在同一个套接字中),然后它的处理方式与工作站情况类似8.

只要硬件配置没有改变,SAD 就可以通过固件进行配置,OS 可以完全不了解它们。
但是如果 OS 重新映射位于节点本地 PCIe link 后面的 PCIe 设备会发生什么?

对于到达此类设备的 MMIO 请求,它必须首先到达设备的节点(因为它是系统其余部分唯一的 link),但这只有在正确重新配置 SAD 时才会发生.
可能需要重新配置 SAD 即使是来自与设备相同的节点的请求9.
但是 OS 应该不知道 SAD,是吗?

我有几个可能的答案:

  1. SAD 不用于访问本地资源,OS 将对本地 IO 的访问限制为父节点中的进程(或内核)运行。这避免了重新配置 SAD 的需要。
  2. 固件配置 SAD,使每个节点都有一部分地址 space(比如 2k / N,其中k是物理地址的大小space,N是个数节点)并在 SRAT ACPI table 中报告。 (但是 SRAT 不是可选的吗?)10 OS 然后仅在每个节点内存部分内分配 MMIO 资源。这可能会导致内存使用不理想。
  3. SAD 是一种优化,如果 uncore 不知道将请求路由到哪里,它将把它传递给 QPI/UPI link(s),直到它被节点接收。
  4. 以上都是错误的

1 例如由于错过或由于 UC。

2 例如 TOUM DRAM 可回收的最大物理地址,尽管它不是连续的块。

3 是 PCI-to-PCI (P2P) 桥接器,有设置 IO、可预取和不可预取内存的寄存器 windows.

4 这就是 PCH 设备出现在总线 0 上的原因。服务器 CPU 有两个“内部”总线,它们的编号可以更改。

5 一个节点id由一个socket号和一个非核心组件id组成。我知道可以作为目标的非核心组件是(根据“box”命名法进行名称翻译后):第一个或第二个 Home 代理 (iMC)、系统代理和DMI link.

6 IO解码器table分为IOS(IO Small decoder)和IOL(IO Large decoder)。这反映了两个table的硬件能力,IOS几乎固定,IOL是CAM。两者都与 DRAM table 并行查询,如果两者匹配,IOS 会覆盖 IOL。

7 范围在所有八个目标之间自动交错(即子分区)。要使用少于八个目标,可以使用重复的条目(例如,所有设置为相同的目标与没有交错相同)。

8 我想知道如果 SAD 将请求路由到非核心组件(比如 iMC)但在其回收范围之外会发生什么情况?估计是废了。

9 看上面粗体部分,我不知道SAD如何处理针对本地资源的请求。

10 Linux 在 UMA 机器中伪造一个 NUMA 节点。在我的盒子中,分配给节点的内存数量 包括 MMIO(几乎分配了 10GiB 与 8GiB 或 DRAM)。似乎使用了 E8020 返回的整个范围。

这个答案使用了 Xeon 5500 和 7500 数据表中的元素(使用环和 Rbox 连接到系统的其余部分),但是这个答案谈到了一个系统,其环形总线架构类似于 IvB-EX Xeon e7 v2(使用 2 个环),但也适用于 Haswell-EX(使用 4 个环,在 2 个之间互连)SnB 和 Broadwell。我假设每个环仍分为 4 个 32 字节双向环:snoop/invalidate、data/block、request/address、确认环。

至强 e7 v2:

在复位信号的下降沿,程序包立即确定 NodeID 和相邻的 NodeID、x2APIC 集群 ID 和逻辑处理器 APIC ID(在台式机上的 SnB CPUs 之前,它用于对 MCH 信号进行采样输入引脚来执行此操作;我不确定自 SnB 以来的多插座)。在此之后,缓存和 TLB 被刷新,核心执行 BIST,然后是多插槽 MP initialisation algorithm occurs。 Xeon D-1500 vol2 显示了一个 CPUNODEID 寄存器;我不确定在更改 post-reset 关于 in-flight 交易时会出现什么样的行为。当 CPUNODEID 在其他内核上更改时,SAD 目标列表是否通过自动生成的写入更改,或者它是否触发 SMI 处理程序,或者这是程序员的任务? IDK。据推测,在更改 SAD 配置之前,必须停止所有代理以阻止他们访问 Cbo。

缓存代理

每个套接字都有一个缓存代理和一个本地代理(或 MCC/HCC 上的 2 个 CA 和 2 个 HA)。缓存代理的功能是 address-hashed 跨 Cbo 切片(在 SnB 之前,缓存代理是 Sbox 和与其关联的 50% Cbox 的组合,其中 Sbox 是拾取的 QPI 接口Cbox消息从环上转为QPI消息直接发给Rbox,Cbox是LLC slice和ring bus的接口;在SnB之后,Cbo实现Sbox的功能,Cbox on发送QPI/IDI消息一环界面)。映射是在启动时设置的,因为那是设置监听模式的时间。在 Haswell-EX 上,侦听模式可以在 BIOS 中在无侦听、家庭侦听、早期侦听、源侦听、HS w 之间切换。目录+OSB+HitME缓存或COD,取决于CPU;尽管我还没有看到任何包含与侦听模式相关的 PCIe 配置寄存器的数据表。我不确定 in-flight 事务在 post-reset 更改时会出现什么行为。当 BIOS 禁用内核时,它不会影响继续运行的 Cbo。缓存代理在 Nehalem-EX 上是一个单独的组件(参见 7500 数据表),但在后来的体系结构中,它被用来指代整个 Cbo。 Haswell-EP 上引入的 COD(Cluster on Die)将缓存代理拆分为每个插槽 2 个

CBO

在每个缓存片中都有一个缓存盒,它是 LLC 与系统其余部分(基本上是 LLC 控制器)之间的控制器和代理。 Cbo 包含 Table Of Requests,其中包含所有未决交易。 Cbo 支持三种类型的事务:1. Core/IIO 发起的请求 2. Intel QPI 外部侦听 3. LLC 容量驱逐。每笔交易在 TOR 中都有一个关联条目。 TOR 条目包含 Cbo 唯一标识请求所需的信息(例如地址和交易类型)和跟踪交易当前状态所需的状态元素。

Core/PCIe 请求被地址散列到 select 一个 Cbo 来翻译并将请求放到环上。 core knows what direction on the ring to send the request for smallest latency 因此它将配置相同的地址映射,并等待环上的空位来容纳交易。

核心发起的请求使用 IDI 数据包接口。 IDI (Intra-Die-Interconnect) 显示在 Broadwell-EX 上。该图暗示内核仅使用 IDI 数据包,而 CBos 使用 QPI 和 IDI。 Xeon e7 v2 操作码显示在 Table 2-18 上,QPI 操作码显示在 Table 2-218 上。这也可以防止像 IIO 这样的东西在解码之前声明一个地址,因为它只接受 QPI 操作码。在某些图表中,Ubox 与 IIO 共用一个站点;在其他情况下,它们是分开的。

当空缺到达时,它与Cbo共享的双向停止逻辑会将32字节的flit放入请求环中,如果Cbo需要同时向同一方向发送,则与目标交易selected,否则将使用其他某种形式的仲裁。我假设核心可以在周期中向两个方向写入,停止上的 Cbo 可以从两个方向读取,或者 Cbo 和核心可以根据仲裁写入一个并读取一个。我会想象 IDI flit 的 link 层 header 包含源、目标 ID,允许更高层事务(传输层)被拆分并到达 non-contiguously 作为自由间隙环上出现,所以它知道是否继续缓冲事务然后从环上取下飞片。 (Ring IDI/QPI 和没有link layer source/dest的QPI不同,因为QPI是点对点的;另外QPI只有80位的flit,很容易找到图的;环形总线不是这种情况 headers)。 Cbo 为每个目的地实施 QPI link 层 credit/debit 方案以阻止缓冲区溢出。这个请求可能只需要 1 个 flit,但缓存行提取需要 3 个。Cbo 在它看到分配给它的地址范围内的相关操作码和地址时进行解码。现在它必须解码地址以查看如何处理它。

在 Cbo 中,请求在分配到 TOR 并发送到 LLC 的同时通过 SAD 。 Non-LLC 消息 class 类型在分配到 TOR 时也会通过 SAD。 SAD 接收地址、地址 space、操作码和一些其他事务详细信息。为了帮助减少不同 DRAM 容量所需的解码器条目数量,地址解码器具有多个交错选项,并且在 Xeon 7500 上分为 3 个解码器,优先级从高到低:I/O 小(IOS ) 解码器,I/O 大 (IOL) 解码器,DRAM 解码器。在 Xeon e7 v2 上,有 4 个解码器:DRAM、MMIO、Interleave、legacy.

这些解码器中的每一个都带有一个地址并可以并行访问。与其中一个解码器中的条目匹配的地址会导致解码器查找并生成 QPI 内存属性和 NodeID。每个解码器只允许一次匹配。 higher-priority 解码器中的地址匹配将覆盖 lower-priority 解码器中的同时匹配。

I/O解码器

这里有8个目标列表,PCI[], MIOU[], MIOL[], FWH[], APIC[], IOH[], CPU[], IO[]。这些,连同一些 I/O 解码器条目 are configurable 通过 CBO 设备下的 CSR,每个 Cbo 都有自己的 SAD。 Local Cfg 寄存器,它只是一个映射本地 PCIe 配置寄存器的固定 MMIO 区域,只有一个目标,本地套接字,不需要任何目标列表(它总是会被路由到 Ubox,所以 NodeID将是 7500 上的本地 Ubox。

Intel Xeon processor E7 v2 product family implements 4-bits of NodeID (NID). Intel Xeon processor E7 v2 product family can support up to 2 HAs in each socket. The HAs in the same socket will be differentiated by NID[2]. In cases where the target is only 3 bits, NID[2] is assumed to be zero. Therefore, the socket ID will be NID[3,1:0]. The Intel® Xeon® processor 7500 series implements 5 bits and can support up to four sockets (chosen by NID[3:2] when NID[4] is zero). Within each socket are four devices (NID[1:0]): Intel® 7500 chipset (00), B0/S0 (01), Ubox (10), B1/S1 (11). B0/S0 and B1/S1 are two sets of HAs (Bboxes) and CAs (Sboxes).

E7 v2 有 4 位 NodeID,这意味着它最多可以支持 8 个插槽和每个插槽 2 个 HA。如果一个套接字有 2 个 HA(MCC、HCC),无论它是否处于 COD 模式,它仍将有 2 个单独的 NodeID,并且缓存和 DRAM 位置仍然可以被 NUMA 感知应用程序使用半球位作为 CBos 来利用始终通过散列算法与其套接字一半(半球)中的 HA 相关联。 hash function for instance might cause addr[6] to select a CBo hemisphere in the core and depending on how many (n) CBos are in the hemisphere, addr[x:7] mod n selects the CBo. Each CBo handles a particular range of LLC sets, where the socket's LLC cache covers the entire address range. COD instead creates 2 cache affinity domains (where the CBos in either hemisphere now each cover the full address range instead of half of the address range and therefore become their own official NUMA nodes with a fully spanning cache (rather than 2 NUCA caches) like it's its own socket -- core cache accesses will now never travel across to the other half of the socket, reducing latency, but reducing hit rate as the cache is now half the size -- you can still get this same level of cache latency and more capacity with COD off if you access only the memory associated with the NUCA/NUMA node). The HA that is associated with the CBo hemisphere is also the HA that the CBo uses for DRAM accesses if the DRAM access is local to the socket, because addr[6] is used to select a HA in the DRAM decoder. When there are multiple sockets, addr[8:6] selects a HA, which may be on another socket, so it will use the CBos in the half of addr[6], but the CBo will send the LLC miss to a home agent on another socket if `addr[8:7] of the home agent they are associated with isn't used, if the NUMA scheduler cannot 'affinitise' the process and the memory properly.

这是I/O 解码器列表的释义。 table 包括 IOS 和 IOL 解码器条目。属性,例如CFG,是输出操作码 class,操作码将从中 selected。

DRAM解码器

在Xeon 7500上,DRAM解码器由两个阵列组成,一个CAM阵列和一个有效载荷阵列。 DRAM 解码器在每个阵列中有 20 个条目,用于 20 个最小 256MiB 的不同区域,具有 8 sub-regions(交错)。 DRAM解码器 条目也可用于定义相干、MMIO、MMCG 和 NXM spaces。如果需要多个 PCI 段,则使用 DRAM 解码器条目将其配置在 DRAM 的顶部,但与 4G 以下的普通 PCIe 条目不同,这些条目不应交错,因此多个目标将需要多个 SAD 条目,并且需要将这些相同的 SAD 条目放入每个套接字中。 CAM 阵列具有特殊的比较逻辑来计算地址是否小于或等于每个条目的区域限制,以允许任何区域大小为 256 MiB 的倍数。区域限制地址位 [43:28] 存储在条目的 CAM 数组中(意味着 256MiB 粒度)。有效负载数组 (tgtlist–attr) 每个条目有 42 位。

您希望看到这些 SAD DRAM 解码器条目的 20 个 64 位(保留 6 位)配置寄存器(并且套接字上的所有 SAD 使用的似乎只有一组 SAD 规则),尽管这是 5500,我认为有 still only one set of registers for all the CBo SADs on newer CPUs.

在5500上,你在[19:6]中设置规则的PA[39:26],在SAD_DRAM_RULE_0中设置索引生成方法,然后在SAD_INTERLEAVE_LIST_0中设置目标列表——这设置了解码器字段,并且可能设置了其他字段。必须有一个寄存器来设置条目的半球位(但它没有在数据表上显示),它告诉它用 CboxID[2] 异或列表中 NID 的第一位(它属于什么 HA -- 与当前 Cbox 的 HA 的 NID[1] 相同,即当前 Cbox 的 addr[6])。这个想法是 NID1 在目标列表中总是为 0,这样与当前 Cbox 的 CboxID[2] 的异或导致它成为属于 Cbox 的家乡代理 select (这就是为什么你不需要每个个体的 SAD 条目CBox).

Xeon 5500 Nehalem-EP (Gainestown) 上的目标列表条目是 2 位,属于 DP(双处理器)服务器系列,因此最大只有 2 个插槽(只有 2 个 QPI links,一个用于 IOH,一个用于 inter-CPU),因此最多 4 个 HA。在 7500 (4x QPI) 上它将是 3 位(4 个插槽,每个插槽有 2HA:8HA),它扩展到 4 位以包括冗余 NID[4]。 SAD 和 DRAM 解码入口配置肯定必须在所有套接字上设置相同。

8 个节点 (HA) 的交错是在地址的 addr[8:6] 上完成的,这些节点从发送到目标 HA 的地址中删除(排除),因为它知道自己的 ID。上面的table是针对7500的,其中addr[6]标识套接字上的HA(NodeID[1])。


有两种类型的请求:

非一致性请求

Non-coherent 请求要么是映射到 non-coherent 地址 space 的数据访问(如 MMIO),要么是 non-memory 请求,如 IO read/write, interrupts/events等。当NC请求访问NC内存时,就像连贯请求一样,根据地址的哈希值发送给Cbo。不以内存为目标的 NC 请求 发送到附加到生成请求的核心的 Cbo

MMIO

Cbo 接收到与特定地址相关的交易,通过 I/O 和 DRAM 解码器,存储在 TOR 中,但如果 IDI 操作码不可缓存(例如 PRd),则不会发送到 LLC 切片核心根据 PAT/MTRR 中的内存类型发送,在 L1 访问时读取,WCiL 除外,我认为这会使其他核心和缓存代理中的别名无效。它将在 MMIO 区域之一的 I/O 解码器条目中匹配。在一些 CPUs 上会有 8 个 IOAPIC(在 Xeon 7500 上没有,因为它谈论 ICH/IOH 并且它是 Beckton(Nehalem-EX),所以这是 ringbus 的第一个实现;但是当 PCH 在 Nehalem Ibex Peak 上引入时,它被集成在 IIO 模块的芯片上)。 FECX_(yyyx)XXXh 中的 yyy(位 [15:13])将用于索引到 NodeID 的 APIC[] table。这意味着在 64KiB 的连续区域中每个 IOAPIC 有 8KiB。 SAD 输出 NodeID 和要使用的操作码 (NcRd)。 Xeon 3400 manual 说 'node Id' 被分配给 IIO,也许这是 'chipset/IOH' 节点 ID,但是 E7 v2 没有这个,所以可能有一个隐藏的 select 之间的扩展IIO 和 Ubox 或者可能有一个单独的 ID 附加到 QPI 请求,Cbos 也有一个 ID。然后,IIO 将根据集成的 IIO 和 PCI 桥接寄存器路由 MMIO 访问,并减法解码到 DMI。

此外,MMIO BAR 有 2 个区域 MMIOL 和 MMIOH。根据 PCIEXBAR 的值(如果 PCIEXBAR 为 2GiB,则 MMIOLL 将不存在),最后 7 个插槽中最多有 256MiB MMIOLL 交错,前 7 个插槽中最多有 256MiB MMIOLU。 7500 数据表说 MMIOH 需要每个插槽单独的 I/O 解码器条目。

一般服务器CPU内存布局是这样的:

有一个 SCA_PCIE 子区域占用 256MiB 配置的前 8MiB space 必须在 4GiB 以下的 256MiB 区域中。当事务中的地址在本地 clump 地址范围内(每个插槽 1MiB clump)时,正常的 PCIe 解码将被覆盖,NodeID 被视为 PhysicalAddr[22:20]。请注意,1MiB 是总线 0 (32 dev * 8 func)——所有套接字的总线 0 对所有其他套接字都是可见的。然后将 NodeID 放入带有 NcCfgRd 操作码和 NodeID 目的地的 QPI 事务中,并将 flit 放置在请求环上;然后这将被识别 NID 范围的 QPI link 吸收,一旦在目标套接字上,它将被路由到 Ubox(在 SnB 上,IIO 似乎根据 Xeon 3400 vol2 5.8.1 处理 NcCfg 请求) 将执行配置读取; Ubox 在 7500 上有一个唯一的 NodeID,所以它会被无缝地路由到它(在 e7 v2 上,我们假设这些插入到数据包中有一个隐藏的 ID)。在QPI报文中,Cbo可能会插入请求者NodeID、请求者CBo ID和交易ID; Ubox 缓冲并跟踪事务(我假设在确认环上发送回确认)并在处理完成后将结果(success/failure)发送回数据环上 QPI 数据包中的源节点 ID,并且它将返回 QPI link。 CBo 完成交易,return向数据环上的核心发送一个 IDI 数据包。

如果地址在 8MiB 区域之外但在 256 PCIe 配置中 space 那么它将匹配 I/O 解码器列表中的顶部条目。 zzz 位(显然是位 27-25)用于在目标列表中索引到 select 一个节点。我们知道这显然是总线编号的前 3 位。这必须表明,假设 index = socket no in interleave list,socket 0 allocation wouldtart at bus 8 (with bus 0 as bus 0) socket 1 将作为总线 32 (with bus 0 as bus 1), socket 2 at bus 64 (with bus 0 as bus 2), socket 3 at 96 (with bus 0在总线 3 上)(在发送到套接字 3 的请求中,我假设它删除了 NodeID 位,这样它会看到总线 1 而不是 96(如果它使用别名而不是添加 1,则可能是总线 0))。从此 PCIEXBAR 配置访问 space 将段中的总线数量限制为 32,因此需要分配专用于每个段的完整 256MiB 别名(在 DRAM 解码器中,您可以设置针对特定套接字的 MMCFG 条目大概将目标列表设置为仅包含套接字上的 NodeID),并且对此范围的任何访问都指向该套接字。 PCI[zzz] 似乎意味着:将 PCI 目标列表索引到 select 一个 NodeID 并为请求提供属性 class 的操作码(NcCfgRd/Wr 基于 TOR 详细信息),Cbo还将地址转换为 bus/device/function 号。 BIOS 必须读取此配置寄存器才能为 PCIe 端口上的 PCI-to-PCI 桥输入正确的从属设备编号。

在I/O解码器上还有条目LclCSRs (Local Config), Glb IOH CSRs (IOH Cfg), Glbl CPU CSRs (CPU Cfg), lcl clump CSR(本地集群 CPU 配置)。这些是在不使用 PCIEXBAR 的情况下访问 PCIe 配置 Space 寄存器 (CSR) 的固定 MMIO 别名。

IO

所有套接字都有固定的IO端口和可以在带内存的BAR中设置的IO端口Space Indicator set to IO space.

IO 请求被 Cbo 接收,并在 IO Table 中查找。 IDI 列表上似乎没有单独的 IO 操作码,也没有 PRd 的 UC 写入对应物,可能有一个未记录的操作码,或者它在 WCiL.[=59= 中对其进行编码]

IO请求可以是IO-PCIE或IO-SCA或Non-PCIe-IO。如果地址与底行中的模式匹配并且设置了 IO 位且地址为 CF8/CFC 则将 4 个零插入地址 [11:8](内核只能发出 8 位寄存器索引) ,使 CONFIG_ADDRESS 功能编号 LSB 从第 12 位而不是第 8 位开始,总线编号 MSB 在第 27 位,现在将其与底部第三行进行比较。如果前 5 个总线位匹配,则 NodeID 由 [22:20] 确定,并且 NcCfgRd/Wr 被发送到该 NodeID。如果它不是 CF8/CFC,则目标节点 ID 是通过使用 IO_Addr[15:13] 查找目标列表条目来确定的——因此是 IO 端口的 3 个最高有效位。这意味着每个套接字有 8KiB 的 I/O space,变量 I/O 必须设置在套接字的范围内。对于固定的 I/O 访问,如果您将前 3 位设为套接字的前 3 位,那么理论上它们可以在匹配时被 Cbo 删除;所以为了访问套接字 1 上的 20h,您需要使用 2020h。

其他

可以通过操作码匹配解码器条目的核心发出的请求是: • IntA、Lock、SplitLock、Unlock、SpCyc、DbgWr、IntPriUp、IntLog、IntPhy、EOI、FERR、Quiesce。它们在 TOR 中分配但不发送给 LLC。当硬件锁定操作跨越 2 个缓存行时,使用 SplitLock。锁过去由 Cbo 定向到 Ubox 以停止所有代理以执行原子操作,但这是不必要的开销,因为它可以在缓存一致性协议中实现。因此,Lock RFO 现在被 Cbo 拾取并且它使其他副本无效并做出响应并且内核在此之前无法读取该行(大概是 LLC 中的一个指示器表明该行已锁定在监听中指示的内核中过滤器)。

一致的请求

一致性请求是访问映射到一致性地址的内存地址的请求space。它们通常用于以缓存行粒度 and/or 传输数据以更改缓存行的状态。最常见的一致请求是数据和代码读取、RFO、ItoM 和写回逐出 (WbMtoI)/写回 (WbMtoE) 到 LLC(仅包括缓存)。 Coherent 请求由 Cbo 提供服务,该 Cbo 持有指定地址的 LLC 切片,由散列函数确定。

如果地址解码到 DRAM 区域并且附加到该 Cbo 的最后一级缓存片表明套接字内的核心拥有该行(用于一致读取),则 Cbo 会侦听对该本地核心的请求(这显然是在谈论通过从其他内核访问在 LLC 切片中使用监听过滤器位的包容性 L3;请注意,在 SKL 服务器网状互连(不是桌面,因为它仍然使用环)上,L3 是 non-inclusive;在包含缓存,如果它在 2 个内核中有效,则 LLC 副本有效)。

如果该行不在缓存中(假设 COD/HS 使用目录 (ecc) + OSB + HitME 缓存的模式),则请求缓存行的缓存代理不会广播窥探。相反,它会将 QPI 中的请求转发到拥有该地址的 HA NodeIDSAD 解码器规则,然后将侦听发送到可能拥有该行的其他缓存代理。转发到主节点会增加延迟。然而,HA 可以在 DRAM 的 ECC 位中实现目录以提高性能。该目录用于过滤对远程套接字或节点控制器的监听;在成功的监听响应后,它将在目录缓存中分配一个条目。该目录编码 3 种状态:不存在于任何节点中,在 1 个节点中被修改(需要写回和降级,并且该位可能指示它在目标广播中的哪一半节点),在多个节点中共享(意味着窥探不'必填项);如果一个目录不受支持,我假设它必须在每次 DRAM 访问时监听所有套接字,同时进行访问。 Haswell-EP 还包括目录缓存 (HitMe) 以加速目录查找。但是,每个 HA 只有 14 KiB,这些缓存非常小。因此,只有在节点之间频繁传输的缓存行才会存储在 HitMe 缓存中。目录缓存存储 8 位向量,指示 8 个节点(Haswell-EP 上最多有 3*2 个逻辑 COD 节点)中的哪些节点具有缓存行的副本。当请求到达主节点时,将检查目录缓存。如果它包含请求行的条目,则按照目录缓存的指示发送探听。如果请求在目录缓存中未命中,则 HA 从内存中的地址获取并读取目录位,如果它在某些套接字中被修改,则相应地发送监听,或者如果不需要监听,则直接发送从内存中获取的数据并且不'分配一个条目。 [3]

E7 v2 HA 实现了一个 128 条目的 In flight Memory Buffer(Home tracker),一个 512 条目的 Tracker(Backup Tracker)。所有传入 HA 的归属信道消息都将通过 BT(如果 BT 已启用)。 BT 维护一组 FIFO 以对等待进入 HT 的请求进行排序,以便 HT 条目在可用时分配给最旧的等待请求。它还具有一个 Home Agent 数据缓冲区(一组数据缓冲区,用于在环和内存控制器之间传输数据。它有 128 个条目,每个 Home Tracker 一个)。 HA 需要根据地址解码适当的 DRAM 通道。这个过程称为“目标地址解码”。每个 HA 的 TAD 规则可通过 CSR 配置;规则包括要匹配的内存范围,然后是交错模式,即截断地址的 addr[8:6] 以索引到 DRAM 通道列表中。因为 TAD 包含匹配的地址范围,它允许对 I/O-解码器被盗范围进行内存回收:配置 SAD DRAM 解码器以解码特定回收范围并在 TAD 条目中配置它。 (工作站 CPUs 使用 TOLUD 和 REMAPBASE 等;这些寄存器的设置会改变从它们读取的 Cbo 解码器)。目标通道解码后,请求转发到相应的 BGF(气泡生成器 fifo)。读取时,数据将从 iMC returned 转发到 HADB。在写入时,数据将从环下载到 HADB 并转发到 iMC。服务器处理器上的 iMC 连接到每个插槽的 2 个 SMI2 端口,用于转接卡,通常带有 12 个 DIMM 和一个可扩展的内存缓冲区(例如 Jordan Creek)。 HA 将数据发送回请求的 CBo ID + NodeID。

不匹配

如果地址不匹配任何范围,或匹配地址空洞(non-existent 内存属性),目标默认为套接字的 Ubox,消息被编码为 NcRdPtl 或 NcWrPtl 操作码零长度或全零字节分别启用。 Ubox 将消息视为错误; errors 可以配置为 return 错误响应,或正常完成(return 读取所有数据或防止写入数据更新),有或没有 MCA。该机制用于防止在某些初始化序列期间从外部路由任何非法访问。 7500 系列缓存代理不会在访问标记为不存在内存 (NXM) 的 SAD 地址区域时发出 MCA,除非访问是具有 write-back (WB) 内存属性的存储。


bus numbering on classic PCIe switch diagrams 非常错误。我的 GPU 实际上在总线 1 上(因为它在 PCIe 端口上)。似乎集成的 PCIe 交换机对软件不可见,端口仅显示为总线 0 上的单个 PCIe 控制器/PCI-to-PCI 桥,点对点连接到端口的设备出现在新总线上 no(以太网总线 2 上的控制器和总线 3 上的 WLAN 控制器)。

实际上,PCI-to-PCI 网桥 1 不存在,因为它需要一个在我的系统中不存在的从属总线号。要么它在我的系统上不存在,并且有 2 个集成的 PCI-to-PCI 网桥,如下所示:

或者它确实存在,但是有程序员不可见的寄存器,这些寄存器根据子或子的内容而改变inate PCI-to-PCI 桥和从属总线 no 必须是 0(而不是图中的 1)(这不会因为 2 个总线编号相同而弄乱路由,因为对面的接口不会是总线 0,但直接连接到 PCH 逻辑,因此在设备看来,事务总是源自 PCI-to-PCI 网桥 1,就好像它是根复合体一样,除此之外别无其他)。该图显示了一个非常具有误导性的 PCH; PCIe 接口并不像那样纯粹,并且在必要时被芯片组分解和连接(太昂贵了,无法将所有集成的 PCH 桥和控制器作为单独的 point-to-point 端口上的 PCIe 设备)。

CPU 和 PCH 用作具有逻辑子设备的单个物理 PCIe 设备。 Ubox 拦截 NcCfgRd/NcCfgWr。 IIO+PCH (CPUBUSNO(0)) 设备实际上可以有一个单独的总线编号到内核 (CPUBUSNO(1))。如果总线号是CPUBUSNO(1),或者CPUBUSNO(0)但低于特定的设备号,那么它将直接处理请求。如果它在 CPUBUSNO(0) 上并且设备号在特定设备号之上,那么它会将 0 型配置 TLP 路由到 DMI 接口,其中除逻辑 PCI 桥以外的任何设备都会响应它们的 function/device 编号(它就像一个逻辑桥,就好像它的从属编号就是那个总线编号,尽管在同一条总线上)。如果总线编号>CPUBUSNO(0),那么它会在 DMI 上生成一个类型 1 配置 TLP,它将被具有该从属总线编号的逻辑桥吸收。