Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 HUAWEI TECHNOLOGIES CO., LTD.
3 : : */
4 : :
5 : : #ifndef _VIRTQUEUE_H_
6 : : #define _VIRTQUEUE_H_
7 : :
8 : : #include <stdint.h>
9 : :
10 : : #include <rte_atomic.h>
11 : : #include <rte_memory.h>
12 : : #include <rte_memzone.h>
13 : : #include <rte_mempool.h>
14 : :
15 : : #include "virtio_cvq.h"
16 : : #include "virtio_pci.h"
17 : : #include "virtio_ring.h"
18 : : #include "virtio_logs.h"
19 : : #include "virtio_crypto.h"
20 : : #include "virtio_rxtx.h"
21 : :
22 : : struct rte_mbuf;
23 : :
24 : : /*
25 : : * Per virtio_config.h in Linux.
26 : : * For virtio_pci on SMP, we don't need to order with respect to MMIO
27 : : * accesses through relaxed memory I/O windows, so smp_mb() et al are
28 : : * sufficient.
29 : : *
30 : : */
31 : : static inline void
32 : : virtio_mb(uint8_t weak_barriers)
33 : : {
34 : : if (weak_barriers)
35 : : rte_atomic_thread_fence(rte_memory_order_seq_cst);
36 : : else
37 : : rte_mb();
38 : : }
39 : :
40 : : static inline void
41 : : virtio_rmb(uint8_t weak_barriers)
42 : : {
43 : : if (weak_barriers)
44 : : rte_atomic_thread_fence(rte_memory_order_acquire);
45 : : else
46 : 0 : rte_io_rmb();
47 : : }
48 : :
49 : : static inline void
50 : : virtio_wmb(uint8_t weak_barriers)
51 : : {
52 [ # # # # ]: 0 : if (weak_barriers)
53 : : rte_atomic_thread_fence(rte_memory_order_release);
54 : : else
55 : 0 : rte_io_wmb();
56 : : }
57 : :
58 : : static inline uint16_t
59 : : virtqueue_fetch_flags_packed(struct vring_packed_desc *dp,
60 : : uint8_t weak_barriers)
61 : : {
62 : : uint16_t flags;
63 : :
64 : 0 : if (weak_barriers) {
65 : : /* x86 prefers to using rte_io_rmb over rte_atomic_load_explicit as it reports
66 : : * a better perf(~1.5%), which comes from the saved branch by the compiler.
67 : : * The if and else branch are identical on the platforms except Arm.
68 : : */
69 : : #ifdef RTE_ARCH_ARM
70 : : flags = rte_atomic_load_explicit(&dp->flags, rte_memory_order_acquire);
71 : : #else
72 : 0 : flags = dp->flags;
73 : 0 : rte_io_rmb();
74 : : #endif
75 : : } else {
76 : 0 : flags = dp->flags;
77 : 0 : rte_io_rmb();
78 : : }
79 : :
80 : : return flags;
81 : : }
82 : :
83 : : static inline void
84 : : virtqueue_store_flags_packed(struct vring_packed_desc *dp,
85 : : uint16_t flags, uint8_t weak_barriers)
86 : : {
87 [ # # # # ]: 0 : if (weak_barriers) {
88 : : /* x86 prefers to using rte_io_wmb over rte_atomic_store_explicit as it reports
89 : : * a better perf(~1.5%), which comes from the saved branch by the compiler.
90 : : * The if and else branch are identical on the platforms except Arm.
91 : : */
92 : : #ifdef RTE_ARCH_ARM
93 : : rte_atomic_store_explicit(&dp->flags, flags, rte_memory_order_release);
94 : : #else
95 : 0 : rte_io_wmb();
96 : 0 : dp->flags = flags;
97 : : #endif
98 : : } else {
99 : 0 : rte_io_wmb();
100 : 0 : dp->flags = flags;
101 : : }
102 : : }
103 : :
104 : : #define VIRTQUEUE_MAX_NAME_SZ 32
105 : :
106 : : enum { VTCRYPTO_DATAQ = 0, VTCRYPTO_CTRLQ = 1 };
107 : :
108 : : /**
109 : : * The maximum virtqueue size is 2^15. Use that value as the end of
110 : : * descriptor chain terminator since it will never be a valid index
111 : : * in the descriptor table. This is used to verify we are correctly
112 : : * handling vq_free_cnt.
113 : : */
114 : : #define VQ_RING_DESC_CHAIN_END 32768
115 : :
116 : : struct vq_desc_extra {
117 : : void *crypto_op;
118 : : void *cookie;
119 : : uint16_t ndescs;
120 : : uint16_t next;
121 : : };
122 : :
123 : : #define virtcrypto_dq_to_vq(dvq) container_of(dvq, struct virtqueue, dq)
124 : : #define virtcrypto_cq_to_vq(cvq) container_of(cvq, struct virtqueue, cq)
125 : :
126 : : struct virtqueue {
127 : : /**< virtio_crypto_hw structure pointer. */
128 : : struct virtio_crypto_hw *hw;
129 : : union {
130 : : struct {
131 : : /**< vring keeping desc, used and avail */
132 : : struct vring ring;
133 : : } vq_split;
134 : :
135 : : struct {
136 : : /**< vring keeping descs and events */
137 : : struct vring_packed ring;
138 : : bool used_wrap_counter;
139 : : uint16_t cached_flags; /**< cached flags for descs */
140 : : uint16_t event_flags_shadow;
141 : : } vq_packed;
142 : : };
143 : :
144 : : union {
145 : : struct virtcrypto_data dq;
146 : : struct virtcrypto_ctl cq;
147 : : };
148 : :
149 : : /**< mem zone to populate RX ring. */
150 : : const struct rte_memzone *mz;
151 : : /**< memzone to populate hdr and request. */
152 : : struct rte_mempool *mpool;
153 : : uint8_t dev_id; /**< Device identifier. */
154 : : uint16_t vq_queue_index; /**< PCI queue index */
155 : :
156 : : void *vq_ring_virt_mem; /**< linear address of vring*/
157 : : unsigned int vq_ring_size;
158 : : phys_addr_t vq_ring_mem; /**< physical address of vring */
159 : :
160 : : uint16_t vq_free_cnt; /**< num of desc available */
161 : : uint16_t vq_nentries; /**< vring desc numbers */
162 : :
163 : : /**
164 : : * Head of the free chain in the descriptor table. If
165 : : * there are no free descriptors, this will be set to
166 : : * VQ_RING_DESC_CHAIN_END.
167 : : */
168 : : uint16_t vq_desc_head_idx;
169 : : uint16_t vq_desc_tail_idx;
170 : : /**
171 : : * Last consumed descriptor in the used table,
172 : : * trails vq_ring.used->idx.
173 : : */
174 : : uint16_t vq_used_cons_idx;
175 : : uint16_t vq_avail_idx;
176 : :
177 : : /* Statistics */
178 : : uint64_t packets_sent_total;
179 : : uint64_t packets_sent_failed;
180 : : uint64_t packets_received_total;
181 : : uint64_t packets_received_failed;
182 : :
183 : : uint16_t *notify_addr;
184 : :
185 : : struct vq_desc_extra vq_descx[];
186 : : };
187 : :
188 : : /**
189 : : * Tell the backend not to interrupt us.
190 : : */
191 : : void virtqueue_disable_intr(struct virtqueue *vq);
192 : :
193 : : /**
194 : : * Get all mbufs to be freed.
195 : : */
196 : : void virtqueue_detatch_unused(struct virtqueue *vq);
197 : :
198 : : struct virtqueue *virtcrypto_queue_alloc(struct virtio_crypto_hw *hw, uint16_t index,
199 : : uint16_t num, int node, const char *name);
200 : :
201 : : void virtcrypto_queue_free(struct virtqueue *vq);
202 : :
203 : : static inline int
204 : : virtqueue_full(const struct virtqueue *vq)
205 : : {
206 : : return vq->vq_free_cnt == 0;
207 : : }
208 : :
209 : : #define VIRTQUEUE_NUSED(vq) \
210 : : ((uint16_t)((vq)->vq_split.ring.used->idx - (vq)->vq_used_cons_idx))
211 : :
212 : : static inline void
213 : : vq_update_avail_idx(struct virtqueue *vq)
214 : : {
215 : : virtio_wmb(0);
216 : 0 : vq->vq_split.ring.avail->idx = vq->vq_avail_idx;
217 : : }
218 : :
219 : : static inline void
220 : : vq_update_avail_ring(struct virtqueue *vq, uint16_t desc_idx)
221 : : {
222 : : uint16_t avail_idx;
223 : : /*
224 : : * Place the head of the descriptor chain into the next slot and make
225 : : * it usable to the host. The chain is made available now rather than
226 : : * deferring to virtqueue_notify() in the hopes that if the host is
227 : : * currently running on another CPU, we can keep it processing the new
228 : : * descriptor.
229 : : */
230 : 0 : avail_idx = (uint16_t)(vq->vq_avail_idx & (vq->vq_nentries - 1));
231 [ # # # # ]: 0 : if (unlikely(vq->vq_split.ring.avail->ring[avail_idx] != desc_idx))
232 : 0 : vq->vq_split.ring.avail->ring[avail_idx] = desc_idx;
233 : 0 : vq->vq_avail_idx++;
234 : : }
235 : :
236 : : static inline int
237 : : virtqueue_kick_prepare(struct virtqueue *vq)
238 : : {
239 [ # # ]: 0 : return !(vq->vq_split.ring.used->flags & VRING_USED_F_NO_NOTIFY);
240 : : }
241 : :
242 : : static inline void
243 : : virtqueue_notify(struct virtqueue *vq)
244 : : {
245 : : /*
246 : : * Ensure updated avail->idx is visible to host.
247 : : * For virtio on IA, the notification is through io port operation
248 : : * which is a serialization instruction itself.
249 : : */
250 : 0 : VTPCI_OPS(vq->hw)->notify_queue(vq->hw, vq);
251 : : }
252 : :
253 : : static inline int
254 : : desc_is_used(struct vring_packed_desc *desc, struct virtqueue *vq)
255 : : {
256 : : uint16_t used, avail, flags;
257 : :
258 [ # # ]: 0 : flags = virtqueue_fetch_flags_packed(desc, vq->hw->weak_barriers);
259 : 0 : used = !!(flags & VRING_PACKED_DESC_F_USED);
260 : 0 : avail = !!(flags & VRING_PACKED_DESC_F_AVAIL);
261 : :
262 [ # # # # ]: 0 : return avail == used && used == vq->vq_packed.used_wrap_counter;
263 : : }
264 : :
265 : : static inline void
266 : : vring_desc_init_packed(struct virtqueue *vq, int n)
267 : : {
268 : : int i;
269 [ # # ]: 0 : for (i = 0; i < n - 1; i++) {
270 : 0 : vq->vq_packed.ring.desc[i].id = i;
271 : 0 : vq->vq_descx[i].next = i + 1;
272 : : }
273 : 0 : vq->vq_packed.ring.desc[i].id = i;
274 : 0 : vq->vq_descx[i].next = VQ_RING_DESC_CHAIN_END;
275 : 0 : }
276 : :
277 : : /* Chain all the descriptors in the ring with an END */
278 : : static inline void
279 : : vring_desc_init_split(struct vring_desc *dp, uint16_t n)
280 : : {
281 : : uint16_t i;
282 : :
283 [ # # ]: 0 : for (i = 0; i < n - 1; i++)
284 : 0 : dp[i].next = (uint16_t)(i + 1);
285 : 0 : dp[i].next = VQ_RING_DESC_CHAIN_END;
286 : 0 : }
287 : :
288 : : static inline int
289 : : virtio_get_queue_type(struct virtio_crypto_hw *hw, uint16_t vq_idx)
290 : : {
291 [ # # # # ]: 0 : if (vq_idx == hw->max_dataqueues)
292 : : return VTCRYPTO_CTRLQ;
293 : : else
294 : 0 : return VTCRYPTO_DATAQ;
295 : : }
296 : :
297 : : /* virtqueue_nused has load-acquire or rte_io_rmb insed */
298 : : static inline uint16_t
299 : : virtqueue_nused(const struct virtqueue *vq)
300 : : {
301 : : uint16_t idx;
302 : :
303 [ # # # # ]: 0 : if (vq->hw->weak_barriers) {
304 : : /**
305 : : * x86 prefers to using rte_smp_rmb over rte_atomic_load_explicit as it
306 : : * reports a slightly better perf, which comes from the saved
307 : : * branch by the compiler.
308 : : * The if and else branches are identical with the smp and io
309 : : * barriers both defined as compiler barriers on x86.
310 : : */
311 : : #ifdef RTE_ARCH_X86_64
312 : 0 : idx = vq->vq_split.ring.used->idx;
313 : : virtio_rmb(0);
314 : : #else
315 : : idx = rte_atomic_load_explicit(&(vq)->vq_split.ring.used->idx,
316 : : rte_memory_order_acquire);
317 : : #endif
318 : : } else {
319 : 0 : idx = vq->vq_split.ring.used->idx;
320 : 0 : rte_io_rmb();
321 : : }
322 [ # # # # ]: 0 : return idx - vq->vq_used_cons_idx;
323 : : }
324 : :
325 : : /**
326 : : * Dump virtqueue internal structures, for debug purpose only.
327 : : */
328 : : #define VIRTQUEUE_SPLIT_DUMP(vq) do { \
329 : : uint16_t used_idx, nused; \
330 : : used_idx = (vq)->vq_split.ring.used->idx; \
331 : : nused = (uint16_t)(used_idx - (vq)->vq_used_cons_idx); \
332 : : VIRTIO_CRYPTO_INIT_LOG_DBG(\
333 : : "VQ: - size=%d; free=%d; used=%d; desc_head_idx=%d;" \
334 : : " avail.idx=%d; used_cons_idx=%d; used.idx=%d;" \
335 : : " avail.flags=0x%x; used.flags=0x%x", \
336 : : (vq)->vq_nentries, (vq)->vq_free_cnt, nused, \
337 : : (vq)->vq_desc_head_idx, (vq)->vq_split.ring.avail->idx, \
338 : : (vq)->vq_used_cons_idx, (vq)->vq_split.ring.used->idx, \
339 : : (vq)->vq_split.ring.avail->flags, (vq)->vq_split.ring.used->flags); \
340 : : } while (0)
341 : :
342 : : #define VIRTQUEUE_PACKED_DUMP(vq) do { \
343 : : uint16_t nused; \
344 : : nused = (vq)->vq_nentries - (vq)->vq_free_cnt; \
345 : : VIRTIO_CRYPTO_INIT_LOG_DBG(\
346 : : "VQ: - size=%d; free=%d; used=%d; desc_head_idx=%d;" \
347 : : " avail_idx=%d; used_cons_idx=%d;" \
348 : : " avail.flags=0x%x; wrap_counter=%d", \
349 : : (vq)->vq_nentries, (vq)->vq_free_cnt, nused, \
350 : : (vq)->vq_desc_head_idx, (vq)->vq_avail_idx, \
351 : : (vq)->vq_used_cons_idx, (vq)->vq_packed.cached_flags, \
352 : : (vq)->vq_packed.used_wrap_counter); \
353 : : } while (0)
354 : :
355 : : #define VIRTQUEUE_DUMP(vq) do { \
356 : : if (vtpci_with_packed_queue((vq)->hw)) \
357 : : VIRTQUEUE_PACKED_DUMP(vq); \
358 : : else \
359 : : VIRTQUEUE_SPLIT_DUMP(vq); \
360 : : } while (0)
361 : :
362 : : #endif /* _VIRTQUEUE_H_ */
|