ipc: static_vrings: Fix timeout management
The ipc_service_get_tx_buffer() has a timeout parameter that can be used to wait a certain amount of time for a TX buffer to be available. Unfortunately, for the static vrings backend, an asymmetry between remote and host exists that makes the usage of this parameter confusing when the user requests a buffer when no buffers are available at that time. When the remote endpoints requests a TX buffer specifying a certain size and there are no TX buffers available, the function ignores the parameter and ipc_service_get_tx_buffer() immediately returns -ENOMEM. The same case on the host endpoint works correctly only when the specified timeout is <= 15 seconds. All timeouts > 15 seconds simply returns -EIO after 15 seconds. This patch is reworking the timeout management trying to behave correctly in all the cases. Signed-off-by: Carlo Caione <ccaione@baylibre.com>
This commit is contained in:
parent
57b1f6622d
commit
2bf678af1b
1 changed files with 28 additions and 25 deletions
|
@ -45,6 +45,9 @@ struct backend_data_t {
|
||||||
/* General */
|
/* General */
|
||||||
unsigned int role;
|
unsigned int role;
|
||||||
atomic_t state;
|
atomic_t state;
|
||||||
|
|
||||||
|
/* TX buffer size */
|
||||||
|
int tx_buffer_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct backend_config_t {
|
struct backend_config_t {
|
||||||
|
@ -445,6 +448,7 @@ static int open(const struct device *instance)
|
||||||
const struct backend_config_t *conf = instance->config;
|
const struct backend_config_t *conf = instance->config;
|
||||||
struct backend_data_t *data = instance->data;
|
struct backend_data_t *data = instance->data;
|
||||||
struct ipc_rpmsg_instance *rpmsg_inst;
|
struct ipc_rpmsg_instance *rpmsg_inst;
|
||||||
|
struct rpmsg_device *rdev;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!atomic_cas(&data->state, STATE_READY, STATE_BUSY)) {
|
if (!atomic_cas(&data->state, STATE_READY, STATE_BUSY)) {
|
||||||
|
@ -482,6 +486,14 @@ static int open(const struct device *instance)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rdev = rpmsg_virtio_get_rpmsg_device(&rpmsg_inst->rvdev);
|
||||||
|
|
||||||
|
data->tx_buffer_size = rpmsg_virtio_get_buffer_size(rdev);
|
||||||
|
if (data->tx_buffer_size < 0) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
atomic_set(&data->state, STATE_INITED);
|
atomic_set(&data->state, STATE_INITED);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -495,27 +507,16 @@ error:
|
||||||
static int get_tx_buffer_size(const struct device *instance, void *token)
|
static int get_tx_buffer_size(const struct device *instance, void *token)
|
||||||
{
|
{
|
||||||
struct backend_data_t *data = instance->data;
|
struct backend_data_t *data = instance->data;
|
||||||
struct ipc_rpmsg_instance *rpmsg_inst;
|
|
||||||
struct rpmsg_device *rdev;
|
|
||||||
int size;
|
|
||||||
|
|
||||||
rpmsg_inst = &data->rpmsg_inst;
|
return data->tx_buffer_size;
|
||||||
rdev = rpmsg_virtio_get_rpmsg_device(&rpmsg_inst->rvdev);
|
|
||||||
|
|
||||||
size = rpmsg_virtio_get_buffer_size(rdev);
|
|
||||||
if (size < 0) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_tx_buffer(const struct device *instance, void *token,
|
static int get_tx_buffer(const struct device *instance, void *token,
|
||||||
void **r_data, uint32_t *size, k_timeout_t wait)
|
void **r_data, uint32_t *size, k_timeout_t wait)
|
||||||
{
|
{
|
||||||
|
struct backend_data_t *data = instance->data;
|
||||||
struct ipc_rpmsg_ept *rpmsg_ept;
|
struct ipc_rpmsg_ept *rpmsg_ept;
|
||||||
void *payload;
|
void *payload;
|
||||||
int buf_size;
|
|
||||||
|
|
||||||
rpmsg_ept = (struct ipc_rpmsg_ept *) token;
|
rpmsg_ept = (struct ipc_rpmsg_ept *) token;
|
||||||
|
|
||||||
|
@ -529,22 +530,24 @@ static int get_tx_buffer(const struct device *instance, void *token,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The user requested a specific size */
|
/* The user requested a specific size */
|
||||||
if (*size) {
|
if ((*size) && (*size > data->tx_buffer_size)) {
|
||||||
buf_size = get_tx_buffer_size(instance, token);
|
|
||||||
if (buf_size < 0) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Too big to fit */
|
/* Too big to fit */
|
||||||
if (*size > buf_size) {
|
*size = data->tx_buffer_size;
|
||||||
*size = buf_size;
|
return -ENOMEM;
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
payload = rpmsg_get_tx_payload_buffer(&rpmsg_ept->ep, size, K_TIMEOUT_EQ(wait, K_FOREVER));
|
/*
|
||||||
|
* OpenAMP doesn't really have the concept of forever but instead it
|
||||||
|
* gives up after 15 seconds. In that case, just keep retrying.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
payload = rpmsg_get_tx_payload_buffer(&rpmsg_ept->ep, size,
|
||||||
|
K_TIMEOUT_EQ(wait, K_FOREVER));
|
||||||
|
} while ((!payload) && K_TIMEOUT_EQ(wait, K_FOREVER));
|
||||||
|
|
||||||
|
/* This should really only be valid for K_NO_WAIT */
|
||||||
if (!payload) {
|
if (!payload) {
|
||||||
return -EIO;
|
return -ENOBUFS;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*r_data) = payload;
|
(*r_data) = payload;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue