Commit c6754d77 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'optee-fix-for-v6.16' of...

Merge tag 'optee-fix-for-v6.16' of https://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee into arm/fixes

A fix in the OP-TEE driver for v6.16

Fixing a sleep in atomic context in the FF-A notification callback by
adding a work queue to process in a non-atomic context.

* tag 'optee-fix-for-v6.16' of https://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee:
  optee: ffa: fix sleep in atomic context
parents f31824a6 312d02ad
Loading
Loading
Loading
Loading
+32 −9
Original line number Diff line number Diff line
@@ -728,12 +728,21 @@ static bool optee_ffa_exchange_caps(struct ffa_device *ffa_dev,
	return true;
}

static void notif_work_fn(struct work_struct *work)
{
	struct optee_ffa *optee_ffa = container_of(work, struct optee_ffa,
						   notif_work);
	struct optee *optee = container_of(optee_ffa, struct optee, ffa);

	optee_do_bottom_half(optee->ctx);
}

static void notif_callback(int notify_id, void *cb_data)
{
	struct optee *optee = cb_data;

	if (notify_id == optee->ffa.bottom_half_value)
		optee_do_bottom_half(optee->ctx);
		queue_work(optee->ffa.notif_wq, &optee->ffa.notif_work);
	else
		optee_notif_send(optee, notify_id);
}
@@ -817,9 +826,11 @@ static void optee_ffa_remove(struct ffa_device *ffa_dev)
	struct optee *optee = ffa_dev_get_drvdata(ffa_dev);
	u32 bottom_half_id = optee->ffa.bottom_half_value;

	if (bottom_half_id != U32_MAX)
	if (bottom_half_id != U32_MAX) {
		ffa_dev->ops->notifier_ops->notify_relinquish(ffa_dev,
							      bottom_half_id);
		destroy_workqueue(optee->ffa.notif_wq);
	}
	optee_remove_common(optee);

	mutex_destroy(&optee->ffa.mutex);
@@ -835,6 +846,13 @@ static int optee_ffa_async_notif_init(struct ffa_device *ffa_dev,
	u32 notif_id = 0;
	int rc;

	INIT_WORK(&optee->ffa.notif_work, notif_work_fn);
	optee->ffa.notif_wq = create_workqueue("optee_notification");
	if (!optee->ffa.notif_wq) {
		rc = -EINVAL;
		goto err;
	}

	while (true) {
		rc = ffa_dev->ops->notifier_ops->notify_request(ffa_dev,
								is_per_vcpu,
@@ -851,19 +869,24 @@ static int optee_ffa_async_notif_init(struct ffa_device *ffa_dev,
		 * notifications in that case.
		 */
		if (rc != -EACCES)
			return rc;
			goto err_wq;
		notif_id++;
		if (notif_id >= OPTEE_FFA_MAX_ASYNC_NOTIF_VALUE)
			return rc;
			goto err_wq;
	}
	optee->ffa.bottom_half_value = notif_id;

	rc = enable_async_notif(optee);
	if (rc < 0) {
		ffa_dev->ops->notifier_ops->notify_relinquish(ffa_dev,
							      notif_id);
	if (rc < 0)
		goto err_rel;

	return 0;
err_rel:
	ffa_dev->ops->notifier_ops->notify_relinquish(ffa_dev, notif_id);
err_wq:
	destroy_workqueue(optee->ffa.notif_wq);
err:
	optee->ffa.bottom_half_value = U32_MAX;
	}

	return rc;
}
+2 −0
Original line number Diff line number Diff line
@@ -165,6 +165,8 @@ struct optee_ffa {
	/* Serializes access to @global_ids */
	struct mutex mutex;
	struct rhashtable global_ids;
	struct workqueue_struct *notif_wq;
	struct work_struct notif_work;
};

struct optee;