Skip to content

Commit

Permalink
virtqueue: add more virtqueue apis for the virtio device side
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
CV-Bowen committed Jan 15, 2025
1 parent 3122cec commit 1cb110f
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 6 deletions.
31 changes: 29 additions & 2 deletions lib/include/openamp/virtqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,21 @@ struct virtqueue_buf {
int len;
};

/** @brief Virtqueue buffers descriptor. */
struct virtqueue_bufs {
/** The descriptor index of the first available buffer */
uint16_t head;

/** The capacity of the virtqueue buffers */
unsigned int vb_capacity;

/** The real number of the virtqueue buffers */
unsigned int vb_num;

/** The virtqueue buffers */
struct virtqueue_buf vb[0];
};

/** @brief Vring descriptor extra information for buffer list management. */
struct vq_desc_extra {
/** Pointer to first descriptor. */
Expand Down Expand Up @@ -289,8 +304,20 @@ void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx);
*
* @return Pointer to available buffer
*/
void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx,
uint32_t *len);
void *virtqueue_get_first_avail_buffer(struct virtqueue *vq, uint16_t *avail_idx,
uint32_t *len);

/**
* @internal
*
* @brief Returns buffer available for use in the VirtIO queue
*
* @param vq Pointer to VirtIO queue control block
* @param vbs Pointer to virtqueue buffers to store available buffers
*
* @return Function status
*/
int virtqueue_get_available_buffer(struct virtqueue *vq, struct virtqueue_bufs *vbs);

/**
* @internal
Expand Down
4 changes: 2 additions & 2 deletions lib/rpmsg/rpmsg_virtio.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ static void *rpmsg_virtio_get_tx_buffer(struct rpmsg_virtio_device *rvdev,
*idx = 0;
}
} else if (VIRTIO_ROLE_IS_DEVICE(rvdev->vdev)) {
data = virtqueue_get_available_buffer(rvdev->svq, idx, len);
data = virtqueue_get_first_avail_buffer(rvdev->svq, idx, len);
}

return data;
Expand Down Expand Up @@ -235,7 +235,7 @@ static void *rpmsg_virtio_get_rx_buffer(struct rpmsg_virtio_device *rvdev,

if (VIRTIO_ROLE_IS_DEVICE(rvdev->vdev)) {
data =
virtqueue_get_available_buffer(rvdev->rvq, idx, len);
virtqueue_get_first_avail_buffer(rvdev->rvq, idx, len);
}

/* Invalidate the buffer before returning it */
Expand Down
62 changes: 60 additions & 2 deletions lib/virtio/virtqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ static int vq_ring_must_notify(struct virtqueue *vq);
static void vq_ring_notify(struct virtqueue *vq);
static int virtqueue_nused(struct virtqueue *vq);
static int virtqueue_navail(struct virtqueue *vq);
static void *virtqueue_get_next_avail_buffer(struct virtqueue *vq, uint16_t idx,
uint16_t *next_idx, uint32_t *next_len);

/* Default implementation of P2V based on libmetal */
static inline void *virtqueue_phys_to_virt(struct virtqueue *vq,
Expand Down Expand Up @@ -200,8 +202,8 @@ void virtqueue_free(struct virtqueue *vq)
}
}

void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx,
uint32_t *len)
void *virtqueue_get_first_avail_buffer(struct virtqueue *vq, uint16_t *avail_idx,
uint32_t *len)
{
uint16_t head_idx = 0;
void *buffer;
Expand Down Expand Up @@ -231,6 +233,40 @@ void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx,
return buffer;
}

int virtqueue_get_available_buffer(struct virtqueue *vq, struct virtqueue_bufs *vbs)
{
unsigned int i;
uint16_t head;
uint16_t idx;
uint32_t len;
void *buf;

buf = virtqueue_get_first_avail_buffer(vq, &head, &len);
if (!buf)
return ERROR_VRING_NO_BUFF;

vbs->head = head;
vbs->vb[0].buf = buf;
vbs->vb[0].len = len;

for (i = 1, idx = head; ; i++) {
buf = virtqueue_get_next_avail_buffer(vq, idx, &idx, &len);
if (!buf)
break;
else if (i >= vbs->vb_capacity) {
metal_log(METAL_LOG_ERROR, "capacity %u is not enough\n",
vbs->vb_capacity);
return ERROR_VQUEUE_INVLD_PARAM;
}

vbs->vb[i].buf = buf;
vbs->vb[i].len = len;
}

vbs->vb_num = i;
return 0;
}

int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx,
uint32_t len)
{
Expand Down Expand Up @@ -697,3 +733,25 @@ static int virtqueue_navail(struct virtqueue *vq)

return navail;
}

static void *virtqueue_get_next_avail_buffer(struct virtqueue *vq, uint16_t idx,
uint16_t *next_idx, uint32_t *next_len)
{
void *buffer;
uint16_t next;

VRING_INVALIDATE(vq->vq_ring.desc[idx], sizeof(struct vring_desc));
if (!(vq->vq_ring.desc[idx].flags & VRING_DESC_F_NEXT))
return NULL;

next = vq->vq_ring.desc[idx].next;
if (next_idx)
*next_idx = next;

VRING_INVALIDATE(vq->vq_ring.desc[next], sizeof(struct vring_desc));
buffer = virtqueue_phys_to_virt(vq, vq->vq_ring.desc[next].addr);
if (next_len)
*next_len = vq->vq_ring.desc[next].len;

return buffer;
}

0 comments on commit 1cb110f

Please sign in to comment.