306 lines
11 KiB
ReStructuredText
306 lines
11 KiB
ReStructuredText
|
.. SPDX-License-Identifier: GPL-2.0
|
||
|
.. _VAS-API:
|
||
|
|
||
|
===================================================
|
||
|
Virtual Accelerator Switchboard (VAS) userspace API
|
||
|
===================================================
|
||
|
|
||
|
Introduction
|
||
|
============
|
||
|
|
||
|
Power9 processor introduced Virtual Accelerator Switchboard (VAS) which
|
||
|
allows both userspace and kernel communicate to co-processor
|
||
|
(hardware accelerator) referred to as the Nest Accelerator (NX). The NX
|
||
|
unit comprises of one or more hardware engines or co-processor types
|
||
|
such as 842 compression, GZIP compression and encryption. On power9,
|
||
|
userspace applications will have access to only GZIP Compression engine
|
||
|
which supports ZLIB and GZIP compression algorithms in the hardware.
|
||
|
|
||
|
To communicate with NX, kernel has to establish a channel or window and
|
||
|
then requests can be submitted directly without kernel involvement.
|
||
|
Requests to the GZIP engine must be formatted as a co-processor Request
|
||
|
Block (CRB) and these CRBs must be submitted to the NX using COPY/PASTE
|
||
|
instructions to paste the CRB to hardware address that is associated with
|
||
|
the engine's request queue.
|
||
|
|
||
|
The GZIP engine provides two priority levels of requests: Normal and
|
||
|
High. Only Normal requests are supported from userspace right now.
|
||
|
|
||
|
This document explains userspace API that is used to interact with
|
||
|
kernel to setup channel / window which can be used to send compression
|
||
|
requests directly to NX accelerator.
|
||
|
|
||
|
|
||
|
Overview
|
||
|
========
|
||
|
|
||
|
Application access to the GZIP engine is provided through
|
||
|
/dev/crypto/nx-gzip device node implemented by the VAS/NX device driver.
|
||
|
An application must open the /dev/crypto/nx-gzip device to obtain a file
|
||
|
descriptor (fd). Then should issue VAS_TX_WIN_OPEN ioctl with this fd to
|
||
|
establish connection to the engine. It means send window is opened on GZIP
|
||
|
engine for this process. Once a connection is established, the application
|
||
|
should use the mmap() system call to map the hardware address of engine's
|
||
|
request queue into the application's virtual address space.
|
||
|
|
||
|
The application can then submit one or more requests to the engine by
|
||
|
using copy/paste instructions and pasting the CRBs to the virtual address
|
||
|
(aka paste_address) returned by mmap(). User space can close the
|
||
|
established connection or send window by closing the file descriptior
|
||
|
(close(fd)) or upon the process exit.
|
||
|
|
||
|
Note that applications can send several requests with the same window or
|
||
|
can establish multiple windows, but one window for each file descriptor.
|
||
|
|
||
|
Following sections provide additional details and references about the
|
||
|
individual steps.
|
||
|
|
||
|
NX-GZIP Device Node
|
||
|
===================
|
||
|
|
||
|
There is one /dev/crypto/nx-gzip node in the system and it provides
|
||
|
access to all GZIP engines in the system. The only valid operations on
|
||
|
/dev/crypto/nx-gzip are:
|
||
|
|
||
|
* open() the device for read and write.
|
||
|
* issue VAS_TX_WIN_OPEN ioctl
|
||
|
* mmap() the engine's request queue into application's virtual
|
||
|
address space (i.e. get a paste_address for the co-processor
|
||
|
engine).
|
||
|
* close the device node.
|
||
|
|
||
|
Other file operations on this device node are undefined.
|
||
|
|
||
|
Note that the copy and paste operations go directly to the hardware and
|
||
|
do not go through this device. Refer COPY/PASTE document for more
|
||
|
details.
|
||
|
|
||
|
Although a system may have several instances of the NX co-processor
|
||
|
engines (typically, one per P9 chip) there is just one
|
||
|
/dev/crypto/nx-gzip device node in the system. When the nx-gzip device
|
||
|
node is opened, Kernel opens send window on a suitable instance of NX
|
||
|
accelerator. It finds CPU on which the user process is executing and
|
||
|
determine the NX instance for the corresponding chip on which this CPU
|
||
|
belongs.
|
||
|
|
||
|
Applications may chose a specific instance of the NX co-processor using
|
||
|
the vas_id field in the VAS_TX_WIN_OPEN ioctl as detailed below.
|
||
|
|
||
|
A userspace library libnxz is available here but still in development:
|
||
|
|
||
|
https://github.com/abalib/power-gzip
|
||
|
|
||
|
Applications that use inflate / deflate calls can link with libnxz
|
||
|
instead of libz and use NX GZIP compression without any modification.
|
||
|
|
||
|
Open /dev/crypto/nx-gzip
|
||
|
========================
|
||
|
|
||
|
The nx-gzip device should be opened for read and write. No special
|
||
|
privileges are needed to open the device. Each window corresponds to one
|
||
|
file descriptor. So if the userspace process needs multiple windows,
|
||
|
several open calls have to be issued.
|
||
|
|
||
|
See open(2) system call man pages for other details such as return values,
|
||
|
error codes and restrictions.
|
||
|
|
||
|
VAS_TX_WIN_OPEN ioctl
|
||
|
=====================
|
||
|
|
||
|
Applications should use the VAS_TX_WIN_OPEN ioctl as follows to establish
|
||
|
a connection with NX co-processor engine:
|
||
|
|
||
|
::
|
||
|
|
||
|
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:
|
||
|
The version field must be currently set to 1.
|
||
|
vas_id:
|
||
|
If '-1' is passed, kernel will make a best-effort attempt
|
||
|
to assign an optimal instance of NX for the process. To
|
||
|
select the specific VAS instance, refer
|
||
|
"Discovery of available VAS engines" section below.
|
||
|
|
||
|
flags, reserved1 and reserved2[6] fields are for future extension
|
||
|
and must be set to 0.
|
||
|
|
||
|
The attributes attr for the VAS_TX_WIN_OPEN ioctl are defined as
|
||
|
follows::
|
||
|
|
||
|
#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);
|
||
|
|
||
|
The VAS_TX_WIN_OPEN ioctl returns 0 on success. On errors, it
|
||
|
returns -1 and sets the errno variable to indicate the error.
|
||
|
|
||
|
Error conditions:
|
||
|
|
||
|
====== ================================================
|
||
|
EINVAL fd does not refer to a valid VAS device.
|
||
|
EINVAL Invalid vas ID
|
||
|
EINVAL version is not set with proper value
|
||
|
EEXIST Window is already opened for the given fd
|
||
|
ENOMEM Memory is not available to allocate window
|
||
|
ENOSPC System has too many active windows (connections)
|
||
|
opened
|
||
|
EINVAL reserved fields are not set to 0.
|
||
|
====== ================================================
|
||
|
|
||
|
See the ioctl(2) man page for more details, error codes and
|
||
|
restrictions.
|
||
|
|
||
|
mmap() NX-GZIP device
|
||
|
=====================
|
||
|
|
||
|
The mmap() system call for a NX-GZIP device fd returns a paste_address
|
||
|
that the application can use to copy/paste its CRB to the hardware engines.
|
||
|
|
||
|
::
|
||
|
|
||
|
paste_addr = mmap(addr, size, prot, flags, fd, offset);
|
||
|
|
||
|
Only restrictions on mmap for a NX-GZIP device fd are:
|
||
|
|
||
|
* size should be PAGE_SIZE
|
||
|
* offset parameter should be 0ULL
|
||
|
|
||
|
Refer to mmap(2) man page for additional details/restrictions.
|
||
|
In addition to the error conditions listed on the mmap(2) man
|
||
|
page, can also fail with one of the following error codes:
|
||
|
|
||
|
====== =============================================
|
||
|
EINVAL fd is not associated with an open window
|
||
|
(i.e mmap() does not follow a successful call
|
||
|
to the VAS_TX_WIN_OPEN ioctl).
|
||
|
EINVAL offset field is not 0ULL.
|
||
|
====== =============================================
|
||
|
|
||
|
Discovery of available VAS engines
|
||
|
==================================
|
||
|
|
||
|
Each available VAS instance in the system will have a device tree node
|
||
|
like /proc/device-tree/vas@* or /proc/device-tree/xscom@*/vas@*.
|
||
|
Determine the chip or VAS instance and use the corresponding ibm,vas-id
|
||
|
property value in this node to select specific VAS instance.
|
||
|
|
||
|
Copy/Paste operations
|
||
|
=====================
|
||
|
|
||
|
Applications should use the copy and paste instructions to send CRB to NX.
|
||
|
Refer section 4.4 in PowerISA for Copy/Paste instructions:
|
||
|
https://openpowerfoundation.org/?resource_lib=power-isa-version-3-0
|
||
|
|
||
|
CRB Specification and use NX
|
||
|
============================
|
||
|
|
||
|
Applications should format requests to the co-processor using the
|
||
|
co-processor Request Block (CRBs). Refer NX-GZIP user's manual for the format
|
||
|
of CRB and use NX from userspace such as sending requests and checking
|
||
|
request status.
|
||
|
|
||
|
NX Fault handling
|
||
|
=================
|
||
|
|
||
|
Applications send requests to NX and wait for the status by polling on
|
||
|
co-processor Status Block (CSB) flags. NX updates status in CSB after each
|
||
|
request is processed. Refer NX-GZIP user's manual for the format of CSB and
|
||
|
status flags.
|
||
|
|
||
|
In case if NX encounters translation error (called NX page fault) on CSB
|
||
|
address or any request buffer, raises an interrupt on the CPU to handle the
|
||
|
fault. Page fault can happen if an application passes invalid addresses or
|
||
|
request buffers are not in memory. The operating system handles the fault by
|
||
|
updating CSB with the following data::
|
||
|
|
||
|
csb.flags = CSB_V;
|
||
|
csb.cc = CSB_CC_FAULT_ADDRESS;
|
||
|
csb.ce = CSB_CE_TERMINATION;
|
||
|
csb.address = fault_address;
|
||
|
|
||
|
When an application receives translation error, it can touch or access
|
||
|
the page that has a fault address so that this page will be in memory. Then
|
||
|
the application can resend this request to NX.
|
||
|
|
||
|
If the OS can not update CSB due to invalid CSB address, sends SEGV signal
|
||
|
to the process who opened the send window on which the original request was
|
||
|
issued. This signal returns with the following siginfo struct::
|
||
|
|
||
|
siginfo.si_signo = SIGSEGV;
|
||
|
siginfo.si_errno = EFAULT;
|
||
|
siginfo.si_code = SEGV_MAPERR;
|
||
|
siginfo.si_addr = CSB adress;
|
||
|
|
||
|
In the case of multi-thread applications, NX send windows can be shared
|
||
|
across all threads. For example, a child thread can open a send window,
|
||
|
but other threads can send requests to NX using this window. These
|
||
|
requests will be successful even in the case of OS handling faults as long
|
||
|
as CSB address is valid. If the NX request contains an invalid CSB address,
|
||
|
the signal will be sent to the child thread that opened the window. But if
|
||
|
the thread is exited without closing the window and the request is issued
|
||
|
using this window. the signal will be issued to the thread group leader
|
||
|
(tgid). It is up to the application whether to ignore or handle these
|
||
|
signals.
|
||
|
|
||
|
NX-GZIP User's Manual:
|
||
|
https://github.com/libnxz/power-gzip/blob/master/doc/power_nx_gzip_um.pdf
|
||
|
|
||
|
Simple example
|
||
|
==============
|
||
|
|
||
|
::
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|
||
|
Refer https://github.com/libnxz/power-gzip for tests or more
|
||
|
use cases.
|