From 6d3d2309cea9a3009638cb34b0940b390334a60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hubert=20Mi=C5=9B?= Date: Fri, 11 Nov 2022 19:44:22 +0100 Subject: [PATCH] ipc: icmsg multi endpoint with nocopy in send path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add nocopy feature to icmsg-me initiator and follower roles in their send path. Signed-off-by: Hubert Miś --- .../backends/ipc_icmsg_me_follower.c | 106 +++++++++++++++++- .../backends/ipc_icmsg_me_initiator.c | 104 ++++++++++++++++- 2 files changed, 207 insertions(+), 3 deletions(-) diff --git a/subsys/ipc/ipc_service/backends/ipc_icmsg_me_follower.c b/subsys/ipc/ipc_service/backends/ipc_icmsg_me_follower.c index a5932149ba5..e4716133bf4 100644 --- a/subsys/ipc/ipc_service/backends/ipc_icmsg_me_follower.c +++ b/subsys/ipc/ipc_service/backends/ipc_icmsg_me_follower.c @@ -107,6 +107,11 @@ static int cache_ept_rmt(struct backend_data_t *data, const char *name, return -ENOMEM; } +static void set_ept_id_in_send_buffer(uint8_t *send_buffer, ept_id_t ept_id) +{ + send_buffer[0] = ept_id; +} + static int bind_ept(const struct icmsg_config_t *conf, struct backend_data_t *data, const struct ipc_ept_cfg *ept, ept_id_t id) @@ -290,7 +295,7 @@ static int send(const struct device *instance, void *token, /* TODO: Optimization: How to avoid this copying? */ /* Scatter list supported by icmsg? */ - dev_data->send_buffer[0] = *id; + set_ept_id_in_send_buffer(dev_data->send_buffer, *id); memcpy(dev_data->send_buffer + sizeof(ept_id_t), msg, len); r = icmsg_send(conf, &dev_data->icmsg_data, dev_data->send_buffer, @@ -309,10 +314,109 @@ static int send(const struct device *instance, void *token, } } +static size_t get_buffer_length_to_pass(size_t allocated_buffer_length) +{ + if (allocated_buffer_length >= sizeof(ept_id_t)) { + return allocated_buffer_length - sizeof(ept_id_t); + } else { + return 0; + } +} + +static int get_tx_buffer(const struct device *instance, void *token, + void **data, uint32_t *len, k_timeout_t wait) +{ + const struct icmsg_config_t *conf = instance->config; + struct backend_data_t *dev_data = instance->data; + char *allocated_buffer; + int r; + size_t len_to_allocate = *len; + + if (!K_TIMEOUT_EQ(wait, K_NO_WAIT)) { + return -ENOTSUP; + } + + if (len_to_allocate) { + len_to_allocate += sizeof(ept_id_t); + } + + r = icmsg_get_tx_buffer(conf, &dev_data->icmsg_data, + (void **)&allocated_buffer, + &len_to_allocate); + if (r == -ENOMEM) { + *len = get_buffer_length_to_pass(len_to_allocate); + return -ENOMEM; + } + + if (r < 0) { + return r; + } + + *len = get_buffer_length_to_pass(len_to_allocate); + /* If requested max buffer length (*len == 0) allocated buffer might be + * shorter than sizeof(ept_id_t). In such circumstances drop the buffer + * and return error. + */ + + if (*len) { + *data = allocated_buffer + sizeof(ept_id_t); + return 0; + } + + r = icmsg_drop_tx_buffer(conf, &dev_data->icmsg_data, + allocated_buffer); + __ASSERT_NO_MSG(!r); + return -ENOBUFS; +} + +static int drop_tx_buffer(const struct device *instance, void *token, + const void *data) +{ + const struct icmsg_config_t *conf = instance->config; + struct backend_data_t *dev_data = instance->data; + const char *buffer_to_drop = data; + + buffer_to_drop -= sizeof(ept_id_t); + + return icmsg_drop_tx_buffer(conf, &dev_data->icmsg_data, buffer_to_drop); +} + +static int send_nocopy(const struct device *instance, void *token, + const void *data, size_t len) +{ + const struct icmsg_config_t *conf = instance->config; + struct backend_data_t *dev_data = instance->data; + ept_id_t *id = token; + char *buffer_to_send = (void *)data; + size_t len_to_send = len; + int r; + + if (*id == INVALID_EPT_ID) { + return -ENOTCONN; + } + + buffer_to_send -= sizeof(ept_id_t); + len_to_send += sizeof(ept_id_t); + + set_ept_id_in_send_buffer(buffer_to_send, *id); + + r = icmsg_send_nocopy(conf, &dev_data->icmsg_data, buffer_to_send, + len_to_send); + if (r > 0) { + return r - sizeof(ept_id_t); + } else { + return r; + } +} + const static struct ipc_service_backend backend_ops = { .open_instance = open, .register_endpoint = register_ept, .send = send, + + .get_tx_buffer = get_tx_buffer, + .drop_tx_buffer = drop_tx_buffer, + .send_nocopy = send_nocopy, }; static int backend_init(const struct device *instance) diff --git a/subsys/ipc/ipc_service/backends/ipc_icmsg_me_initiator.c b/subsys/ipc/ipc_service/backends/ipc_icmsg_me_initiator.c index 4dd0010f6ca..a783752521f 100644 --- a/subsys/ipc/ipc_service/backends/ipc_icmsg_me_initiator.c +++ b/subsys/ipc/ipc_service/backends/ipc_icmsg_me_initiator.c @@ -45,6 +45,11 @@ static void bound(void *priv) k_event_post(&dev_data->event, EVENT_BOUND); } +static void set_ept_id_in_send_buffer(uint8_t *send_buffer, ept_id_t ept_id) +{ + send_buffer[0] = ept_id; +} + static void received(const void *data, size_t len, void *priv) { const struct device *instance = priv; @@ -180,13 +185,13 @@ static int send(const struct device *instance, void *token, /* We could implement scatter list for icmsg_send, but it would require * scatter list also for SPSC buffer implementation. */ - dev_data->send_buffer[0] = *id; + set_ept_id_in_send_buffer(dev_data->send_buffer, *id); memcpy(dev_data->send_buffer + sizeof(ept_id_t), msg, len); r = icmsg_send(conf, &dev_data->icmsg_data, dev_data->send_buffer, len + sizeof(ept_id_t)); if (r > 0) { - sent_bytes = r - 1; + sent_bytes = r - sizeof(ept_id_t);; } k_mutex_unlock(&dev_data->send_mutex); @@ -198,10 +203,105 @@ static int send(const struct device *instance, void *token, } } +static size_t get_buffer_length_to_pass(size_t allocated_buffer_length) +{ + if (allocated_buffer_length >= sizeof(ept_id_t)) { + return allocated_buffer_length - sizeof(ept_id_t); + } else { + return 0; + } +} + +static int get_tx_buffer(const struct device *instance, void *token, + void **data, uint32_t *len, k_timeout_t wait) +{ + const struct icmsg_config_t *conf = instance->config; + struct backend_data_t *dev_data = instance->data; + char *allocated_buffer; + int r; + size_t len_to_allocate = *len; + + if (!K_TIMEOUT_EQ(wait, K_NO_WAIT)) { + return -ENOTSUP; + } + + if (len_to_allocate) { + len_to_allocate += sizeof(ept_id_t); + } + + r = icmsg_get_tx_buffer(conf, &dev_data->icmsg_data, + (void **)&allocated_buffer, + &len_to_allocate); + if (r == -ENOMEM) { + *len = get_buffer_length_to_pass(len_to_allocate); + return -ENOMEM; + } + + if (r < 0) { + return r; + } + + *len = get_buffer_length_to_pass(len_to_allocate); + /* If requested max buffer length (*len == 0) allocated buffer might be + * shorter than sizeof(ept_id_t). In such circumstances drop the buffer + * and return error. + */ + + if (*len) { + *data = allocated_buffer + sizeof(ept_id_t); + return 0; + } + + r = icmsg_drop_tx_buffer(conf, &dev_data->icmsg_data, + allocated_buffer); + __ASSERT_NO_MSG(!r); + return -ENOBUFS; +} + +static int drop_tx_buffer(const struct device *instance, void *token, + const void *data) +{ + const struct icmsg_config_t *conf = instance->config; + struct backend_data_t *dev_data = instance->data; + const char *buffer_to_drop = data; + + buffer_to_drop -= sizeof(ept_id_t); + + return icmsg_drop_tx_buffer(conf, &dev_data->icmsg_data, buffer_to_drop); +} + +static int send_nocopy(const struct device *instance, void *token, + const void *data, size_t len) +{ + const struct icmsg_config_t *conf = instance->config; + struct backend_data_t *dev_data = instance->data; + ept_id_t *id = token; + char *buffer_to_send = (void *)data; + size_t len_to_send = len; + int r; + + buffer_to_send -= sizeof(ept_id_t); + len_to_send += sizeof(ept_id_t); + + set_ept_id_in_send_buffer(buffer_to_send, *id); + + r = icmsg_send_nocopy(conf, &dev_data->icmsg_data, buffer_to_send, + len_to_send); + if (r > 0) { + return r - sizeof(ept_id_t); + } else { + return r; + } +} + const static struct ipc_service_backend backend_ops = { .open_instance = open, .register_endpoint = register_ept, .send = send, + + .get_tx_buffer = get_tx_buffer, + .drop_tx_buffer = drop_tx_buffer, + .send_nocopy = send_nocopy, }; static int backend_init(const struct device *instance)