brintos

brintos / linux-shallow public Read only

0
0
Text · 16.3 KiB · 56fc63e Raw
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