blob: 2b77ea45a39a60009be3886ca1e1884d41d78440 [file] [log] [blame]
/*
* Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <stddef.h>
#include <trace.h>
#include "openamp_messenger.h"
#include "openamp_messenger_api.h"
#include "openamp_mhu.h"
#include "openamp_virtio.h"
#include <protocols/rpc/common/packed-c/status.h>
#define OPENAMP_TRANSACTION_IDLE 0x0
#define OPENAMP_TRANSACTION_INPROGRESS 0x1
#define OPENAMP_TRANSACTION_INVOKED 0x2
int openamp_messenger_call_begin(struct openamp_messenger *openamp,
uint8_t **req_buf, size_t req_len)
{
const struct openamp_platform_ops *ops = openamp->platform_ops;
int ret;
if (!openamp)
return -EINVAL;
ops = openamp->platform_ops;
if (!req_buf) {
EMSG("openamp: call_begin: not req_buf");
return -EINVAL;
}
if (req_len > UINT32_MAX || req_len == 0) {
EMSG("openamp: call_begin: resp_len invalid: %lu", req_len);
return -EINVAL;
}
if (openamp->status != OPENAMP_TRANSACTION_IDLE) {
EMSG("openamp: call_begin: transaction not idle");
return -EINVAL;
}
ret = ops->platform_call_begin(openamp, req_buf, req_len);
if (ret < 0) {
EMSG("openamp: call_begin: platform begin failed: %d", ret);
return -EINVAL;
}
openamp->status = OPENAMP_TRANSACTION_INPROGRESS;
return 0;
}
int openamp_messenger_call_invoke(struct openamp_messenger *openamp,
uint8_t **resp_buf, size_t *resp_len)
{
const struct openamp_platform_ops *ops;
int ret;
if (!openamp || !resp_buf || !resp_len) {
EMSG("openamp: call_invoke: invalid arguments");
return -EINVAL;
}
if (openamp->status != OPENAMP_TRANSACTION_INPROGRESS) {
EMSG("openamp: call_invoke: transaction needed to be started");
return -ENOTCONN;
}
ops = openamp->platform_ops;
ret = ops->platform_call_invoke(openamp, resp_buf, resp_len);
if (ret < 0)
return ret;
openamp->status = OPENAMP_TRANSACTION_INVOKED;
return 0;
}
void openamp_messenger_call_end(struct openamp_messenger *openamp)
{
const struct openamp_platform_ops *ops;
if (!openamp)
return;
if (openamp->status == OPENAMP_TRANSACTION_IDLE) {
EMSG("openamp: call_end: transaction idle");
return;
}
ops = openamp->platform_ops;
ops->platform_call_end(openamp);
openamp->status = OPENAMP_TRANSACTION_IDLE;
}
void *openamp_messenger_phys_to_virt(struct openamp_messenger *openamp,
void *pa)
{
const struct openamp_platform_ops *ops = openamp->platform_ops;
return ops->platform_phys_to_virt(openamp, pa);
}
void *openamp_messenger_virt_to_phys(struct openamp_messenger *openamp,
void *va)
{
const struct openamp_platform_ops *ops = openamp->platform_ops;
return ops->platform_virt_to_phys(openamp, va);
}
static const struct openamp_platform_ops openamp_virtio_ops = {
.transport_init = openamp_mhu_init,
.transport_deinit = openamp_mhu_deinit,
.transport_notify = openamp_mhu_notify_peer,
.transport_receive = openamp_mhu_receive,
.platform_init = openamp_virtio_init,
.platform_call_begin = openamp_virtio_call_begin,
.platform_call_invoke = openamp_virtio_call_invoke,
.platform_call_end = openamp_virtio_call_end,
.platform_virt_to_phys = openamp_virtio_virt_to_phys,
.platform_phys_to_virt = openamp_virtio_phys_to_virt,
};
int openamp_messenger_init(struct openamp_messenger *openamp)
{
const struct openamp_platform_ops *ops;
int ret;
if (openamp->ref_count)
return 0;
openamp->platform_ops = &openamp_virtio_ops;
ops = openamp->platform_ops;
ret = ops->transport_init(openamp);
if (ret < 0)
return ret;
ret = ops->platform_init(openamp);
if (ret < 0)
goto denit_transport;
openamp->ref_count++;
return 0;
denit_transport:
ops->transport_deinit(openamp);
return ret;
}
void openamp_messenger_deinit(struct openamp_messenger *openamp)
{
if (--openamp->ref_count)
return;
}