Commit | Line | Data |
---|---|---|
c12e38b1 HM |
1 | .. SPDX-License-Identifier: GPL-2.0 |
2 | .. _VAS-API: | |
3 | ||
4 | =================================================== | |
5 | Virtual Accelerator Switchboard (VAS) userspace API | |
6 | =================================================== | |
7 | ||
8 | Introduction | |
9 | ============ | |
10 | ||
11 | Power9 processor introduced Virtual Accelerator Switchboard (VAS) which | |
12 | allows both userspace and kernel communicate to co-processor | |
13 | (hardware accelerator) referred to as the Nest Accelerator (NX). The NX | |
14 | unit comprises of one or more hardware engines or co-processor types | |
15 | such as 842 compression, GZIP compression and encryption. On power9, | |
16 | userspace applications will have access to only GZIP Compression engine | |
17 | which supports ZLIB and GZIP compression algorithms in the hardware. | |
18 | ||
19 | To communicate with NX, kernel has to establish a channel or window and | |
20 | then requests can be submitted directly without kernel involvement. | |
21 | Requests to the GZIP engine must be formatted as a co-processor Request | |
22 | Block (CRB) and these CRBs must be submitted to the NX using COPY/PASTE | |
23 | instructions to paste the CRB to hardware address that is associated with | |
24 | the engine's request queue. | |
25 | ||
26 | The GZIP engine provides two priority levels of requests: Normal and | |
27 | High. Only Normal requests are supported from userspace right now. | |
28 | ||
29 | This document explains userspace API that is used to interact with | |
30 | kernel to setup channel / window which can be used to send compression | |
31 | requests directly to NX accelerator. | |
32 | ||
33 | ||
34 | Overview | |
35 | ======== | |
36 | ||
37 | Application access to the GZIP engine is provided through | |
38 | /dev/crypto/nx-gzip device node implemented by the VAS/NX device driver. | |
39 | An application must open the /dev/crypto/nx-gzip device to obtain a file | |
40 | descriptor (fd). Then should issue VAS_TX_WIN_OPEN ioctl with this fd to | |
41 | establish connection to the engine. It means send window is opened on GZIP | |
42 | engine for this process. Once a connection is established, the application | |
43 | should use the mmap() system call to map the hardware address of engine's | |
44 | request queue into the application's virtual address space. | |
45 | ||
e77bfed0 | 46 | The application can then submit one or more requests to the engine by |
c12e38b1 HM |
47 | using copy/paste instructions and pasting the CRBs to the virtual address |
48 | (aka paste_address) returned by mmap(). User space can close the | |
49 | established connection or send window by closing the file descriptior | |
50 | (close(fd)) or upon the process exit. | |
51 | ||
52 | Note that applications can send several requests with the same window or | |
53 | can establish multiple windows, but one window for each file descriptor. | |
54 | ||
55 | Following sections provide additional details and references about the | |
56 | individual steps. | |
57 | ||
58 | NX-GZIP Device Node | |
59 | =================== | |
60 | ||
61 | There is one /dev/crypto/nx-gzip node in the system and it provides | |
62 | access to all GZIP engines in the system. The only valid operations on | |
63 | /dev/crypto/nx-gzip are: | |
64 | ||
65 | * open() the device for read and write. | |
66 | * issue VAS_TX_WIN_OPEN ioctl | |
67 | * mmap() the engine's request queue into application's virtual | |
68 | address space (i.e. get a paste_address for the co-processor | |
69 | engine). | |
70 | * close the device node. | |
71 | ||
72 | Other file operations on this device node are undefined. | |
73 | ||
74 | Note that the copy and paste operations go directly to the hardware and | |
75 | do not go through this device. Refer COPY/PASTE document for more | |
76 | details. | |
77 | ||
78 | Although a system may have several instances of the NX co-processor | |
79 | engines (typically, one per P9 chip) there is just one | |
80 | /dev/crypto/nx-gzip device node in the system. When the nx-gzip device | |
81 | node is opened, Kernel opens send window on a suitable instance of NX | |
82 | accelerator. It finds CPU on which the user process is executing and | |
83 | determine the NX instance for the corresponding chip on which this CPU | |
84 | belongs. | |
85 | ||
86 | Applications may chose a specific instance of the NX co-processor using | |
87 | the vas_id field in the VAS_TX_WIN_OPEN ioctl as detailed below. | |
88 | ||
89 | A userspace library libnxz is available here but still in development: | |
cadcb83f | 90 | |
c12e38b1 HM |
91 | https://github.com/abalib/power-gzip |
92 | ||
93 | Applications that use inflate / deflate calls can link with libnxz | |
94 | instead of libz and use NX GZIP compression without any modification. | |
95 | ||
96 | Open /dev/crypto/nx-gzip | |
97 | ======================== | |
98 | ||
99 | The nx-gzip device should be opened for read and write. No special | |
100 | privileges are needed to open the device. Each window corresponds to one | |
101 | file descriptor. So if the userspace process needs multiple windows, | |
102 | several open calls have to be issued. | |
103 | ||
104 | See open(2) system call man pages for other details such as return values, | |
105 | error codes and restrictions. | |
106 | ||
107 | VAS_TX_WIN_OPEN ioctl | |
108 | ===================== | |
109 | ||
110 | Applications should use the VAS_TX_WIN_OPEN ioctl as follows to establish | |
111 | a connection with NX co-processor engine: | |
112 | ||
113 | :: | |
cadcb83f | 114 | |
c12e38b1 HM |
115 | struct vas_tx_win_open_attr { |
116 | __u32 version; | |
117 | __s16 vas_id; /* specific instance of vas or -1 | |
118 | for default */ | |
119 | __u16 reserved1; | |
120 | __u64 flags; /* For future use */ | |
121 | __u64 reserved2[6]; | |
122 | }; | |
123 | ||
cadcb83f MCC |
124 | version: |
125 | The version field must be currently set to 1. | |
126 | vas_id: | |
127 | If '-1' is passed, kernel will make a best-effort attempt | |
c12e38b1 HM |
128 | to assign an optimal instance of NX for the process. To |
129 | select the specific VAS instance, refer | |
130 | "Discovery of available VAS engines" section below. | |
131 | ||
132 | flags, reserved1 and reserved2[6] fields are for future extension | |
133 | and must be set to 0. | |
134 | ||
135 | The attributes attr for the VAS_TX_WIN_OPEN ioctl are defined as | |
cadcb83f MCC |
136 | follows:: |
137 | ||
c12e38b1 HM |
138 | #define VAS_MAGIC 'v' |
139 | #define VAS_TX_WIN_OPEN _IOW(VAS_MAGIC, 1, | |
140 | struct vas_tx_win_open_attr) | |
141 | ||
142 | struct vas_tx_win_open_attr attr; | |
143 | rc = ioctl(fd, VAS_TX_WIN_OPEN, &attr); | |
144 | ||
145 | The VAS_TX_WIN_OPEN ioctl returns 0 on success. On errors, it | |
146 | returns -1 and sets the errno variable to indicate the error. | |
147 | ||
148 | Error conditions: | |
cadcb83f MCC |
149 | |
150 | ====== ================================================ | |
c12e38b1 HM |
151 | EINVAL fd does not refer to a valid VAS device. |
152 | EINVAL Invalid vas ID | |
153 | EINVAL version is not set with proper value | |
154 | EEXIST Window is already opened for the given fd | |
155 | ENOMEM Memory is not available to allocate window | |
156 | ENOSPC System has too many active windows (connections) | |
157 | opened | |
158 | EINVAL reserved fields are not set to 0. | |
cadcb83f | 159 | ====== ================================================ |
c12e38b1 HM |
160 | |
161 | See the ioctl(2) man page for more details, error codes and | |
162 | restrictions. | |
163 | ||
164 | mmap() NX-GZIP device | |
165 | ===================== | |
166 | ||
167 | The mmap() system call for a NX-GZIP device fd returns a paste_address | |
168 | that the application can use to copy/paste its CRB to the hardware engines. | |
cadcb83f | 169 | |
c12e38b1 HM |
170 | :: |
171 | ||
172 | paste_addr = mmap(addr, size, prot, flags, fd, offset); | |
173 | ||
174 | Only restrictions on mmap for a NX-GZIP device fd are: | |
cadcb83f | 175 | |
c12e38b1 HM |
176 | * size should be PAGE_SIZE |
177 | * offset parameter should be 0ULL | |
178 | ||
179 | Refer to mmap(2) man page for additional details/restrictions. | |
180 | In addition to the error conditions listed on the mmap(2) man | |
181 | page, can also fail with one of the following error codes: | |
182 | ||
cadcb83f | 183 | ====== ============================================= |
c12e38b1 HM |
184 | EINVAL fd is not associated with an open window |
185 | (i.e mmap() does not follow a successful call | |
186 | to the VAS_TX_WIN_OPEN ioctl). | |
187 | EINVAL offset field is not 0ULL. | |
cadcb83f | 188 | ====== ============================================= |
c12e38b1 HM |
189 | |
190 | Discovery of available VAS engines | |
191 | ================================== | |
192 | ||
193 | Each available VAS instance in the system will have a device tree node | |
194 | like /proc/device-tree/vas@* or /proc/device-tree/xscom@*/vas@*. | |
195 | Determine the chip or VAS instance and use the corresponding ibm,vas-id | |
196 | property value in this node to select specific VAS instance. | |
197 | ||
198 | Copy/Paste operations | |
199 | ===================== | |
200 | ||
201 | Applications should use the copy and paste instructions to send CRB to NX. | |
202 | Refer section 4.4 in PowerISA for Copy/Paste instructions: | |
203 | https://openpowerfoundation.org/?resource_lib=power-isa-version-3-0 | |
204 | ||
205 | CRB Specification and use NX | |
206 | ============================ | |
207 | ||
208 | Applications should format requests to the co-processor using the | |
209 | co-processor Request Block (CRBs). Refer NX-GZIP user's manual for the format | |
210 | of CRB and use NX from userspace such as sending requests and checking | |
211 | request status. | |
212 | ||
213 | NX Fault handling | |
214 | ================= | |
215 | ||
216 | Applications send requests to NX and wait for the status by polling on | |
217 | co-processor Status Block (CSB) flags. NX updates status in CSB after each | |
218 | request is processed. Refer NX-GZIP user's manual for the format of CSB and | |
219 | status flags. | |
220 | ||
221 | In case if NX encounters translation error (called NX page fault) on CSB | |
222 | address or any request buffer, raises an interrupt on the CPU to handle the | |
223 | fault. Page fault can happen if an application passes invalid addresses or | |
224 | request buffers are not in memory. The operating system handles the fault by | |
cadcb83f | 225 | updating CSB with the following data:: |
c12e38b1 HM |
226 | |
227 | csb.flags = CSB_V; | |
6068e1a4 | 228 | csb.cc = CSB_CC_FAULT_ADDRESS; |
c12e38b1 HM |
229 | csb.ce = CSB_CE_TERMINATION; |
230 | csb.address = fault_address; | |
231 | ||
232 | When an application receives translation error, it can touch or access | |
233 | the page that has a fault address so that this page will be in memory. Then | |
234 | the application can resend this request to NX. | |
235 | ||
236 | If the OS can not update CSB due to invalid CSB address, sends SEGV signal | |
237 | to the process who opened the send window on which the original request was | |
cadcb83f | 238 | issued. This signal returns with the following siginfo struct:: |
c12e38b1 HM |
239 | |
240 | siginfo.si_signo = SIGSEGV; | |
241 | siginfo.si_errno = EFAULT; | |
242 | siginfo.si_code = SEGV_MAPERR; | |
243 | siginfo.si_addr = CSB adress; | |
244 | ||
245 | In the case of multi-thread applications, NX send windows can be shared | |
246 | across all threads. For example, a child thread can open a send window, | |
247 | but other threads can send requests to NX using this window. These | |
248 | requests will be successful even in the case of OS handling faults as long | |
249 | as CSB address is valid. If the NX request contains an invalid CSB address, | |
250 | the signal will be sent to the child thread that opened the window. But if | |
251 | the thread is exited without closing the window and the request is issued | |
252 | using this window. the signal will be issued to the thread group leader | |
253 | (tgid). It is up to the application whether to ignore or handle these | |
254 | signals. | |
255 | ||
256 | NX-GZIP User's Manual: | |
2886e2df | 257 | https://github.com/libnxz/power-gzip/blob/master/doc/power_nx_gzip_um.pdf |
c12e38b1 HM |
258 | |
259 | Simple example | |
260 | ============== | |
261 | ||
262 | :: | |
cadcb83f | 263 | |
c12e38b1 HM |
264 | int use_nx_gzip() |
265 | { | |
266 | int rc, fd; | |
267 | void *addr; | |
268 | struct vas_setup_attr txattr; | |
269 | ||
270 | fd = open("/dev/crypto/nx-gzip", O_RDWR); | |
271 | if (fd < 0) { | |
272 | fprintf(stderr, "open nx-gzip failed\n"); | |
273 | return -1; | |
274 | } | |
275 | memset(&txattr, 0, sizeof(txattr)); | |
276 | txattr.version = 1; | |
277 | txattr.vas_id = -1 | |
278 | rc = ioctl(fd, VAS_TX_WIN_OPEN, | |
279 | (unsigned long)&txattr); | |
280 | if (rc < 0) { | |
281 | fprintf(stderr, "ioctl() n %d, error %d\n", | |
282 | rc, errno); | |
283 | return rc; | |
284 | } | |
285 | addr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, | |
286 | MAP_SHARED, fd, 0ULL); | |
287 | if (addr == MAP_FAILED) { | |
288 | fprintf(stderr, "mmap() failed, errno %d\n", | |
289 | errno); | |
290 | return -errno; | |
291 | } | |
292 | do { | |
293 | //Format CRB request with compression or | |
294 | //uncompression | |
295 | // Refer tests for vas_copy/vas_paste | |
296 | vas_copy((&crb, 0, 1); | |
297 | vas_paste(addr, 0, 1); | |
298 | // Poll on csb.flags with timeout | |
299 | // csb address is listed in CRB | |
300 | } while (true) | |
301 | close(fd) or window can be closed upon process exit | |
302 | } | |
303 | ||
2886e2df | 304 | Refer https://github.com/libnxz/power-gzip for tests or more |
c12e38b1 | 305 | use cases. |