3d84192714f05e938c31a2e1849c856d19a902a9
[dpdk.git] / drivers / raw / ioat / rte_ioat_rawdev.h
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019 Intel Corporation
3  */
4
5 #ifndef _RTE_IOAT_RAWDEV_H_
6 #define _RTE_IOAT_RAWDEV_H_
7
8 #ifdef __cplusplus
9 extern "C" {
10 #endif
11
12 /**
13  * @file rte_ioat_rawdev.h
14  *
15  * Definitions for using the ioat rawdev device driver
16  *
17  * @warning
18  * @b EXPERIMENTAL: these structures and APIs may change without prior notice
19  */
20
21 #include <x86intrin.h>
22 #include <rte_atomic.h>
23 #include <rte_memory.h>
24 #include <rte_memzone.h>
25 #include <rte_prefetch.h>
26 #include "rte_ioat_spec.h"
27
28 /** Name of the device driver */
29 #define IOAT_PMD_RAWDEV_NAME rawdev_ioat
30 /** String reported as the device driver name by rte_rawdev_info_get() */
31 #define IOAT_PMD_RAWDEV_NAME_STR "rawdev_ioat"
32
33 /**
34  * Configuration structure for an ioat rawdev instance
35  *
36  * This structure is to be passed as the ".dev_private" parameter when
37  * calling the rte_rawdev_get_info() and rte_rawdev_configure() APIs on
38  * an ioat rawdev instance.
39  */
40 struct rte_ioat_rawdev_config {
41         unsigned short ring_size;
42 };
43
44 /**
45  * @internal
46  * Structure representing a device instance
47  */
48 struct rte_ioat_rawdev {
49         struct rte_rawdev *rawdev;
50         const struct rte_memzone *mz;
51         const struct rte_memzone *desc_mz;
52
53         volatile struct rte_ioat_registers *regs;
54         phys_addr_t status_addr;
55         phys_addr_t ring_addr;
56
57         unsigned short ring_size;
58         struct rte_ioat_generic_hw_desc *desc_ring;
59         __m128i *hdls; /* completion handles for returning to user */
60
61
62         unsigned short next_read;
63         unsigned short next_write;
64
65         /* some statistics for tracking, if added/changed update xstats fns*/
66         uint64_t enqueue_failed __rte_cache_aligned;
67         uint64_t enqueued;
68         uint64_t started;
69         uint64_t completed;
70
71         /* to report completions, the device will write status back here */
72         volatile uint64_t status __rte_cache_aligned;
73 };
74
75 /**
76  * Enqueue a copy operation onto the ioat device
77  *
78  * This queues up a copy operation to be performed by hardware, but does not
79  * trigger hardware to begin that operation.
80  *
81  * @param dev_id
82  *   The rawdev device id of the ioat instance
83  * @param src
84  *   The physical address of the source buffer
85  * @param dst
86  *   The physical address of the destination buffer
87  * @param length
88  *   The length of the data to be copied
89  * @param src_hdl
90  *   An opaque handle for the source data, to be returned when this operation
91  *   has been completed and the user polls for the completion details
92  * @param dst_hdl
93  *   An opaque handle for the destination data, to be returned when this
94  *   operation has been completed and the user polls for the completion details
95  * @param fence
96  *   A flag parameter indicating that hardware should not begin to perform any
97  *   subsequently enqueued copy operations until after this operation has
98  *   completed
99  * @return
100  *   Number of operations enqueued, either 0 or 1
101  */
102 static inline int
103 rte_ioat_enqueue_copy(int dev_id, phys_addr_t src, phys_addr_t dst,
104                 unsigned int length, uintptr_t src_hdl, uintptr_t dst_hdl,
105                 int fence)
106 {
107         struct rte_ioat_rawdev *ioat =
108                         (struct rte_ioat_rawdev *)rte_rawdevs[dev_id].dev_private;
109         unsigned short read = ioat->next_read;
110         unsigned short write = ioat->next_write;
111         unsigned short mask = ioat->ring_size - 1;
112         unsigned short space = mask + read - write;
113         struct rte_ioat_generic_hw_desc *desc;
114
115         if (space == 0) {
116                 ioat->enqueue_failed++;
117                 return 0;
118         }
119
120         ioat->next_write = write + 1;
121         write &= mask;
122
123         desc = &ioat->desc_ring[write];
124         desc->size = length;
125         /* set descriptor write-back every 16th descriptor */
126         desc->u.control_raw = (uint32_t)((!!fence << 4) | (!(write & 0xF)) << 3);
127         desc->src_addr = src;
128         desc->dest_addr = dst;
129
130         ioat->hdls[write] = _mm_set_epi64x((int64_t)dst_hdl, (int64_t)src_hdl);
131         rte_prefetch0(&ioat->desc_ring[ioat->next_write & mask]);
132
133         ioat->enqueued++;
134         return 1;
135 }
136
137 /**
138  * Trigger hardware to begin performing enqueued copy operations
139  *
140  * This API is used to write the "doorbell" to the hardware to trigger it
141  * to begin the copy operations previously enqueued by rte_ioat_enqueue_copy()
142  *
143  * @param dev_id
144  *   The rawdev device id of the ioat instance
145  */
146 static inline void
147 rte_ioat_do_copies(int dev_id)
148 {
149         struct rte_ioat_rawdev *ioat =
150                         (struct rte_ioat_rawdev *)rte_rawdevs[dev_id].dev_private;
151         ioat->desc_ring[(ioat->next_write - 1) & (ioat->ring_size - 1)].u
152                         .control.completion_update = 1;
153         rte_compiler_barrier();
154         ioat->regs->dmacount = ioat->next_write;
155         ioat->started = ioat->enqueued;
156 }
157
158 /**
159  * @internal
160  * Returns the index of the last completed operation.
161  */
162 static inline int
163 rte_ioat_get_last_completed(struct rte_ioat_rawdev *ioat, int *error)
164 {
165         uint64_t status = ioat->status;
166
167         /* lower 3 bits indicate "transfer status" : active, idle, halted.
168          * We can ignore bit 0.
169          */
170         *error = status & (RTE_IOAT_CHANSTS_SUSPENDED | RTE_IOAT_CHANSTS_ARMED);
171         return (status - ioat->ring_addr) >> 6;
172 }
173
174 /**
175  * Returns details of copy operations that have been completed
176  *
177  * Returns to the caller the user-provided "handles" for the copy operations
178  * which have been completed by the hardware, and not already returned by
179  * a previous call to this API.
180  *
181  * @param dev_id
182  *   The rawdev device id of the ioat instance
183  * @param max_copies
184  *   The number of entries which can fit in the src_hdls and dst_hdls
185  *   arrays, i.e. max number of completed operations to report
186  * @param src_hdls
187  *   Array to hold the source handle parameters of the completed copies
188  * @param dst_hdls
189  *   Array to hold the destination handle parameters of the completed copies
190  * @return
191  *   -1 on error, with rte_errno set appropriately.
192  *   Otherwise number of completed operations i.e. number of entries written
193  *   to the src_hdls and dst_hdls array parameters.
194  */
195 static inline int
196 rte_ioat_completed_copies(int dev_id, uint8_t max_copies,
197                 uintptr_t *src_hdls, uintptr_t *dst_hdls)
198 {
199         struct rte_ioat_rawdev *ioat =
200                         (struct rte_ioat_rawdev *)rte_rawdevs[dev_id].dev_private;
201         unsigned short mask = (ioat->ring_size - 1);
202         unsigned short read = ioat->next_read;
203         unsigned short end_read, count;
204         int error;
205         int i = 0;
206
207         end_read = (rte_ioat_get_last_completed(ioat, &error) + 1) & mask;
208         count = (end_read - (read & mask)) & mask;
209
210         if (error) {
211                 rte_errno = EIO;
212                 return -1;
213         }
214
215         if (count > max_copies)
216                 count = max_copies;
217
218         for (; i < count - 1; i += 2, read += 2) {
219                 __m128i hdls0 = _mm_load_si128(&ioat->hdls[read & mask]);
220                 __m128i hdls1 = _mm_load_si128(&ioat->hdls[(read + 1) & mask]);
221
222                 _mm_storeu_si128((__m128i *)&src_hdls[i],
223                                 _mm_unpacklo_epi64(hdls0, hdls1));
224                 _mm_storeu_si128((__m128i *)&dst_hdls[i],
225                                 _mm_unpackhi_epi64(hdls0, hdls1));
226         }
227         for (; i < count; i++, read++) {
228                 uintptr_t *hdls = (uintptr_t *)&ioat->hdls[read & mask];
229                 src_hdls[i] = hdls[0];
230                 dst_hdls[i] = hdls[1];
231         }
232
233         ioat->next_read = read;
234         ioat->completed += count;
235         return count;
236 }
237
238 #ifdef __cplusplus
239 }
240 #endif
241
242 #endif /* _RTE_IOAT_RAWDEV_H_ */