Merge "remoteproc: helios: using SMCInvoke instead of Qseecom framework"

This commit is contained in:
qctecmdr 2022-08-04 15:32:42 -07:00 committed by Gerrit - the friendly Code Review server
commit 789c6ab8c7
2 changed files with 331 additions and 83 deletions

View File

@ -26,6 +26,8 @@
#include <misc/qseecom_kernel.h> #include <misc/qseecom_kernel.h>
#include <soc/qcom/qseecomi.h> #include <soc/qcom/qseecomi.h>
#include <soc/qcom/ramdump.h> #include <soc/qcom/ramdump.h>
#include <soc/qcom/smcinvoke_object.h>
#include <linux/smcinvoke.h>
#include "../soc/qcom/helioscom.h" #include "../soc/qcom/helioscom.h"
@ -33,13 +35,23 @@
#include "qcom_pil_info.h" #include "qcom_pil_info.h"
#include "remoteproc_internal.h" #include "remoteproc_internal.h"
#define SECURE_APP "heliosapp" #include "../soc/qcom/helios_app_smc_interface.h"
#include <soc/qcom/CAppClient.h>
#include <soc/qcom/CAppLoader.h>
#include <soc/qcom/IAppClient.h>
#include <soc/qcom/IAppController.h>
#include <soc/qcom/IAppLoader.h>
#include <soc/qcom/IClientEnv.h>
#include <soc/qcom/IOpener.h>
#define RESULT_SUCCESS 0 #define RESULT_SUCCESS 0
#define RESULT_FAILURE -1 #define RESULT_FAILURE -1
/* Helios Ramdump Size 3100 KB */ /* Helios Ramdump Size 4 MB */
#define HELIOS_RAMDUMP_SZ (0x307000) #define HELIOS_RAMDUMP_SZ SZ_4M
uint32_t helios_app_uid = 286;
/* tzapp command list.*/ /* tzapp command list.*/
enum helios_tz_commands { enum helios_tz_commands {
@ -153,31 +165,6 @@ static void helios_crash_handler(void *handle, void *priv)
rproc_report_crash(helios_rproc, RPROC_FATAL_ERROR); rproc_report_crash(helios_rproc, RPROC_FATAL_ERROR);
} }
/**
* get_cmd_rsp_buffers() - Function sets cmd & rsp buffer pointers and
* aligns buffer lengths
* @handle: index of qseecom_handle
* @cmd: req buffer - set to qseecom_handle.sbuf
* @cmd_len: ptr to req buffer len
* @rsp: rsp buffer - set to qseecom_handle.sbuf + offset
* @rsp_len: ptr to rsp buffer len
*
* Return: Success always .
*/
static int get_cmd_rsp_buffers(struct qseecom_handle *handle, void **cmd,
uint32_t *cmd_len, void **rsp, uint32_t *rsp_len)
{
*cmd = handle->sbuf;
if (*cmd_len & QSEECOM_ALIGN_MASK)
*cmd_len = QSEECOM_ALIGN(*cmd_len);
*rsp = handle->sbuf + *cmd_len;
if (*rsp_len & QSEECOM_ALIGN_MASK)
*rsp_len = QSEECOM_ALIGN(*rsp_len);
return 0;
}
/** /**
* load_helios_tzapp() - Called to load TZ app. * load_helios_tzapp() - Called to load TZ app.
* @pbd: struct containing private <helios> data. * @pbd: struct containing private <helios> data.
@ -186,23 +173,122 @@ static int get_cmd_rsp_buffers(struct qseecom_handle *handle, void **cmd,
*/ */
static int load_helios_tzapp(struct qcom_helios *pbd) static int load_helios_tzapp(struct qcom_helios *pbd)
{ {
int rc; int rc = 0;
uint8_t *buffer = NULL;
struct qtee_shm shm = {0};
size_t size = 0;
char *app_name = "heliosapp";
struct Object client_env = {NULL, NULL};
struct Object app_client = {NULL, NULL};
struct Object app_loader = {NULL, NULL};
struct Object app_controller_obj = {NULL, NULL};
/* return success if already loaded */ pbd->app_status = RESULT_FAILURE;
if (pbd->qseecom_handle && !pbd->app_status)
return 0;
/* Load the APP */ /* Load the APP */
pr_debug("Start loading of secure app\n"); pr_debug("Start loading of secure app\n");
rc = qseecom_start_app(&pbd->qseecom_handle, SECURE_APP, SZ_4K); rc = get_client_env_object(&client_env);
if (rc < 0) { if (rc) {
dev_err(pbd->dev, "<helios> TZ app load failure\n"); client_env.invoke = NULL;
pbd->app_status = RESULT_FAILURE; client_env.context = NULL;
return -EIO; dev_err(pbd->dev, "<helios> get client env object failure\n");
rc = -EIO;
goto end;
} }
rc = IClientEnv_open(client_env, CAppLoader_UID, &app_loader);
if (rc) {
app_loader.invoke = NULL;
app_loader.context = NULL;
dev_err(pbd->dev, "<helios> IClientEnv_open failure\n");
rc = -EIO;
goto end;
}
buffer = firmware_request_from_smcinvoke(app_name, &size, &shm);
if (buffer == NULL) {
dev_err(pbd->dev, "firmware_request_from_smcinvoke failure\n");
rc = -EINVAL;
goto end;
}
rc = IAppLoader_loadFromBuffer(app_loader, (const void *)buffer, size,
&app_controller_obj);
if (rc) {
app_controller_obj.invoke = NULL;
app_controller_obj.context = NULL;
dev_err(pbd->dev, "<helios> IAppLoader_loadFromBuffer failure\n");
rc = -EIO;
goto end;
}
rc = IClientEnv_open(client_env, CAppClient_UID, &app_client);
if (rc) {
app_client.invoke = NULL;
app_client.context = NULL;
dev_err(pbd->dev, "<helios> CAppClient_UID failure\n");
rc = -EIO;
goto end;
}
pbd->app_status = RESULT_SUCCESS; pbd->app_status = RESULT_SUCCESS;
pr_debug("App loaded\n"); end:
return 0; Object_ASSIGN_NULL(app_controller_obj);
Object_ASSIGN_NULL(app_loader);
Object_ASSIGN_NULL(client_env);
Object_ASSIGN_NULL(app_client);
return rc;
}
static int32_t get_helios_app_object(struct Object *helios_app_obj)
{
int32_t ret = 0;
const char *app_name = "heliosapp";
struct Object remote_obj = {NULL, NULL};
struct Object client_env = {NULL, NULL};
struct Object app_client = {NULL, NULL};
ret = get_client_env_object(&client_env);
if (ret) {
client_env.invoke = NULL;
client_env.context = NULL;
pr_err("<helios> get client env object failure:[%d]\n", ret);
ret = -EIO;
goto end;
}
ret = IClientEnv_open(client_env, CAppClient_UID, &app_client);
if (ret) {
app_client.invoke = NULL;
app_client.context = NULL;
pr_err("<helios> CAppClient_UID failure:[%d]\n", ret);
ret = -EIO;
goto end;
}
ret = IAppClient_getAppObject(app_client, app_name, strlen(app_name), &remote_obj);
if (ret) {
pr_err("IAppClient_getAppObject failure:[%d]\n", ret);
remote_obj.invoke = NULL;
remote_obj.context = NULL;
ret = -EIO;
goto end;
}
ret = IOpener_open(remote_obj, helios_app_uid, helios_app_obj);
if (ret) {
pr_err("IOpener_open failure: ret:[%d]\n", ret);
helios_app_obj->invoke = NULL;
helios_app_obj->context = NULL;
ret = -EIO;
goto end;
}
end:
Object_ASSIGN_NULL(remote_obj);
Object_ASSIGN_NULL(client_env);
Object_ASSIGN_NULL(app_client);
return ret;
} }
/** /**
@ -215,32 +301,62 @@ static int load_helios_tzapp(struct qcom_helios *pbd)
static long helios_tzapp_comm(struct qcom_helios *pbd, static long helios_tzapp_comm(struct qcom_helios *pbd,
struct tzapp_helios_req *req) struct tzapp_helios_req *req)
{ {
struct tzapp_helios_req *helios_tz_req; int32_t ret = 0;
struct tzapp_helios_rsp *helios_tz_rsp; struct Object helios_app_obj = {NULL, NULL};
int rc, req_len, rsp_len; size_t rsp_len = 0;
/* Fill command structure */ pr_debug("command id = %d\n", req->tzapp_helios_cmd);
req_len = sizeof(struct tzapp_helios_req); ret = get_helios_app_object(&helios_app_obj);
rsp_len = sizeof(struct tzapp_helios_rsp); if (ret) {
rc = get_cmd_rsp_buffers(pbd->qseecom_handle, dev_err(pbd->dev, "<helios> Failed to get helios TA context\n");
(void **)&helios_tz_req, &req_len,
(void **)&helios_tz_rsp, &rsp_len);
if (rc)
goto end; goto end;
}
helios_tz_req->tzapp_helios_cmd = req->tzapp_helios_cmd; switch (req->tzapp_helios_cmd) {
helios_tz_req->address_fw = req->address_fw;
helios_tz_req->size_fw = req->size_fw;
rc = qseecom_send_command(pbd->qseecom_handle, case HELIOS_RPROC_AUTH_MDT:
(void *)helios_tz_req, req_len, (void *)helios_tz_rsp, rsp_len); pbd->cmd_status = helios_app_load_meta_data(
if (rc || helios_tz_rsp->status) helios_app_obj,
pbd->cmd_status = helios_tz_rsp->status; (void *)req,
else sizeof(struct tzapp_helios_req));
pbd->cmd_status = 0;
break;
case HELIOS_RPROC_IMAGE_LOAD:
pbd->cmd_status = helios_app_transfer_and_authenticate_fw(
helios_app_obj,
(void *)req,
sizeof(struct tzapp_helios_req));
break;
case HELIOS_RPROC_RAMDUMP:
pbd->cmd_status = helios_app_collect_ramdump(
helios_app_obj,
(void *)req,
sizeof(struct tzapp_helios_req),
&rsp_len);
break;
case HELIOS_RPROC_RESTART:
pbd->cmd_status = helios_app_force_restart(helios_app_obj);
break;
case HELIOS_RPROC_SHUTDOWN:
pbd->cmd_status = helios_app_shutdown(helios_app_obj);
break;
case HELIOS_RPROC_POWERDOWN:
pbd->cmd_status = helios_app_force_power_down(helios_app_obj);
break;
default:
pr_debug("Invalid command\n");
break;
}
end: end:
return rc; Object_ASSIGN_NULL(helios_app_obj);
return ret;
} }
/** /**
@ -349,7 +465,7 @@ static int helios_prepare(struct rproc *rproc)
int ret = 0; int ret = 0;
init_completion(&helios->err_ready); init_completion(&helios->err_ready);
if (!helios->qseecom_handle) { if (helios->app_status != RESULT_SUCCESS) {
ret = load_helios_tzapp(helios); ret = load_helios_tzapp(helios);
if (ret) { if (ret) {
dev_err(helios->dev, dev_err(helios->dev,
@ -357,8 +473,9 @@ static int helios_prepare(struct rproc *rproc)
__func__); __func__);
return ret; return ret;
} }
helios->is_ready = true;
} }
helios->is_ready = true;
pr_debug("heliosapp loaded\n"); pr_debug("heliosapp loaded\n");
return ret; return ret;
} }
@ -608,7 +725,26 @@ static void helios_coredump(struct rproc *rproc)
start_addr, DMA_ATTR_SKIP_ZEROING); start_addr, DMA_ATTR_SKIP_ZEROING);
} }
static int helios_shutdown(struct rproc *rproc) static int helios_force_powerdown(struct qcom_helios *helios)
{
int ret;
struct tzapp_helios_req helios_tz_req;
pr_debug("Force powerdown helios\n");
helios_tz_req.tzapp_helios_cmd = HELIOS_RPROC_POWERDOWN;
helios_tz_req.address_fw = 0;
helios_tz_req.size_fw = 0;
ret = helios_tzapp_comm(helios, &helios_tz_req);
if (ret || helios->cmd_status) {
dev_err(helios->dev, "%s: Helios Power Down failed\n", __func__);
return helios->cmd_status;
}
pr_debug("Helios is powered down.\n");
return ret;
}
static int helios_force_restart(struct rproc *rproc)
{ {
struct qcom_helios *helios = (struct qcom_helios *)rproc->priv; struct qcom_helios *helios = (struct qcom_helios *)rproc->priv;
struct tzapp_helios_req helios_tz_req; struct tzapp_helios_req helios_tz_req;
@ -626,31 +762,54 @@ static int helios_shutdown(struct rproc *rproc)
pr_info("A2H response is received! Collect ramdump now!\n"); pr_info("A2H response is received! Collect ramdump now!\n");
helios_coredump(rproc); helios_coredump(rproc);
} else { } else {
/* Helios is not responding. So forcing S3 reset to power down Helios n Yoda /* Helios is not responding. So forcing S3 reset to power down Helios
* It should be powered on in Start Sequence. * and Yoda. It should be powered on in Start Sequence.
* If Helios not responding, we need to Helios SSR or Aurora+Helios power cycle
*/ */
pr_debug("Powerdown helios\n"); pr_debug("Helios is not responding. Powerdown helios\n");
helios_tz_req.tzapp_helios_cmd = HELIOS_RPROC_POWERDOWN; ret = helios_force_powerdown(helios);
helios_tz_req.address_fw = 0; if (ret) {
helios_tz_req.size_fw = 0;
ret = helios_tzapp_comm(helios, &helios_tz_req);
if (ret || helios->cmd_status) {
dev_err(helios->dev, "%s: Helios Power Down failed\n", __func__); dev_err(helios->dev, "%s: Helios Power Down failed\n", __func__);
return helios->cmd_status; return ret;
} }
pr_debug("Helios is powered down.\n");
} }
pr_debug("Helios Restart is success!\n");
return ret;
}
static int helios_shutdown(struct rproc *rproc)
{
struct qcom_helios *helios = rproc->priv;
struct tzapp_helios_req helios_tz_req;
int ret;
helios_tz_req.tzapp_helios_cmd = HELIOS_RPROC_SHUTDOWN;
helios_tz_req.address_fw = 0;
helios_tz_req.size_fw = 0;
ret = helios_tzapp_comm(helios, &helios_tz_req);
if (ret || helios->cmd_status) {
/* Helios is not responding. So forcing S3 reset to power down Helios.
* It should be powered on in Start Sequence.
*/
pr_debug("Helios is not responding. Powerdown helios\n");
ret = helios_force_powerdown(helios);
if (ret) {
dev_err(helios->dev, "%s: Helios Power Down failed\n", __func__);
return ret;
}
}
pr_debug("Helios Shutdown is success!\n");
return ret; return ret;
} }
/** /**
* helios_stop() - Called by stop operation of remoteproc framework * helios_stop() - Called by stop operation of remoteproc framework
* Triggers a watchdog bite in helios to start ramdump collection * It can help to force restart or shutdown Helios based on recovery option.
* @rproc: struct containing private helios data. * @rproc: struct containing private helios data.
* *
* Return: always success * Return: success or TA response error code
*/ */
static int helios_stop(struct rproc *rproc) static int helios_stop(struct rproc *rproc)
{ {
@ -659,14 +818,18 @@ static int helios_stop(struct rproc *rproc)
/* In case of crash, STOP operation is dummy */ /* In case of crash, STOP operation is dummy */
if (rproc->state == RPROC_CRASHED) { if (rproc->state == RPROC_CRASHED) {
pr_err("Helios is crashed!. No need to do anything here! Collect ramdump directly.\n"); pr_err("Helios is crashed! Skip stop and collect ramdump directly.\n");
return ret; return ret;
} }
if (helios->is_ready) if (helios->is_ready) {
ret = helios_shutdown(rproc); if (rproc->recovery_disabled)
ret = helios_shutdown(rproc);
else
ret = helios_force_restart(rproc);
}
pr_info("Helios Shutdown is success\n"); pr_info("Helios Stop is %s\n", ret ? "failed" : "success");
return ret; return ret;
} }
@ -688,16 +851,16 @@ static int helios_reboot_notify(struct notifier_block *nb, unsigned long action,
if (action != SYS_RESTART) if (action != SYS_RESTART)
return NOTIFY_OK; return NOTIFY_OK;
pr_debug("System is going for reboot!. Powerdown helios.\n"); pr_debug("System is going for reboot!. Shutdown helios.\n");
helios_tz_req.tzapp_helios_cmd = HELIOS_RPROC_POWERDOWN; helios_tz_req.tzapp_helios_cmd = HELIOS_RPROC_SHUTDOWN;
helios_tz_req.address_fw = 0; helios_tz_req.address_fw = 0;
helios_tz_req.size_fw = 0; helios_tz_req.size_fw = 0;
ret = helios_tzapp_comm(helios, &helios_tz_req); ret = helios_tzapp_comm(helios, &helios_tz_req);
if (ret || helios->cmd_status) { if (ret || helios->cmd_status) {
dev_err(helios->dev, "%s: Helios Power Down failed\n", __func__); dev_err(helios->dev, "%s: Helios Shutdown failed\n", __func__);
return helios->cmd_status; return helios->cmd_status;
} }
pr_debug("Helios is powered down.\n"); pr_debug("Helios is Shutdown successfully.\n");
return NOTIFY_OK; return NOTIFY_OK;
} }
@ -733,6 +896,7 @@ static int rproc_helios_driver_probe(struct platform_device *pdev)
helios->ssr_name = ssr_name; helios->ssr_name = ssr_name;
helios->firmware_name = fw_name; helios->firmware_name = fw_name;
helios->dev = &pdev->dev; helios->dev = &pdev->dev;
helios->app_status = RESULT_FAILURE;
rproc->dump_conf = RPROC_COREDUMP_ENABLED; rproc->dump_conf = RPROC_COREDUMP_ENABLED;
rproc->recovery_disabled = true; rproc->recovery_disabled = true;
rproc->auto_boot = false; rproc->auto_boot = false;

View File

@ -0,0 +1,84 @@
/* SPDX-License-Identifier: GPL-2.0-only
*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
enum heliosapp_op {
LOAD_META_DATA,
TRANSFER_AND_AUTHENTICATE_FW,
COLLECT_RAMDUMP,
FORCE_RESTART,
SHUTDOWN,
FORCE_POWER_DOWN
};
static inline int32_t
helios_app_release(struct Object self)
{
return Object_invoke(self, Object_OP_release, 0, 0);
}
static inline int32_t
helios_app_retain(struct Object self)
{
return Object_invoke(self, Object_OP_retain, 0, 0);
}
static inline int32_t
helios_app_load_meta_data(struct Object self, const void *metadata_ptr,
size_t metadata_len)
{
union ObjectArg arg[1] = {{{0, 0}}};
arg[0].bi = (struct ObjectBufIn) { metadata_ptr, metadata_len * 1 };
return Object_invoke(self, LOAD_META_DATA, arg,
ObjectCounts_pack(1, 0, 0, 0));
}
static inline int32_t
helios_app_transfer_and_authenticate_fw(struct Object self,
const void *firmware_ptr, size_t firmware_len)
{
union ObjectArg arg[1] = {{{0, 0}}};
arg[0].bi = (struct ObjectBufIn) { firmware_ptr, firmware_len * 1 };
return Object_invoke(self, TRANSFER_AND_AUTHENTICATE_FW, arg,
ObjectCounts_pack(1, 0, 0, 0));
}
static inline int32_t
helios_app_collect_ramdump(struct Object self, void *ramdump_ptr,
size_t ramdump_len, size_t *ramdump_lenout)
{
int32_t result;
union ObjectArg arg[1] = {{{0, 0}}};
arg[0].b = (struct ObjectBuf) { ramdump_ptr, ramdump_len * 1 };
result = Object_invoke(self, COLLECT_RAMDUMP, arg,
ObjectCounts_pack(0, 1, 0, 0));
*ramdump_lenout = arg[0].b.size / 1;
return result;
}
static inline int32_t
helios_app_force_restart(struct Object self)
{
return Object_invoke(self, FORCE_RESTART, 0, 0);
}
static inline int32_t
helios_app_shutdown(struct Object self)
{
return Object_invoke(self, SHUTDOWN, 0, 0);
}
static inline int32_t
helios_app_force_power_down(struct Object self)
{
return Object_invoke(self, FORCE_POWER_DOWN, 0, 0);
}