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:
parent
3a1c9bce6e
commit
6d3d2309ce
2 changed files with 207 additions and 3 deletions
|
@ -107,6 +107,11 @@ static int cache_ept_rmt(struct backend_data_t *data, const char *name,
|
||||||
return -ENOMEM;
|
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,
|
static int bind_ept(const struct icmsg_config_t *conf,
|
||||||
struct backend_data_t *data, const struct ipc_ept_cfg *ept,
|
struct backend_data_t *data, const struct ipc_ept_cfg *ept,
|
||||||
ept_id_t id)
|
ept_id_t id)
|
||||||
|
@ -290,7 +295,7 @@ static int send(const struct device *instance, void *token,
|
||||||
|
|
||||||
/* TODO: Optimization: How to avoid this copying? */
|
/* TODO: Optimization: How to avoid this copying? */
|
||||||
/* Scatter list supported by icmsg? */
|
/* 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);
|
memcpy(dev_data->send_buffer + sizeof(ept_id_t), msg, len);
|
||||||
|
|
||||||
r = icmsg_send(conf, &dev_data->icmsg_data, dev_data->send_buffer,
|
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 = {
|
const static struct ipc_service_backend backend_ops = {
|
||||||
.open_instance = open,
|
.open_instance = open,
|
||||||
.register_endpoint = register_ept,
|
.register_endpoint = register_ept,
|
||||||
.send = send,
|
.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)
|
static int backend_init(const struct device *instance)
|
||||||
|
|
|
@ -45,6 +45,11 @@ static void bound(void *priv)
|
||||||
k_event_post(&dev_data->event, EVENT_BOUND);
|
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)
|
static void received(const void *data, size_t len, void *priv)
|
||||||
{
|
{
|
||||||
const struct device *instance = 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
|
/* We could implement scatter list for icmsg_send, but it would require
|
||||||
* scatter list also for SPSC buffer implementation.
|
* 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);
|
memcpy(dev_data->send_buffer + sizeof(ept_id_t), msg, len);
|
||||||
|
|
||||||
r = icmsg_send(conf, &dev_data->icmsg_data, dev_data->send_buffer,
|
r = icmsg_send(conf, &dev_data->icmsg_data, dev_data->send_buffer,
|
||||||
len + sizeof(ept_id_t));
|
len + sizeof(ept_id_t));
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
sent_bytes = r - 1;
|
sent_bytes = r - sizeof(ept_id_t);;
|
||||||
}
|
}
|
||||||
|
|
||||||
k_mutex_unlock(&dev_data->send_mutex);
|
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 = {
|
const static struct ipc_service_backend backend_ops = {
|
||||||
.open_instance = open,
|
.open_instance = open,
|
||||||
.register_endpoint = register_ept,
|
.register_endpoint = register_ept,
|
||||||
.send = send,
|
.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)
|
static int backend_init(const struct device *instance)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue