android_kernel_samsung_sm86.../dsp/adsprpc_rpmsg.c
Anvesh Jain P dbd9441b48 msm: adsprpc: Add support for cdsp1 remoteproc
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>
2024-06-06 10:50:53 +05:30

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);
}