虚拟加速器交换机 (VAS) 用户空间 API¶
简介¶
Power9 处理器引入了虚拟加速器交换机 (VAS),它允许用户空间和内核与称为嵌套加速器 (NX) 的协处理器(硬件加速器)通信。NX 单元由一个或多个硬件引擎或协处理器类型组成,例如 842 压缩、GZIP 压缩和加密。在 power9 上,用户空间应用程序将只能访问硬件中支持 ZLIB 和 GZIP 压缩算法的 GZIP 压缩引擎。
为了与 NX 通信,内核必须建立一个通道或窗口,然后可以直接提交请求,而无需内核参与。发送到 GZIP 引擎的请求必须格式化为协处理器请求块 (CRB),并且这些 CRB 必须使用 COPY/PASTE 指令提交到 NX,以将 CRB 粘贴到与引擎的请求队列关联的硬件地址。
GZIP 引擎提供两个优先级的请求:普通和高。目前,用户空间仅支持普通请求。
本文档介绍了用于与内核交互以设置通道/窗口的用户空间 API,该通道/窗口可用于将压缩请求直接发送到 NX 加速器。
概述¶
通过 VAS/NX 设备驱动程序实现的 /dev/crypto/nx-gzip 设备节点提供应用程序对 GZIP 引擎的访问。应用程序必须打开 /dev/crypto/nx-gzip 设备才能获取文件描述符 (fd)。然后应使用此 fd 发出 VAS_TX_WIN_OPEN ioctl 以建立与引擎的连接。这意味着在此进程的 GZIP 引擎上打开了发送窗口。建立连接后,应用程序应使用 mmap() 系统调用将引擎请求队列的硬件地址映射到应用程序的虚拟地址空间。
然后,应用程序可以使用 copy/paste 指令并将 CRB 粘贴到 mmap() 返回的虚拟地址(又名 paste_address),从而向引擎提交一个或多个请求。用户空间可以通过关闭文件描述符 (close(fd)) 或在进程退出时关闭已建立的连接或发送窗口。
请注意,应用程序可以使用同一个窗口发送多个请求,也可以建立多个窗口,但每个文件描述符对应一个窗口。
以下部分提供了有关各个步骤的更多详细信息和参考资料。
NX-GZIP 设备节点¶
系统中有一个 /dev/crypto/nx-gzip 节点,它提供对系统中所有 GZIP 引擎的访问。/dev/crypto/nx-gzip 上唯一有效的操作是
打开 () 设备进行读取和写入。
发出 VAS_TX_WIN_OPEN ioctl
将引擎的请求队列 mmap() 到应用程序的虚拟地址空间中(即,获取协处理器引擎的 paste_address)。
关闭设备节点。
此设备节点上的其他文件操作是未定义的。
请注意,复制和粘贴操作直接转到硬件,而不是通过此设备。有关更多详细信息,请参阅 COPY/PASTE 文档。
尽管系统可能具有多个 NX 协处理器引擎实例(通常,每个 P9 芯片一个),但系统中只有一个 /dev/crypto/nx-gzip 设备节点。当打开 nx-gzip 设备节点时,内核会在 NX 加速器的合适实例上打开发送窗口。它会找到用户进程正在执行的 CPU,并确定此 CPU 所属芯片的相应 NX 实例。
应用程序可以使用 VAS_TX_WIN_OPEN ioctl 中的 vas_id 字段来选择特定的 NX 协处理器实例,如下所述。
这里提供了一个用户空间库 libnxz,但仍在开发中
使用 inflate/deflate 调用的应用程序可以链接 libnxz 而不是 libz,并使用 NX GZIP 压缩,而无需进行任何修改。
打开 /dev/crypto/nx-gzip¶
应打开 nx-gzip 设备进行读取和写入。打开设备不需要特殊权限。每个窗口对应一个文件描述符。因此,如果用户空间进程需要多个窗口,则必须发出多个打开调用。
有关其他详细信息(例如返回值、错误代码和限制),请参阅 open(2) 系统调用手册页。
VAS_TX_WIN_OPEN ioctl¶
应用程序应按如下方式使用 VAS_TX_WIN_OPEN ioctl 以建立与 NX 协处理器引擎的连接
struct vas_tx_win_open_attr { __u32 version; __s16 vas_id; /* specific instance of vas or -1 for default */ __u16 reserved1; __u64 flags; /* For future use */ __u64 reserved2[6]; };
- 版本
version 字段当前必须设置为 1。
- vas_id
如果传递了“-1”,则内核会尽最大努力为进程分配 NX 的最佳实例。要选择特定的 VAS 实例,请参阅下面的“发现可用的 VAS 引擎”部分。
flags、reserved1 和 reserved2[6] 字段用于未来扩展,必须设置为 0。
VAS_TX_WIN_OPEN ioctl 的属性 attr 定义如下
#define VAS_MAGIC 'v' #define VAS_TX_WIN_OPEN _IOW(VAS_MAGIC, 1, struct vas_tx_win_open_attr) struct vas_tx_win_open_attr attr; rc = ioctl(fd, VAS_TX_WIN_OPEN, &attr);VAS_TX_WIN_OPEN ioctl 成功返回 0。如果出错,则返回 -1 并设置 errno 变量以指示错误。
错误条件
EINVAL
fd 不引用有效的 VAS 设备。
EINVAL
无效的 vas ID
EINVAL
version 未设置为正确的值
EEXIST
已为给定的 fd 打开窗口
ENOMEM
没有可用于分配窗口的内存
ENOSPC
系统打开了太多活动窗口(连接)
EINVAL
保留字段未设置为 0。
有关更多详细信息、错误代码和限制,请参阅 ioctl(2) 手册页。
mmap() NX-GZIP 设备¶
NX-GZIP 设备 fd 的 mmap() 系统调用返回 paste_address,应用程序可以使用该地址将其 CRB 复制/粘贴到硬件引擎。
paste_addr = mmap(addr, size, prot, flags, fd, offset);对 NX-GZIP 设备 fd 的 mmap 的唯一限制是
大小应为 PAGE_SIZE
offset 参数应为 0ULL
有关其他详细信息/限制,请参阅 mmap(2) 手册页。除了 mmap(2) 手册页上列出的错误条件外,还可能因以下错误代码之一而失败
EINVAL
fd 未与打开的窗口关联(即 mmap() 不遵循对 VAS_TX_WIN_OPEN ioctl 的成功调用)。
EINVAL
offset 字段不是 0ULL。
发现可用的 VAS 引擎¶
系统中每个可用的 VAS 实例都将具有一个设备树节点,例如 /proc/device-tree/vas@* 或 /proc/device-tree/xscom@*/vas@*。确定芯片或 VAS 实例,并使用此节点中对应的 ibm,vas-id 属性值来选择特定的 VAS 实例。
复制/粘贴操作¶
应用程序应使用复制和粘贴指令将 CRB 发送到 NX。有关复制/粘贴指令,请参阅 PowerISA 中的第 4.4 节:https://openpowerfoundation.org/?resource_lib=power-isa-version-3-0
CRB 规范和使用 NX¶
应用程序应使用协处理器请求块 (CRB) 来格式化发送到协处理器的请求。有关 CRB 的格式以及如何从用户空间使用 NX(例如发送请求和检查请求状态),请参阅 NX-GZIP 用户手册。
NX 故障处理¶
应用程序将请求发送到 NX 并通过轮询协处理器状态块 (CSB) 标志来等待状态。NX 在处理每个请求后都会更新 CSB 中的状态。有关 CSB 和状态标志的格式,请参阅 NX-GZIP 用户手册。
如果 NX 在 CSB 地址或任何请求缓冲区上遇到转换错误(称为 NX 页面错误),则会在 CPU 上引发中断以处理该错误。如果应用程序传递了无效地址或请求缓冲区不在内存中,则可能会发生页面错误。操作系统通过使用以下数据更新 CSB 来处理该错误
csb.flags = CSB_V;
csb.cc = CSB_CC_FAULT_ADDRESS;
csb.ce = CSB_CE_TERMINATION;
csb.address = fault_address;
当应用程序收到转换错误时,它可以触摸或访问具有故障地址的页面,以便该页面位于内存中。然后,应用程序可以将此请求重新发送到 NX。
如果操作系统由于 CSB 地址无效而无法更新 CSB,则会向在发出原始请求时打开发送窗口的进程发送 SEGV 信号。此信号返回以下 siginfo 结构
siginfo.si_signo = SIGSEGV;
siginfo.si_errno = EFAULT;
siginfo.si_code = SEGV_MAPERR;
siginfo.si_addr = CSB address;
在多线程应用程序中,NX 发送窗口可以在所有线程之间共享。例如,子线程可以打开一个发送窗口,但其他线程可以使用此窗口向 NX 发送请求。即使在操作系统处理故障的情况下,只要 CSB 地址有效,这些请求也会成功。如果 NX 请求包含无效的 CSB 地址,则信号将发送到打开窗口的子线程。但是,如果线程在未关闭窗口的情况下退出,并且使用此窗口发出请求,则信号将发送到线程组领导者 (tgid)。应用程序可以选择忽略或处理这些信号。
NX-GZIP 用户手册: https://github.com/libnxz/power-gzip/blob/master/doc/power_nx_gzip_um.pdf
简单示例¶
int use_nx_gzip() { int rc, fd; void *addr; struct vas_setup_attr txattr; fd = open("/dev/crypto/nx-gzip", O_RDWR); if (fd < 0) { fprintf(stderr, "open nx-gzip failed\n"); return -1; } memset(&txattr, 0, sizeof(txattr)); txattr.version = 1; txattr.vas_id = -1 rc = ioctl(fd, VAS_TX_WIN_OPEN, (unsigned long)&txattr); if (rc < 0) { fprintf(stderr, "ioctl() n %d, error %d\n", rc, errno); return rc; } addr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0ULL); if (addr == MAP_FAILED) { fprintf(stderr, "mmap() failed, errno %d\n", errno); return -errno; } do { //Format CRB request with compression or //uncompression // Refer tests for vas_copy/vas_paste vas_copy((&crb, 0, 1); vas_paste(addr, 0, 1); // Poll on csb.flags with timeout // csb address is listed in CRB } while (true) close(fd) or window can be closed upon process exit }有关测试或更多用例,请参考 https://github.com/libnxz/power-gzip。