Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2015 Intel Corporation
3 : : */
4 : : #include <stdint.h>
5 : : #include <unistd.h>
6 : :
7 : : #include <rte_eal_paging.h>
8 : : #include <rte_malloc.h>
9 : : #include <rte_mbuf.h>
10 : : #include <rte_memzone.h>
11 : :
12 : : #include "virtqueue.h"
13 : : #include "virtio_logs.h"
14 : : #include "virtio.h"
15 : : #include "virtio_rxtx_simple.h"
16 : :
17 : : /*
18 : : * Two types of mbuf to be cleaned:
19 : : * 1) mbuf that has been consumed by backend but not used by virtio.
20 : : * 2) mbuf that hasn't been consumed by backend.
21 : : */
22 : : struct rte_mbuf *
23 : 0 : virtqueue_detach_unused(struct virtqueue *vq)
24 : : {
25 : : struct rte_mbuf *cookie;
26 : : struct virtio_hw *hw;
27 : : uint16_t start, end;
28 : : int type, idx;
29 : :
30 [ # # ]: 0 : if (vq == NULL)
31 : : return NULL;
32 : :
33 : 0 : hw = vq->hw;
34 [ # # ]: 0 : type = virtio_get_queue_type(hw, vq->vq_queue_index);
35 : 0 : start = vq->vq_avail_idx & (vq->vq_nentries - 1);
36 : 0 : end = (vq->vq_avail_idx + vq->vq_free_cnt) & (vq->vq_nentries - 1);
37 : :
38 [ # # ]: 0 : for (idx = 0; idx < vq->vq_nentries; idx++) {
39 [ # # # # : 0 : if (hw->use_vec_rx && !virtio_with_packed_queue(hw) &&
# # ]
40 : : type == VTNET_RQ) {
41 [ # # # # : 0 : if (start <= end && idx >= start && idx < end)
# # ]
42 : 0 : continue;
43 [ # # # # : 0 : if (start > end && (idx >= start || idx < end))
# # ]
44 : 0 : continue;
45 : 0 : cookie = vq->rxq.sw_ring[idx];
46 [ # # ]: 0 : if (cookie != NULL) {
47 : 0 : vq->rxq.sw_ring[idx] = NULL;
48 : 0 : return cookie;
49 : : }
50 : : } else {
51 : 0 : cookie = vq->vq_descx[idx].cookie;
52 [ # # ]: 0 : if (cookie != NULL) {
53 : 0 : vq->vq_descx[idx].cookie = NULL;
54 : 0 : return cookie;
55 : : }
56 : : }
57 : : }
58 : :
59 : : return NULL;
60 : : }
61 : :
62 : : /* Flush used descs */
63 : : static void
64 : 0 : virtqueue_rxvq_flush_packed(struct virtqueue *vq)
65 : : {
66 : : struct vq_desc_extra *dxp;
67 : : uint16_t i;
68 : :
69 : 0 : struct vring_packed_desc *descs = vq->vq_packed.ring.desc;
70 : : int cnt = 0;
71 : :
72 : 0 : i = vq->vq_used_cons_idx;
73 [ # # # # ]: 0 : while (desc_is_used(&descs[i], vq) && cnt++ < vq->vq_nentries) {
74 : 0 : dxp = &vq->vq_descx[descs[i].id];
75 [ # # ]: 0 : if (dxp->cookie != NULL) {
76 : 0 : rte_pktmbuf_free(dxp->cookie);
77 : 0 : dxp->cookie = NULL;
78 : : }
79 : 0 : vq->vq_free_cnt++;
80 : 0 : vq->vq_used_cons_idx++;
81 [ # # ]: 0 : if (vq->vq_used_cons_idx >= vq->vq_nentries) {
82 : 0 : vq->vq_used_cons_idx -= vq->vq_nentries;
83 : 0 : vq->vq_packed.used_wrap_counter ^= 1;
84 : : }
85 : 0 : i = vq->vq_used_cons_idx;
86 : : }
87 : 0 : }
88 : :
89 : : /* Flush the elements in the used ring. */
90 : : static void
91 : 0 : virtqueue_rxvq_flush_split(struct virtqueue *vq)
92 : : {
93 : 0 : struct virtnet_rx *rxq = &vq->rxq;
94 [ # # ]: 0 : struct virtio_hw *hw = vq->hw;
95 : : struct vring_used_elem *uep;
96 : : struct vq_desc_extra *dxp;
97 : : uint16_t used_idx, desc_idx;
98 : : uint16_t nb_used, i;
99 : :
100 : : nb_used = virtqueue_nused(vq);
101 : :
102 [ # # ]: 0 : for (i = 0; i < nb_used; i++) {
103 : 0 : used_idx = vq->vq_used_cons_idx & (vq->vq_nentries - 1);
104 : 0 : uep = &vq->vq_split.ring.used->ring[used_idx];
105 [ # # ]: 0 : if (hw->use_vec_rx) {
106 : : desc_idx = used_idx;
107 : 0 : rte_pktmbuf_free(vq->rxq.sw_ring[desc_idx]);
108 : 0 : vq->vq_free_cnt++;
109 [ # # ]: 0 : } else if (hw->use_inorder_rx) {
110 : 0 : desc_idx = (uint16_t)uep->id;
111 : 0 : dxp = &vq->vq_descx[desc_idx];
112 [ # # ]: 0 : if (dxp->cookie != NULL) {
113 : 0 : rte_pktmbuf_free(dxp->cookie);
114 : 0 : dxp->cookie = NULL;
115 : : }
116 : 0 : vq_ring_free_inorder(vq, desc_idx, 1);
117 : : } else {
118 : 0 : desc_idx = (uint16_t)uep->id;
119 : 0 : dxp = &vq->vq_descx[desc_idx];
120 [ # # ]: 0 : if (dxp->cookie != NULL) {
121 : 0 : rte_pktmbuf_free(dxp->cookie);
122 : 0 : dxp->cookie = NULL;
123 : : }
124 : 0 : vq_ring_free_chain(vq, desc_idx);
125 : : }
126 : 0 : vq->vq_used_cons_idx++;
127 : : }
128 : :
129 [ # # ]: 0 : if (hw->use_vec_rx) {
130 [ # # ]: 0 : while (vq->vq_free_cnt >= RTE_VIRTIO_VPMD_RX_REARM_THRESH) {
131 : 0 : virtio_rxq_rearm_vec(rxq);
132 [ # # ]: 0 : if (virtqueue_kick_prepare(vq))
133 : : virtqueue_notify(vq);
134 : : }
135 : : }
136 : 0 : }
137 : :
138 : : /* Flush the elements in the used ring. */
139 : : void
140 : 0 : virtqueue_rxvq_flush(struct virtqueue *vq)
141 : : {
142 [ # # ]: 0 : struct virtio_hw *hw = vq->hw;
143 : :
144 [ # # ]: 0 : if (virtio_with_packed_queue(hw))
145 : 0 : virtqueue_rxvq_flush_packed(vq);
146 : : else
147 : 0 : virtqueue_rxvq_flush_split(vq);
148 : 0 : }
149 : :
150 : : static void
151 : : virtqueue_txq_indirect_header_init_packed(struct virtqueue *vq, uint32_t idx)
152 : : {
153 : : struct virtio_tx_region *txr;
154 : : struct vring_packed_desc *desc;
155 : : rte_iova_t hdr_mem;
156 : :
157 : 0 : txr = vq->txq.hdr_mz->addr;
158 : 0 : hdr_mem = vq->txq.hdr_mem;
159 : 0 : desc = txr[idx].tx_packed_indir;
160 : :
161 : : vring_desc_init_indirect_packed(desc, RTE_DIM(txr[idx].tx_packed_indir));
162 : 0 : desc->addr = hdr_mem + idx * sizeof(*txr) + offsetof(struct virtio_tx_region, tx_hdr);
163 : 0 : desc->len = vq->hw->vtnet_hdr_size;
164 : 0 : }
165 : :
166 : : static void
167 : 0 : virtqueue_txq_indirect_header_init_split(struct virtqueue *vq, uint32_t idx)
168 : : {
169 : : struct virtio_tx_region *txr;
170 : : struct vring_desc *desc;
171 : : rte_iova_t hdr_mem;
172 : :
173 : 0 : txr = vq->txq.hdr_mz->addr;
174 : 0 : hdr_mem = vq->txq.hdr_mem;
175 : 0 : desc = txr[idx].tx_indir;
176 : :
177 : : vring_desc_init_split(desc, RTE_DIM(txr[idx].tx_indir));
178 : 0 : desc->addr = hdr_mem + idx * sizeof(*txr) + offsetof(struct virtio_tx_region, tx_hdr);
179 : 0 : desc->len = vq->hw->vtnet_hdr_size;
180 : 0 : desc->flags = VRING_DESC_F_NEXT;
181 : 0 : }
182 : :
183 : : void
184 : 0 : virtqueue_txq_indirect_headers_init(struct virtqueue *vq)
185 : : {
186 : : uint32_t i;
187 : :
188 [ # # ]: 0 : if (!virtio_with_feature(vq->hw, VIRTIO_RING_F_INDIRECT_DESC))
189 : : return;
190 : :
191 [ # # ]: 0 : for (i = 0; i < vq->vq_nentries; i++)
192 [ # # ]: 0 : if (virtio_with_packed_queue(vq->hw))
193 : : virtqueue_txq_indirect_header_init_packed(vq, i);
194 : : else
195 : 0 : virtqueue_txq_indirect_header_init_split(vq, i);
196 : : }
197 : :
198 : : int
199 : 0 : virtqueue_rxvq_reset_packed(struct virtqueue *vq)
200 : : {
201 : 0 : int size = vq->vq_nentries;
202 : : struct vq_desc_extra *dxp;
203 : : uint16_t desc_idx;
204 : :
205 : 0 : vq->vq_used_cons_idx = 0;
206 : 0 : vq->vq_desc_head_idx = 0;
207 : 0 : vq->vq_avail_idx = 0;
208 : 0 : vq->vq_desc_tail_idx = (uint16_t)(vq->vq_nentries - 1);
209 : 0 : vq->vq_free_cnt = vq->vq_nentries;
210 : :
211 : 0 : vq->vq_packed.used_wrap_counter = 1;
212 : : vq->vq_packed.cached_flags = VRING_PACKED_DESC_F_AVAIL;
213 : 0 : vq->vq_packed.event_flags_shadow = 0;
214 : 0 : vq->vq_packed.cached_flags |= VRING_DESC_F_WRITE;
215 : :
216 : 0 : memset(vq->mz->addr, 0, vq->mz->len);
217 : :
218 [ # # ]: 0 : for (desc_idx = 0; desc_idx < vq->vq_nentries; desc_idx++) {
219 : 0 : dxp = &vq->vq_descx[desc_idx];
220 [ # # ]: 0 : if (dxp->cookie != NULL) {
221 : 0 : rte_pktmbuf_free(dxp->cookie);
222 : 0 : dxp->cookie = NULL;
223 : : }
224 : : }
225 : :
226 : : vring_desc_init_packed(vq, size);
227 : :
228 : : virtqueue_disable_intr(vq);
229 : 0 : return 0;
230 : : }
231 : :
232 : : int
233 : 0 : virtqueue_txvq_reset_packed(struct virtqueue *vq)
234 : : {
235 : 0 : int size = vq->vq_nentries;
236 : : struct vq_desc_extra *dxp;
237 : : uint16_t desc_idx;
238 : :
239 : 0 : vq->vq_used_cons_idx = 0;
240 : 0 : vq->vq_desc_head_idx = 0;
241 : 0 : vq->vq_avail_idx = 0;
242 : 0 : vq->vq_desc_tail_idx = (uint16_t)(vq->vq_nentries - 1);
243 : 0 : vq->vq_free_cnt = vq->vq_nentries;
244 : :
245 : 0 : vq->vq_packed.used_wrap_counter = 1;
246 : 0 : vq->vq_packed.cached_flags = VRING_PACKED_DESC_F_AVAIL;
247 : 0 : vq->vq_packed.event_flags_shadow = 0;
248 : :
249 : 0 : memset(vq->mz->addr, 0, vq->mz->len);
250 : 0 : memset(vq->txq.hdr_mz->addr, 0, vq->txq.hdr_mz->len);
251 : :
252 [ # # ]: 0 : for (desc_idx = 0; desc_idx < vq->vq_nentries; desc_idx++) {
253 : 0 : dxp = &vq->vq_descx[desc_idx];
254 [ # # ]: 0 : if (dxp->cookie != NULL) {
255 : 0 : rte_pktmbuf_free(dxp->cookie);
256 : 0 : dxp->cookie = NULL;
257 : : }
258 : : }
259 : :
260 : 0 : virtqueue_txq_indirect_headers_init(vq);
261 : : vring_desc_init_packed(vq, size);
262 : : virtqueue_disable_intr(vq);
263 : :
264 : 0 : return 0;
265 : : }
266 : :
267 : :
268 : : static void
269 : 0 : virtio_init_vring(struct virtqueue *vq)
270 : : {
271 : 0 : int size = vq->vq_nentries;
272 : 0 : uint8_t *ring_mem = vq->vq_ring_virt_mem;
273 : :
274 : 0 : PMD_INIT_FUNC_TRACE();
275 : :
276 [ # # ]: 0 : memset(ring_mem, 0, vq->vq_ring_size);
277 : :
278 : 0 : vq->vq_used_cons_idx = 0;
279 : 0 : vq->vq_desc_head_idx = 0;
280 : 0 : vq->vq_avail_idx = 0;
281 : 0 : vq->vq_desc_tail_idx = (uint16_t)(vq->vq_nentries - 1);
282 : 0 : vq->vq_free_cnt = vq->vq_nentries;
283 : 0 : memset(vq->vq_descx, 0, sizeof(struct vq_desc_extra) * vq->vq_nentries);
284 [ # # ]: 0 : if (virtio_with_packed_queue(vq->hw)) {
285 : 0 : vring_init_packed(&vq->vq_packed.ring, ring_mem, vq->vq_ring_mem,
286 : : VIRTIO_VRING_ALIGN, size);
287 : : vring_desc_init_packed(vq, size);
288 : : } else {
289 : : struct vring *vr = &vq->vq_split.ring;
290 : :
291 : 0 : vring_init_split(vr, ring_mem, vq->vq_ring_mem, VIRTIO_VRING_ALIGN, size);
292 : : vring_desc_init_split(vr->desc, size);
293 : : }
294 : : /*
295 : : * Disable device(host) interrupting guest
296 : : */
297 : : virtqueue_disable_intr(vq);
298 : 0 : }
299 : :
300 : : static int
301 : 0 : virtio_alloc_queue_headers(struct virtqueue *vq, int numa_node, const char *name)
302 : : {
303 : : char hdr_name[VIRTQUEUE_MAX_NAME_SZ];
304 : : const struct rte_memzone **hdr_mz;
305 : : rte_iova_t *hdr_mem;
306 : : ssize_t size;
307 : : int queue_type;
308 : :
309 [ # # ]: 0 : queue_type = virtio_get_queue_type(vq->hw, vq->vq_queue_index);
310 : : switch (queue_type) {
311 : : case VTNET_TQ:
312 : : /*
313 : : * For each xmit packet, allocate a virtio_net_hdr
314 : : * and indirect ring elements
315 : : */
316 : 0 : size = vq->vq_nentries * sizeof(struct virtio_tx_region);
317 : 0 : hdr_mz = &vq->txq.hdr_mz;
318 : 0 : hdr_mem = &vq->txq.hdr_mem;
319 : 0 : break;
320 : : case VTNET_CQ:
321 : : /* Allocate a page for control vq command, data and status */
322 : 0 : size = rte_mem_page_size();
323 : 0 : hdr_mz = &vq->cq.hdr_mz;
324 : 0 : hdr_mem = &vq->cq.hdr_mem;
325 : 0 : break;
326 : : case VTNET_RQ:
327 : : /* fallthrough */
328 : : default:
329 : : return 0;
330 : : }
331 : :
332 : : snprintf(hdr_name, sizeof(hdr_name), "%s_hdr", name);
333 : 0 : *hdr_mz = rte_memzone_reserve_aligned(hdr_name, size, numa_node,
334 : : RTE_MEMZONE_IOVA_CONTIG, RTE_CACHE_LINE_SIZE);
335 [ # # ]: 0 : if (*hdr_mz == NULL) {
336 [ # # ]: 0 : if (rte_errno == EEXIST)
337 : 0 : *hdr_mz = rte_memzone_lookup(hdr_name);
338 [ # # ]: 0 : if (*hdr_mz == NULL)
339 : : return -ENOMEM;
340 : : }
341 : :
342 [ # # ]: 0 : memset((*hdr_mz)->addr, 0, size);
343 : :
344 [ # # ]: 0 : if (vq->hw->use_va)
345 : 0 : *hdr_mem = (uintptr_t)(*hdr_mz)->addr;
346 : : else
347 : 0 : *hdr_mem = (uintptr_t)(*hdr_mz)->iova;
348 : :
349 : : return 0;
350 : : }
351 : :
352 : : static void
353 : 0 : virtio_free_queue_headers(struct virtqueue *vq)
354 : : {
355 : : const struct rte_memzone **hdr_mz;
356 : : rte_iova_t *hdr_mem;
357 : : int queue_type;
358 : :
359 [ # # ]: 0 : queue_type = virtio_get_queue_type(vq->hw, vq->vq_queue_index);
360 : : switch (queue_type) {
361 : : case VTNET_TQ:
362 : 0 : hdr_mz = &vq->txq.hdr_mz;
363 : 0 : hdr_mem = &vq->txq.hdr_mem;
364 : 0 : break;
365 : : case VTNET_CQ:
366 : 0 : hdr_mz = &vq->cq.hdr_mz;
367 : 0 : hdr_mem = &vq->cq.hdr_mem;
368 : 0 : break;
369 : : case VTNET_RQ:
370 : : /* fallthrough */
371 : : default:
372 : : return;
373 : : }
374 : :
375 : 0 : rte_memzone_free(*hdr_mz);
376 : 0 : *hdr_mz = NULL;
377 : 0 : *hdr_mem = 0;
378 : : }
379 : :
380 : : static int
381 : 0 : virtio_rxq_sw_ring_alloc(struct virtqueue *vq, int numa_node)
382 : : {
383 : : void *sw_ring;
384 : : struct rte_mbuf *mbuf;
385 : : size_t size;
386 : :
387 : : /* SW ring is only used with vectorized datapath */
388 [ # # ]: 0 : if (!vq->hw->use_vec_rx)
389 : : return 0;
390 : :
391 : 0 : size = (RTE_PMD_VIRTIO_RX_MAX_BURST + vq->vq_nentries) * sizeof(vq->rxq.sw_ring[0]);
392 : :
393 : 0 : sw_ring = rte_zmalloc_socket("sw_ring", size, RTE_CACHE_LINE_SIZE, numa_node);
394 [ # # ]: 0 : if (!sw_ring) {
395 : 0 : PMD_INIT_LOG(ERR, "can not allocate RX soft ring");
396 : 0 : return -ENOMEM;
397 : : }
398 : :
399 : 0 : mbuf = rte_zmalloc_socket("sw_ring", sizeof(*mbuf), RTE_CACHE_LINE_SIZE, numa_node);
400 [ # # ]: 0 : if (!mbuf) {
401 : 0 : PMD_INIT_LOG(ERR, "can not allocate fake mbuf");
402 : 0 : rte_free(sw_ring);
403 : 0 : return -ENOMEM;
404 : : }
405 : :
406 : 0 : vq->rxq.sw_ring = sw_ring;
407 : 0 : vq->rxq.fake_mbuf = mbuf;
408 : :
409 : 0 : return 0;
410 : : }
411 : :
412 : : static void
413 : : virtio_rxq_sw_ring_free(struct virtqueue *vq)
414 : : {
415 : 0 : rte_free(vq->rxq.fake_mbuf);
416 : 0 : vq->rxq.fake_mbuf = NULL;
417 : 0 : rte_free(vq->rxq.sw_ring);
418 : 0 : vq->rxq.sw_ring = NULL;
419 : 0 : }
420 : :
421 : : struct virtqueue *
422 : 0 : virtqueue_alloc(struct virtio_hw *hw, uint16_t index, uint16_t num, int type,
423 : : int node, const char *name)
424 : : {
425 : : struct virtqueue *vq;
426 : : const struct rte_memzone *mz;
427 : : unsigned int size;
428 : :
429 : 0 : size = sizeof(*vq) + num * sizeof(struct vq_desc_extra);
430 : 0 : size = RTE_ALIGN_CEIL(size, RTE_CACHE_LINE_SIZE);
431 : :
432 : 0 : vq = rte_zmalloc_socket(name, size, RTE_CACHE_LINE_SIZE, node);
433 [ # # ]: 0 : if (vq == NULL) {
434 : 0 : PMD_INIT_LOG(ERR, "can not allocate vq");
435 : 0 : return NULL;
436 : : }
437 : :
438 : 0 : vq->hw = hw;
439 : 0 : vq->vq_queue_index = index;
440 [ # # ]: 0 : vq->vq_nentries = num;
441 [ # # ]: 0 : if (virtio_with_packed_queue(hw)) {
442 : 0 : vq->vq_packed.used_wrap_counter = 1;
443 : 0 : vq->vq_packed.cached_flags = VRING_PACKED_DESC_F_AVAIL;
444 : 0 : vq->vq_packed.event_flags_shadow = 0;
445 [ # # ]: 0 : if (type == VTNET_RQ)
446 : 0 : vq->vq_packed.cached_flags |= VRING_DESC_F_WRITE;
447 : : }
448 : :
449 : : /*
450 : : * Reserve a memzone for vring elements
451 : : */
452 : 0 : size = vring_size(hw, num, VIRTIO_VRING_ALIGN);
453 : 0 : vq->vq_ring_size = RTE_ALIGN_CEIL(size, VIRTIO_VRING_ALIGN);
454 : 0 : PMD_INIT_LOG(DEBUG, "vring_size: %d, rounded_vring_size: %d", size, vq->vq_ring_size);
455 : :
456 : 0 : mz = rte_memzone_reserve_aligned(name, vq->vq_ring_size, node,
457 : : RTE_MEMZONE_IOVA_CONTIG, VIRTIO_VRING_ALIGN);
458 [ # # ]: 0 : if (mz == NULL) {
459 [ # # ]: 0 : if (rte_errno == EEXIST)
460 : 0 : mz = rte_memzone_lookup(name);
461 [ # # ]: 0 : if (mz == NULL)
462 : 0 : goto free_vq;
463 : : }
464 : :
465 [ # # ]: 0 : memset(mz->addr, 0, mz->len);
466 : 0 : vq->mz = mz;
467 : 0 : vq->vq_ring_virt_mem = mz->addr;
468 : :
469 [ # # ]: 0 : if (hw->use_va) {
470 : 0 : vq->vq_ring_mem = (uintptr_t)mz->addr;
471 : 0 : vq->mbuf_addr_offset = offsetof(struct rte_mbuf, buf_addr);
472 : 0 : vq->mbuf_addr_mask = UINTPTR_MAX;
473 : : } else {
474 : 0 : vq->vq_ring_mem = mz->iova;
475 : 0 : vq->mbuf_addr_offset = offsetof(struct rte_mbuf, buf_iova);
476 : 0 : vq->mbuf_addr_mask = UINT64_MAX;
477 : : }
478 : :
479 : 0 : PMD_INIT_LOG(DEBUG, "vq->vq_ring_mem: 0x%" PRIx64, vq->vq_ring_mem);
480 : 0 : PMD_INIT_LOG(DEBUG, "vq->vq_ring_virt_mem: %p", vq->vq_ring_virt_mem);
481 : :
482 : 0 : virtio_init_vring(vq);
483 : :
484 [ # # ]: 0 : if (virtio_alloc_queue_headers(vq, node, name)) {
485 : 0 : PMD_INIT_LOG(ERR, "Failed to alloc queue headers");
486 : 0 : goto free_mz;
487 : : }
488 : :
489 [ # # # ]: 0 : switch (type) {
490 : 0 : case VTNET_RQ:
491 [ # # ]: 0 : if (virtio_rxq_sw_ring_alloc(vq, node))
492 : 0 : goto free_hdr_mz;
493 : : break;
494 : 0 : case VTNET_TQ:
495 : 0 : virtqueue_txq_indirect_headers_init(vq);
496 : 0 : break;
497 : : }
498 : :
499 : : return vq;
500 : :
501 : : free_hdr_mz:
502 : 0 : virtio_free_queue_headers(vq);
503 : 0 : free_mz:
504 : 0 : rte_memzone_free(mz);
505 : 0 : free_vq:
506 : 0 : rte_free(vq);
507 : :
508 : 0 : return NULL;
509 : : }
510 : :
511 : : void
512 : 0 : virtqueue_free(struct virtqueue *vq)
513 : : {
514 : : int type;
515 : :
516 [ # # ]: 0 : type = virtio_get_queue_type(vq->hw, vq->vq_queue_index);
517 : : switch (type) {
518 : : case VTNET_RQ:
519 : : virtio_rxq_sw_ring_free(vq);
520 : : break;
521 : 0 : case VTNET_TQ:
522 : : case VTNET_CQ:
523 : 0 : virtio_free_queue_headers(vq);
524 : 0 : break;
525 : : }
526 : :
527 : 0 : rte_memzone_free(vq->mz);
528 : 0 : rte_free(vq);
529 : 0 : }
|