PCIe 中的 ARI 介绍

1、PCIe 配置空间回顾

在这里插入图片描述

  • PCI 3.0 Compatible Configuration Space:64 字节是标准配置空间 header,兼容 PCI 3.0
  • PCI Express Capability Structure:标准 PCI 配置空间(前 256 字节)中的一项能力结构,用来描述设备是否支持 PCI Express 及其基本特性。例如:Link Capabilities(链路能力,如带宽、速率)、Device Capabilities(设备能力)、Link Status(链路状态)等
  • PCI Express Extended Configuration Space:PCI Express 为每个功能块(Function)定义了比传统 PCI 更大的配置空间,容纳更多高级能力结构(Extended Capabilities)。例如:Advanced Error Reporting (AER)、Power Budgeting、SR-IOV / ARI Capabilities 等

2、ARI 概念

  Alternative Routing-ID Interpretation (ARI),即可替代的 ID 路由机制,首次在 PCIe gen3 提出。在 PCIe gen1 和 PCIe gen2 中,Requester ID 和 Comleter ID 等 Routing ID 是 16bit 的标识符,由三部分组成,分别是

  • 8-bit Bus Number
  • 5-bit Device Number
  • 3-bit Function Number
    在这里插入图片描述

  由于 PCIe 是端对端设备,作为 Endpoint 类型的设备,只有一个 device,即 device number 恒为 0,此时 5-bit 的 Device Number 没有多大意义,而 3-bit Function Number 只能表示 8 个function,在部分虚拟化场景中(例如 SR-IOV),常常不够用。

  基于以上原因,PCIe gen3 提出了 ARI 机制,通过取消 Device Number 字段,采用 8-bit Function Number 和 8-bit Bus Number 组成 Routing IDs,因此占用一个 bus number 的 Endpoint 设备最大可以拥有 256 个 function(PS:一个Endpoint 可以占用多个 bus number)
在这里插入图片描述
  图 6-13 显示了具有两个 ARI 设备的示例系统拓扑,一个位于 Root Port 下方,一个在 Switch 下方。要访问 ARI Device X 中的扩展功能,Root Port A 必须支持 ARI 转发,并由软件启用。为了访问 ARI Device Y 中的扩展功能,Switch Downstream Port D 必须支持 ARI 转发,并通过软件启用。使用此配置,建议软件不要在 Root Port B 或 Switch Downstream Port C 中启用 ARI 转发。

在这里插入图片描述

2.1 是否支持 ARI Forwarding

  上面我们提到 ARI Forwarding(ARI 转发)的概念。Root Port 或者 Switch Downstream Port 是否支持该功能,是由 PCI Express Capability Structure 中 Device Capabilities 2 Register 寄存器的 Bit5 决定的。
在这里插入图片描述

  • ARI Forwarding Supported :仅适用于 Switch Downstream Ports 和 Root Ports;对于其他 function 类型,必须为 0b。如果 Switch Downstream Ports 或 Root Ports 支持此可选功能,则此位必须设置为1b。

2.2 ARI Forwarding 原理

  当软件启用 ARI Forwarding 并将其应用于一个下行端口(Downstream Port)时,配置请求处理逻辑会发生改变。原本,设备只允许将 Device Number 为 0 的 Type 1 配置请求转换为 Type 0 请求;而启用 ARI Forwarding 后,这一限制被取消。设备可以将任意 Device Number(0–255)对应的 Type 1 请求转换为 Type 0 请求,从而支持扩展的 Function 编号空间。

关于 Type 1 配置请求和 Type 0 配置请求,可以阅读 PCI 总线学习笔记(五)

2.3 注意事项

  强烈建议:软件在设置下行端口(Downstream Port)的 ARI Forwarding Enable 位时,必须确保该端口下挂的设备确实支持 ARI 功能。

  如果在下挂的是非 ARI 设备的情况下启用了 ARI Forwarding,那么该设备可能会错误地将不同的 Device Number 解释为自己的不同功能(Function),从而导致多个 Device Numbers 映射到同一个功能,形成所谓的“别名”(aliasing)问题。这种行为往往会造成配置空间访问混乱,并可能引发严重的系统异常或设备功能错误。

从上面的描述我们也可以看出来,一个带 ARI 功能的 PCIe 设备,只需要使能其直连的 Downstream Port 的 ARI Forwarding 功能,
而不需要关心其所在链路上的所有 Downstream Port。因为 Type1 配置请求转 Type 0 只发生在 Downstream Port 到其直连的 PCIe 设备之间

3、ARI Capability

  ARI 是一项可选功能。每个 ARI 设备中需各自实现该功能。该功能不适用于根端口(Root Port)、交换机下行端口(Switch Downstream Port)、RCiEP,或根复合事件收集器(Root Complex Event Collector)。
在这里插入图片描述

3.1 ARI Capability Header (Offset 00h)

在这里插入图片描述

3.2 ARI Capability Register (Offset 04h)

在这里插入图片描述
在这里插入图片描述
这其中的 next function number,可以知道下一个 func 的编号,用来访问 ARI 设备的下一个 func。

static unsigned next_fn(struct pci_bus *bus, struct pci_dev *dev, unsigned fn)
{
	int pos;
	u16 cap = 0;
	unsigned next_fn;
	/* 处理开启 ARI 情况 */
	if (pci_ari_enabled(bus)) {
		if (!dev)
			return 0;
		pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
		if (!pos)
			return 0;
		/* 这里读取的就是 Next Function Number 寄存器来获取下一个 func 号 */
		pci_read_config_word(dev, pos + PCI_ARI_CAP, &cap);
		next_fn = PCI_ARI_CAP_NFN(cap);
		if (next_fn <= fn)
			return 0;	/* protect against malformed list */

		return next_fn;
	}
	
	/* 处理一般情况(no-ARI) */
	/* dev may be NULL for non-contiguous multifunction devices */
	if (!dev || dev->multifunction)
		return (fn + 1) % 8;

	return 0;
}

int pci_scan_slot(struct pci_bus *bus, int devfn)
{
	unsigned fn, nr = 0;
	struct pci_dev *dev;
	
	/* 这里会过滤所有 devfn 不为 0 的设备 */
	if (only_one_child(bus) && (devfn > 0))
		return 0; /* Already scanned the entire slot */

	dev = pci_scan_single_device(bus, devfn);
	if (!dev)
		return 0;
	if (!pci_dev_is_added(dev))
		nr++;

	/* 这里就是为了处理,对于多 func 设备来说(包括开启 ARI),在扫描 devfn=0 时,就需要把其它功能一块扫描了 */
	for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) {
		dev = pci_scan_single_device(bus, devfn + fn);
		if (dev) {
			if (!pci_dev_is_added(dev))
				nr++;
			dev->multifunction = 1;
		}
	}

	/* Only one slot has PCIe device */
	if (bus->self && nr)
		pcie_aspm_init_link_state(bus->self);

	return nr;
}

3.3 ARI Control Register (Offset 06h)

在这里插入图片描述

4、ARI 配置过程

Linux 下 ARI 配置的一个过程

pci_device_add 
--> pci_init_capabilities()
	--> pci_configure_ari()

这个函数其实挺简单,我们来梳理一下:

/**
 * pci_configure_ari - enable or disable ARI forwarding
 * @dev: the PCI device
 *
 * If @dev and its upstream bridge both support ARI, enable ARI in the
 * bridge.  Otherwise, disable ARI in the bridge.
 */
void pci_configure_ari(struct pci_dev *dev)
{
	u32 cap;
	struct pci_dev *bridge;

	if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn)
		return;
		
	/* bridge 可以理解为 dev 的 Upstream Port,也就是 Switch 的 Downstream Port */
	bridge = dev->bus->self;
	if (!bridge)
		return;
	
	/* 判断 Downstream Port 是否支持 ARI Forwarding */
	pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap);
	if (!(cap & PCI_EXP_DEVCAP2_ARI))
		return;

	/* 
	 *  判断 dev 是否支持 ARI 功能(通过寻找 ARI Capability)
 	 *  如果 dev 支持 ARI 功能,则使能其上一级 Upstream Port 的 ARI Forwarding 功能
 	 *  否则,关闭其上一级 Upstream Port 的 ARI Forwarding 功能
	 */
	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI)) {
		pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2,
					 PCI_EXP_DEVCTL2_ARI);
		bridge->ari_enabled = 1;
	} else {
		pcie_capability_clear_word(bridge, PCI_EXP_DEVCTL2,
					   PCI_EXP_DEVCTL2_ARI);
		bridge->ari_enabled = 0;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值