1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2021 Intel Corporation
4 #ifndef _RTE_IDXD_RAWDEV_FNS_H_
5 #define _RTE_IDXD_RAWDEV_FNS_H_
9 * This header file contains the implementation of the various ioat
10 * rawdev functions for DSA hardware. The API specification and key
11 * public structures are defined in "rte_ioat_rawdev.h".
13 * This file should not be included directly, but instead applications should
14 * include "rte_ioat_rawdev.h", which then includes this file - and the
15 * IOAT/CBDMA equivalent header - in turn.
21 * Defines used in the data path for interacting with IDXD hardware.
23 #define IDXD_CMD_OP_SHIFT 24
32 #define IDXD_FLAG_FENCE (1 << 0)
33 #define IDXD_FLAG_COMPLETION_ADDR_VALID (1 << 2)
34 #define IDXD_FLAG_REQUEST_COMPLETION (1 << 3)
35 #define IDXD_FLAG_CACHE_CONTROL (1 << 8)
37 #define IOAT_COMP_UPDATE_SHIFT 3
38 #define IOAT_CMD_OP_SHIFT 24
40 ioat_op_copy = 0, /* Standard DMA Operation */
41 ioat_op_fill /* Block Fill */
45 * Hardware descriptor used by DSA hardware, for both bursts and
46 * for individual operations.
48 struct rte_idxd_hw_desc {
51 rte_iova_t completion;
55 rte_iova_t src; /* source address for copy ops etc. */
56 rte_iova_t desc_addr; /* descriptor pointer for batch */
60 uint32_t size; /* length of data for op, or batch size */
62 uint16_t intr_handle; /* completion interrupt handle */
64 /* remaining 26 bytes are reserved */
65 uint16_t __reserved[13];
69 * Completion record structure written back by DSA
71 struct rte_idxd_completion {
74 /* 16-bits pad here */
75 uint32_t completed_size; /* data length, or descriptors for batch */
77 rte_iova_t fault_address;
78 uint32_t invalid_flags;
82 * structure used to save the "handles" provided by the user to be
83 * returned to the user on job completion.
85 struct rte_idxd_user_hdl {
92 * Structure representing an IDXD device instance
94 struct rte_idxd_rawdev {
95 enum rte_ioat_dev_type type;
96 struct rte_ioat_xstats xstats;
98 void *portal; /* address to write the batch descriptor */
100 struct rte_ioat_rawdev_config cfg;
101 rte_iova_t desc_iova; /* base address of desc ring, needed for completions */
103 /* counters to track the batches */
104 unsigned short max_batches;
105 unsigned short batch_idx_read;
106 unsigned short batch_idx_write;
107 unsigned short *batch_idx_ring; /* store where each batch ends */
109 /* track descriptors and handles */
110 unsigned short desc_ring_mask;
111 unsigned short hdls_avail; /* handles for ops completed */
112 unsigned short hdls_read; /* the read pointer for hdls/desc rings */
113 unsigned short batch_start; /* start+size == write pointer for hdls/desc */
114 unsigned short batch_size;
116 struct rte_idxd_hw_desc *desc_ring;
117 struct rte_idxd_user_hdl *hdl_ring;
120 static __rte_always_inline uint16_t
121 __idxd_burst_capacity(int dev_id)
123 struct rte_idxd_rawdev *idxd =
124 (struct rte_idxd_rawdev *)rte_rawdevs[dev_id].dev_private;
125 uint16_t write_idx = idxd->batch_start + idxd->batch_size;
128 /* Check for space in the batch ring */
129 if ((idxd->batch_idx_read == 0 && idxd->batch_idx_write == idxd->max_batches) ||
130 idxd->batch_idx_write + 1 == idxd->batch_idx_read)
133 /* for descriptors, check for wrap-around on write but not read */
134 if (idxd->hdls_read > write_idx)
135 write_idx += idxd->desc_ring_mask + 1;
136 used_space = write_idx - idxd->hdls_read;
138 /* Return amount of free space in the descriptor ring */
139 return idxd->desc_ring_mask - used_space;
142 static __rte_always_inline rte_iova_t
143 __desc_idx_to_iova(struct rte_idxd_rawdev *idxd, uint16_t n)
145 return idxd->desc_iova + (n * sizeof(struct rte_idxd_hw_desc));
148 static __rte_always_inline int
149 __idxd_write_desc(int dev_id,
150 const uint32_t op_flags,
151 const rte_iova_t src,
152 const rte_iova_t dst,
154 const struct rte_idxd_user_hdl *hdl)
156 struct rte_idxd_rawdev *idxd =
157 (struct rte_idxd_rawdev *)rte_rawdevs[dev_id].dev_private;
158 uint16_t write_idx = idxd->batch_start + idxd->batch_size;
160 /* first check batch ring space then desc ring space */
161 if ((idxd->batch_idx_read == 0 && idxd->batch_idx_write == idxd->max_batches) ||
162 idxd->batch_idx_write + 1 == idxd->batch_idx_read)
164 if (((write_idx + 1) & idxd->desc_ring_mask) == idxd->hdls_read)
167 /* write desc and handle. Note, descriptors don't wrap */
168 idxd->desc_ring[write_idx].pasid = 0;
169 idxd->desc_ring[write_idx].op_flags = op_flags | IDXD_FLAG_COMPLETION_ADDR_VALID;
170 idxd->desc_ring[write_idx].completion = __desc_idx_to_iova(idxd, write_idx);
171 idxd->desc_ring[write_idx].src = src;
172 idxd->desc_ring[write_idx].dst = dst;
173 idxd->desc_ring[write_idx].size = size;
175 idxd->hdl_ring[write_idx & idxd->desc_ring_mask] = *hdl;
178 idxd->xstats.enqueued++;
180 rte_prefetch0_write(&idxd->desc_ring[write_idx + 1]);
184 idxd->xstats.enqueue_failed++;
189 static __rte_always_inline int
190 __idxd_enqueue_fill(int dev_id, uint64_t pattern, rte_iova_t dst,
191 unsigned int length, uintptr_t dst_hdl)
193 const struct rte_idxd_user_hdl hdl = {
196 return __idxd_write_desc(dev_id,
197 (idxd_op_fill << IDXD_CMD_OP_SHIFT) | IDXD_FLAG_CACHE_CONTROL,
198 pattern, dst, length, &hdl);
201 static __rte_always_inline int
202 __idxd_enqueue_copy(int dev_id, rte_iova_t src, rte_iova_t dst,
203 unsigned int length, uintptr_t src_hdl, uintptr_t dst_hdl)
205 const struct rte_idxd_user_hdl hdl = {
209 return __idxd_write_desc(dev_id,
210 (idxd_op_memmove << IDXD_CMD_OP_SHIFT) | IDXD_FLAG_CACHE_CONTROL,
211 src, dst, length, &hdl);
214 static __rte_always_inline int
215 __idxd_fence(int dev_id)
217 static const struct rte_idxd_user_hdl null_hdl;
218 /* only op field needs filling - zero src, dst and length */
219 return __idxd_write_desc(dev_id, IDXD_FLAG_FENCE, 0, 0, 0, &null_hdl);
222 static __rte_always_inline void
223 __idxd_movdir64b(volatile void *dst, const struct rte_idxd_hw_desc *src)
225 asm volatile (".byte 0x66, 0x0f, 0x38, 0xf8, 0x02"
227 : "a" (dst), "d" (src)
231 static __rte_always_inline int
232 __idxd_perform_ops(int dev_id)
234 struct rte_idxd_rawdev *idxd =
235 (struct rte_idxd_rawdev *)rte_rawdevs[dev_id].dev_private;
236 /* write completion to last desc in the batch */
237 uint16_t comp_idx = idxd->batch_start + idxd->batch_size - 1;
238 if (comp_idx > idxd->desc_ring_mask) {
239 comp_idx &= idxd->desc_ring_mask;
240 *((uint64_t *)&idxd->desc_ring[comp_idx]) = 0; /* zero start of desc */
243 if (idxd->batch_size == 0)
246 _mm_sfence(); /* fence before writing desc to device */
247 if (idxd->batch_size > 1) {
248 struct rte_idxd_hw_desc batch_desc = {
249 .op_flags = (idxd_op_batch << IDXD_CMD_OP_SHIFT) |
250 IDXD_FLAG_COMPLETION_ADDR_VALID |
251 IDXD_FLAG_REQUEST_COMPLETION,
252 .desc_addr = __desc_idx_to_iova(idxd, idxd->batch_start),
253 .completion = __desc_idx_to_iova(idxd, comp_idx),
254 .size = idxd->batch_size,
257 __idxd_movdir64b(idxd->portal, &batch_desc);
259 /* special case batch size of 1, as not allowed by HW */
260 /* comp_idx == batch_start */
261 struct rte_idxd_hw_desc *desc = &idxd->desc_ring[comp_idx];
262 desc->op_flags |= IDXD_FLAG_COMPLETION_ADDR_VALID |
263 IDXD_FLAG_REQUEST_COMPLETION;
264 desc->completion = __desc_idx_to_iova(idxd, comp_idx);
266 __idxd_movdir64b(idxd->portal, desc);
269 idxd->xstats.started += idxd->batch_size;
271 idxd->batch_start += idxd->batch_size;
272 idxd->batch_start &= idxd->desc_ring_mask;
273 idxd->batch_size = 0;
275 idxd->batch_idx_ring[idxd->batch_idx_write++] = comp_idx;
276 if (idxd->batch_idx_write > idxd->max_batches)
277 idxd->batch_idx_write = 0;
282 static __rte_always_inline int
283 __idxd_completed_ops(int dev_id, uint8_t max_ops,
284 uintptr_t *src_hdls, uintptr_t *dst_hdls)
286 struct rte_idxd_rawdev *idxd =
287 (struct rte_idxd_rawdev *)rte_rawdevs[dev_id].dev_private;
288 unsigned short n, h_idx;
290 while (idxd->batch_idx_read != idxd->batch_idx_write) {
291 uint16_t idx_to_chk = idxd->batch_idx_ring[idxd->batch_idx_read];
292 volatile struct rte_idxd_completion *comp_to_chk =
293 (struct rte_idxd_completion *)&idxd->desc_ring[idx_to_chk];
294 if (comp_to_chk->status == 0)
296 /* avail points to one after the last one written */
297 idxd->hdls_avail = (idx_to_chk + 1) & idxd->desc_ring_mask;
298 idxd->batch_idx_read++;
299 if (idxd->batch_idx_read > idxd->max_batches)
300 idxd->batch_idx_read = 0;
303 if (idxd->cfg.hdls_disable) {
304 n = (idxd->hdls_avail < idxd->hdls_read) ?
305 (idxd->hdls_avail + idxd->desc_ring_mask + 1 - idxd->hdls_read) :
306 (idxd->hdls_avail - idxd->hdls_read);
307 idxd->hdls_read = idxd->hdls_avail;
311 for (n = 0, h_idx = idxd->hdls_read;
312 n < max_ops && h_idx != idxd->hdls_avail; n++) {
313 src_hdls[n] = idxd->hdl_ring[h_idx].src;
314 dst_hdls[n] = idxd->hdl_ring[h_idx].dst;
315 if (++h_idx > idxd->desc_ring_mask)
318 idxd->hdls_read = h_idx;
321 idxd->xstats.completed += n;