Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 HUAWEI TECHNOLOGIES CO., LTD.
3 : : */
4 : :
5 : : #include <stdint.h>
6 : :
7 : : #include <rte_mbuf.h>
8 : : #include <rte_crypto.h>
9 : : #include <rte_malloc.h>
10 : : #include <rte_errno.h>
11 : :
12 : : #include "virtio_cryptodev.h"
13 : : #include "virtqueue.h"
14 : :
15 : : static inline void
16 : : virtqueue_disable_intr_packed(struct virtqueue *vq)
17 : : {
18 : : /*
19 : : * Set RING_EVENT_FLAGS_DISABLE to hint host
20 : : * not to interrupt when it consumes packets
21 : : * Note: this is only considered a hint to the host
22 : : */
23 [ # # ]: 0 : if (vq->vq_packed.event_flags_shadow != RING_EVENT_FLAGS_DISABLE) {
24 : 0 : vq->vq_packed.event_flags_shadow = RING_EVENT_FLAGS_DISABLE;
25 : 0 : vq->vq_packed.ring.driver->desc_event_flags =
26 : : vq->vq_packed.event_flags_shadow;
27 : : }
28 : : }
29 : :
30 : : static inline void
31 : : virtqueue_disable_intr_split(struct virtqueue *vq)
32 : : {
33 : : /*
34 : : * Set VRING_AVAIL_F_NO_INTERRUPT to hint host
35 : : * not to interrupt when it consumes packets
36 : : * Note: this is only considered a hint to the host
37 : : */
38 : 0 : vq->vq_split.ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
39 : 0 : }
40 : :
41 : : void
42 : 0 : virtqueue_disable_intr(struct virtqueue *vq)
43 : : {
44 [ # # ]: 0 : if (vtpci_with_packed_queue(vq->hw))
45 : : virtqueue_disable_intr_packed(vq);
46 : : else
47 : : virtqueue_disable_intr_split(vq);
48 : 0 : }
49 : :
50 : : void
51 : 0 : virtqueue_detatch_unused(struct virtqueue *vq)
52 : : {
53 : : struct rte_crypto_op *cop = NULL;
54 : :
55 : : int idx;
56 : :
57 [ # # ]: 0 : if (vq != NULL)
58 [ # # ]: 0 : for (idx = 0; idx < vq->vq_nentries; idx++) {
59 : 0 : cop = vq->vq_descx[idx].crypto_op;
60 [ # # ]: 0 : if (cop) {
61 [ # # ]: 0 : if (cop->type == RTE_CRYPTO_OP_TYPE_SYMMETRIC) {
62 : 0 : rte_pktmbuf_free(cop->sym->m_src);
63 : 0 : rte_pktmbuf_free(cop->sym->m_dst);
64 : : }
65 : :
66 : 0 : rte_crypto_op_free(cop);
67 : 0 : vq->vq_descx[idx].crypto_op = NULL;
68 : : }
69 : : }
70 : 0 : }
71 : :
72 : : static void
73 : 0 : virtio_init_vring(struct virtqueue *vq)
74 : : {
75 : 0 : uint8_t *ring_mem = vq->vq_ring_virt_mem;
76 : 0 : int size = vq->vq_nentries;
77 : :
78 : 0 : PMD_INIT_FUNC_TRACE();
79 : :
80 [ # # ]: 0 : memset(ring_mem, 0, vq->vq_ring_size);
81 : :
82 : 0 : vq->vq_used_cons_idx = 0;
83 : 0 : vq->vq_desc_head_idx = 0;
84 : 0 : vq->vq_avail_idx = 0;
85 : 0 : vq->vq_desc_tail_idx = (uint16_t)(vq->vq_nentries - 1);
86 : 0 : vq->vq_free_cnt = vq->vq_nentries;
87 : 0 : memset(vq->vq_descx, 0, sizeof(struct vq_desc_extra) * vq->vq_nentries);
88 [ # # ]: 0 : if (vtpci_with_packed_queue(vq->hw)) {
89 : 0 : vring_init_packed(&vq->vq_packed.ring, ring_mem, vq->vq_ring_mem,
90 : : VIRTIO_PCI_VRING_ALIGN, size);
91 : : vring_desc_init_packed(vq, size);
92 : : } else {
93 : : struct vring *vr = &vq->vq_split.ring;
94 : :
95 : 0 : vring_init_split(vr, ring_mem, vq->vq_ring_mem, VIRTIO_PCI_VRING_ALIGN, size);
96 : : vring_desc_init_split(vr->desc, size);
97 : : }
98 : : /*
99 : : * Disable device(host) interrupting guest
100 : : */
101 : 0 : virtqueue_disable_intr(vq);
102 : 0 : }
103 : :
104 : : static int
105 : 0 : virtio_alloc_queue_headers(struct virtqueue *vq, int numa_node, const char *name)
106 : : {
107 : : char hdr_name[VIRTQUEUE_MAX_NAME_SZ];
108 : : const struct rte_memzone **hdr_mz;
109 : : rte_iova_t *hdr_mem;
110 : : ssize_t size;
111 : : int queue_type;
112 : :
113 [ # # ]: 0 : queue_type = virtio_get_queue_type(vq->hw, vq->vq_queue_index);
114 : : switch (queue_type) {
115 : : case VTCRYPTO_DATAQ:
116 : : /*
117 : : * Op cookie for every ring element. This memory can be optimized
118 : : * based on descriptor requirements. For example, if a descriptor
119 : : * is indirect, then the cookie can be shared among all the
120 : : * descriptors in the chain.
121 : : */
122 : 0 : size = vq->vq_nentries * sizeof(struct virtio_crypto_op_cookie);
123 : 0 : hdr_mz = &vq->dq.hdr_mz;
124 : 0 : hdr_mem = &vq->dq.hdr_mem;
125 : 0 : break;
126 : : case VTCRYPTO_CTRLQ:
127 : : /* One control operation at a time in control queue */
128 : : size = sizeof(struct virtio_pmd_ctrl);
129 : 0 : hdr_mz = &vq->cq.hdr_mz;
130 : 0 : hdr_mem = &vq->cq.hdr_mem;
131 : 0 : break;
132 : : default:
133 : : return 0;
134 : : }
135 : :
136 : : snprintf(hdr_name, sizeof(hdr_name), "%s_hdr", name);
137 : 0 : *hdr_mz = rte_memzone_reserve_aligned(hdr_name, size, numa_node,
138 : : RTE_MEMZONE_IOVA_CONTIG, RTE_CACHE_LINE_SIZE);
139 [ # # ]: 0 : if (*hdr_mz == NULL) {
140 [ # # ]: 0 : if (rte_errno == EEXIST)
141 : 0 : *hdr_mz = rte_memzone_lookup(hdr_name);
142 [ # # ]: 0 : if (*hdr_mz == NULL)
143 : : return -ENOMEM;
144 : : }
145 : :
146 [ # # ]: 0 : memset((*hdr_mz)->addr, 0, size);
147 : :
148 [ # # ]: 0 : if (vq->hw->use_va)
149 : 0 : *hdr_mem = (uintptr_t)(*hdr_mz)->addr;
150 : : else
151 : 0 : *hdr_mem = (uintptr_t)(*hdr_mz)->iova;
152 : :
153 : : return 0;
154 : : }
155 : :
156 : : static void
157 : : virtio_free_queue_headers(struct virtqueue *vq)
158 : : {
159 : : const struct rte_memzone **hdr_mz;
160 : : rte_iova_t *hdr_mem;
161 : : int queue_type;
162 : :
163 : 0 : queue_type = virtio_get_queue_type(vq->hw, vq->vq_queue_index);
164 : : switch (queue_type) {
165 : : case VTCRYPTO_DATAQ:
166 : 0 : hdr_mz = &vq->dq.hdr_mz;
167 : 0 : hdr_mem = &vq->dq.hdr_mem;
168 : 0 : break;
169 : : case VTCRYPTO_CTRLQ:
170 : 0 : hdr_mz = &vq->cq.hdr_mz;
171 : 0 : hdr_mem = &vq->cq.hdr_mem;
172 : 0 : break;
173 : : default:
174 : : return;
175 : : }
176 : :
177 : 0 : rte_memzone_free(*hdr_mz);
178 : 0 : *hdr_mz = NULL;
179 : 0 : *hdr_mem = 0;
180 : : }
181 : :
182 : : struct virtqueue *
183 : 0 : virtcrypto_queue_alloc(struct virtio_crypto_hw *hw, uint16_t index, uint16_t num,
184 : : int node, const char *name)
185 : : {
186 : : const struct rte_memzone *mz;
187 : : struct virtqueue *vq;
188 : : unsigned int size;
189 : :
190 : 0 : size = sizeof(*vq) + num * sizeof(struct vq_desc_extra);
191 : 0 : size = RTE_ALIGN_CEIL(size, RTE_CACHE_LINE_SIZE);
192 : :
193 : 0 : vq = rte_zmalloc_socket(name, size, RTE_CACHE_LINE_SIZE, node);
194 [ # # ]: 0 : if (vq == NULL) {
195 : 0 : PMD_INIT_LOG(ERR, "can not allocate vq");
196 : 0 : return NULL;
197 : : }
198 : :
199 : 0 : PMD_INIT_LOG(DEBUG, "vq: %p", vq);
200 : 0 : vq->hw = hw;
201 : 0 : vq->vq_queue_index = index;
202 [ # # ]: 0 : vq->vq_nentries = num;
203 [ # # ]: 0 : if (vtpci_with_packed_queue(hw)) {
204 : 0 : vq->vq_packed.used_wrap_counter = 1;
205 : 0 : vq->vq_packed.cached_flags = VRING_PACKED_DESC_F_AVAIL;
206 : 0 : vq->vq_packed.event_flags_shadow = 0;
207 : : }
208 : :
209 : : /*
210 : : * Reserve a memzone for vring elements
211 : : */
212 : 0 : size = vring_size(hw, num, VIRTIO_PCI_VRING_ALIGN);
213 : 0 : vq->vq_ring_size = RTE_ALIGN_CEIL(size, VIRTIO_PCI_VRING_ALIGN);
214 : 0 : PMD_INIT_LOG(DEBUG, "vring_size: %d, rounded_vring_size: %d", size, vq->vq_ring_size);
215 : :
216 : 0 : mz = rte_memzone_reserve_aligned(name, vq->vq_ring_size, node,
217 : : RTE_MEMZONE_IOVA_CONTIG, VIRTIO_PCI_VRING_ALIGN);
218 [ # # ]: 0 : if (mz == NULL) {
219 [ # # ]: 0 : if (rte_errno == EEXIST)
220 : 0 : mz = rte_memzone_lookup(name);
221 [ # # ]: 0 : if (mz == NULL)
222 : 0 : goto free_vq;
223 : : }
224 : :
225 [ # # ]: 0 : memset(mz->addr, 0, mz->len);
226 : 0 : vq->mz = mz;
227 : 0 : vq->vq_ring_virt_mem = mz->addr;
228 : :
229 [ # # ]: 0 : if (hw->use_va)
230 : 0 : vq->vq_ring_mem = (uintptr_t)mz->addr;
231 : : else
232 : 0 : vq->vq_ring_mem = mz->iova;
233 : :
234 : 0 : PMD_INIT_LOG(DEBUG, "vq->vq_ring_mem: 0x%" PRIx64, vq->vq_ring_mem);
235 : 0 : PMD_INIT_LOG(DEBUG, "vq->vq_ring_virt_mem: %p", vq->vq_ring_virt_mem);
236 : :
237 : 0 : virtio_init_vring(vq);
238 : :
239 [ # # ]: 0 : if (virtio_alloc_queue_headers(vq, node, name)) {
240 : 0 : PMD_INIT_LOG(ERR, "Failed to alloc queue headers");
241 : 0 : goto free_mz;
242 : : }
243 : :
244 : : return vq;
245 : :
246 : : free_mz:
247 : 0 : rte_memzone_free(mz);
248 : 0 : free_vq:
249 : 0 : rte_free(vq);
250 : :
251 : 0 : return NULL;
252 : : }
253 : :
254 : : void
255 [ # # ]: 0 : virtcrypto_queue_free(struct virtqueue *vq)
256 : : {
257 : : virtio_free_queue_headers(vq);
258 : 0 : rte_memzone_free(vq->mz);
259 : 0 : rte_free(vq);
260 : 0 : }
|