ipc: icmsg multi endpoint with nocopy in send path

Add nocopy feature to icmsg-me initiator and follower roles
in their send path.

Signed-off-by: Hubert Miś <hubert.mis@gmail.com>
This commit is contained in:
Hubert Miś 2022-11-11 19:44:22 +01:00 committed by Carles Cufí
commit 6d3d2309ce
2 changed files with 207 additions and 3 deletions

View file

@ -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)

View file

@ -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)