The fastrpc driver supports 4 remoteproc. There are some products such as automotive which support cdsp1 remoteproc. Add changes to support cdsp1 remoteproc. Change-Id: I3a9b221c53ccd4331de089ab38ccd6d715db4bf4 Signed-off-by: Anvesh Jain P <quic_ajainp@quicinc.com>
285 lines
7.2 KiB
C
285 lines
7.2 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/rpmsg.h>
|
|
#include <linux/of.h>
|
|
#include <linux/module.h>
|
|
#include "fastrpc_trace.h"
|
|
#include <trace/events/rproc_qcom.h>
|
|
#include "adsprpc_shared.h"
|
|
|
|
struct frpc_transport_session_control {
|
|
struct rpmsg_device *rpdev;
|
|
struct mutex rpmsg_mutex;
|
|
char *subsys;
|
|
/* Flags for DSP up mutex */
|
|
wait_queue_head_t wait_for_rpmsg_ch;
|
|
atomic_t is_rpmsg_ch_up;
|
|
};
|
|
|
|
static struct frpc_transport_session_control rpmsg_session_control[NUM_CHANNELS];
|
|
|
|
inline int verify_transport_device(int cid, int tvm_remote_domain)
|
|
{
|
|
int err = 0;
|
|
struct frpc_transport_session_control *rpmsg_session = &rpmsg_session_control[cid];
|
|
|
|
mutex_lock(&rpmsg_session->rpmsg_mutex);
|
|
VERIFY(err, NULL != rpmsg_session->rpdev);
|
|
if (err) {
|
|
err = -ENODEV;
|
|
mutex_unlock(&rpmsg_session->rpmsg_mutex);
|
|
goto bail;
|
|
}
|
|
mutex_unlock(&rpmsg_session->rpmsg_mutex);
|
|
bail:
|
|
return err;
|
|
}
|
|
|
|
static inline int get_cid_from_rpdev(struct rpmsg_device *rpdev)
|
|
{
|
|
int err = 0, cid = -1;
|
|
const char *label = 0;
|
|
|
|
VERIFY(err, !IS_ERR_OR_NULL(rpdev));
|
|
if (err)
|
|
return -ENODEV;
|
|
|
|
err = of_property_read_string(rpdev->dev.parent->of_node, "label",
|
|
&label);
|
|
|
|
if (err)
|
|
label = rpdev->dev.parent->of_node->name;
|
|
|
|
if (!strcmp(label, "cdsp"))
|
|
cid = CDSP_DOMAIN_ID;
|
|
else if (!strcmp(label, "adsp"))
|
|
cid = ADSP_DOMAIN_ID;
|
|
else if (!strcmp(label, "slpi"))
|
|
cid = SDSP_DOMAIN_ID;
|
|
else if (!strcmp(label, "mdsp"))
|
|
cid = MDSP_DOMAIN_ID;
|
|
else if (!strcmp(label, "cdsp1"))
|
|
cid = CDSP1_DOMAIN_ID;
|
|
|
|
return cid;
|
|
}
|
|
|
|
static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
|
|
{
|
|
int err = 0;
|
|
int cid = -1;
|
|
struct frpc_transport_session_control *transport_session_control = NULL;
|
|
|
|
VERIFY(err, !IS_ERR_OR_NULL(rpdev));
|
|
if (err)
|
|
return -ENODEV;
|
|
|
|
cid = get_cid_from_rpdev(rpdev);
|
|
VERIFY(err, VALID_FASTRPC_CID(cid));
|
|
if (err) {
|
|
err = -ECHRNG;
|
|
goto bail;
|
|
}
|
|
transport_session_control = &rpmsg_session_control[cid];
|
|
mutex_lock(&transport_session_control->rpmsg_mutex);
|
|
transport_session_control->rpdev = rpdev;
|
|
mutex_unlock(&transport_session_control->rpmsg_mutex);
|
|
|
|
/*
|
|
* Set atomic variable to 1 when rpmsg channel is up
|
|
* and wake up all threads waiting for rpmsg channel
|
|
*/
|
|
atomic_set(&transport_session_control->is_rpmsg_ch_up, 1);
|
|
wake_up_interruptible(&transport_session_control->wait_for_rpmsg_ch);
|
|
|
|
ADSPRPC_INFO("opened rpmsg channel for %s\n",
|
|
rpmsg_session_control[cid].subsys);
|
|
bail:
|
|
if (err)
|
|
ADSPRPC_ERR("rpmsg probe of %s cid %d failed\n",
|
|
rpdev->dev.parent->of_node->name, cid);
|
|
return err;
|
|
}
|
|
|
|
static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
|
|
{
|
|
int err = 0;
|
|
int cid = -1;
|
|
struct frpc_transport_session_control *transport_session_control = NULL;
|
|
|
|
VERIFY(err, !IS_ERR_OR_NULL(rpdev));
|
|
if (err) {
|
|
err = -ENODEV;
|
|
return;
|
|
}
|
|
|
|
cid = get_cid_from_rpdev(rpdev);
|
|
VERIFY(err, VALID_FASTRPC_CID(cid));
|
|
if (err) {
|
|
err = -ECHRNG;
|
|
goto bail;
|
|
}
|
|
transport_session_control = &rpmsg_session_control[cid];
|
|
mutex_lock(&transport_session_control->rpmsg_mutex);
|
|
transport_session_control->rpdev = NULL;
|
|
mutex_unlock(&transport_session_control->rpmsg_mutex);
|
|
|
|
/*
|
|
* Set atomic variable to 0 when rpmsg channel is down and
|
|
* make threads wait on is_rpmsg_ch_up
|
|
*/
|
|
atomic_set(&transport_session_control->is_rpmsg_ch_up, 0);
|
|
|
|
ADSPRPC_INFO("closed rpmsg channel of %s\n",
|
|
rpmsg_session_control[cid].subsys);
|
|
bail:
|
|
if (err)
|
|
ADSPRPC_ERR("rpmsg remove of %s cid %d failed\n",
|
|
rpdev->dev.parent->of_node->name, cid);
|
|
}
|
|
|
|
static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
|
|
int len, void *priv, u32 addr)
|
|
{
|
|
int err = 0;
|
|
int rpmsg_err = 0;
|
|
int cid = -1;
|
|
|
|
trace_fastrpc_msg("rpmsg_callback: begin");
|
|
cid = get_cid_from_rpdev(rpdev);
|
|
VERIFY(err, VALID_FASTRPC_CID(cid));
|
|
if (err) {
|
|
err = -ECHRNG;
|
|
goto bail;
|
|
}
|
|
|
|
rpmsg_err = fastrpc_handle_rpc_response(data, len, cid);
|
|
bail:
|
|
if (err) {
|
|
err = -ENOKEY;
|
|
ADSPRPC_ERR(
|
|
"invalid response data %pK, len %d from remote subsystem err %d\n",
|
|
data, len, err);
|
|
} else
|
|
err = rpmsg_err;
|
|
|
|
trace_fastrpc_msg("rpmsg_callback: end");
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* This function is called from fastrpc_channel open to wait
|
|
* for rpmsg channel in the respective domain. The wait in this
|
|
* function is done only for CDSP, Audio and Sensors Daemons.
|
|
*/
|
|
int fastrpc_wait_for_transport_interrupt(int cid,
|
|
unsigned int flags)
|
|
{
|
|
struct frpc_transport_session_control *transport_session_control = NULL;
|
|
int err = 0;
|
|
|
|
/*
|
|
* The flags which are applicable only for daemons are checked.
|
|
* Dynamic PDs will fail and return immediately if the
|
|
* remote subsystem is not up.
|
|
*/
|
|
if (flags == FASTRPC_INIT_ATTACH || flags == FASTRPC_INIT_ATTACH_SENSORS
|
|
|| flags == FASTRPC_INIT_CREATE_STATIC) {
|
|
transport_session_control = &rpmsg_session_control[cid];
|
|
ADSPRPC_DEBUG("Thread waiting for cid %d rpmsg channel", cid);
|
|
err = wait_event_interruptible(transport_session_control->wait_for_rpmsg_ch,
|
|
atomic_read(&transport_session_control->is_rpmsg_ch_up));
|
|
ADSPRPC_DEBUG("Thread received signal for cid %d rpmsg channel (interrupted %d)",
|
|
cid, err);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
int fastrpc_transport_send(int cid, void *rpc_msg, uint32_t rpc_msg_size, int tvm_remote_domain)
|
|
{
|
|
int err = 0;
|
|
struct frpc_transport_session_control *rpmsg_session = &rpmsg_session_control[cid];
|
|
|
|
mutex_lock(&rpmsg_session->rpmsg_mutex);
|
|
VERIFY(err, !IS_ERR_OR_NULL(rpmsg_session->rpdev));
|
|
if (err) {
|
|
err = -ENODEV;
|
|
ADSPRPC_ERR("No rpmsg device for %s, err %d\n", current->comm, err);
|
|
mutex_unlock(&rpmsg_session->rpmsg_mutex);
|
|
goto bail;
|
|
}
|
|
err = rpmsg_send(rpmsg_session->rpdev->ept, rpc_msg, rpc_msg_size);
|
|
mutex_unlock(&rpmsg_session->rpmsg_mutex);
|
|
bail:
|
|
return err;
|
|
}
|
|
|
|
static const struct rpmsg_device_id fastrpc_rpmsg_match[] = {
|
|
{ FASTRPC_GLINK_GUID },
|
|
{ },
|
|
};
|
|
|
|
static const struct of_device_id fastrpc_rpmsg_of_match[] = {
|
|
{ .compatible = "qcom,msm-fastrpc-rpmsg" },
|
|
{ },
|
|
};
|
|
MODULE_DEVICE_TABLE(of, fastrpc_rpmsg_of_match);
|
|
|
|
static struct rpmsg_driver fastrpc_rpmsg_client = {
|
|
.id_table = fastrpc_rpmsg_match,
|
|
.probe = fastrpc_rpmsg_probe,
|
|
.remove = fastrpc_rpmsg_remove,
|
|
.callback = fastrpc_rpmsg_callback,
|
|
.drv = {
|
|
.name = "qcom,msm_fastrpc_rpmsg",
|
|
.of_match_table = fastrpc_rpmsg_of_match,
|
|
},
|
|
};
|
|
|
|
void fastrpc_rproc_trace_events(const char *name, const char *event,
|
|
const char *subevent)
|
|
{
|
|
trace_rproc_qcom_event(name, event, subevent);
|
|
}
|
|
|
|
inline void fastrpc_transport_session_init(int cid, char *subsys)
|
|
{
|
|
rpmsg_session_control[cid].subsys = subsys;
|
|
mutex_init(&rpmsg_session_control[cid].rpmsg_mutex);
|
|
init_waitqueue_head(&rpmsg_session_control[cid].wait_for_rpmsg_ch);
|
|
}
|
|
|
|
inline void fastrpc_transport_session_deinit(int cid)
|
|
{
|
|
mutex_destroy(&rpmsg_session_control[cid].rpmsg_mutex);
|
|
}
|
|
|
|
int fastrpc_set_tvm_remote_domain(struct fastrpc_file *fl, struct fastrpc_ioctl_init *init)
|
|
{
|
|
fl->tvm_remote_domain = -1;
|
|
return 0;
|
|
}
|
|
|
|
int fastrpc_transport_init(void)
|
|
{
|
|
int err = 0;
|
|
|
|
err = register_rpmsg_driver(&fastrpc_rpmsg_client);
|
|
if (err) {
|
|
pr_err("Error: adsprpc: %s: register_rpmsg_driver failed with err %d\n",
|
|
__func__, err);
|
|
goto bail;
|
|
}
|
|
bail:
|
|
return err;
|
|
}
|
|
|
|
void fastrpc_transport_deinit(void)
|
|
{
|
|
unregister_rpmsg_driver(&fastrpc_rpmsg_client);
|
|
}
|