Skip to content

Commit 1cb110f

Browse files
committed
virtqueue: add more virtqueue apis for the virtio device side
In virtio device side, we always need to get the next avaiable buffer based on current buffer index. So add these two APIs for convinience use. For example, virtio blk driver origanize the buffer: +----------+ | Reqeust | (Flags: Read | Next) +----------+ | Buffer | (Flags: Read/Write | Next) +----------+ | Response | (Flags: Write) +----------+ For the virtio blk device size, we need get the Buffer and Response buffer based on the Request buffer index. So modify the virtqueue_get_available_buffer() to support get more than one available buffer. Signed-off-by: Bowen Wang <[email protected]> Signed-off-by: Yongrong Wang <[email protected]>
1 parent 3122cec commit 1cb110f

File tree

3 files changed

+91
-6
lines changed

3 files changed

+91
-6
lines changed

lib/include/openamp/virtqueue.h

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,21 @@ struct virtqueue_buf {
7272
int len;
7373
};
7474

75+
/** @brief Virtqueue buffers descriptor. */
76+
struct virtqueue_bufs {
77+
/** The descriptor index of the first available buffer */
78+
uint16_t head;
79+
80+
/** The capacity of the virtqueue buffers */
81+
unsigned int vb_capacity;
82+
83+
/** The real number of the virtqueue buffers */
84+
unsigned int vb_num;
85+
86+
/** The virtqueue buffers */
87+
struct virtqueue_buf vb[0];
88+
};
89+
7590
/** @brief Vring descriptor extra information for buffer list management. */
7691
struct vq_desc_extra {
7792
/** Pointer to first descriptor. */
@@ -289,8 +304,20 @@ void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx);
289304
*
290305
* @return Pointer to available buffer
291306
*/
292-
void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx,
293-
uint32_t *len);
307+
void *virtqueue_get_first_avail_buffer(struct virtqueue *vq, uint16_t *avail_idx,
308+
uint32_t *len);
309+
310+
/**
311+
* @internal
312+
*
313+
* @brief Returns buffer available for use in the VirtIO queue
314+
*
315+
* @param vq Pointer to VirtIO queue control block
316+
* @param vbs Pointer to virtqueue buffers to store available buffers
317+
*
318+
* @return Function status
319+
*/
320+
int virtqueue_get_available_buffer(struct virtqueue *vq, struct virtqueue_bufs *vbs);
294321

295322
/**
296323
* @internal

lib/rpmsg/rpmsg_virtio.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ static void *rpmsg_virtio_get_tx_buffer(struct rpmsg_virtio_device *rvdev,
207207
*idx = 0;
208208
}
209209
} else if (VIRTIO_ROLE_IS_DEVICE(rvdev->vdev)) {
210-
data = virtqueue_get_available_buffer(rvdev->svq, idx, len);
210+
data = virtqueue_get_first_avail_buffer(rvdev->svq, idx, len);
211211
}
212212

213213
return data;
@@ -235,7 +235,7 @@ static void *rpmsg_virtio_get_rx_buffer(struct rpmsg_virtio_device *rvdev,
235235

236236
if (VIRTIO_ROLE_IS_DEVICE(rvdev->vdev)) {
237237
data =
238-
virtqueue_get_available_buffer(rvdev->rvq, idx, len);
238+
virtqueue_get_first_avail_buffer(rvdev->rvq, idx, len);
239239
}
240240

241241
/* Invalidate the buffer before returning it */

lib/virtio/virtqueue.c

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ static int vq_ring_must_notify(struct virtqueue *vq);
2323
static void vq_ring_notify(struct virtqueue *vq);
2424
static int virtqueue_nused(struct virtqueue *vq);
2525
static int virtqueue_navail(struct virtqueue *vq);
26+
static void *virtqueue_get_next_avail_buffer(struct virtqueue *vq, uint16_t idx,
27+
uint16_t *next_idx, uint32_t *next_len);
2628

2729
/* Default implementation of P2V based on libmetal */
2830
static inline void *virtqueue_phys_to_virt(struct virtqueue *vq,
@@ -200,8 +202,8 @@ void virtqueue_free(struct virtqueue *vq)
200202
}
201203
}
202204

203-
void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx,
204-
uint32_t *len)
205+
void *virtqueue_get_first_avail_buffer(struct virtqueue *vq, uint16_t *avail_idx,
206+
uint32_t *len)
205207
{
206208
uint16_t head_idx = 0;
207209
void *buffer;
@@ -231,6 +233,40 @@ void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx,
231233
return buffer;
232234
}
233235

236+
int virtqueue_get_available_buffer(struct virtqueue *vq, struct virtqueue_bufs *vbs)
237+
{
238+
unsigned int i;
239+
uint16_t head;
240+
uint16_t idx;
241+
uint32_t len;
242+
void *buf;
243+
244+
buf = virtqueue_get_first_avail_buffer(vq, &head, &len);
245+
if (!buf)
246+
return ERROR_VRING_NO_BUFF;
247+
248+
vbs->head = head;
249+
vbs->vb[0].buf = buf;
250+
vbs->vb[0].len = len;
251+
252+
for (i = 1, idx = head; ; i++) {
253+
buf = virtqueue_get_next_avail_buffer(vq, idx, &idx, &len);
254+
if (!buf)
255+
break;
256+
else if (i >= vbs->vb_capacity) {
257+
metal_log(METAL_LOG_ERROR, "capacity %u is not enough\n",
258+
vbs->vb_capacity);
259+
return ERROR_VQUEUE_INVLD_PARAM;
260+
}
261+
262+
vbs->vb[i].buf = buf;
263+
vbs->vb[i].len = len;
264+
}
265+
266+
vbs->vb_num = i;
267+
return 0;
268+
}
269+
234270
int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx,
235271
uint32_t len)
236272
{
@@ -697,3 +733,25 @@ static int virtqueue_navail(struct virtqueue *vq)
697733

698734
return navail;
699735
}
736+
737+
static void *virtqueue_get_next_avail_buffer(struct virtqueue *vq, uint16_t idx,
738+
uint16_t *next_idx, uint32_t *next_len)
739+
{
740+
void *buffer;
741+
uint16_t next;
742+
743+
VRING_INVALIDATE(vq->vq_ring.desc[idx], sizeof(struct vring_desc));
744+
if (!(vq->vq_ring.desc[idx].flags & VRING_DESC_F_NEXT))
745+
return NULL;
746+
747+
next = vq->vq_ring.desc[idx].next;
748+
if (next_idx)
749+
*next_idx = next;
750+
751+
VRING_INVALIDATE(vq->vq_ring.desc[next], sizeof(struct vring_desc));
752+
buffer = virtqueue_phys_to_virt(vq, vq->vq_ring.desc[next].addr);
753+
if (next_len)
754+
*next_len = vq->vq_ring.desc[next].len;
755+
756+
return buffer;
757+
}

0 commit comments

Comments
 (0)