633 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2019-2021 Linaro Ltd.4 */5 6#include <linux/io.h>7#include <linux/of.h>8#include <linux/of_address.h>9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/mutex.h>12#include <linux/platform_device.h>13#include <linux/slab.h>14#include <linux/tee_drv.h>15#include <linux/uuid.h>16#include <uapi/linux/tee.h>17 18#include "../common.h"19 20#define SCMI_OPTEE_MAX_MSG_SIZE 12821 22enum scmi_optee_pta_cmd {23 /*24 * PTA_SCMI_CMD_CAPABILITIES - Get channel capabilities25 *26 * [out] value[0].a: Capability bit mask (enum pta_scmi_caps)27 * [out] value[0].b: Extended capabilities or 028 */29 PTA_SCMI_CMD_CAPABILITIES = 0,30 31 /*32 * PTA_SCMI_CMD_PROCESS_SMT_CHANNEL - Process SCMI message in SMT buffer33 *34 * [in] value[0].a: Channel handle35 *36 * Shared memory used for SCMI message/response exhange is expected37 * already identified and bound to channel handle in both SCMI agent38 * and SCMI server (OP-TEE) parts.39 * The memory uses SMT header to carry SCMI meta-data (protocol ID and40 * protocol message ID).41 */42 PTA_SCMI_CMD_PROCESS_SMT_CHANNEL = 1,43 44 /*45 * PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE - Process SMT/SCMI message46 *47 * [in] value[0].a: Channel handle48 * [in/out] memref[1]: Message/response buffer (SMT and SCMI payload)49 *50 * Shared memory used for SCMI message/response is a SMT buffer51 * referenced by param[1]. It shall be 128 bytes large to fit response52 * payload whatever message playload size.53 * The memory uses SMT header to carry SCMI meta-data (protocol ID and54 * protocol message ID).55 */56 PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE = 2,57 58 /*59 * PTA_SCMI_CMD_GET_CHANNEL - Get channel handle60 *61 * SCMI shm information are 0 if agent expects to use OP-TEE regular SHM62 *63 * [in] value[0].a: Channel identifier64 * [out] value[0].a: Returned channel handle65 * [in] value[0].b: Requested capabilities mask (enum pta_scmi_caps)66 */67 PTA_SCMI_CMD_GET_CHANNEL = 3,68 69 /*70 * PTA_SCMI_CMD_PROCESS_MSG_CHANNEL - Process SCMI message in a MSG71 * buffer pointed by memref parameters72 *73 * [in] value[0].a: Channel handle74 * [in] memref[1]: Message buffer (MSG and SCMI payload)75 * [out] memref[2]: Response buffer (MSG and SCMI payload)76 *77 * Shared memories used for SCMI message/response are MSG buffers78 * referenced by param[1] and param[2]. MSG transport protocol79 * uses a 32bit header to carry SCMI meta-data (protocol ID and80 * protocol message ID) followed by the effective SCMI message81 * payload.82 */83 PTA_SCMI_CMD_PROCESS_MSG_CHANNEL = 4,84};85 86/*87 * OP-TEE SCMI service capabilities bit flags (32bit)88 *89 * PTA_SCMI_CAPS_SMT_HEADER90 * When set, OP-TEE supports command using SMT header protocol (SCMI shmem) in91 * shared memory buffers to carry SCMI protocol synchronisation information.92 *93 * PTA_SCMI_CAPS_MSG_HEADER94 * When set, OP-TEE supports command using MSG header protocol in an OP-TEE95 * shared memory to carry SCMI protocol synchronisation information and SCMI96 * message payload.97 */98#define PTA_SCMI_CAPS_NONE 099#define PTA_SCMI_CAPS_SMT_HEADER BIT(0)100#define PTA_SCMI_CAPS_MSG_HEADER BIT(1)101#define PTA_SCMI_CAPS_MASK (PTA_SCMI_CAPS_SMT_HEADER | \102 PTA_SCMI_CAPS_MSG_HEADER)103 104/**105 * struct scmi_optee_channel - Description of an OP-TEE SCMI channel106 *107 * @channel_id: OP-TEE channel ID used for this transport108 * @tee_session: TEE session identifier109 * @caps: OP-TEE SCMI channel capabilities110 * @rx_len: Response size111 * @mu: Mutex protection on channel access112 * @cinfo: SCMI channel information113 * @req: union for SCMI interface114 * @req.shmem: Virtual base address of the shared memory115 * @req.msg: Shared memory protocol handle for SCMI request and116 * synchronous response117 * @tee_shm: TEE shared memory handle @req or NULL if using IOMEM shmem118 * @link: Reference in agent's channel list119 */120struct scmi_optee_channel {121 u32 channel_id;122 u32 tee_session;123 u32 caps;124 u32 rx_len;125 struct mutex mu;126 struct scmi_chan_info *cinfo;127 union {128 struct scmi_shared_mem __iomem *shmem;129 struct scmi_msg_payld *msg;130 } req;131 struct tee_shm *tee_shm;132 struct list_head link;133};134 135/**136 * struct scmi_optee_agent - OP-TEE transport private data137 *138 * @dev: Device used for communication with TEE139 * @tee_ctx: TEE context used for communication140 * @caps: Supported channel capabilities141 * @mu: Mutex for protection of @channel_list142 * @channel_list: List of all created channels for the agent143 */144struct scmi_optee_agent {145 struct device *dev;146 struct tee_context *tee_ctx;147 u32 caps;148 struct mutex mu;149 struct list_head channel_list;150};151 152static struct scmi_transport_core_operations *core;153 154/* There can be only 1 SCMI service in OP-TEE we connect to */155static struct scmi_optee_agent *scmi_optee_private;156 157/* Open a session toward SCMI OP-TEE service with REE_KERNEL identity */158static int open_session(struct scmi_optee_agent *agent, u32 *tee_session)159{160 struct device *dev = agent->dev;161 struct tee_client_device *scmi_pta = to_tee_client_device(dev);162 struct tee_ioctl_open_session_arg arg = { };163 int ret;164 165 memcpy(arg.uuid, scmi_pta->id.uuid.b, TEE_IOCTL_UUID_LEN);166 arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;167 168 ret = tee_client_open_session(agent->tee_ctx, &arg, NULL);169 if (ret < 0 || arg.ret) {170 dev_err(dev, "Can't open tee session: %d / %#x\n", ret, arg.ret);171 return -EOPNOTSUPP;172 }173 174 *tee_session = arg.session;175 176 return 0;177}178 179static void close_session(struct scmi_optee_agent *agent, u32 tee_session)180{181 tee_client_close_session(agent->tee_ctx, tee_session);182}183 184static int get_capabilities(struct scmi_optee_agent *agent)185{186 struct tee_ioctl_invoke_arg arg = { };187 struct tee_param param[1] = { };188 u32 caps;189 u32 tee_session;190 int ret;191 192 ret = open_session(agent, &tee_session);193 if (ret)194 return ret;195 196 arg.func = PTA_SCMI_CMD_CAPABILITIES;197 arg.session = tee_session;198 arg.num_params = 1;199 200 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;201 202 ret = tee_client_invoke_func(agent->tee_ctx, &arg, param);203 204 close_session(agent, tee_session);205 206 if (ret < 0 || arg.ret) {207 dev_err(agent->dev, "Can't get capabilities: %d / %#x\n", ret, arg.ret);208 return -EOPNOTSUPP;209 }210 211 caps = param[0].u.value.a;212 213 if (!(caps & (PTA_SCMI_CAPS_SMT_HEADER | PTA_SCMI_CAPS_MSG_HEADER))) {214 dev_err(agent->dev, "OP-TEE SCMI PTA doesn't support SMT and MSG\n");215 return -EOPNOTSUPP;216 }217 218 agent->caps = caps;219 220 return 0;221}222 223static int get_channel(struct scmi_optee_channel *channel)224{225 struct device *dev = scmi_optee_private->dev;226 struct tee_ioctl_invoke_arg arg = { };227 struct tee_param param[1] = { };228 unsigned int caps = 0;229 int ret;230 231 if (channel->tee_shm)232 caps = PTA_SCMI_CAPS_MSG_HEADER;233 else234 caps = PTA_SCMI_CAPS_SMT_HEADER;235 236 arg.func = PTA_SCMI_CMD_GET_CHANNEL;237 arg.session = channel->tee_session;238 arg.num_params = 1;239 240 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;241 param[0].u.value.a = channel->channel_id;242 param[0].u.value.b = caps;243 244 ret = tee_client_invoke_func(scmi_optee_private->tee_ctx, &arg, param);245 246 if (ret || arg.ret) {247 dev_err(dev, "Can't get channel with caps %#x: %d / %#x\n", caps, ret, arg.ret);248 return -EOPNOTSUPP;249 }250 251 /* From now on use channel identifer provided by OP-TEE SCMI service */252 channel->channel_id = param[0].u.value.a;253 channel->caps = caps;254 255 return 0;256}257 258static int invoke_process_smt_channel(struct scmi_optee_channel *channel)259{260 struct tee_ioctl_invoke_arg arg = {261 .func = PTA_SCMI_CMD_PROCESS_SMT_CHANNEL,262 .session = channel->tee_session,263 .num_params = 1,264 };265 struct tee_param param[1] = { };266 int ret;267 268 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;269 param[0].u.value.a = channel->channel_id;270 271 ret = tee_client_invoke_func(scmi_optee_private->tee_ctx, &arg, param);272 if (ret < 0 || arg.ret) {273 dev_err(scmi_optee_private->dev, "Can't invoke channel %u: %d / %#x\n",274 channel->channel_id, ret, arg.ret);275 return -EIO;276 }277 278 return 0;279}280 281static int invoke_process_msg_channel(struct scmi_optee_channel *channel, size_t msg_size)282{283 struct tee_ioctl_invoke_arg arg = {284 .func = PTA_SCMI_CMD_PROCESS_MSG_CHANNEL,285 .session = channel->tee_session,286 .num_params = 3,287 };288 struct tee_param param[3] = { };289 int ret;290 291 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;292 param[0].u.value.a = channel->channel_id;293 294 param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;295 param[1].u.memref.shm = channel->tee_shm;296 param[1].u.memref.size = msg_size;297 298 param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;299 param[2].u.memref.shm = channel->tee_shm;300 param[2].u.memref.size = SCMI_OPTEE_MAX_MSG_SIZE;301 302 ret = tee_client_invoke_func(scmi_optee_private->tee_ctx, &arg, param);303 if (ret < 0 || arg.ret) {304 dev_err(scmi_optee_private->dev, "Can't invoke channel %u: %d / %#x\n",305 channel->channel_id, ret, arg.ret);306 return -EIO;307 }308 309 /* Save response size */310 channel->rx_len = param[2].u.memref.size;311 312 return 0;313}314 315static bool scmi_optee_chan_available(struct device_node *of_node, int idx)316{317 u32 channel_id;318 319 return !of_property_read_u32_index(of_node, "linaro,optee-channel-id",320 idx, &channel_id);321}322 323static void scmi_optee_clear_channel(struct scmi_chan_info *cinfo)324{325 struct scmi_optee_channel *channel = cinfo->transport_info;326 327 if (!channel->tee_shm)328 core->shmem->clear_channel(channel->req.shmem);329}330 331static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *channel)332{333 const size_t msg_size = SCMI_OPTEE_MAX_MSG_SIZE;334 void *shbuf;335 336 channel->tee_shm = tee_shm_alloc_kernel_buf(scmi_optee_private->tee_ctx, msg_size);337 if (IS_ERR(channel->tee_shm)) {338 dev_err(channel->cinfo->dev, "shmem allocation failed\n");339 return -ENOMEM;340 }341 342 shbuf = tee_shm_get_va(channel->tee_shm, 0);343 memset(shbuf, 0, msg_size);344 channel->req.msg = shbuf;345 channel->rx_len = msg_size;346 347 return 0;348}349 350static int setup_static_shmem(struct device *dev, struct scmi_chan_info *cinfo,351 struct scmi_optee_channel *channel)352{353 channel->req.shmem = core->shmem->setup_iomap(cinfo, dev, true, NULL);354 if (IS_ERR(channel->req.shmem))355 return PTR_ERR(channel->req.shmem);356 357 return 0;358}359 360static int setup_shmem(struct device *dev, struct scmi_chan_info *cinfo,361 struct scmi_optee_channel *channel)362{363 if (of_property_present(cinfo->dev->of_node, "shmem"))364 return setup_static_shmem(dev, cinfo, channel);365 else366 return setup_dynamic_shmem(dev, channel);367}368 369static int scmi_optee_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, bool tx)370{371 struct scmi_optee_channel *channel;372 uint32_t channel_id;373 int ret;374 375 if (!tx)376 return -ENODEV;377 378 channel = devm_kzalloc(dev, sizeof(*channel), GFP_KERNEL);379 if (!channel)380 return -ENOMEM;381 382 ret = of_property_read_u32_index(cinfo->dev->of_node, "linaro,optee-channel-id",383 0, &channel_id);384 if (ret)385 return ret;386 387 cinfo->transport_info = channel;388 channel->cinfo = cinfo;389 channel->channel_id = channel_id;390 mutex_init(&channel->mu);391 392 ret = setup_shmem(dev, cinfo, channel);393 if (ret)394 return ret;395 396 ret = open_session(scmi_optee_private, &channel->tee_session);397 if (ret)398 goto err_free_shm;399 400 ret = tee_client_system_session(scmi_optee_private->tee_ctx, channel->tee_session);401 if (ret)402 dev_warn(dev, "Could not switch to system session, do best effort\n");403 404 ret = get_channel(channel);405 if (ret)406 goto err_close_sess;407 408 /* Enable polling */409 cinfo->no_completion_irq = true;410 411 mutex_lock(&scmi_optee_private->mu);412 list_add(&channel->link, &scmi_optee_private->channel_list);413 mutex_unlock(&scmi_optee_private->mu);414 415 return 0;416 417err_close_sess:418 close_session(scmi_optee_private, channel->tee_session);419err_free_shm:420 if (channel->tee_shm)421 tee_shm_free(channel->tee_shm);422 423 return ret;424}425 426static int scmi_optee_chan_free(int id, void *p, void *data)427{428 struct scmi_chan_info *cinfo = p;429 struct scmi_optee_channel *channel = cinfo->transport_info;430 431 /*432 * Different protocols might share the same chan info, so a previous433 * call might have already freed the structure.434 */435 if (!channel)436 return 0;437 438 mutex_lock(&scmi_optee_private->mu);439 list_del(&channel->link);440 mutex_unlock(&scmi_optee_private->mu);441 442 close_session(scmi_optee_private, channel->tee_session);443 444 if (channel->tee_shm) {445 tee_shm_free(channel->tee_shm);446 channel->tee_shm = NULL;447 }448 449 cinfo->transport_info = NULL;450 channel->cinfo = NULL;451 452 return 0;453}454 455static int scmi_optee_send_message(struct scmi_chan_info *cinfo,456 struct scmi_xfer *xfer)457{458 struct scmi_optee_channel *channel = cinfo->transport_info;459 int ret;460 461 mutex_lock(&channel->mu);462 463 if (channel->tee_shm) {464 core->msg->tx_prepare(channel->req.msg, xfer);465 ret = invoke_process_msg_channel(channel,466 core->msg->command_size(xfer));467 } else {468 core->shmem->tx_prepare(channel->req.shmem, xfer, cinfo);469 ret = invoke_process_smt_channel(channel);470 }471 472 if (ret)473 mutex_unlock(&channel->mu);474 475 return ret;476}477 478static void scmi_optee_fetch_response(struct scmi_chan_info *cinfo,479 struct scmi_xfer *xfer)480{481 struct scmi_optee_channel *channel = cinfo->transport_info;482 483 if (channel->tee_shm)484 core->msg->fetch_response(channel->req.msg,485 channel->rx_len, xfer);486 else487 core->shmem->fetch_response(channel->req.shmem, xfer);488}489 490static void scmi_optee_mark_txdone(struct scmi_chan_info *cinfo, int ret,491 struct scmi_xfer *__unused)492{493 struct scmi_optee_channel *channel = cinfo->transport_info;494 495 mutex_unlock(&channel->mu);496}497 498static struct scmi_transport_ops scmi_optee_ops = {499 .chan_available = scmi_optee_chan_available,500 .chan_setup = scmi_optee_chan_setup,501 .chan_free = scmi_optee_chan_free,502 .send_message = scmi_optee_send_message,503 .mark_txdone = scmi_optee_mark_txdone,504 .fetch_response = scmi_optee_fetch_response,505 .clear_channel = scmi_optee_clear_channel,506};507 508static int scmi_optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)509{510 return ver->impl_id == TEE_IMPL_ID_OPTEE;511}512 513static struct scmi_desc scmi_optee_desc = {514 .ops = &scmi_optee_ops,515 .max_rx_timeout_ms = 30,516 .max_msg = 20,517 .max_msg_size = SCMI_OPTEE_MAX_MSG_SIZE,518 .sync_cmds_completed_on_ret = true,519};520 521static const struct of_device_id scmi_of_match[] = {522 { .compatible = "linaro,scmi-optee" },523 { /* Sentinel */ },524};525 526DEFINE_SCMI_TRANSPORT_DRIVER(scmi_optee, scmi_optee_driver, scmi_optee_desc,527 scmi_of_match, core);528 529static int scmi_optee_service_probe(struct device *dev)530{531 struct scmi_optee_agent *agent;532 struct tee_context *tee_ctx;533 int ret;534 535 /* Only one SCMI OP-TEE device allowed */536 if (scmi_optee_private) {537 dev_err(dev, "An SCMI OP-TEE device was already initialized: only one allowed\n");538 return -EBUSY;539 }540 541 tee_ctx = tee_client_open_context(NULL, scmi_optee_ctx_match, NULL, NULL);542 if (IS_ERR(tee_ctx))543 return -ENODEV;544 545 agent = devm_kzalloc(dev, sizeof(*agent), GFP_KERNEL);546 if (!agent) {547 ret = -ENOMEM;548 goto err;549 }550 551 agent->dev = dev;552 agent->tee_ctx = tee_ctx;553 INIT_LIST_HEAD(&agent->channel_list);554 mutex_init(&agent->mu);555 556 ret = get_capabilities(agent);557 if (ret)558 goto err;559 560 /* Ensure agent resources are all visible before scmi_optee_private is */561 smp_mb();562 scmi_optee_private = agent;563 564 ret = platform_driver_register(&scmi_optee_driver);565 if (ret) {566 scmi_optee_private = NULL;567 goto err;568 }569 570 return 0;571 572err:573 tee_client_close_context(tee_ctx);574 575 return ret;576}577 578static int scmi_optee_service_remove(struct device *dev)579{580 struct scmi_optee_agent *agent = scmi_optee_private;581 582 if (!scmi_optee_private)583 return -EINVAL;584 585 platform_driver_unregister(&scmi_optee_driver);586 587 if (!list_empty(&scmi_optee_private->channel_list))588 return -EBUSY;589 590 /* Ensure cleared reference is visible before resources are released */591 smp_store_mb(scmi_optee_private, NULL);592 593 tee_client_close_context(agent->tee_ctx);594 595 return 0;596}597 598static const struct tee_client_device_id scmi_optee_service_id[] = {599 {600 UUID_INIT(0xa8cfe406, 0xd4f5, 0x4a2e,601 0x9f, 0x8d, 0xa2, 0x5d, 0xc7, 0x54, 0xc0, 0x99)602 },603 { }604};605 606MODULE_DEVICE_TABLE(tee, scmi_optee_service_id);607 608static struct tee_client_driver scmi_optee_service_driver = {609 .id_table = scmi_optee_service_id,610 .driver = {611 .name = "scmi-optee",612 .bus = &tee_bus_type,613 .probe = scmi_optee_service_probe,614 .remove = scmi_optee_service_remove,615 },616};617 618static int __init scmi_transport_optee_init(void)619{620 return driver_register(&scmi_optee_service_driver.driver);621}622module_init(scmi_transport_optee_init);623 624static void __exit scmi_transport_optee_exit(void)625{626 driver_unregister(&scmi_optee_service_driver.driver);627}628module_exit(scmi_transport_optee_exit);629 630MODULE_AUTHOR("Etienne Carriere <etienne.carriere@foss.st.com>");631MODULE_DESCRIPTION("SCMI OPTEE Transport driver");632MODULE_LICENSE("GPL");633