Line data Source code
1 0 : /*
2 : * Copyright (c) 2024 Antmicro <www.antmicro.com>
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : #ifndef ZEPHYR_VIRTIO_VIRTQUEUE_H_
8 : #define ZEPHYR_VIRTIO_VIRTQUEUE_H_
9 : #include <stdint.h>
10 : #include <stddef.h>
11 : #include <zephyr/kernel.h>
12 :
13 : #ifdef __cplusplus
14 : extern "C" {
15 : #endif
16 :
17 : /*
18 : * Based on Virtual I/O Device (VIRTIO) Version 1.3 specification:
19 : * https://docs.oasis-open.org/virtio/virtio/v1.3/csd01/virtio-v1.3-csd01.pdf
20 : */
21 :
22 : /**
23 : * @brief Virtqueue Interface
24 : * @defgroup virtqueue_interface Virtqueue Interface
25 : * @ingroup virtio_interface
26 : * @{
27 : */
28 :
29 : /**
30 : * used in virtq_desc::flags, enables chaining descriptor via virtq_desc::next
31 : */
32 1 : #define VIRTQ_DESC_F_NEXT 1
33 : /**
34 : * used in virtq_desc::flags, makes descriptor device writeable
35 : */
36 1 : #define VIRTQ_DESC_F_WRITE 2
37 :
38 : /**
39 : * @brief virtqueue descriptor
40 : *
41 : * Describes a single buffer
42 : */
43 1 : struct virtq_desc {
44 : /**
45 : * physical address of the buffer
46 : */
47 1 : uint64_t addr;
48 : /**
49 : * length of the buffer
50 : */
51 1 : uint32_t len;
52 : /**
53 : * buffer flags
54 : */
55 1 : uint16_t flags;
56 : /**
57 : * chaining next descriptor, valid if flags & VIRTQ_DESC_F_NEXT
58 : */
59 1 : uint16_t next;
60 : };
61 :
62 : /**
63 : * @brief virtqueue available ring
64 : *
65 : * Used to pass descriptors to the virtio device. Driver writeable, device readable
66 : */
67 1 : struct virtq_avail {
68 : /**
69 : * ring flags, e.g. VIRTQ_AVAIL_F_NO_INTERRUPT, currently unused
70 : */
71 1 : uint16_t flags;
72 : /**
73 : * head of the ring, by increasing it newly added descriptors are committed
74 : */
75 1 : uint16_t idx;
76 : /**
77 : * ring with indexes of descriptors
78 : */
79 1 : uint16_t ring[];
80 : };
81 :
82 : /**
83 : * @brief used descriptor chain
84 : *
85 : * Describes a single descriptor chain returned by the virtio device
86 : */
87 1 : struct virtq_used_elem {
88 : /**
89 : * index of the head of descriptor chain
90 : */
91 1 : uint32_t id;
92 : /**
93 : * total amount of bytes written to descriptor chain by the virtio device
94 : */
95 1 : uint32_t len;
96 : };
97 :
98 : /**
99 : * @brief virtqueue used ring
100 : *
101 : * Used to receive descriptors from the virtio device. Driver readable, device writeable
102 : */
103 1 : struct virtq_used {
104 : /**
105 : * ring flags, e.g. VIRTQ_USED_F_NO_NOTIFY, currently unused
106 : */
107 1 : uint16_t flags;
108 : /**
109 : * head of the ring
110 : */
111 1 : uint16_t idx;
112 : /**
113 : * ring of struct virtq_used_elem
114 : */
115 1 : struct virtq_used_elem ring[];
116 : };
117 :
118 : /**
119 : * @brief receive callback function type
120 : *
121 : * @param opaque argument passed to the callback
122 : * @param used_len total amount of bytes written to the descriptor chain by the virtio device
123 : */
124 1 : typedef void (*virtq_receive_callback)(void *opaque, uint32_t used_len);
125 :
126 : /**
127 : * @brief callback descriptor
128 : *
129 : * contains callback function ad its argument, invoked after virtio device return
130 : * descriptor chain its associated with
131 : */
132 1 : struct virtq_receive_callback_entry {
133 : /**
134 : * callback function pointer
135 : */
136 1 : virtq_receive_callback cb;
137 : /**
138 : * argument passed to the callback function
139 : */
140 1 : void *opaque;
141 : };
142 :
143 : /**
144 : * @brief virtqueue
145 : *
146 : * contains structures required for virtqueue operation
147 : */
148 1 : struct virtq {
149 : /**
150 : * lock used to synchronize operations on virtqueue
151 : */
152 1 : struct k_spinlock lock;
153 :
154 : /**
155 : * size of virtqueue
156 : */
157 1 : uint16_t num;
158 : /**
159 : * array with descriptors
160 : */
161 1 : struct virtq_desc *desc;
162 : /**
163 : * available ring
164 : */
165 1 : struct virtq_avail *avail;
166 : /**
167 : * used ring
168 : */
169 1 : struct virtq_used *used;
170 :
171 : /**
172 : * last seen idx in used ring, used to determine first descriptor to process
173 : * after receiving virtqueue interrupt
174 : */
175 1 : uint16_t last_used_idx;
176 : /**
177 : * Stack containing indexes of free descriptors. Because virtio devices are
178 : * not required to use received descriptors in order (see 2.7.9) unless
179 : * VIRTIO_F_IN_ORDER was offered, we can't use array with descriptors as another
180 : * ring buffer, always taking next descriptor. This is an auxilary structure to
181 : * easily determine next free descriptor
182 : */
183 1 : struct k_stack free_desc_stack;
184 :
185 : /**
186 : * amount of free descriptors in the free_desc_stack
187 : */
188 1 : uint16_t free_desc_n;
189 :
190 : /**
191 : * array with callbacks invoked after receiving buffers back from the device
192 : */
193 1 : struct virtq_receive_callback_entry *recv_cbs;
194 : };
195 :
196 :
197 : /**
198 : * @brief creates virtqueue
199 : *
200 : * @param v virtqueue to be created
201 : * @param size size of the virtqueue
202 : * @return 0 or error code on failure
203 : */
204 1 : int virtq_create(struct virtq *v, size_t size);
205 :
206 : /**
207 : * @brief frees virtqueue
208 : *
209 : * @param v virtqueue to be freed
210 : */
211 1 : void virtq_free(struct virtq *v);
212 :
213 : /**
214 : * @brief single buffer passed to virtq_add_buffer_chain
215 : */
216 1 : struct virtq_buf {
217 : /**
218 : * virtual address of the buffer
219 : */
220 1 : void *addr;
221 : /**
222 : * length of the buffer
223 : */
224 1 : uint32_t len;
225 : };
226 :
227 : /**
228 : * @brief adds chain of buffers to the virtqueue
229 : *
230 : * Note that according to spec 2.7.13.3 the device may access the buffers as soon
231 : * as the avail->idx is increased, which is done at the end of this function, so
232 : * the device may access the buffers without notifying it with virtio_notify_virtqueue
233 : *
234 : * @param v virtqueue it operates on
235 : * @param bufs array of buffers to be added to the virtqueue
236 : * @param bufs_size amount of buffers
237 : * @param device_readable_count amount of bufferes readable by the device, the first
238 : * device_readable_count buffers will be set as device readable
239 : * @param cb callback to be invoked after device returns the buffer chain, can be NULL
240 : * @param cb_opaque opaque value that will be passed to the cb
241 : * @param timeout amount of time it will wait for free descriptors, with K_NO_WAIT it
242 : * can be called from isr
243 : * @return 0 or error code on failure
244 : */
245 1 : int virtq_add_buffer_chain(
246 : struct virtq *v, struct virtq_buf *bufs, uint16_t bufs_size,
247 : uint16_t device_readable_count, virtq_receive_callback cb, void *cb_opaque,
248 : k_timeout_t timeout
249 : );
250 :
251 : /**
252 : * @brief adds free descriptor back
253 : *
254 : * @param v virtqueue it operates on
255 : * @param desc_idx index of returned descriptor
256 : */
257 1 : void virtq_add_free_desc(struct virtq *v, uint16_t desc_idx);
258 :
259 : /**
260 : * @brief gets next free descriptor
261 : *
262 : * @param v virtqueue it operates on
263 : * @param desc_idx address where index of descriptor will be stored
264 : * @param timeout amount of time it will wait for free descriptor, with K_NO_WAIT it
265 : * can be called from isr
266 : * @return 0 or error code on failure
267 : */
268 1 : int virtq_get_free_desc(struct virtq *v, uint16_t *desc_idx, k_timeout_t timeout);
269 :
270 : /**
271 : * @}
272 : */
273 :
274 : #ifdef __cplusplus
275 : }
276 : #endif
277 :
278 : #endif /* ZEPHYR_VIRTIO_VIRTQUEUE_H_ */
|