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 _VIRTIO_RING_H_ 6 : : #define _VIRTIO_RING_H_ 7 : : 8 : : #include <stdint.h> 9 : : 10 : : #include <rte_common.h> 11 : : 12 : : /* This marks a buffer as continuing via the next field. */ 13 : : #define VRING_DESC_F_NEXT 1 14 : : /* This marks a buffer as write-only (otherwise read-only). */ 15 : : #define VRING_DESC_F_WRITE 2 16 : : /* This means the buffer contains a list of buffer descriptors. */ 17 : : #define VRING_DESC_F_INDIRECT 4 18 : : 19 : : /* The Host uses this in used->flags to advise the Guest: don't kick me 20 : : * when you add a buffer. It's unreliable, so it's simply an 21 : : * optimization. Guest will still kick if it's out of buffers. 22 : : */ 23 : : #define VRING_USED_F_NO_NOTIFY 1 24 : : /* The Guest uses this in avail->flags to advise the Host: don't 25 : : * interrupt me when you consume a buffer. It's unreliable, so it's 26 : : * simply an optimization. 27 : : */ 28 : : #define VRING_AVAIL_F_NO_INTERRUPT 1 29 : : 30 : : /* VirtIO ring descriptors: 16 bytes. 31 : : * These can chain together via "next". 32 : : */ 33 : : struct vring_desc { 34 : : uint64_t addr; /* Address (guest-physical). */ 35 : : uint32_t len; /* Length. */ 36 : : uint16_t flags; /* The flags as indicated above. */ 37 : : uint16_t next; /* We chain unused descriptors via this. */ 38 : : }; 39 : : 40 : : struct vring_avail { 41 : : uint16_t flags; 42 : : uint16_t idx; 43 : : uint16_t ring[]; 44 : : }; 45 : : 46 : : /* id is a 16bit index. uint32_t is used here for ids for padding reasons. */ 47 : : struct vring_used_elem { 48 : : /* Index of start of used descriptor chain. */ 49 : : uint32_t id; 50 : : /* Total length of the descriptor chain which was written to. */ 51 : : uint32_t len; 52 : : }; 53 : : 54 : : struct vring_used { 55 : : uint16_t flags; 56 : : volatile uint16_t idx; 57 : : struct vring_used_elem ring[]; 58 : : }; 59 : : 60 : : struct vring { 61 : : unsigned int num; 62 : : struct vring_desc *desc; 63 : : struct vring_avail *avail; 64 : : struct vring_used *used; 65 : : }; 66 : : 67 : : /* The standard layout for the ring is a continuous chunk of memory which 68 : : * looks like this. We assume num is a power of 2. 69 : : * 70 : : * struct vring { 71 : : * // The actual descriptors (16 bytes each) 72 : : * struct vring_desc desc[num]; 73 : : * 74 : : * // A ring of available descriptor heads with free-running index. 75 : : * __u16 avail_flags; 76 : : * __u16 avail_idx; 77 : : * __u16 available[num]; 78 : : * __u16 used_event_idx; 79 : : * 80 : : * // Padding to the next align boundary. 81 : : * char pad[]; 82 : : * 83 : : * // A ring of used descriptor heads with free-running index. 84 : : * __u16 used_flags; 85 : : * __u16 used_idx; 86 : : * struct vring_used_elem used[num]; 87 : : * __u16 avail_event_idx; 88 : : * }; 89 : : * 90 : : * NOTE: for VirtIO PCI, align is 4096. 91 : : */ 92 : : 93 : : /* 94 : : * We publish the used event index at the end of the available ring, and vice 95 : : * versa. They are at the end for backwards compatibility. 96 : : */ 97 : : #define vring_used_event(vr) ((vr)->avail->ring[(vr)->num]) 98 : : #define vring_avail_event(vr) (*(uint16_t *)&(vr)->used->ring[(vr)->num]) 99 : : 100 : : static inline size_t 101 : : vring_size(unsigned int num, unsigned long align) 102 : : { 103 : : size_t size; 104 : : 105 : 0 : size = num * sizeof(struct vring_desc); 106 : 0 : size += sizeof(struct vring_avail) + (num * sizeof(uint16_t)); 107 : 0 : size = RTE_ALIGN_CEIL(size, align); 108 : 0 : size += sizeof(struct vring_used) + 109 [ # # ]: 0 : (num * sizeof(struct vring_used_elem)); 110 : : return size; 111 : : } 112 : : 113 : : static inline void 114 : : vring_init(struct vring *vr, unsigned int num, uint8_t *p, 115 : : unsigned long align) 116 : : { 117 : 0 : vr->num = num; 118 : 0 : vr->desc = (struct vring_desc *) p; 119 : 0 : vr->avail = (struct vring_avail *) (p + 120 : 0 : num * sizeof(struct vring_desc)); 121 : 0 : vr->used = (void *) 122 : 0 : RTE_ALIGN_CEIL((uintptr_t)(&vr->avail->ring[num]), align); 123 : : } 124 : : 125 : : /* 126 : : * The following is used with VIRTIO_RING_F_EVENT_IDX. 127 : : * Assuming a given event_idx value from the other size, if we have 128 : : * just incremented index from old to new_idx, should we trigger an 129 : : * event? 130 : : */ 131 : : static inline int 132 : : vring_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old) 133 : : { 134 : : return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old); 135 : : } 136 : : 137 : : #endif /* _VIRTIO_RING_H_ */