From b3b6bd9f3b79b003f56f26dd25c6010644725008 Mon Sep 17 00:00:00 2001 From: Lucy Date: Fri, 18 Feb 2022 14:30:04 +1100 Subject: [PATCH 1/5] shared memory ring buffer mechanism Signed-off-by: Lucy --- CMakeLists.txt | 1 + libsharedringbuffer/CMakeLists.txt | 26 +++ .../shared_ringbuffer/shared_ringbuffer.h | 195 ++++++++++++++++++ libsharedringbuffer/src/shared_ringbuffer.c | 20 ++ libvirtqueue/README.md | 2 +- libvirtqueue/include/virtqueue.h | 4 + libvirtqueue/src/virtqueue.c | 16 ++ 7 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 libsharedringbuffer/CMakeLists.txt create mode 100644 libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h create mode 100644 libsharedringbuffer/src/shared_ringbuffer.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 775af9b..4ca2631 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,3 +17,4 @@ add_subdirectory(libvswitch) add_subdirectory(libfdtgen) add_subdirectory(libtx2bpmp) add_subdirectory(libplatsupportports) +add_subdirectory(libsharedringbuffer) \ No newline at end of file diff --git a/libsharedringbuffer/CMakeLists.txt b/libsharedringbuffer/CMakeLists.txt new file mode 100644 index 0000000..03b25bd --- /dev/null +++ b/libsharedringbuffer/CMakeLists.txt @@ -0,0 +1,26 @@ +# +# Copyright 2022, Trustworthy Systems, UNSW +# +# + +cmake_minimum_required(VERSION 3.7.2) + +project(libsharedringbuffer C) + +set(configure_string "") + +config_string( + LibsharedringbufferDescCount + LIB_SHARED_RINGBUFFER_DESC_COUNT + "Number of buffer descriptors in the ring buffer" + DEFAULT + 512 + UNQUOTE +) + +mark_as_advanced(LibsharedringbufferDescCount) +add_config_library(shared_ringbuffer "${configure_string}") + +add_library(shared_ringbuffer STATIC EXCLUDE_FROM_ALL src/shared_ringbuffer.c) +target_include_directories(shared_ringbuffer PUBLIC include) +target_link_libraries(shared_ringbuffer shared_ringbuffer_Config muslc utils sel4utils) diff --git a/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h b/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h new file mode 100644 index 0000000..b0b5160 --- /dev/null +++ b/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h @@ -0,0 +1,195 @@ +/* + * Copyright 2022, UNSW + * University of New South Wales (UNSW) + */ + +#pragma once + +#include +#include +#include +#include +#include + +/* Function pointer to be used to 'notify' components on either end of the shared memory */ +typedef void (*notify_fn)(void); + +/* Buffer descriptor */ +typedef struct buff_desc { + uintptr_t encoded_addr; /* encoded dma addresses */ + unsigned int len; /* associated memory lengths */ + void *cookie; /* index into client side metadata */ +} buff_desc_t; + +/* Circular buffer containing descriptors */ +typedef struct ring_buffer { + buff_desc_t buffers[CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT]; + uint32_t write_idx; + uint32_t read_idx; +} ring_buffer_t; + +/* A ring handle for enqueing/dequeuing into */ +typedef struct ring_handle { + ring_buffer_t *used_ring; + ring_buffer_t *avail_ring; + /* Function to be used to signal that work is queued in the used_ring */ + notify_fn notify; +} ring_handle_t; + + +/** + * Initialise the shared ring buffer + * + * @param ring ring handle to use + * @param avail pointer to available ring in shared memory + * @param used pointer to 'used' ring in shared memory + * @param notify function pointer used to notify the other user + * @param buffer_init 1 indicates the read and write indices in shared memory need to be initialised. + * 0 inidicates they do not. Only one side of the shared memory regions needs to do this. + */ +void ring_init(ring_handle_t *ring, ring_buffer_t *avail, ring_buffer_t *used, notify_fn notify, int buffer_init); + +/** + * Check if the ring buffer is empty + * + * @param ring ring buffer to check + * + * @return true indicates the buffer is empty, false otherwise. + */ +static inline int ring_empty(ring_buffer_t *ring) +{ + return !((ring->write_idx - ring->read_idx) % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT); +} + +/** + * Check if the ring buffer is full + * + * @param ring ring buffer to check + * + * @return true indicates the buffer is full, false otherwise. + */ +static inline int ring_full(ring_buffer_t *ring) +{ + return !((ring->write_idx - ring->read_idx + 1) % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT); +} + +static inline void notify(ring_handle_t *ring) +{ + return ring->notify(); +} + +/** + * Enqueue an element to a ring buffer + * + * @param ring Ring buffer to enqueue into + * @param buffer address into shared memory where data is stored. + * @param len length of data inside the buffer above + * @param cookie optional pointer to data required on dequeueing. + * + * @return -1 when ring is empty, 0 on success + */ +static inline int enqueue(ring_buffer_t *ring, uintptr_t buffer, unsigned int len, void *cookie) +{ + if (ring_full(ring)) { + ZF_LOGE("Ring full"); + return -1; + } + + ring->buffers[ring->write_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT].encoded_addr = buffer; + ring->buffers[ring->write_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT].len = len; + ring->buffers[ring->write_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT].cookie = cookie; + ring->write_idx++; + + THREAD_MEMORY_RELEASE(); + + return 0; +} + +/** + * Dequeue an element to a ring buffer + * + * @param ring Ring buffer to Dequeue from + * @param buffer pointer to the address of where to store buffer address. + * @param len pointer to variable to store length of data dequeueing + * @param cookie pointer optional pointer to data required on dequeueing. + * + * @return -1 when ring is empty, 0 on success + */ +static inline int dequeue(ring_buffer_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) +{ + if (ring_empty(ring)) { + ZF_LOGF("Ring is empty"); + return -1; + } + + *addr = ring->buffers[ring->read_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT].encoded_addr; + *len = ring->buffers[ring->read_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT].len; + *cookie = ring->buffers[ring->read_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT].cookie; + + THREAD_MEMORY_RELEASE(); + ring->read_idx++; + + return 0; +} + +/** + * Enqueue an element into an available ring buffer + * This indicates the buffer address parameter is currently available for use. + * + * @param ring Ring handle to enqueue into + * @param buffer address into shared memory where data is stored. + * @param len length of data inside the buffer above + * @param cookie optional pointer to data required on dequeueing. + * + * @return -1 when ring is empty, 0 on success + */ +static inline int enqueue_avail(ring_handle_t *ring, uintptr_t addr, unsigned int len, void *cookie) +{ + return enqueue(ring->avail_ring, addr, len, cookie); +} + +/** + * Enqueue an element into a used ring buffer + * This indicates the buffer address parameter is currently in use. + * + * @param ring Ring handle to enqueue into + * @param buffer address into shared memory where data is stored. + * @param len length of data inside the buffer above + * @param cookie optional pointer to data required on dequeueing. + * + * @return -1 when ring is empty, 0 on success + */ +static inline int enqueue_used(ring_handle_t *ring, uintptr_t addr, unsigned int len, void *cookie) +{ + return enqueue(ring->used_ring, addr, len, cookie); +} + +/** + * Dequeue an element from an available ring buffer + * + * @param ring Ring handle to dequeue from + * @param buffer pointer to the address of where to store buffer address. + * @param len pointer to variable to store length of data dequeueing + * @param cookie pointer optional pointer to data required on dequeueing. + * + * @return -1 when ring is empty, 0 on success + */ +static inline int dequeue_avail(ring_handle_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) +{ + return dequeue(ring->avail_ring, addr, len, cookie); +} + +/** + * Dequeue an element from a used ring buffer + * + * @param ring Ring handle to dequeue from + * @param buffer pointer to the address of where to store buffer address. + * @param len pointer to variable to store length of data dequeueing + * @param cookie pointer optional pointer to data required on dequeueing. + * + * @return -1 when ring is empty, 0 on success + */ +static inline int dequeue_used(ring_handle_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) +{ + return dequeue(ring->used_ring, addr, len, cookie); +} diff --git a/libsharedringbuffer/src/shared_ringbuffer.c b/libsharedringbuffer/src/shared_ringbuffer.c new file mode 100644 index 0000000..660be42 --- /dev/null +++ b/libsharedringbuffer/src/shared_ringbuffer.c @@ -0,0 +1,20 @@ +/* + * Copyright 2022, UNSW + * University of New South Wales (UNSW) + */ + +#include + +void ring_init(ring_handle_t *ring, ring_buffer_t *avail, ring_buffer_t *used, notify_fn notify, int buffer_init) +{ + ring->used_ring = used; + ring->avail_ring = avail; + ring->notify = notify; + + if (buffer_init) { + ring->used_ring->write_idx = 0; + ring->used_ring->read_idx = 0; + ring->avail_ring->write_idx = 0; + ring->avail_ring->read_idx = 0; + } +} \ No newline at end of file diff --git a/libvirtqueue/README.md b/libvirtqueue/README.md index 5c60b4a..f5016c2 100644 --- a/libvirtqueue/README.md +++ b/libvirtqueue/README.md @@ -10,7 +10,7 @@ libvirtqueue **_This implementation is currently a work in progress_** This directory contains a library implementation of a virtqueue inspired from -the virtio specification. This is intended to be used as a communication +the specification. This is intended to be used as a communication mechanism between system components for bulk data transfer. The goal of this implementation is to provide a generic interface for manipulating and managing a 'virtqueue' connection. This library doesn't contain any code that diff --git a/libvirtqueue/include/virtqueue.h b/libvirtqueue/include/virtqueue.h index e561fc8..43139ab 100644 --- a/libvirtqueue/include/virtqueue.h +++ b/libvirtqueue/include/virtqueue.h @@ -189,3 +189,7 @@ int virtqueue_gather_available(virtqueue_device_t *vq, virtqueue_ring_object_t * */ int virtqueue_gather_used(virtqueue_driver_t *vq, virtqueue_ring_object_t *robj, void **buf, unsigned *len, vq_flags_t *flag); + +int virtqueue_get_num_used(); +void add_rx_used_count(); +void decrement_rx_used_count(); \ No newline at end of file diff --git a/libvirtqueue/src/virtqueue.c b/libvirtqueue/src/virtqueue.c index 3276ebe..2fa25cf 100644 --- a/libvirtqueue/src/virtqueue.c +++ b/libvirtqueue/src/virtqueue.c @@ -7,6 +7,8 @@ #include #include +int num_used_buffs = 0; + void virtqueue_init_driver(virtqueue_driver_t *vq, unsigned queue_len, vq_vring_avail_t *avail_ring, vq_vring_used_t *used_ring, vq_vring_desc_t *desc, void (*notify)(void), void *cookie) @@ -129,6 +131,7 @@ int virtqueue_add_available_buf(virtqueue_driver_t *vq, virtqueue_ring_object_t vq->avail_ring->ring[vq->avail_ring->idx] = idx; vq->avail_ring->idx = (vq->avail_ring->idx + 1) & (vq->queue_len - 1); } + return 1; } @@ -153,6 +156,7 @@ int virtqueue_add_used_buf(virtqueue_device_t *vq, virtqueue_ring_object_t *robj vq->used_ring->ring[cur].id = robj->first; vq->used_ring->ring[cur].len = len; vq->used_ring->idx = (cur + 1) & (vq->queue_len - 1); + return 1; } @@ -215,3 +219,15 @@ int virtqueue_gather_used(virtqueue_driver_t *vq, virtqueue_ring_object_t *robj, robj->cur = vq_pop_desc(vq, robj->cur, buf, len, flag); return 1; } + +int virtqueue_get_num_used() { + return num_used_buffs; +} + +void add_rx_used_count() { + num_used_buffs++; +} + +void decrement_rx_used_count() { + num_used_buffs--; +} \ No newline at end of file From 0403877e8bbcb8097122277dfb6af24e718f9a47 Mon Sep 17 00:00:00 2001 From: Lucy Date: Mon, 7 Mar 2022 09:08:43 +1100 Subject: [PATCH 2/5] README with set up instructions and use case Signed-off-by: Lucy --- libsharedringbuffer/README.md | 66 +++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 libsharedringbuffer/README.md diff --git a/libsharedringbuffer/README.md b/libsharedringbuffer/README.md new file mode 100644 index 0000000..2b30dd9 --- /dev/null +++ b/libsharedringbuffer/README.md @@ -0,0 +1,66 @@ + + +libsharedringbuffer +------------------- + +This directory contains a library implementation of shared ring +buffers for the transportation of data. This is intended to be used as a +communication mechanism between system components for bulk data transfer, +and was originally created as a data plane between an ethernet driver and +network stack for the sDDF. This library doesn't contain any code that +interfaces with seL4. It is expected that the user will provide shared +memory regions and notification/signalling handlers to this library. + +To use this library in a project you can link `shared_ringbuffer` in your +target applications CMake configuration. + +This libary is intented to be used by both a producer and consumer. For +example, an ethernet driver produces data for a network stack to consume. +2 seperate shared memory regions are required for each ring handle; one +to store available buffers and one to store used buffers. Each ring buffer +contains a separate read index and write index. The reader only ever +increments the read index, and the writer the write index. As read and +writes of a small integer are atomic, we can keep memory consistent +without locks. +The size of the ring buffers can be set with the cmake config option, +`LIB_SHARED_RINGBUFFER_DESC_COUNT` but defaults to 512. The user must +ensure that the shared memory regions handed to the library are of +appropriate size to match this. + +Use case +--------- + +This library is intended to be used with a separate shared memory region, +usually allocated for DMA for a driver. The ring buffers can then contain +pointers into this shared memory, indicating which buffers are in use or +available to be used by either component. +Typically, 2 shared ring buffers are required, with seperate structures +required on the recieve path and transmit path. Thus there are 4 regions +of shared memory required: 1 storing pointers to available RX buffers, +1 storing pointers to used RX buffers, 1 storing pointers to TX +buffers, and another storing pointers to available TX buffers. + +On initialisation, both the producer and consumer should allocate their +own ring handles (`struct ring_handle`). These data structures simply +store pointers to the actual shared memory regions and are used to +interface with this library. The ring handle should then be passed into +`ring_init` along with 2 shared memory regions, an optional function +pointer to signal the other component, and either 1 or 0 to indicate +whether the read/write indices need to be initialised (note that only one +side of the shared memory regions needs to do this). + +After initialisation, a typical use case would look like: +The driver wants to add some buffer that will be read by another component +(for example, a network stack processing incoming packets). + + 1. The driver dequeues a pointer to an available buffer from the + available ring. + 2. Once data is inserted into the buffer (eg. via DMA), the driver + then enqueues the pointer to it into the used ring. + 3. The driver can then notify the reciever. + 4. Similarly, the reciever dequeues the pointer from the used ring, + processes the data, and once finished, can enqueue it back into + the available ring to be used once more by the driver. + From 04d283651bef53a95783097513aa61a0c0b3e5d9 Mon Sep 17 00:00:00 2001 From: Lucy Date: Mon, 7 Mar 2022 09:20:26 +1100 Subject: [PATCH 3/5] Driver dequeue Signed-off-by: Lucy --- .../shared_ringbuffer/shared_ringbuffer.h | 102 ++++++++++++------ libsharedringbuffer/src/shared_ringbuffer.c | 3 +- 2 files changed, 70 insertions(+), 35 deletions(-) diff --git a/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h b/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h index b0b5160..a3892ef 100644 --- a/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h +++ b/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h @@ -1,6 +1,5 @@ /* - * Copyright 2022, UNSW - * University of New South Wales (UNSW) + * Copyright 2022, UNSW ??? */ #pragma once @@ -38,21 +37,21 @@ typedef struct ring_handle { /** - * Initialise the shared ring buffer + * Initialise the shared ring buffer. * - * @param ring ring handle to use - * @param avail pointer to available ring in shared memory - * @param used pointer to 'used' ring in shared memory - * @param notify function pointer used to notify the other user + * @param ring ring handle to use. + * @param avail pointer to available ring in shared memory. + * @param used pointer to 'used' ring in shared memory. + * @param notify function pointer used to notify the other user. * @param buffer_init 1 indicates the read and write indices in shared memory need to be initialised. * 0 inidicates they do not. Only one side of the shared memory regions needs to do this. */ void ring_init(ring_handle_t *ring, ring_buffer_t *avail, ring_buffer_t *used, notify_fn notify, int buffer_init); /** - * Check if the ring buffer is empty + * Check if the ring buffer is empty. * - * @param ring ring buffer to check + * @param ring ring buffer to check. * * @return true indicates the buffer is empty, false otherwise. */ @@ -64,7 +63,7 @@ static inline int ring_empty(ring_buffer_t *ring) /** * Check if the ring buffer is full * - * @param ring ring buffer to check + * @param ring ring buffer to check. * * @return true indicates the buffer is full, false otherwise. */ @@ -73,6 +72,12 @@ static inline int ring_full(ring_buffer_t *ring) return !((ring->write_idx - ring->read_idx + 1) % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT); } +/** + * Notify the other user of changes to the shared ring buffers. + * + * @param ring the ring handle used. + * + */ static inline void notify(ring_handle_t *ring) { return ring->notify(); @@ -81,12 +86,12 @@ static inline void notify(ring_handle_t *ring) /** * Enqueue an element to a ring buffer * - * @param ring Ring buffer to enqueue into + * @param ring Ring buffer to enqueue into. * @param buffer address into shared memory where data is stored. - * @param len length of data inside the buffer above + * @param len length of data inside the buffer above. * @param cookie optional pointer to data required on dequeueing. * - * @return -1 when ring is empty, 0 on success + * @return -1 when ring is empty, 0 on success. */ static inline int enqueue(ring_buffer_t *ring, uintptr_t buffer, unsigned int len, void *cookie) { @@ -106,14 +111,14 @@ static inline int enqueue(ring_buffer_t *ring, uintptr_t buffer, unsigned int le } /** - * Dequeue an element to a ring buffer + * Dequeue an element to a ring buffer. * - * @param ring Ring buffer to Dequeue from + * @param ring Ring buffer to Dequeue from. * @param buffer pointer to the address of where to store buffer address. - * @param len pointer to variable to store length of data dequeueing + * @param len pointer to variable to store length of data dequeueing. * @param cookie pointer optional pointer to data required on dequeueing. * - * @return -1 when ring is empty, 0 on success + * @return -1 when ring is empty, 0 on success. */ static inline int dequeue(ring_buffer_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) { @@ -133,15 +138,15 @@ static inline int dequeue(ring_buffer_t *ring, uintptr_t *addr, unsigned int *le } /** - * Enqueue an element into an available ring buffer + * Enqueue an element into an available ring buffer. * This indicates the buffer address parameter is currently available for use. * - * @param ring Ring handle to enqueue into + * @param ring Ring handle to enqueue into. * @param buffer address into shared memory where data is stored. - * @param len length of data inside the buffer above + * @param len length of data inside the buffer above. * @param cookie optional pointer to data required on dequeueing. * - * @return -1 when ring is empty, 0 on success + * @return -1 when ring is empty, 0 on success. */ static inline int enqueue_avail(ring_handle_t *ring, uintptr_t addr, unsigned int len, void *cookie) { @@ -149,15 +154,15 @@ static inline int enqueue_avail(ring_handle_t *ring, uintptr_t addr, unsigned in } /** - * Enqueue an element into a used ring buffer + * Enqueue an element into a used ring buffer. * This indicates the buffer address parameter is currently in use. * - * @param ring Ring handle to enqueue into + * @param ring Ring handle to enqueue into. * @param buffer address into shared memory where data is stored. - * @param len length of data inside the buffer above + * @param len length of data inside the buffer above. * @param cookie optional pointer to data required on dequeueing. * - * @return -1 when ring is empty, 0 on success + * @return -1 when ring is empty, 0 on success. */ static inline int enqueue_used(ring_handle_t *ring, uintptr_t addr, unsigned int len, void *cookie) { @@ -165,14 +170,14 @@ static inline int enqueue_used(ring_handle_t *ring, uintptr_t addr, unsigned int } /** - * Dequeue an element from an available ring buffer + * Dequeue an element from an available ring buffer. * - * @param ring Ring handle to dequeue from + * @param ring Ring handle to dequeue from. * @param buffer pointer to the address of where to store buffer address. - * @param len pointer to variable to store length of data dequeueing + * @param len pointer to variable to store length of data dequeueing. * @param cookie pointer optional pointer to data required on dequeueing. * - * @return -1 when ring is empty, 0 on success + * @return -1 when ring is empty, 0 on success. */ static inline int dequeue_avail(ring_handle_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) { @@ -180,16 +185,47 @@ static inline int dequeue_avail(ring_handle_t *ring, uintptr_t *addr, unsigned i } /** - * Dequeue an element from a used ring buffer + * Dequeue an element from a used ring buffer. * - * @param ring Ring handle to dequeue from + * @param ring Ring handle to dequeue from. * @param buffer pointer to the address of where to store buffer address. - * @param len pointer to variable to store length of data dequeueing + * @param len pointer to variable to store length of data dequeueing. * @param cookie pointer optional pointer to data required on dequeueing. * - * @return -1 when ring is empty, 0 on success + * @return -1 when ring is empty, 0 on success. */ static inline int dequeue_used(ring_handle_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) { return dequeue(ring->used_ring, addr, len, cookie); } + +/** + * Dequeue an element from a ring buffer. + * This function is intended for use by the driver, to collect a pointer + * into this structure to be passed around as a cookie. + * + * @param ring Ring buffer to dequeue from. + * @param addr pointer to the address of where to store buffer address. + * @param len pointer to variable to store length of data dequeueing. + * @param cookie pointer to store a pointer to this particular entry. + * + * @return -1 when ring is empty, 0 on success. + */ + +static int driver_dequeue(ring_buffer_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) +{ + if (!((ring->write_idx - ring->read_idx) % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT)) { + ZF_LOGW("write idx = %d, read idx = %d", ring->write_idx, ring->read_idx); + ZF_LOGW("Ring is empty"); + return -1; + } + + *addr = ring->buffers[ring->read_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT].encoded_addr; + *len = ring->buffers[ring->read_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT].len; + *cookie = &ring->buffers[ring->read_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT]; + + THREAD_MEMORY_RELEASE(); + ring->read_idx++; + + return 0; +} \ No newline at end of file diff --git a/libsharedringbuffer/src/shared_ringbuffer.c b/libsharedringbuffer/src/shared_ringbuffer.c index 660be42..223ef5e 100644 --- a/libsharedringbuffer/src/shared_ringbuffer.c +++ b/libsharedringbuffer/src/shared_ringbuffer.c @@ -1,6 +1,5 @@ /* - * Copyright 2022, UNSW - * University of New South Wales (UNSW) + * Copyright 2022, UNSW ?? */ #include From 07af3a0e2a2a0c4c01e2306d8d44249c186747df Mon Sep 17 00:00:00 2001 From: Lucy Date: Mon, 7 Mar 2022 10:19:32 +1100 Subject: [PATCH 4/5] Trivial: Style Signed-off-by: Lucy --- libsharedringbuffer/README.md | 6 +++--- .../include/shared_ringbuffer/shared_ringbuffer.h | 2 +- libvirtqueue/README.md | 2 +- libvirtqueue/include/virtqueue.h | 6 +----- libvirtqueue/src/virtqueue.c | 14 -------------- 5 files changed, 6 insertions(+), 24 deletions(-) diff --git a/libsharedringbuffer/README.md b/libsharedringbuffer/README.md index 2b30dd9..ac1ab27 100644 --- a/libsharedringbuffer/README.md +++ b/libsharedringbuffer/README.md @@ -16,9 +16,9 @@ memory regions and notification/signalling handlers to this library. To use this library in a project you can link `shared_ringbuffer` in your target applications CMake configuration. -This libary is intented to be used by both a producer and consumer. For +This libary is intended to be used by both a producer and consumer. For example, an ethernet driver produces data for a network stack to consume. -2 seperate shared memory regions are required for each ring handle; one +2 separate shared memory regions are required for each ring handle; one to store available buffers and one to store used buffers. Each ring buffer contains a separate read index and write index. The reader only ever increments the read index, and the writer the write index. As read and @@ -36,7 +36,7 @@ This library is intended to be used with a separate shared memory region, usually allocated for DMA for a driver. The ring buffers can then contain pointers into this shared memory, indicating which buffers are in use or available to be used by either component. -Typically, 2 shared ring buffers are required, with seperate structures +Typically, 2 shared ring buffers are required, with separate structures required on the recieve path and transmit path. Thus there are 4 regions of shared memory required: 1 storing pointers to available RX buffers, 1 storing pointers to used RX buffers, 1 storing pointers to TX diff --git a/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h b/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h index a3892ef..a1f3eb6 100644 --- a/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h +++ b/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h @@ -22,9 +22,9 @@ typedef struct buff_desc { /* Circular buffer containing descriptors */ typedef struct ring_buffer { - buff_desc_t buffers[CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT]; uint32_t write_idx; uint32_t read_idx; + buff_desc_t buffers[CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT]; } ring_buffer_t; /* A ring handle for enqueing/dequeuing into */ diff --git a/libvirtqueue/README.md b/libvirtqueue/README.md index f5016c2..5c60b4a 100644 --- a/libvirtqueue/README.md +++ b/libvirtqueue/README.md @@ -10,7 +10,7 @@ libvirtqueue **_This implementation is currently a work in progress_** This directory contains a library implementation of a virtqueue inspired from -the specification. This is intended to be used as a communication +the virtio specification. This is intended to be used as a communication mechanism between system components for bulk data transfer. The goal of this implementation is to provide a generic interface for manipulating and managing a 'virtqueue' connection. This library doesn't contain any code that diff --git a/libvirtqueue/include/virtqueue.h b/libvirtqueue/include/virtqueue.h index 43139ab..f949482 100644 --- a/libvirtqueue/include/virtqueue.h +++ b/libvirtqueue/include/virtqueue.h @@ -188,8 +188,4 @@ int virtqueue_gather_available(virtqueue_device_t *vq, virtqueue_ring_object_t * * @return 1 on success, 0 on failure (no more buffer available) */ int virtqueue_gather_used(virtqueue_driver_t *vq, virtqueue_ring_object_t *robj, - void **buf, unsigned *len, vq_flags_t *flag); - -int virtqueue_get_num_used(); -void add_rx_used_count(); -void decrement_rx_used_count(); \ No newline at end of file + void **buf, unsigned *len, vq_flags_t *flag); \ No newline at end of file diff --git a/libvirtqueue/src/virtqueue.c b/libvirtqueue/src/virtqueue.c index 2fa25cf..baa0b73 100644 --- a/libvirtqueue/src/virtqueue.c +++ b/libvirtqueue/src/virtqueue.c @@ -7,8 +7,6 @@ #include #include -int num_used_buffs = 0; - void virtqueue_init_driver(virtqueue_driver_t *vq, unsigned queue_len, vq_vring_avail_t *avail_ring, vq_vring_used_t *used_ring, vq_vring_desc_t *desc, void (*notify)(void), void *cookie) @@ -218,16 +216,4 @@ int virtqueue_gather_used(virtqueue_driver_t *vq, virtqueue_ring_object_t *robj, } robj->cur = vq_pop_desc(vq, robj->cur, buf, len, flag); return 1; -} - -int virtqueue_get_num_used() { - return num_used_buffs; -} - -void add_rx_used_count() { - num_used_buffs++; -} - -void decrement_rx_used_count() { - num_used_buffs--; } \ No newline at end of file From 09528e856cc008d03168838188801edf1b82fbf7 Mon Sep 17 00:00:00 2001 From: Lucy Date: Tue, 8 Mar 2022 11:34:36 +1100 Subject: [PATCH 5/5] Trivial: Copyright headers Signed-off-by: Lucy --- CMakeLists.txt | 2 +- libsharedringbuffer/CMakeLists.txt | 4 +- libsharedringbuffer/README.md | 46 +++++++++--------- .../shared_ringbuffer/shared_ringbuffer.h | 48 +++++++++---------- libsharedringbuffer/src/shared_ringbuffer.c | 5 +- libvirtqueue/include/virtqueue.h | 2 +- libvirtqueue/src/virtqueue.c | 4 +- 7 files changed, 55 insertions(+), 56 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ca2631..2a63685 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,4 +17,4 @@ add_subdirectory(libvswitch) add_subdirectory(libfdtgen) add_subdirectory(libtx2bpmp) add_subdirectory(libplatsupportports) -add_subdirectory(libsharedringbuffer) \ No newline at end of file +add_subdirectory(libsharedringbuffer) diff --git a/libsharedringbuffer/CMakeLists.txt b/libsharedringbuffer/CMakeLists.txt index 03b25bd..ac66176 100644 --- a/libsharedringbuffer/CMakeLists.txt +++ b/libsharedringbuffer/CMakeLists.txt @@ -1,6 +1,6 @@ # -# Copyright 2022, Trustworthy Systems, UNSW -# +# Copyright 2022, UNSW +# SPDX-License-Identifier: BSD-2-Clause # cmake_minimum_required(VERSION 3.7.2) diff --git a/libsharedringbuffer/README.md b/libsharedringbuffer/README.md index ac1ab27..f308488 100644 --- a/libsharedringbuffer/README.md +++ b/libsharedringbuffer/README.md @@ -1,33 +1,34 @@ libsharedringbuffer ------------------- -This directory contains a library implementation of shared ring -buffers for the transportation of data. This is intended to be used as a +This directory contains a library implementation of shared ring +buffers for the transportation of data. This is intended to be used as a communication mechanism between system components for bulk data transfer, and was originally created as a data plane between an ethernet driver and network stack for the sDDF. This library doesn't contain any code that -interfaces with seL4. It is expected that the user will provide shared +interfaces with seL4. It is expected that the user will provide shared memory regions and notification/signalling handlers to this library. To use this library in a project you can link `shared_ringbuffer` in your target applications CMake configuration. -This libary is intended to be used by both a producer and consumer. For +This libary is intended to be used by both a producer and a consumer. For example, an ethernet driver produces data for a network stack to consume. 2 separate shared memory regions are required for each ring handle; one to store available buffers and one to store used buffers. Each ring buffer -contains a separate read index and write index. The reader only ever -increments the read index, and the writer the write index. As read and +contains a separate read index and write index. The reader only ever +increments the read index, and the writer the write index. As read and writes of a small integer are atomic, we can keep memory consistent without locks. The size of the ring buffers can be set with the cmake config option, `LIB_SHARED_RINGBUFFER_DESC_COUNT` but defaults to 512. The user must -ensure that the shared memory regions handed to the library are of -appropriate size to match this. +ensure that the shared memory regions handed to the library are of +appropriate size to match this. Use case --------- @@ -35,32 +36,31 @@ Use case This library is intended to be used with a separate shared memory region, usually allocated for DMA for a driver. The ring buffers can then contain pointers into this shared memory, indicating which buffers are in use or -available to be used by either component. +available to be used by either component. Typically, 2 shared ring buffers are required, with separate structures required on the recieve path and transmit path. Thus there are 4 regions -of shared memory required: 1 storing pointers to available RX buffers, +of shared memory required: 1 storing pointers to available RX buffers, 1 storing pointers to used RX buffers, 1 storing pointers to TX buffers, and another storing pointers to available TX buffers. -On initialisation, both the producer and consumer should allocate their +On initialisation, both the producer and consumer should allocate their own ring handles (`struct ring_handle`). These data structures simply -store pointers to the actual shared memory regions and are used to +store pointers to the actual shared memory regions and are used to interface with this library. The ring handle should then be passed into -`ring_init` along with 2 shared memory regions, an optional function -pointer to signal the other component, and either 1 or 0 to indicate +`ring_init` along with 2 shared memory regions, an optional function +pointer to signal the other component, and either 1 or 0 to indicate whether the read/write indices need to be initialised (note that only one -side of the shared memory regions needs to do this). +side of the shared memory regions needs to do this). -After initialisation, a typical use case would look like: +After initialisation, a typical use case would look like: The driver wants to add some buffer that will be read by another component -(for example, a network stack processing incoming packets). +(for example, a network stack processing incoming packets). - 1. The driver dequeues a pointer to an available buffer from the + 1. The driver dequeues a pointer to an available buffer from the available ring. - 2. Once data is inserted into the buffer (eg. via DMA), the driver + 2. Once data is inserted into the buffer (eg. via DMA), the driver then enqueues the pointer to it into the used ring. - 3. The driver can then notify the reciever. - 4. Similarly, the reciever dequeues the pointer from the used ring, + 3. The driver can then notify the reciever. + 4. Similarly, the reciever dequeues the pointer from the used ring, processes the data, and once finished, can enqueue it back into the available ring to be used once more by the driver. - diff --git a/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h b/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h index a1f3eb6..5835e2c 100644 --- a/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h +++ b/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h @@ -1,8 +1,10 @@ /* - * Copyright 2022, UNSW ??? + * Copyright 2022, UNSW + * + * SPDX-License-Identifier: BSD-2-Clause */ -#pragma once +#pragma once #include #include @@ -35,7 +37,6 @@ typedef struct ring_handle { notify_fn notify; } ring_handle_t; - /** * Initialise the shared ring buffer. * @@ -44,7 +45,7 @@ typedef struct ring_handle { * @param used pointer to 'used' ring in shared memory. * @param notify function pointer used to notify the other user. * @param buffer_init 1 indicates the read and write indices in shared memory need to be initialised. - * 0 inidicates they do not. Only one side of the shared memory regions needs to do this. + * 0 inidicates they do not. Only one side of the shared memory regions needs to do this. */ void ring_init(ring_handle_t *ring, ring_buffer_t *avail, ring_buffer_t *used, notify_fn notify, int buffer_init); @@ -55,7 +56,7 @@ void ring_init(ring_handle_t *ring, ring_buffer_t *avail, ring_buffer_t *used, n * * @return true indicates the buffer is empty, false otherwise. */ -static inline int ring_empty(ring_buffer_t *ring) +static inline int ring_empty(ring_buffer_t *ring) { return !((ring->write_idx - ring->read_idx) % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT); } @@ -74,11 +75,11 @@ static inline int ring_full(ring_buffer_t *ring) /** * Notify the other user of changes to the shared ring buffers. - * + * * @param ring the ring handle used. * */ -static inline void notify(ring_handle_t *ring) +static inline void notify(ring_handle_t *ring) { return ring->notify(); } @@ -89,15 +90,15 @@ static inline void notify(ring_handle_t *ring) * @param ring Ring buffer to enqueue into. * @param buffer address into shared memory where data is stored. * @param len length of data inside the buffer above. - * @param cookie optional pointer to data required on dequeueing. + * @param cookie optional pointer to data required on dequeueing. * * @return -1 when ring is empty, 0 on success. */ -static inline int enqueue(ring_buffer_t *ring, uintptr_t buffer, unsigned int len, void *cookie) +static inline int enqueue(ring_buffer_t *ring, uintptr_t buffer, unsigned int len, void *cookie) { if (ring_full(ring)) { ZF_LOGE("Ring full"); - return -1; + return -1; } ring->buffers[ring->write_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT].encoded_addr = buffer; @@ -116,11 +117,11 @@ static inline int enqueue(ring_buffer_t *ring, uintptr_t buffer, unsigned int le * @param ring Ring buffer to Dequeue from. * @param buffer pointer to the address of where to store buffer address. * @param len pointer to variable to store length of data dequeueing. - * @param cookie pointer optional pointer to data required on dequeueing. + * @param cookie pointer optional pointer to data required on dequeueing. * * @return -1 when ring is empty, 0 on success. */ -static inline int dequeue(ring_buffer_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) +static inline int dequeue(ring_buffer_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) { if (ring_empty(ring)) { ZF_LOGF("Ring is empty"); @@ -139,16 +140,16 @@ static inline int dequeue(ring_buffer_t *ring, uintptr_t *addr, unsigned int *le /** * Enqueue an element into an available ring buffer. - * This indicates the buffer address parameter is currently available for use. + * This indicates the buffer address parameter is currently available for use. * * @param ring Ring handle to enqueue into. * @param buffer address into shared memory where data is stored. * @param len length of data inside the buffer above. - * @param cookie optional pointer to data required on dequeueing. + * @param cookie optional pointer to data required on dequeueing. * * @return -1 when ring is empty, 0 on success. */ -static inline int enqueue_avail(ring_handle_t *ring, uintptr_t addr, unsigned int len, void *cookie) +static inline int enqueue_avail(ring_handle_t *ring, uintptr_t addr, unsigned int len, void *cookie) { return enqueue(ring->avail_ring, addr, len, cookie); } @@ -160,11 +161,11 @@ static inline int enqueue_avail(ring_handle_t *ring, uintptr_t addr, unsigned in * @param ring Ring handle to enqueue into. * @param buffer address into shared memory where data is stored. * @param len length of data inside the buffer above. - * @param cookie optional pointer to data required on dequeueing. + * @param cookie optional pointer to data required on dequeueing. * * @return -1 when ring is empty, 0 on success. */ -static inline int enqueue_used(ring_handle_t *ring, uintptr_t addr, unsigned int len, void *cookie) +static inline int enqueue_used(ring_handle_t *ring, uintptr_t addr, unsigned int len, void *cookie) { return enqueue(ring->used_ring, addr, len, cookie); } @@ -175,11 +176,11 @@ static inline int enqueue_used(ring_handle_t *ring, uintptr_t addr, unsigned int * @param ring Ring handle to dequeue from. * @param buffer pointer to the address of where to store buffer address. * @param len pointer to variable to store length of data dequeueing. - * @param cookie pointer optional pointer to data required on dequeueing. + * @param cookie pointer optional pointer to data required on dequeueing. * * @return -1 when ring is empty, 0 on success. */ -static inline int dequeue_avail(ring_handle_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) +static inline int dequeue_avail(ring_handle_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) { return dequeue(ring->avail_ring, addr, len, cookie); } @@ -190,11 +191,11 @@ static inline int dequeue_avail(ring_handle_t *ring, uintptr_t *addr, unsigned i * @param ring Ring handle to dequeue from. * @param buffer pointer to the address of where to store buffer address. * @param len pointer to variable to store length of data dequeueing. - * @param cookie pointer optional pointer to data required on dequeueing. + * @param cookie pointer optional pointer to data required on dequeueing. * * @return -1 when ring is empty, 0 on success. */ -static inline int dequeue_used(ring_handle_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) +static inline int dequeue_used(ring_handle_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) { return dequeue(ring->used_ring, addr, len, cookie); } @@ -202,7 +203,7 @@ static inline int dequeue_used(ring_handle_t *ring, uintptr_t *addr, unsigned in /** * Dequeue an element from a ring buffer. * This function is intended for use by the driver, to collect a pointer - * into this structure to be passed around as a cookie. + * into this structure to be passed around as a cookie. * * @param ring Ring buffer to dequeue from. * @param addr pointer to the address of where to store buffer address. @@ -211,7 +212,6 @@ static inline int dequeue_used(ring_handle_t *ring, uintptr_t *addr, unsigned in * * @return -1 when ring is empty, 0 on success. */ - static int driver_dequeue(ring_buffer_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) { if (!((ring->write_idx - ring->read_idx) % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT)) { @@ -228,4 +228,4 @@ static int driver_dequeue(ring_buffer_t *ring, uintptr_t *addr, unsigned int *le ring->read_idx++; return 0; -} \ No newline at end of file +} diff --git a/libsharedringbuffer/src/shared_ringbuffer.c b/libsharedringbuffer/src/shared_ringbuffer.c index 223ef5e..de3e367 100644 --- a/libsharedringbuffer/src/shared_ringbuffer.c +++ b/libsharedringbuffer/src/shared_ringbuffer.c @@ -1,5 +1,6 @@ /* - * Copyright 2022, UNSW ?? + * Copyright 2022, UNSW + * SPDX-License-Identifier: BSD-2-Clause */ #include @@ -16,4 +17,4 @@ void ring_init(ring_handle_t *ring, ring_buffer_t *avail, ring_buffer_t *used, n ring->avail_ring->write_idx = 0; ring->avail_ring->read_idx = 0; } -} \ No newline at end of file +} diff --git a/libvirtqueue/include/virtqueue.h b/libvirtqueue/include/virtqueue.h index f949482..e561fc8 100644 --- a/libvirtqueue/include/virtqueue.h +++ b/libvirtqueue/include/virtqueue.h @@ -188,4 +188,4 @@ int virtqueue_gather_available(virtqueue_device_t *vq, virtqueue_ring_object_t * * @return 1 on success, 0 on failure (no more buffer available) */ int virtqueue_gather_used(virtqueue_driver_t *vq, virtqueue_ring_object_t *robj, - void **buf, unsigned *len, vq_flags_t *flag); \ No newline at end of file + void **buf, unsigned *len, vq_flags_t *flag); diff --git a/libvirtqueue/src/virtqueue.c b/libvirtqueue/src/virtqueue.c index baa0b73..3276ebe 100644 --- a/libvirtqueue/src/virtqueue.c +++ b/libvirtqueue/src/virtqueue.c @@ -129,7 +129,6 @@ int virtqueue_add_available_buf(virtqueue_driver_t *vq, virtqueue_ring_object_t vq->avail_ring->ring[vq->avail_ring->idx] = idx; vq->avail_ring->idx = (vq->avail_ring->idx + 1) & (vq->queue_len - 1); } - return 1; } @@ -154,7 +153,6 @@ int virtqueue_add_used_buf(virtqueue_device_t *vq, virtqueue_ring_object_t *robj vq->used_ring->ring[cur].id = robj->first; vq->used_ring->ring[cur].len = len; vq->used_ring->idx = (cur + 1) & (vq->queue_len - 1); - return 1; } @@ -216,4 +214,4 @@ int virtqueue_gather_used(virtqueue_driver_t *vq, virtqueue_ring_object_t *robj, } robj->cur = vq_pop_desc(vq, robj->cur, buf, len, flag); return 1; -} \ No newline at end of file +}