From 3c591deb00193c73f2b94becc584457b735f893c Mon Sep 17 00:00:00 2001 From: Bowen Wang Date: Tue, 31 Oct 2023 21:18:37 +0800 Subject: [PATCH] virtio: add alloc_buf/free_buf in virtio ops Buffer management is different for different transport layer: For MMIO transport layer, the buffer can direclty malloced from the gust os heap beacase the hypervisor can access all the memmory own by guest os. For remoteproc transpor layer, the buffer should be malloced from the share memory region to make sure the remote core can access this buffer too. So add alloc_buf/free_buf in virtio ops to make different transport can implement their own share memory management: 1. add alloc_buf/free_buf api in virtio ops; 2. support the alloc_buf/free_buf for remoteproc transport layer; Signed-off-by: Bowen Wang --- lib/include/openamp/remoteproc_virtio.h | 26 ++++++++++++ lib/include/openamp/virtio.h | 54 +++++++++++++++++++++++++ lib/remoteproc/remoteproc_virtio.c | 41 +++++++++++++++++++ 3 files changed, 121 insertions(+) diff --git a/lib/include/openamp/remoteproc_virtio.h b/lib/include/openamp/remoteproc_virtio.h index 0b747cacc..55fbd8711 100644 --- a/lib/include/openamp/remoteproc_virtio.h +++ b/lib/include/openamp/remoteproc_virtio.h @@ -39,6 +39,11 @@ extern "C" { /* define vdev notification function user should implement */ typedef int (*rpvdev_notify_func)(void *priv, uint32_t id); +/* Define remoteproc virtio memory managerment function */ +struct remoteproc_virtio; +typedef void *(*rpvdev_alloc_buf)(struct remoteproc_virtio *rpvdev, size_t size, size_t align); +typedef void (*rpvdev_free_buf)(struct remoteproc_virtio *rpvdev, void *buf); + /** @brief Virtio structure for remoteproc instance */ struct remoteproc_virtio { /** Pointer to private data */ @@ -56,6 +61,12 @@ struct remoteproc_virtio { /** Virtio device */ struct virtio_device vdev; + /** Share memory alloc function */ + rpvdev_alloc_buf alloc_buf; + + /** Share memory free function */ + rpvdev_free_buf free_buf; + /** List node */ struct metal_list node; }; @@ -126,6 +137,21 @@ int rproc_virtio_notified(struct virtio_device *vdev, uint32_t notifyid); */ void rproc_virtio_wait_remote_ready(struct virtio_device *vdev); +/** + * rproc_virtio_set_mm_callback + * + * Set the share memory management callback function + * + * @param vdev Pointer to the virtio device + * @param alloc_buf Alloc buffer callback function + * @param free_buf Free buffer callback function + * + * return 0 for success, negative value for failure. + */ +int rproc_virtio_set_mm_callback(struct virtio_device *vdev, + rpvdev_alloc_buf alloc_buf, + rpvdev_free_buf free_buf); + #if defined __cplusplus } #endif diff --git a/lib/include/openamp/virtio.h b/lib/include/openamp/virtio.h index 9febd1eaf..49061df52 100644 --- a/lib/include/openamp/virtio.h +++ b/lib/include/openamp/virtio.h @@ -227,6 +227,12 @@ __deprecated void virtio_describe(struct virtio_device *dev, const char *msg, */ struct virtio_dispatch { + /** Alloc buffer from transport layer heap */ + void *(*alloc_buf)(struct virtio_device *vdev, size_t size, size_t align); + + /** Free buffer to transport layer heap */ + void (*free_buf)(struct virtio_device *vdev, void *buf); + /** Create virtio queue instances. */ int (*create_virtqueues)(struct virtio_device *vdev, unsigned int flags, @@ -277,6 +283,54 @@ struct virtio_dispatch { void (*notify)(struct virtqueue *vq); }; +/** + * @brief Alloc a buffer from virtio transport layer. + * + * @param vdev Pointer to virtio device structure. + * @param size Alloc buffer size. + * @param align Buffer alignment. + * + * @return Pointer to the return buffer. NULL indicates no enough buffer + * or some errors happened. + */ +static inline void *virtio_alloc_buf(struct virtio_device *vdev, + size_t size, size_t align) +{ + return vdev->func->alloc_buf(vdev, size, align); +} + +/** + * @brief Alloc a buffer from virtio transport layer with zero value. + * + * @param vdev Pointer to virtio device structure. + * @param size Alloc buffer size. + * @param align Buffer alignment. + * + * @return Pointer to the return buffer. NULL indicates no enough buffer + * or some errors happened. + */ +static inline void *virtio_zalloc_buf(struct virtio_device *vdev, + size_t size, size_t align) +{ + void *ptr = virtio_alloc_buf(vdev, size, align); + + if (ptr) + memset(ptr, 0, size); + + return ptr; +} + +/** + * @brief Free a buffer alloced from transport layer. + * + * @param vdev Pointer to virtio device structure. + * @param buf Pointer to an allocated buffer from transport layer. + */ +static inline void virtio_free_buf(struct virtio_device *vdev, void *buf) +{ + vdev->func->free_buf(vdev, buf); +} + /** * @brief Create the virtio device virtqueue. * diff --git a/lib/remoteproc/remoteproc_virtio.c b/lib/remoteproc/remoteproc_virtio.c index 7ef1064d8..98722ed41 100644 --- a/lib/remoteproc/remoteproc_virtio.c +++ b/lib/remoteproc/remoteproc_virtio.c @@ -16,6 +16,29 @@ #include #include +static void *rproc_virtio_alloc_buf(struct virtio_device *vdev, + size_t size, size_t align) +{ + struct remoteproc_virtio *rpvdev; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + if (!rpvdev->alloc_buf) + return NULL; + + return rpvdev->alloc_buf(rpvdev, size, align); +} + +static void rproc_virtio_free_buf(struct virtio_device *vdev, void *buf) +{ + struct remoteproc_virtio *rpvdev; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + if (!rpvdev->free_buf) + return; + + rpvdev->free_buf(rpvdev, buf); +} + static void rproc_virtio_virtqueue_notify(struct virtqueue *vq) { struct remoteproc_virtio *rpvdev; @@ -183,6 +206,8 @@ static void rproc_virtio_reset_device(struct virtio_device *vdev) #endif static const struct virtio_dispatch remoteproc_virtio_dispatch_funcs = { + .alloc_buf = rproc_virtio_alloc_buf, + .free_buf = rproc_virtio_free_buf, .get_status = rproc_virtio_get_status, .get_features = rproc_virtio_get_features, .read_config = rproc_virtio_read_config, @@ -364,3 +389,19 @@ void rproc_virtio_wait_remote_ready(struct virtio_device *vdev) metal_cpu_yield(); } } + +int rproc_virtio_set_mm_callback(struct virtio_device *vdev, + rpvdev_alloc_buf alloc_buf, + rpvdev_free_buf free_buf) +{ + struct remoteproc_virtio *rpvdev; + + if (!vdev || !alloc_buf || !free_buf) + return -RPROC_EINVAL; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + rpvdev->alloc_buf = alloc_buf; + rpvdev->free_buf = free_buf; + + return 0; +}