From 75582fc2e69ac18f03a144d78c6d136d5594c7f5 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 29 Mar 2023 22:24:57 +0800 Subject: [PATCH] virtio: Allocate virtqueue in page-size units In preparation for explicit bouncing of virtqueue pages for devices advertising the VIRTIO_F_IOMMU_PLATFORM feature, introduce a couple of wrappers around virtqueue allocation and freeing operations, ensuring that buffers are handled in terms of page-size units. Signed-off-by: Will Deacon [ Paul: pick from the Android tree. Rebase to the upstream ] Signed-off-by: Ying-Chun Liu (PaulLiu) Cc: Bin Meng Link: https://android.googlesource.com/platform/external/u-boot/+/b4bb5227d4cf4fdfcd8b4e1ff2692d3a54d1482a Reviewed-by: Simon Glass --- drivers/virtio/virtio_ring.c | 24 ++++++++++++++++++++---- include/virtio_ring.h | 16 +++++++++------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index f71bab7847..5aeb13fd59 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -15,6 +15,17 @@ #include #include #include +#include + +static void *virtio_alloc_pages(struct udevice *vdev, u32 npages) +{ + return memalign(PAGE_SIZE, npages * PAGE_SIZE); +} + +static void virtio_free_pages(struct udevice *vdev, void *ptr, u32 npages) +{ + free(ptr); +} static unsigned int virtqueue_attach_desc(struct virtqueue *vq, unsigned int i, struct virtio_sg *sg, u16 flags) @@ -271,6 +282,8 @@ struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num, unsigned int vring_align, struct udevice *udev) { + struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev); + struct udevice *vdev = uc_priv->vdev; struct virtqueue *vq; void *queue = NULL; struct vring vring; @@ -283,7 +296,9 @@ struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num, /* TODO: allocate each queue chunk individually */ for (; num && vring_size(num, vring_align) > PAGE_SIZE; num /= 2) { - queue = memalign(PAGE_SIZE, vring_size(num, vring_align)); + size_t sz = vring_size(num, vring_align); + + queue = virtio_alloc_pages(vdev, DIV_ROUND_UP(sz, PAGE_SIZE)); if (queue) break; } @@ -293,7 +308,7 @@ struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num, if (!queue) { /* Try to get a single page. You are my only hope! */ - queue = memalign(PAGE_SIZE, vring_size(num, vring_align)); + queue = virtio_alloc_pages(vdev, 1); } if (!queue) return NULL; @@ -303,7 +318,7 @@ struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num, vq = __vring_new_virtqueue(index, vring, udev); if (!vq) { - free(queue); + virtio_free_pages(vdev, queue, DIV_ROUND_UP(vring.size, PAGE_SIZE)); return NULL; } debug("(%s): created vring @ %p for vq @ %p with num %u\n", udev->name, @@ -314,7 +329,8 @@ struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num, void vring_del_virtqueue(struct virtqueue *vq) { - free(vq->vring.desc); + virtio_free_pages(vq->vdev, vq->vring.desc, + DIV_ROUND_UP(vq->vring.size, PAGE_SIZE)); free(vq->vring_desc_shadow); list_del(&vq->list); free(vq); diff --git a/include/virtio_ring.h b/include/virtio_ring.h index c77c212cff..8f8a55c7bd 100644 --- a/include/virtio_ring.h +++ b/include/virtio_ring.h @@ -86,6 +86,7 @@ struct vring_used { struct vring { unsigned int num; + size_t size; struct vring_desc *desc; struct vring_avail *avail; struct vring_used *used; @@ -137,23 +138,24 @@ struct virtqueue { #define vring_used_event(vr) ((vr)->avail->ring[(vr)->num]) #define vring_avail_event(vr) (*(__virtio16 *)&(vr)->used->ring[(vr)->num]) +static inline unsigned int vring_size(unsigned int num, unsigned long align) +{ + return ((sizeof(struct vring_desc) * num + + sizeof(__virtio16) * (3 + num) + align - 1) & ~(align - 1)) + + sizeof(__virtio16) * 3 + sizeof(struct vring_used_elem) * num; +} + static inline void vring_init(struct vring *vr, unsigned int num, void *p, unsigned long align) { vr->num = num; + vr->size = vring_size(num, align); vr->desc = p; vr->avail = p + num * sizeof(struct vring_desc); vr->used = (void *)(((uintptr_t)&vr->avail->ring[num] + sizeof(__virtio16) + align - 1) & ~(align - 1)); } -static inline unsigned int vring_size(unsigned int num, unsigned long align) -{ - return ((sizeof(struct vring_desc) * num + - sizeof(__virtio16) * (3 + num) + align - 1) & ~(align - 1)) + - sizeof(__virtio16) * 3 + sizeof(struct vring_used_elem) * num; -} - /* * The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX. * Assuming a given event_idx value from the other side, if we have just -- 2.39.5