Skip to content

Commit d0476a5

Browse files
committed
optee: ffa_abi: add asynchronous notifications
Adds support for asynchronous notifications from OP-TEE in secure world when communicating via FF-A. In principle from OP-TEE and kernel driver point of view this works in the same way as for the SMC ABI based implementation. The OP-TEE FF-A ABI is expanded in OPTEE_FFA_EXCHANGE_CAPABILITIES with the capability OPTEE_FFA_SEC_CAP_ASYNC_NOTIF to indicate that OP-TEE supports asynchronous notifications. OPTEE_FFA_ENABLE_ASYNC_NOTIF is also added to tell that the driver has successfully initialized these notifications. Notification capability is negotiated while the driver is initialized. If both sides supports these notifications then they are enabled. The notification concept in this driver is merged with the FF-A concept, the lower 64 values are reserved for FF-A as asynchronous notifications while the synchronous notifications use the higher values. So a FF-A notification has to be allocated for each discrete asynchronous notification value needed. Only one asynchronous notification value is used at the moment, the "do bottom half" notification. Signed-off-by: Jens Wiklander <[email protected]> Reviewed-by: Sumit Garg <[email protected]> Tested-by: Sudeep Holla <[email protected]>
1 parent 6dea635 commit d0476a5

File tree

3 files changed

+117
-8
lines changed

3 files changed

+117
-8
lines changed

drivers/tee/optee/ffa_abi.c

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/*
3-
* Copyright (c) 2021, Linaro Limited
3+
* Copyright (c) 2021, 2023 Linaro Limited
44
*/
55

66
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -695,7 +695,8 @@ static bool optee_ffa_api_is_compatbile(struct ffa_device *ffa_dev,
695695
static bool optee_ffa_exchange_caps(struct ffa_device *ffa_dev,
696696
const struct ffa_ops *ops,
697697
u32 *sec_caps,
698-
unsigned int *rpc_param_count)
698+
unsigned int *rpc_param_count,
699+
unsigned int *max_notif_value)
699700
{
700701
struct ffa_send_direct_data data = { OPTEE_FFA_EXCHANGE_CAPABILITIES };
701702
int rc;
@@ -712,10 +713,39 @@ static bool optee_ffa_exchange_caps(struct ffa_device *ffa_dev,
712713

713714
*rpc_param_count = (u8)data.data1;
714715
*sec_caps = data.data2;
716+
if (data.data3)
717+
*max_notif_value = data.data3;
718+
else
719+
*max_notif_value = OPTEE_DEFAULT_MAX_NOTIF_VALUE;
715720

716721
return true;
717722
}
718723

724+
static void notif_callback(int notify_id, void *cb_data)
725+
{
726+
struct optee *optee = cb_data;
727+
728+
if (notify_id == optee->ffa.bottom_half_value)
729+
optee_do_bottom_half(optee->ctx);
730+
else
731+
optee_notif_send(optee, notify_id);
732+
}
733+
734+
static int enable_async_notif(struct optee *optee)
735+
{
736+
struct ffa_device *ffa_dev = optee->ffa.ffa_dev;
737+
struct ffa_send_direct_data data = {
738+
.data0 = OPTEE_FFA_ENABLE_ASYNC_NOTIF,
739+
.data1 = optee->ffa.bottom_half_value,
740+
};
741+
int rc;
742+
743+
rc = ffa_dev->ops->msg_ops->sync_send_receive(ffa_dev, &data);
744+
if (rc)
745+
return rc;
746+
return data.data0;
747+
}
748+
719749
static void optee_ffa_get_version(struct tee_device *teedev,
720750
struct tee_ioctl_version_data *vers)
721751
{
@@ -778,7 +808,11 @@ static const struct optee_ops optee_ffa_ops = {
778808
static void optee_ffa_remove(struct ffa_device *ffa_dev)
779809
{
780810
struct optee *optee = ffa_dev_get_drvdata(ffa_dev);
811+
u32 bottom_half_id = optee->ffa.bottom_half_value;
781812

813+
if (bottom_half_id != U32_MAX)
814+
ffa_dev->ops->notifier_ops->notify_relinquish(ffa_dev,
815+
bottom_half_id);
782816
optee_remove_common(optee);
783817

784818
mutex_destroy(&optee->ffa.mutex);
@@ -787,9 +821,51 @@ static void optee_ffa_remove(struct ffa_device *ffa_dev)
787821
kfree(optee);
788822
}
789823

824+
static int optee_ffa_async_notif_init(struct ffa_device *ffa_dev,
825+
struct optee *optee)
826+
{
827+
bool is_per_vcpu = false;
828+
u32 notif_id = 0;
829+
int rc;
830+
831+
while (true) {
832+
rc = ffa_dev->ops->notifier_ops->notify_request(ffa_dev,
833+
is_per_vcpu,
834+
notif_callback,
835+
optee,
836+
notif_id);
837+
if (!rc)
838+
break;
839+
/*
840+
* -EACCES means that the notification ID was
841+
* already bound, try the next one as long as we
842+
* haven't reached the max. Any other error is a
843+
* permanent error, so skip asynchronous
844+
* notifications in that case.
845+
*/
846+
if (rc != -EACCES)
847+
return rc;
848+
notif_id++;
849+
if (notif_id >= OPTEE_FFA_MAX_ASYNC_NOTIF_VALUE)
850+
return rc;
851+
}
852+
optee->ffa.bottom_half_value = notif_id;
853+
854+
rc = enable_async_notif(optee);
855+
if (rc < 0) {
856+
ffa_dev->ops->notifier_ops->notify_relinquish(ffa_dev,
857+
notif_id);
858+
optee->ffa.bottom_half_value = U32_MAX;
859+
}
860+
861+
return rc;
862+
}
863+
790864
static int optee_ffa_probe(struct ffa_device *ffa_dev)
791865
{
866+
const struct ffa_notifier_ops *notif_ops;
792867
const struct ffa_ops *ffa_ops;
868+
unsigned int max_notif_value;
793869
unsigned int rpc_param_count;
794870
struct tee_shm_pool *pool;
795871
struct tee_device *teedev;
@@ -800,12 +876,13 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
800876
int rc;
801877

802878
ffa_ops = ffa_dev->ops;
879+
notif_ops = ffa_ops->notifier_ops;
803880

804881
if (!optee_ffa_api_is_compatbile(ffa_dev, ffa_ops))
805882
return -EINVAL;
806883

807884
if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps,
808-
&rpc_param_count))
885+
&rpc_param_count, &max_notif_value))
809886
return -EINVAL;
810887
if (sec_caps & OPTEE_FFA_SEC_CAP_ARG_OFFSET)
811888
arg_cache_flags |= OPTEE_SHM_ARG_SHARED;
@@ -823,6 +900,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
823900

824901
optee->ops = &optee_ffa_ops;
825902
optee->ffa.ffa_dev = ffa_dev;
903+
optee->ffa.bottom_half_value = U32_MAX;
826904
optee->rpc_param_count = rpc_param_count;
827905

828906
teedev = tee_device_alloc(&optee_ffa_clnt_desc, NULL, optee->pool,
@@ -866,6 +944,12 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
866944
rc = optee_notif_init(optee, OPTEE_DEFAULT_MAX_NOTIF_VALUE);
867945
if (rc)
868946
goto err_close_ctx;
947+
if (sec_caps & OPTEE_FFA_SEC_CAP_ASYNC_NOTIF) {
948+
rc = optee_ffa_async_notif_init(ffa_dev, optee);
949+
if (rc < 0)
950+
pr_err("Failed to initialize async notifications: %d",
951+
rc);
952+
}
869953

870954
rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES);
871955
if (rc)
@@ -876,6 +960,9 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
876960

877961
err_unregister_devices:
878962
optee_unregister_devices();
963+
if (optee->ffa.bottom_half_value != U32_MAX)
964+
notif_ops->notify_relinquish(ffa_dev,
965+
optee->ffa.bottom_half_value);
879966
optee_notif_uninit(optee);
880967
err_close_ctx:
881968
teedev_close_context(ctx);

drivers/tee/optee/optee_ffa.h

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* SPDX-License-Identifier: BSD-2-Clause */
22
/*
3-
* Copyright (c) 2019-2021, Linaro Limited
3+
* Copyright (c) 2019-2021, 2023 Linaro Limited
44
*/
55

66
/*
@@ -73,7 +73,7 @@
7373
*
7474
* Call register usage:
7575
* w3: Service ID, OPTEE_FFA_EXCHANGE_CAPABILITIES
76-
* w4-w7: Note used (MBZ)
76+
* w4-w7: Not used (MBZ)
7777
*
7878
* Return register usage:
7979
* w3: Error code, 0 on success
@@ -82,14 +82,16 @@
8282
* OPTEE_FFA_YIELDING_CALL_WITH_ARG.
8383
* Bit[31:8]: Reserved (MBZ)
8484
* w5: Bitfield of secure world capabilities OPTEE_FFA_SEC_CAP_* below,
85-
* unused bits MBZ.
86-
* w6-w7: Not used (MBZ)
85+
* w6: The maximum secure world notification number
86+
* w7: Not used (MBZ)
8787
*/
8888
/*
8989
* Secure world supports giving an offset into the argument shared memory
9090
* object, see also OPTEE_FFA_YIELDING_CALL_WITH_ARG
9191
*/
9292
#define OPTEE_FFA_SEC_CAP_ARG_OFFSET BIT(0)
93+
/* OP-TEE supports asynchronous notification via FF-A */
94+
#define OPTEE_FFA_SEC_CAP_ASYNC_NOTIF BIT(1)
9395

9496
#define OPTEE_FFA_EXCHANGE_CAPABILITIES OPTEE_FFA_BLOCKING_CALL(2)
9597

@@ -108,6 +110,24 @@
108110
*/
109111
#define OPTEE_FFA_UNREGISTER_SHM OPTEE_FFA_BLOCKING_CALL(3)
110112

113+
/*
114+
* Inform OP-TEE that the normal world is able to receive asynchronous
115+
* notifications.
116+
*
117+
* Call register usage:
118+
* w3: Service ID, OPTEE_FFA_ENABLE_ASYNC_NOTIF
119+
* w4: Notification value to request bottom half processing, should be
120+
* less than OPTEE_FFA_MAX_ASYNC_NOTIF_VALUE.
121+
* w5-w7: Not used (MBZ)
122+
*
123+
* Return register usage:
124+
* w3: Error code, 0 on success
125+
* w4-w7: Note used (MBZ)
126+
*/
127+
#define OPTEE_FFA_ENABLE_ASYNC_NOTIF OPTEE_FFA_BLOCKING_CALL(5)
128+
129+
#define OPTEE_FFA_MAX_ASYNC_NOTIF_VALUE 64
130+
111131
/*
112132
* Call with struct optee_msg_arg as argument in the supplied shared memory
113133
* with a zero internal offset and normal cached memory attributes.

drivers/tee/optee/optee_private.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,14 @@ struct optee_smc {
147147
* struct optee_ffa_data - FFA communication struct
148148
* @ffa_dev FFA device, contains the destination id, the id of
149149
* OP-TEE in secure world
150-
* @ffa_ops FFA operations
150+
* @bottom_half_value Notification ID used for bottom half signalling or
151+
* U32_MAX if unused
151152
* @mutex Serializes access to @global_ids
152153
* @global_ids FF-A shared memory global handle translation
153154
*/
154155
struct optee_ffa {
155156
struct ffa_device *ffa_dev;
157+
u32 bottom_half_value;
156158
/* Serializes access to @global_ids */
157159
struct mutex mutex;
158160
struct rhashtable global_ids;

0 commit comments

Comments
 (0)