--- /dev/null
+From aceeafefff736057e8f93f19bbfbef26abd94604 Mon Sep 17 00:00:00 2001
+From: Jens Wiklander <jens.wiklander@linaro.org>
+Date: Thu, 27 Jan 2022 15:29:39 +0100
+Subject: optee: use driver internal tee_context for some rpc
+
+From: Jens Wiklander <jens.wiklander@linaro.org>
+
+commit aceeafefff736057e8f93f19bbfbef26abd94604 upstream.
+
+Adds a driver private tee_context by moving the tee_context in struct
+optee_notif to struct optee. This tee_context was previously used when
+doing internal calls to secure world to deliver notification.
+
+The new driver internal tee_context is now also when allocating driver
+private shared memory. This decouples the shared memory object from its
+original tee_context. This is needed when the life time of such a memory
+allocation outlives the client tee_context.
+
+This patch fixes the problem described below:
+
+The addition of a shutdown hook by commit f25889f93184 ("optee: fix tee out
+of memory failure seen during kexec reboot") introduced a kernel shutdown
+regression that can be triggered after running the OP-TEE xtest suites.
+
+Once the shutdown hook is called it is not possible to communicate any more
+with the supplicant process because the system is not scheduling task any
+longer. Thus if the optee driver shutdown path receives a supplicant RPC
+request from the OP-TEE we will deadlock the kernel's shutdown.
+
+Fixes: f25889f93184 ("optee: fix tee out of memory failure seen during kexec reboot")
+Fixes: 217e0250cccb ("tee: use reference counting for tee_context")
+Reported-by: Lars Persson <larper@axis.com>
+Cc: stable@vger.kernel.org
+Reviewed-by: Sumit Garg <sumit.garg@linaro.org>
+[JW: backport to 5.16-stable + update commit message]
+Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tee/optee/core.c | 1
+ drivers/tee/optee/ffa_abi.c | 70 +++++++++++++++++++++-----------------
+ drivers/tee/optee/optee_private.h | 4 +-
+ drivers/tee/optee/smc_abi.c | 13 +++++--
+ 4 files changed, 54 insertions(+), 34 deletions(-)
+
+--- a/drivers/tee/optee/core.c
++++ b/drivers/tee/optee/core.c
+@@ -157,6 +157,7 @@ void optee_remove_common(struct optee *o
+ /* Unregister OP-TEE specific client devices on TEE bus */
+ optee_unregister_devices();
+
++ teedev_close_context(optee->ctx);
+ /*
+ * The two devices have to be unregistered before we can free the
+ * other resources.
+--- a/drivers/tee/optee/ffa_abi.c
++++ b/drivers/tee/optee/ffa_abi.c
+@@ -424,6 +424,7 @@ static struct tee_shm_pool_mgr *optee_ff
+ */
+
+ static void handle_ffa_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
++ struct optee *optee,
+ struct optee_msg_arg *arg)
+ {
+ struct tee_shm *shm;
+@@ -439,7 +440,7 @@ static void handle_ffa_rpc_func_cmd_shm_
+ shm = optee_rpc_cmd_alloc_suppl(ctx, arg->params[0].u.value.b);
+ break;
+ case OPTEE_RPC_SHM_TYPE_KERNEL:
+- shm = tee_shm_alloc(ctx, arg->params[0].u.value.b,
++ shm = tee_shm_alloc(optee->ctx, arg->params[0].u.value.b,
+ TEE_SHM_MAPPED | TEE_SHM_PRIV);
+ break;
+ default:
+@@ -493,14 +494,13 @@ err_bad_param:
+ }
+
+ static void handle_ffa_rpc_func_cmd(struct tee_context *ctx,
++ struct optee *optee,
+ struct optee_msg_arg *arg)
+ {
+- struct optee *optee = tee_get_drvdata(ctx->teedev);
+-
+ arg->ret_origin = TEEC_ORIGIN_COMMS;
+ switch (arg->cmd) {
+ case OPTEE_RPC_CMD_SHM_ALLOC:
+- handle_ffa_rpc_func_cmd_shm_alloc(ctx, arg);
++ handle_ffa_rpc_func_cmd_shm_alloc(ctx, optee, arg);
+ break;
+ case OPTEE_RPC_CMD_SHM_FREE:
+ handle_ffa_rpc_func_cmd_shm_free(ctx, optee, arg);
+@@ -510,12 +510,12 @@ static void handle_ffa_rpc_func_cmd(stru
+ }
+ }
+
+-static void optee_handle_ffa_rpc(struct tee_context *ctx, u32 cmd,
+- struct optee_msg_arg *arg)
++static void optee_handle_ffa_rpc(struct tee_context *ctx, struct optee *optee,
++ u32 cmd, struct optee_msg_arg *arg)
+ {
+ switch (cmd) {
+ case OPTEE_FFA_YIELDING_CALL_RETURN_RPC_CMD:
+- handle_ffa_rpc_func_cmd(ctx, arg);
++ handle_ffa_rpc_func_cmd(ctx, optee, arg);
+ break;
+ case OPTEE_FFA_YIELDING_CALL_RETURN_INTERRUPT:
+ /* Interrupt delivered by now */
+@@ -582,7 +582,7 @@ static int optee_ffa_yielding_call(struc
+ * above.
+ */
+ cond_resched();
+- optee_handle_ffa_rpc(ctx, data->data1, rpc_arg);
++ optee_handle_ffa_rpc(ctx, optee, data->data1, rpc_arg);
+ cmd = OPTEE_FFA_YIELDING_CALL_RESUME;
+ data->data0 = cmd;
+ data->data1 = 0;
+@@ -802,7 +802,9 @@ static int optee_ffa_probe(struct ffa_de
+ {
+ const struct ffa_dev_ops *ffa_ops;
+ unsigned int rpc_arg_count;
++ struct tee_shm_pool *pool;
+ struct tee_device *teedev;
++ struct tee_context *ctx;
+ struct optee *optee;
+ int rc;
+
+@@ -822,12 +824,12 @@ static int optee_ffa_probe(struct ffa_de
+ if (!optee)
+ return -ENOMEM;
+
+- optee->pool = optee_ffa_config_dyn_shm();
+- if (IS_ERR(optee->pool)) {
+- rc = PTR_ERR(optee->pool);
+- optee->pool = NULL;
+- goto err;
++ pool = optee_ffa_config_dyn_shm();
++ if (IS_ERR(pool)) {
++ rc = PTR_ERR(pool);
++ goto err_free_optee;
+ }
++ optee->pool = pool;
+
+ optee->ops = &optee_ffa_ops;
+ optee->ffa.ffa_dev = ffa_dev;
+@@ -838,7 +840,7 @@ static int optee_ffa_probe(struct ffa_de
+ optee);
+ if (IS_ERR(teedev)) {
+ rc = PTR_ERR(teedev);
+- goto err;
++ goto err_free_pool;
+ }
+ optee->teedev = teedev;
+
+@@ -846,46 +848,54 @@ static int optee_ffa_probe(struct ffa_de
+ optee);
+ if (IS_ERR(teedev)) {
+ rc = PTR_ERR(teedev);
+- goto err;
++ goto err_unreg_teedev;
+ }
+ optee->supp_teedev = teedev;
+
+ rc = tee_device_register(optee->teedev);
+ if (rc)
+- goto err;
++ goto err_unreg_supp_teedev;
+
+ rc = tee_device_register(optee->supp_teedev);
+ if (rc)
+- goto err;
++ goto err_unreg_supp_teedev;
+
+ rc = rhashtable_init(&optee->ffa.global_ids, &shm_rhash_params);
+ if (rc)
+- goto err;
++ goto err_unreg_supp_teedev;
+ mutex_init(&optee->ffa.mutex);
+ mutex_init(&optee->call_queue.mutex);
+ INIT_LIST_HEAD(&optee->call_queue.waiters);
+ optee_wait_queue_init(&optee->wait_queue);
+ optee_supp_init(&optee->supp);
+ ffa_dev_set_drvdata(ffa_dev, optee);
++ ctx = teedev_open(optee->teedev);
++ if (IS_ERR(ctx))
++ goto err_rhashtable_free;
++ optee->ctx = ctx;
++
+
+ rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES);
+- if (rc) {
+- optee_ffa_remove(ffa_dev);
+- return rc;
+- }
++ if (rc)
++ goto err_unregister_devices;
+
+ pr_info("initialized driver\n");
+ return 0;
+-err:
+- /*
+- * tee_device_unregister() is safe to call even if the
+- * devices hasn't been registered with
+- * tee_device_register() yet.
+- */
++
++err_unregister_devices:
++ optee_unregister_devices();
++ teedev_close_context(ctx);
++err_rhashtable_free:
++ rhashtable_free_and_destroy(&optee->ffa.global_ids, rh_free_fn, NULL);
++ optee_supp_uninit(&optee->supp);
++ mutex_destroy(&optee->call_queue.mutex);
++err_unreg_supp_teedev:
+ tee_device_unregister(optee->supp_teedev);
++err_unreg_teedev:
+ tee_device_unregister(optee->teedev);
+- if (optee->pool)
+- tee_shm_pool_free(optee->pool);
++err_free_pool:
++ tee_shm_pool_free(pool);
++err_free_optee:
+ kfree(optee);
+ return rc;
+ }
+--- a/drivers/tee/optee/optee_private.h
++++ b/drivers/tee/optee/optee_private.h
+@@ -123,9 +123,10 @@ struct optee_ops {
+ /**
+ * struct optee - main service struct
+ * @supp_teedev: supplicant device
++ * @teedev: client device
+ * @ops: internal callbacks for different ways to reach secure
+ * world
+- * @teedev: client device
++ * @ctx: driver internal TEE context
+ * @smc: specific to SMC ABI
+ * @ffa: specific to FF-A ABI
+ * @call_queue: queue of threads waiting to call @invoke_fn
+@@ -142,6 +143,7 @@ struct optee {
+ struct tee_device *supp_teedev;
+ struct tee_device *teedev;
+ const struct optee_ops *ops;
++ struct tee_context *ctx;
+ union {
+ struct optee_smc smc;
+ struct optee_ffa ffa;
+--- a/drivers/tee/optee/smc_abi.c
++++ b/drivers/tee/optee/smc_abi.c
+@@ -608,6 +608,7 @@ static void handle_rpc_func_cmd_shm_free
+ }
+
+ static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
++ struct optee *optee,
+ struct optee_msg_arg *arg,
+ struct optee_call_ctx *call_ctx)
+ {
+@@ -637,7 +638,8 @@ static void handle_rpc_func_cmd_shm_allo
+ shm = optee_rpc_cmd_alloc_suppl(ctx, sz);
+ break;
+ case OPTEE_RPC_SHM_TYPE_KERNEL:
+- shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED | TEE_SHM_PRIV);
++ shm = tee_shm_alloc(optee->ctx, sz,
++ TEE_SHM_MAPPED | TEE_SHM_PRIV);
+ break;
+ default:
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+@@ -733,7 +735,7 @@ static void handle_rpc_func_cmd(struct t
+ switch (arg->cmd) {
+ case OPTEE_RPC_CMD_SHM_ALLOC:
+ free_pages_list(call_ctx);
+- handle_rpc_func_cmd_shm_alloc(ctx, arg, call_ctx);
++ handle_rpc_func_cmd_shm_alloc(ctx, optee, arg, call_ctx);
+ break;
+ case OPTEE_RPC_CMD_SHM_FREE:
+ handle_rpc_func_cmd_shm_free(ctx, arg);
+@@ -762,7 +764,7 @@ static void optee_handle_rpc(struct tee_
+
+ switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) {
+ case OPTEE_SMC_RPC_FUNC_ALLOC:
+- shm = tee_shm_alloc(ctx, param->a1,
++ shm = tee_shm_alloc(optee->ctx, param->a1,
+ TEE_SHM_MAPPED | TEE_SHM_PRIV);
+ if (!IS_ERR(shm) && !tee_shm_get_pa(shm, 0, &pa)) {
+ reg_pair_from_64(¶m->a1, ¶m->a2, pa);
+@@ -1207,6 +1209,7 @@ static int optee_probe(struct platform_d
+ struct optee *optee = NULL;
+ void *memremaped_shm = NULL;
+ struct tee_device *teedev;
++ struct tee_context *ctx;
+ u32 sec_caps;
+ int rc;
+
+@@ -1284,6 +1287,10 @@ static int optee_probe(struct platform_d
+ optee_supp_init(&optee->supp);
+ optee->smc.memremaped_shm = memremaped_shm;
+ optee->pool = pool;
++ ctx = teedev_open(optee->teedev);
++ if (IS_ERR(ctx))
++ goto err;
++ optee->ctx = ctx;
+
+ /*
+ * Ensure that there are no pre-existing shm objects before enabling