xref: /dpdk/drivers/crypto/virtio/virtqueue.h (revision 013b4c52c708dc8fed079ff05fbe66f475365586)
125500d4bSJay Zhou /* SPDX-License-Identifier: BSD-3-Clause
225500d4bSJay Zhou  * Copyright(c) 2018 HUAWEI TECHNOLOGIES CO., LTD.
325500d4bSJay Zhou  */
425500d4bSJay Zhou 
525500d4bSJay Zhou #ifndef _VIRTQUEUE_H_
625500d4bSJay Zhou #define _VIRTQUEUE_H_
725500d4bSJay Zhou 
825500d4bSJay Zhou #include <stdint.h>
925500d4bSJay Zhou 
1025500d4bSJay Zhou #include <rte_atomic.h>
1125500d4bSJay Zhou #include <rte_memory.h>
1225500d4bSJay Zhou #include <rte_memzone.h>
1325500d4bSJay Zhou #include <rte_mempool.h>
1425500d4bSJay Zhou 
1525500d4bSJay Zhou #include "virtio_pci.h"
1625500d4bSJay Zhou #include "virtio_ring.h"
1725500d4bSJay Zhou #include "virtio_logs.h"
1825500d4bSJay Zhou #include "virtio_crypto.h"
1925500d4bSJay Zhou 
2025500d4bSJay Zhou struct rte_mbuf;
2125500d4bSJay Zhou 
2225500d4bSJay Zhou /*
2325500d4bSJay Zhou  * Per virtio_config.h in Linux.
2425500d4bSJay Zhou  *     For virtio_pci on SMP, we don't need to order with respect to MMIO
2525500d4bSJay Zhou  *     accesses through relaxed memory I/O windows, so smp_mb() et al are
2625500d4bSJay Zhou  *     sufficient.
2725500d4bSJay Zhou  *
2825500d4bSJay Zhou  */
2925500d4bSJay Zhou #define virtio_mb()	rte_smp_mb()
3025500d4bSJay Zhou #define virtio_rmb()	rte_smp_rmb()
3125500d4bSJay Zhou #define virtio_wmb()	rte_smp_wmb()
3225500d4bSJay Zhou 
3325500d4bSJay Zhou #define VIRTQUEUE_MAX_NAME_SZ 32
3425500d4bSJay Zhou 
3525500d4bSJay Zhou enum { VTCRYPTO_DATAQ = 0, VTCRYPTO_CTRLQ = 1 };
3625500d4bSJay Zhou 
3725500d4bSJay Zhou /**
3825500d4bSJay Zhou  * The maximum virtqueue size is 2^15. Use that value as the end of
3925500d4bSJay Zhou  * descriptor chain terminator since it will never be a valid index
4025500d4bSJay Zhou  * in the descriptor table. This is used to verify we are correctly
4125500d4bSJay Zhou  * handling vq_free_cnt.
4225500d4bSJay Zhou  */
4325500d4bSJay Zhou #define VQ_RING_DESC_CHAIN_END 32768
4425500d4bSJay Zhou 
4525500d4bSJay Zhou struct vq_desc_extra {
4625500d4bSJay Zhou 	void     *crypto_op;
4725500d4bSJay Zhou 	void     *cookie;
4825500d4bSJay Zhou 	uint16_t ndescs;
4925500d4bSJay Zhou };
5025500d4bSJay Zhou 
5125500d4bSJay Zhou struct virtqueue {
5225500d4bSJay Zhou 	/**< virtio_crypto_hw structure pointer. */
5325500d4bSJay Zhou 	struct virtio_crypto_hw *hw;
5425500d4bSJay Zhou 	/**< mem zone to populate RX ring. */
5525500d4bSJay Zhou 	const struct rte_memzone *mz;
5625500d4bSJay Zhou 	/**< memzone to populate hdr and request. */
5725500d4bSJay Zhou 	struct rte_mempool *mpool;
5825500d4bSJay Zhou 	uint8_t     dev_id;              /**< Device identifier. */
5925500d4bSJay Zhou 	uint16_t    vq_queue_index;       /**< PCI queue index */
6025500d4bSJay Zhou 
6125500d4bSJay Zhou 	void        *vq_ring_virt_mem;    /**< linear address of vring*/
6225500d4bSJay Zhou 	unsigned int vq_ring_size;
6325500d4bSJay Zhou 	phys_addr_t vq_ring_mem;          /**< physical address of vring */
6425500d4bSJay Zhou 
6525500d4bSJay Zhou 	struct vring vq_ring;    /**< vring keeping desc, used and avail */
6625500d4bSJay Zhou 	uint16_t    vq_free_cnt; /**< num of desc available */
6725500d4bSJay Zhou 	uint16_t    vq_nentries; /**< vring desc numbers */
6825500d4bSJay Zhou 
6925500d4bSJay Zhou 	/**
7025500d4bSJay Zhou 	 * Head of the free chain in the descriptor table. If
7125500d4bSJay Zhou 	 * there are no free descriptors, this will be set to
7225500d4bSJay Zhou 	 * VQ_RING_DESC_CHAIN_END.
7325500d4bSJay Zhou 	 */
7425500d4bSJay Zhou 	uint16_t  vq_desc_head_idx;
7525500d4bSJay Zhou 	uint16_t  vq_desc_tail_idx;
7625500d4bSJay Zhou 	/**
7725500d4bSJay Zhou 	 * Last consumed descriptor in the used table,
7825500d4bSJay Zhou 	 * trails vq_ring.used->idx.
7925500d4bSJay Zhou 	 */
8025500d4bSJay Zhou 	uint16_t vq_used_cons_idx;
8125500d4bSJay Zhou 	uint16_t vq_avail_idx;
8225500d4bSJay Zhou 
8325500d4bSJay Zhou 	/* Statistics */
8425500d4bSJay Zhou 	uint64_t	packets_sent_total;
8525500d4bSJay Zhou 	uint64_t	packets_sent_failed;
8625500d4bSJay Zhou 	uint64_t	packets_received_total;
8725500d4bSJay Zhou 	uint64_t	packets_received_failed;
8825500d4bSJay Zhou 
8925500d4bSJay Zhou 	uint16_t  *notify_addr;
9025500d4bSJay Zhou 
91*013b4c52SBruce Richardson 	struct vq_desc_extra vq_descx[];
9225500d4bSJay Zhou };
9325500d4bSJay Zhou 
9425500d4bSJay Zhou /**
9525500d4bSJay Zhou  * Tell the backend not to interrupt us.
9625500d4bSJay Zhou  */
9725500d4bSJay Zhou void virtqueue_disable_intr(struct virtqueue *vq);
9825500d4bSJay Zhou 
9925500d4bSJay Zhou /**
10025500d4bSJay Zhou  *  Get all mbufs to be freed.
10125500d4bSJay Zhou  */
10225500d4bSJay Zhou void virtqueue_detatch_unused(struct virtqueue *vq);
10325500d4bSJay Zhou 
10425500d4bSJay Zhou static inline int
virtqueue_full(const struct virtqueue * vq)10525500d4bSJay Zhou virtqueue_full(const struct virtqueue *vq)
10625500d4bSJay Zhou {
10725500d4bSJay Zhou 	return vq->vq_free_cnt == 0;
10825500d4bSJay Zhou }
10925500d4bSJay Zhou 
11025500d4bSJay Zhou #define VIRTQUEUE_NUSED(vq) \
11125500d4bSJay Zhou 	((uint16_t)((vq)->vq_ring.used->idx - (vq)->vq_used_cons_idx))
11225500d4bSJay Zhou 
11325500d4bSJay Zhou static inline void
vq_update_avail_idx(struct virtqueue * vq)11425500d4bSJay Zhou vq_update_avail_idx(struct virtqueue *vq)
11525500d4bSJay Zhou {
11625500d4bSJay Zhou 	virtio_wmb();
11725500d4bSJay Zhou 	vq->vq_ring.avail->idx = vq->vq_avail_idx;
11825500d4bSJay Zhou }
11925500d4bSJay Zhou 
12025500d4bSJay Zhou static inline void
vq_update_avail_ring(struct virtqueue * vq,uint16_t desc_idx)12125500d4bSJay Zhou vq_update_avail_ring(struct virtqueue *vq, uint16_t desc_idx)
12225500d4bSJay Zhou {
12325500d4bSJay Zhou 	uint16_t avail_idx;
12425500d4bSJay Zhou 	/*
12525500d4bSJay Zhou 	 * Place the head of the descriptor chain into the next slot and make
12625500d4bSJay Zhou 	 * it usable to the host. The chain is made available now rather than
12725500d4bSJay Zhou 	 * deferring to virtqueue_notify() in the hopes that if the host is
12825500d4bSJay Zhou 	 * currently running on another CPU, we can keep it processing the new
12925500d4bSJay Zhou 	 * descriptor.
13025500d4bSJay Zhou 	 */
13125500d4bSJay Zhou 	avail_idx = (uint16_t)(vq->vq_avail_idx & (vq->vq_nentries - 1));
13225500d4bSJay Zhou 	if (unlikely(vq->vq_ring.avail->ring[avail_idx] != desc_idx))
13325500d4bSJay Zhou 		vq->vq_ring.avail->ring[avail_idx] = desc_idx;
13425500d4bSJay Zhou 	vq->vq_avail_idx++;
13525500d4bSJay Zhou }
13625500d4bSJay Zhou 
13725500d4bSJay Zhou static inline int
virtqueue_kick_prepare(struct virtqueue * vq)13825500d4bSJay Zhou virtqueue_kick_prepare(struct virtqueue *vq)
13925500d4bSJay Zhou {
14025500d4bSJay Zhou 	return !(vq->vq_ring.used->flags & VRING_USED_F_NO_NOTIFY);
14125500d4bSJay Zhou }
14225500d4bSJay Zhou 
14325500d4bSJay Zhou static inline void
virtqueue_notify(struct virtqueue * vq)14425500d4bSJay Zhou virtqueue_notify(struct virtqueue *vq)
14525500d4bSJay Zhou {
14625500d4bSJay Zhou 	/*
14725500d4bSJay Zhou 	 * Ensure updated avail->idx is visible to host.
1487be78d02SJosh Soref 	 * For virtio on IA, the notification is through io port operation
14925500d4bSJay Zhou 	 * which is a serialization instruction itself.
15025500d4bSJay Zhou 	 */
15125500d4bSJay Zhou 	VTPCI_OPS(vq->hw)->notify_queue(vq->hw, vq);
15225500d4bSJay Zhou }
15325500d4bSJay Zhou 
15425500d4bSJay Zhou /**
15525500d4bSJay Zhou  * Dump virtqueue internal structures, for debug purpose only.
15625500d4bSJay Zhou  */
15725500d4bSJay Zhou #define VIRTQUEUE_DUMP(vq) do { \
15825500d4bSJay Zhou 	uint16_t used_idx, nused; \
15925500d4bSJay Zhou 	used_idx = (vq)->vq_ring.used->idx; \
16025500d4bSJay Zhou 	nused = (uint16_t)(used_idx - (vq)->vq_used_cons_idx); \
16125500d4bSJay Zhou 	VIRTIO_CRYPTO_INIT_LOG_DBG(\
16225500d4bSJay Zhou 	  "VQ: - size=%d; free=%d; used=%d; desc_head_idx=%d;" \
16325500d4bSJay Zhou 	  " avail.idx=%d; used_cons_idx=%d; used.idx=%d;" \
16425500d4bSJay Zhou 	  " avail.flags=0x%x; used.flags=0x%x", \
16525500d4bSJay Zhou 	  (vq)->vq_nentries, (vq)->vq_free_cnt, nused, \
16625500d4bSJay Zhou 	  (vq)->vq_desc_head_idx, (vq)->vq_ring.avail->idx, \
16725500d4bSJay Zhou 	  (vq)->vq_used_cons_idx, (vq)->vq_ring.used->idx, \
16825500d4bSJay Zhou 	  (vq)->vq_ring.avail->flags, (vq)->vq_ring.used->flags); \
16925500d4bSJay Zhou } while (0)
17025500d4bSJay Zhou 
17125500d4bSJay Zhou #endif /* _VIRTQUEUE_H_ */
172