From 32ac22edb42b8770b9af16ff4862881e7bc6f47b Mon Sep 17 00:00:00 2001 From: Praveen koya Date: Tue, 20 Jul 2021 15:39:21 +0530 Subject: [PATCH] slatecom: add rpmsg glink support for slatecom_interface Add rpmsg support for slatecom interface driver to send msm state transition commands to slate. Add Opcodes to be received on slate-ctrl channel from hal. Send TWM_ENTER, DEEP SLEEP ENTER & EXIT to slate. Mot-CRs-fixed: (CR) CVE-Fixed: CVE-2023-33085 CRs-Fixed: 3512209 Change-Id: Ic29b116da7b90e1a1d71a14b970a2a53b1b3c20f Signed-off-by: Praveen koya Signed-off-by: Ashutosh Verma Reviewed-on: https://gerrit.mot.com/2762749 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Xiangpo Zhao Submit-Approved: Jira Key --- drivers/soc/qcom/Kconfig | 9 ++ drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/slatecom_interface.c | 117 +++++++++++++++++++++++- drivers/soc/qcom/slatecom_interface.h | 74 +++++++++++++++ drivers/soc/qcom/slatecom_rpmsg.c | 101 ++++++++++++++++++++ drivers/soc/qcom/slatecom_rpmsg.h | 31 +++++++ include/uapi/linux/slatecom_interface.h | 13 +++ 7 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 drivers/soc/qcom/slatecom_rpmsg.c create mode 100644 drivers/soc/qcom/slatecom_rpmsg.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 524a5cdf8a94..7f2f34b3c008 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -1483,6 +1483,15 @@ config MSM_SLATECOM_INTERFACE from hardware. Hardware will provide access to read registers and read/write AHB memory in the device. +config MSM_SLATECOM_RPMSG + tristate "Provide support for slate GLINK channel" + depends on MSM_SLATECOM_INTERFACE + help + MSM_SLATECOM_RPMSG informs SLATECOM_INTERFACE driver if GLINK channel + has been opened by remote processor. It doesn't maintain state machine + and is probed when Slate opens channel and removed when the channel is + closed by remote processor. + config QCOM_AOP_SET_DDR tristate "Sysfs to communicate with AOP using QMP protocol" help diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 6bd8d4a71359..7faed000a678 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -119,6 +119,7 @@ obj-$(CONFIG_RENAME_BLOCK_DEVICE) += rename_block_device.o obj-$(CONFIG_QCOM_ADSP_MANUAL_VOTE) += adsp_vote_qmi.o adsp_lpm_voting_v01.o obj-$(CONFIG_MSM_SLATECOM) += slatecom_spi.o obj-$(CONFIG_MSM_SLATECOM_INTERFACE) += slatecom_interface.o +obj-$(CONFIG_MSM_SLATECOM_RPMSG) += slatecom_rpmsg.o obj-$(CONFIG_QCOM_AOP_SET_DDR) += aop-set-ddr.o obj-$(CONFIG_CPU_V7) += idle-v7.o obj-$(CONFIG_DUMP_XBL_LOG) += dump_boot_log.o diff --git a/drivers/soc/qcom/slatecom_interface.c b/drivers/soc/qcom/slatecom_interface.c index 36bf60355d8a..9517cd8c877a 100644 --- a/drivers/soc/qcom/slatecom_interface.c +++ b/drivers/soc/qcom/slatecom_interface.c @@ -31,7 +31,7 @@ #include "peripheral-loader.h" #include "../../misc/qseecom_kernel.h" -//#include "pil_slate_intf.h" +#include "slatecom_rpmsg.h" #define SLATECOM "slate_com_dev" @@ -95,7 +95,14 @@ struct slatedaemon_priv { unsigned long attrs; u32 cmd_status; struct device *platform_dev; + bool slatecom_rpmsg; + bool slate_resp_cmplt; + void *lhndl; + wait_queue_head_t link_state_wait; + char rx_buf[20]; + struct mutex glink_mutex; }; +static void *slatecom_intf_drv; struct slate_event { enum slate_event_type e_type; @@ -182,6 +189,104 @@ static int send_uevent(struct slate_event *pce) return kobject_uevent_env(&dev_ret->kobj, KOBJ_CHANGE, envp); } +void slatecom_intf_notify_glink_channel_state(bool state) +{ + struct slatedaemon_priv *dev = + container_of(slatecom_intf_drv, struct slatedaemon_priv, lhndl); + + pr_debug("%s: slate_ctrl channel state: %d\n", __func__, state); + dev->slatecom_rpmsg = state; +} +EXPORT_SYMBOL(slatecom_intf_notify_glink_channel_state); + +void slatecom_rx_msg(void *data, int len) +{ + struct slatedaemon_priv *dev = + container_of(slatecom_intf_drv, struct slatedaemon_priv, lhndl); + + dev->slate_resp_cmplt = true; + wake_up(&dev->link_state_wait); + memcpy(dev->rx_buf, data, len); +} +EXPORT_SYMBOL(slatecom_rx_msg); + +static int slatecom_tx_msg(struct slatedaemon_priv *dev, void *msg, size_t len) +{ + int rc = 0; + uint8_t resp = 0; + + mutex_lock(&dev->glink_mutex); + if (!dev->slatecom_rpmsg) { + pr_err("slatecom-rpmsg is not probed yet, waiting for it to be probed\n"); + goto err_ret; + } + rc = slatecom_rpmsg_tx_msg(msg, len); + + /* wait for sending command to SLATE */ + rc = wait_event_timeout(dev->link_state_wait, + (rc == 0), msecs_to_jiffies(TIMEOUT_MS)); + if (rc == 0) { + pr_err("failed to send command to SLATE %d\n", rc); + goto err_ret; + } + + /* wait for getting response from SLATE */ + rc = wait_event_timeout(dev->link_state_wait, + dev->slate_resp_cmplt, + msecs_to_jiffies(TIMEOUT_MS)); + if (rc == 0) { + pr_err("failed to get SLATE response %d\n", rc); + goto err_ret; + } + dev->slate_resp_cmplt = false; + /* check SLATE response */ + resp = *(uint8_t *)dev->rx_buf; + if (!(resp == 0x01)) { + pr_err("Bad SLATE response\n"); + rc = -EINVAL; + goto err_ret; + } + rc = 0; + +err_ret: + mutex_unlock(&dev->glink_mutex); + return rc; +} + +/** + * send_state_change_cmd send state transition event to Slate + * and wait for the response. + * The response is returned to the caller. + */ +static int send_state_change_cmd(struct slate_ui_data *ui_obj_msg) +{ + int ret = 0; + struct wear_header wear_header_t = {0, 0}; + struct slatedaemon_priv *dev = container_of(slatecom_intf_drv, + struct slatedaemon_priv, + lhndl); + uint32_t state = ui_obj_msg->cmd; + + switch (state) { + case STATE_TWM_ENTER: + wear_header_t.opcode = GMI_WEAR_MGR_ENTER_TWM; + break; + case STATE_DS_ENTER: + wear_header_t.opcode = GMI_WEAR_MGR_ENTER_TRACKER_DS; + break; + case STATE_DS_EXIT: + wear_header_t.opcode = GMI_WEAR_MGR_EXIT_TRACKER_DS; + break; + default: + pr_err("Invalid MSM State transtion cmd\n"); + break; + } + ret = slatecom_tx_msg(dev, &wear_header_t.opcode, sizeof(wear_header_t.opcode)); + if (ret < 0) + pr_err("MSM State transtion event cmd failed\n"); + return ret; +} + static int slatecom_char_open(struct inode *inode, struct file *file) { int ret; @@ -382,6 +487,16 @@ static long slate_com_ioctl(struct file *filp, } ret = 0; break; + case DEVICE_STATE_TRANSITION: + if (copy_from_user(&ui_obj_msg, (void __user *)arg, + sizeof(ui_obj_msg))) { + pr_err("The copy from user failed for state transition cmd\n"); + ret = -EFAULT; + } + ret = send_state_change_cmd(&ui_obj_msg); + if (ret < 0) + pr_err("device state transition cmd failed\n"); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/soc/qcom/slatecom_interface.h b/drivers/soc/qcom/slatecom_interface.h index a64777a3b12f..9fa010771415 100644 --- a/drivers/soc/qcom/slatecom_interface.h +++ b/drivers/soc/qcom/slatecom_interface.h @@ -36,6 +36,80 @@ void set_slate_dsp_state(bool status); * Set slate bt state */ void set_slate_bt_state(bool status); +void slatecom_intf_notify_glink_channel_state(bool state); +void slatecom_rx_msg(void *data, int len); +/* + * WM header type - generic header structure + */ +struct wear_header { + uint32_t opcode; + uint32_t payload_size; +}; + +/** + * Opcodes to be received on slate-control channel. + */ +enum WMSlateCtrlChnlOpcode { + /* + * Command to slate to enter TWM mode + */ + GMI_WEAR_MGR_ENTER_TWM = 1, + + /* + * Notification to slate about Modem Processor Sub System + * is down due to a subsystem reset. + */ + GMI_WEAR_MGR_SSR_MPSS_DOWN_NOTIFICATION = 2, + + /* + * Notification to slate about Modem Processor Sub System + * being brought up after a subsystem reset. + */ + GMI_WEAR_MGR_SSR_MPSS_UP_NOTIFICATION = 3, + + /* + * Notification to slate about ADSP Sub System + * is down due to a subsystem reset. + */ + GMI_WEAR_MGR_SSR_ADSP_DOWN_INDICATION = 8, + + /* + * Notification to slate about Modem Processor + * Sub System being brought up after a subsystem reset. + */ + GMI_WEAR_MGR_SSR_ADSP_UP_INDICATION = 9, + + /* + * Notification to MSM for generic wakeup in tracker mode + */ + GMI_WEAR_MGR_WAKE_UP_NO_REASON = 10, + + /* + * Notification to Slate About Entry to Tracker-DS + */ + GMI_WEAR_MGR_ENTER_TRACKER_DS = 11, + + /* + * Notification to Slate About Entry to Tracker-DS + */ + GMI_WEAR_MGR_EXIT_TRACKER_DS = 12, + + /* + * Notification to Slate About Time-sync update + */ + GMI_WEAR_MGR_TIME_SYNC_UPDATE = 13, /* payload struct: wear_time_sync_t*/ + + /* + * Notification to Slate About Timeval UTC + */ + GMI_WEAR_MGR_TIMEVAL_UTC = 14, /* payload struct: wear_timeval_utc_t*/ + + /* + * Notification to Slate About Daylight saving time + */ + GMI_WEAR_MGR_DST = 15, /* payload struct: wear_dst_t*/ + +}; #endif /* SLATECOM_INTERFACE_H */ diff --git a/drivers/soc/qcom/slatecom_rpmsg.c b/drivers/soc/qcom/slatecom_rpmsg.c new file mode 100644 index 000000000000..919be0338bde --- /dev/null +++ b/drivers/soc/qcom/slatecom_rpmsg.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include "slatecom_rpmsg.h" + +static struct slatecom_rpmsg_dev *pdev; + +int slatecom_rpmsg_tx_msg(void *msg, size_t len) +{ + int ret = 0; + + if (pdev == NULL || !pdev->chnl_state) + pr_err("pmsg_device is null, channel is closed\n"); + + pdev->message = msg; + pdev->message_length = len; + if (pdev->message) { + ret = rpmsg_send(pdev->channel, pdev->message, pdev->message_length); + if (ret) + pr_err("rpmsg_send failed: %d\n", ret); + + } + return ret; +} +EXPORT_SYMBOL(slatecom_rpmsg_tx_msg); + +static int slatecom_rpmsg_probe(struct rpmsg_device *rpdev) +{ + int ret = 0; + void *msg = NULL; + + pdev = devm_kzalloc(&rpdev->dev, sizeof(*pdev), GFP_KERNEL); + if (!pdev) + return -ENOMEM; + + pdev->channel = rpdev->ept; + pdev->dev = &rpdev->dev; + if (pdev->channel == NULL) + return -ENOMEM; + + pdev->chnl_state = true; + dev_set_drvdata(&rpdev->dev, pdev); + + /* send a callback to slatecom-interface driver*/ + slatecom_intf_notify_glink_channel_state(true); + if (pdev->message == NULL) + ret = slatecom_rpmsg_tx_msg(msg, 0); + return 0; +} + +static void slatecom_rpmsg_remove(struct rpmsg_device *rpdev) +{ + pdev->chnl_state = false; + pdev->message = NULL; + dev_dbg(&rpdev->dev, "rpmsg client driver is removed\n"); + slatecom_intf_notify_glink_channel_state(false); + dev_set_drvdata(&rpdev->dev, NULL); +} + +static int slatecom_rpmsg_cb(struct rpmsg_device *rpdev, + void *data, int len, void *priv, u32 src) +{ + struct slatecom_rpmsg_dev *dev = + dev_get_drvdata(&rpdev->dev); + + if (!dev) + return -ENODEV; + slatecom_rx_msg(data, len); + return 0; +} + +static const struct rpmsg_device_id rpmsg_driver_slatecom_id_table[] = { + { "SLATECOM_CTRL" }, + {}, +}; +MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_slatecom_id_table); + +static const struct of_device_id rpmsg_driver_slatecom_of_match[] = { + { .compatible = "qcom,slatecom-rpmsg" }, + {}, +}; + +static struct rpmsg_driver rpmsg_slatecom_client = { + .id_table = rpmsg_driver_slatecom_id_table, + .probe = slatecom_rpmsg_probe, + .callback = slatecom_rpmsg_cb, + .remove = slatecom_rpmsg_remove, + .drv = { + .name = "qcom,slatecom_rpmsg", + .of_match_table = rpmsg_driver_slatecom_of_match, + }, +}; +module_rpmsg_driver(rpmsg_slatecom_client); + +MODULE_DESCRIPTION("Interface Driver for SLATECOM and RPMSG"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/slatecom_rpmsg.h b/drivers/soc/qcom/slatecom_rpmsg.h new file mode 100644 index 000000000000..1d80bb0511dc --- /dev/null +++ b/drivers/soc/qcom/slatecom_rpmsg.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ +#ifndef SLATECOMRPMSG_H +#define SLATECOMRPMSG_H + +#include +#include "slatecom_interface.h" + +#define TIMEOUT_MS 2000 + +struct slatecom_rpmsg_dev { + struct rpmsg_endpoint *channel; + struct device *dev; + bool chnl_state; + void *message; + size_t message_length; +}; + + +#if IS_ENABLED(CONFIG_MSM_SLATECOM_RPMSG) +int slatecom_rpmsg_tx_msg(void *msg, size_t len); +#else +static inline int slatecom_rpmsg_tx_msg(void *msg, size_t len) +{ + return -EIO; +} +#endif + +#endif diff --git a/include/uapi/linux/slatecom_interface.h b/include/uapi/linux/slatecom_interface.h index 6f58ef8057e6..d41af0e47178 100644 --- a/include/uapi/linux/slatecom_interface.h +++ b/include/uapi/linux/slatecom_interface.h @@ -20,6 +20,7 @@ #define SLATECOM_ADSP_DOWN2_SLATE 10 #define SLATECOM_SLATE_WEAR_LOAD 11 #define SLATECOM_SLATE_WEAR_UNLOAD 12 +#define SLATECOM_DEVICE_STATE_TRANSITION 13 #define EXCHANGE_CODE 'V' struct slate_ui_data { @@ -47,6 +48,15 @@ enum slate_event_type { SLATE_BT_READY, }; +enum device_state_transition { + STATE_TWM_ENTER = 1, + STATE_TWM_EXIT, + STATE_DS_ENTER, + STATE_DS_EXIT, + STATE_S2D_ENTER, + STATE_S2D_EXIT, +}; + #define REG_READ \ _IOWR(EXCHANGE_CODE, SLATECOM_REG_READ, \ struct slate_ui_data) @@ -86,6 +96,9 @@ enum slate_event_type { #define SLATE_ADSP_DOWN2_SLATE_DONE \ _IOWR(EXCHANGE_CODE, SLATECOM_ADSP_DOWN2_SLATE, \ struct slate_ui_data) +#define DEVICE_STATE_TRANSITION \ + _IOWR(EXCHANGE_CODE, SLATECOM_DEVICE_STATE_TRANSITION, \ + struct slate_ui_data) #endif /* LINUX_SLATECOM_INTERFACE_H */