Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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 | |
Randy Dunlap | e77bfed | 2020-07-07 11:04:09 -0700 | [diff] [blame] | 46 | The application can then submit one or more requests to the engine by |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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: |
Mauro Carvalho Chehab | cadcb83 | 2020-06-23 09:09:07 +0200 | [diff] [blame] | 90 | |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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 | :: |
Mauro Carvalho Chehab | cadcb83 | 2020-06-23 09:09:07 +0200 | [diff] [blame] | 114 | |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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 | |
Mauro Carvalho Chehab | cadcb83 | 2020-06-23 09:09:07 +0200 | [diff] [blame] | 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 |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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 |
Mauro Carvalho Chehab | cadcb83 | 2020-06-23 09:09:07 +0200 | [diff] [blame] | 136 | follows:: |
| 137 | |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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: |
Mauro Carvalho Chehab | cadcb83 | 2020-06-23 09:09:07 +0200 | [diff] [blame] | 149 | |
| 150 | ====== ================================================ |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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. |
Mauro Carvalho Chehab | cadcb83 | 2020-06-23 09:09:07 +0200 | [diff] [blame] | 159 | ====== ================================================ |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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. |
Mauro Carvalho Chehab | cadcb83 | 2020-06-23 09:09:07 +0200 | [diff] [blame] | 169 | |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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: |
Mauro Carvalho Chehab | cadcb83 | 2020-06-23 09:09:07 +0200 | [diff] [blame] | 175 | |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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 | |
Mauro Carvalho Chehab | cadcb83 | 2020-06-23 09:09:07 +0200 | [diff] [blame] | 183 | ====== ============================================= |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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. |
Mauro Carvalho Chehab | cadcb83 | 2020-06-23 09:09:07 +0200 | [diff] [blame] | 188 | ====== ============================================= |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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 |
Mauro Carvalho Chehab | cadcb83 | 2020-06-23 09:09:07 +0200 | [diff] [blame] | 225 | updating CSB with the following data:: |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 226 | |
| 227 | csb.flags = CSB_V; |
Haren Myneni | 6068e1a | 2020-07-10 16:47:19 -0700 | [diff] [blame] | 228 | csb.cc = CSB_CC_FAULT_ADDRESS; |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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 |
Mauro Carvalho Chehab | cadcb83 | 2020-06-23 09:09:07 +0200 | [diff] [blame] | 238 | issued. This signal returns with the following siginfo struct:: |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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: |
Haren Myneni | 2886e2d | 2021-04-18 12:29:42 -0700 | [diff] [blame] | 257 | https://github.com/libnxz/power-gzip/blob/master/doc/power_nx_gzip_um.pdf |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 258 | |
| 259 | Simple example |
| 260 | ============== |
| 261 | |
| 262 | :: |
Mauro Carvalho Chehab | cadcb83 | 2020-06-23 09:09:07 +0200 | [diff] [blame] | 263 | |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 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 | |
Haren Myneni | 2886e2d | 2021-04-18 12:29:42 -0700 | [diff] [blame] | 304 | Refer https://github.com/libnxz/power-gzip for tests or more |
Haren Myneni | c12e38b | 2020-04-17 02:11:55 -0700 | [diff] [blame] | 305 | use cases. |