linux/drivers/tee/optee/notif.c
Arnd Bergmann 30c577a852 optee: add timeout parameter for notification wait
-----BEGIN PGP SIGNATURE-----
 
 iQJOBAABCgA4FiEEFV+gSSXZJY9ZyuB5LinzTIcAHJcFAmZ9M1IaHGplbnMud2lr
 bGFuZGVyQGxpbmFyby5vcmcACgkQLinzTIcAHJdnng/+JR9RDaFSfa02pnHPzSnX
 KQcIRL0YUv2go5RQHXC9lzN+t/oDo/pC4PGmxU3RQX/PQYFwGDWeer30VSdA8Emm
 zDNl+K2YTocGXvKB1dXWOwtNPtDYgKNkpsIk+RZQzsj/6mAsanCHP9cv0kAMPrVt
 Cv9tj7U8PcgD8OujqW0b7rq5CmgGJpGcOtk/I8E97pcBXbpPLLIGHlMFYeQZgelC
 4vd9RzOPGCEtKK79ZAh5rc7z7RymPDA1Ada2MYG/J54iiRe43xgRaCxiq2SuvNHq
 5yKL+ZDBo38ejAQwOV6xUsXo7XaOu6+seyVA/GGqBoB+RAPCjMGqzZmQDEJwYFQW
 2X8ViYXO3MMOPT9kmtt/1oPq50xP3EbvwnaOJws9fbSG+n6cc3ZmCB65ByaO8LbZ
 5/hu6zKZ+b5L0m3QSQjkanoVFwRm6oefeQB/kHHNqgzGEh9ijogWf1boWui2wKpF
 pO7ohQlxQzpkAvUF0HmWM4JmTSsmyYYMqbLRIJXJRTX/KdrHZFcS7NuRnOuXE3qf
 uyiXo4rzUZhtecgyCiTJ7Pb20NuvaWR49RADASk+D5OP6pfbhw0wVGP9Kc/icU9h
 AdUYUbGokrFxSCGYx/+wnBEuR5Nf1f35/9VWhs+UXkfuy38B6qxnv7/ePDD3/pcu
 VReDFHMF6GlWTXX1nRiLIWk=
 =mkge
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEiK/NIGsWEZVxh/FrYKtH/8kJUicFAmZ9etUACgkQYKtH/8kJ
 UifBJRAAqh9Od+EkNpFSukrWorFUlt794wS/n6YxR2vWB+RJsQsbH1KIh+F5/GJl
 5RD97ZCfz095njxgTQD/344oldvAf1EBEkpyyebVn71pTAn2QpglrisI4t0lba4F
 nzlOtud7AEDReaPR1z5VUB/S2eF+33/N4/U8I7/JOiEjNmEK6UGPm9o/1T6UVxNv
 hIRpdNv3SBy/0KDv1SXlhLlXxIN5akNomPQncOGL2e7tLQgGIjGstvyADZ6fkSey
 hLvovuyRD06fLyqE+IhWmjwr0pgZ1kq32Cbeq2n2yns42hsy7wwelODcQibv5PYs
 +Vq+gbgCThxyRAL/8bsg0fR7sUSUm6UJ07MLFsP0J4U21wjqlr2VEKHNuurpAWPy
 /TAk8LqC7ZtxwfaT1c4yor0euGjCw8xBn4JjADLdixPCHPqOwBUvKCWxVP1HaTOc
 7u+ijpRRIZxNHsErbUP08TjXOEF3wi00sQygxZed0Sm8faQRfGRySiUQ3Lt6LJlv
 /wxXW9/ARW55K3AOoIsd47EG9MT+y3FwAc9R5NKIpHsshvCstgWnJgTCOuQaPyEo
 YyXYsiZlh94b308EwyIRnVmtbiby7htKbmD6DeC8CaBabMmvaaHTCH9wRyyi+w5J
 rLKqYqMTyCRnF/xILdq9fUmdG9I4FIQEBrQXrhIlpdwCg9a0dNs=
 =bm1W
 -----END PGP SIGNATURE-----

Merge tag 'optee-notif-wait-timeout-for-v6.11' of https://git.linaro.org/people/jens.wiklander/linux-tee into soc/drivers

optee: add timeout parameter for notification wait

* tag 'optee-notif-wait-timeout-for-v6.11' of https://git.linaro.org/people/jens.wiklander/linux-tee:
  optee: add timeout value to optee_notif_wait() to support timeout

Link: https://lore.kernel.org/r/20240627095325.GA2585076@rayden
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2024-06-27 16:44:37 +02:00

130 lines
2.6 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015-2021, Linaro Limited
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/arm-smccc.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/tee_core.h>
#include "optee_private.h"
struct notif_entry {
struct list_head link;
struct completion c;
u_int key;
};
static bool have_key(struct optee *optee, u_int key)
{
struct notif_entry *entry;
list_for_each_entry(entry, &optee->notif.db, link)
if (entry->key == key)
return true;
return false;
}
int optee_notif_wait(struct optee *optee, u_int key, u32 timeout)
{
unsigned long flags;
struct notif_entry *entry;
int rc = 0;
if (key > optee->notif.max_key)
return -EINVAL;
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
init_completion(&entry->c);
entry->key = key;
spin_lock_irqsave(&optee->notif.lock, flags);
/*
* If the bit is already set it means that the key has already
* been posted and we must not wait.
*/
if (test_bit(key, optee->notif.bitmap)) {
clear_bit(key, optee->notif.bitmap);
goto out;
}
/*
* Check if someone is already waiting for this key. If there is
* it's a programming error.
*/
if (have_key(optee, key)) {
rc = -EBUSY;
goto out;
}
list_add_tail(&entry->link, &optee->notif.db);
/*
* Unlock temporarily and wait for completion.
*/
spin_unlock_irqrestore(&optee->notif.lock, flags);
if (timeout != 0) {
if (!wait_for_completion_timeout(&entry->c, timeout))
rc = -ETIMEDOUT;
} else {
wait_for_completion(&entry->c);
}
spin_lock_irqsave(&optee->notif.lock, flags);
list_del(&entry->link);
out:
spin_unlock_irqrestore(&optee->notif.lock, flags);
kfree(entry);
return rc;
}
int optee_notif_send(struct optee *optee, u_int key)
{
unsigned long flags;
struct notif_entry *entry;
if (key > optee->notif.max_key)
return -EINVAL;
spin_lock_irqsave(&optee->notif.lock, flags);
list_for_each_entry(entry, &optee->notif.db, link)
if (entry->key == key) {
complete(&entry->c);
goto out;
}
/* Only set the bit in case there where nobody waiting */
set_bit(key, optee->notif.bitmap);
out:
spin_unlock_irqrestore(&optee->notif.lock, flags);
return 0;
}
int optee_notif_init(struct optee *optee, u_int max_key)
{
spin_lock_init(&optee->notif.lock);
INIT_LIST_HEAD(&optee->notif.db);
optee->notif.bitmap = bitmap_zalloc(max_key, GFP_KERNEL);
if (!optee->notif.bitmap)
return -ENOMEM;
optee->notif.max_key = max_key;
return 0;
}
void optee_notif_uninit(struct optee *optee)
{
bitmap_free(optee->notif.bitmap);
}