1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2015-2021, Linaro Limited
6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8 #include <linux/arm-smccc.h>
9 #include <linux/errno.h>
10 #include <linux/slab.h>
11 #include <linux/spinlock.h>
12 #include <linux/tee_drv.h>
13 #include "optee_private.h"
16 struct list_head link;
21 static bool have_key(struct optee *optee, u_int key)
23 struct notif_entry *entry;
25 list_for_each_entry(entry, &optee->notif.db, link)
26 if (entry->key == key)
32 int optee_notif_wait(struct optee *optee, u_int key)
35 struct notif_entry *entry;
38 if (key > optee->notif.max_key)
41 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
44 init_completion(&entry->c);
47 spin_lock_irqsave(&optee->notif.lock, flags);
50 * If the bit is already set it means that the key has already
51 * been posted and we must not wait.
53 if (test_bit(key, optee->notif.bitmap)) {
54 clear_bit(key, optee->notif.bitmap);
59 * Check if someone is already waiting for this key. If there is
60 * it's a programming error.
62 if (have_key(optee, key)) {
67 list_add_tail(&entry->link, &optee->notif.db);
70 * Unlock temporarily and wait for completion.
72 spin_unlock_irqrestore(&optee->notif.lock, flags);
73 wait_for_completion(&entry->c);
74 spin_lock_irqsave(&optee->notif.lock, flags);
76 list_del(&entry->link);
78 spin_unlock_irqrestore(&optee->notif.lock, flags);
85 int optee_notif_send(struct optee *optee, u_int key)
88 struct notif_entry *entry;
90 if (key > optee->notif.max_key)
93 spin_lock_irqsave(&optee->notif.lock, flags);
95 list_for_each_entry(entry, &optee->notif.db, link)
96 if (entry->key == key) {
101 /* Only set the bit in case there where nobody waiting */
102 set_bit(key, optee->notif.bitmap);
104 spin_unlock_irqrestore(&optee->notif.lock, flags);
109 int optee_notif_init(struct optee *optee, u_int max_key)
111 spin_lock_init(&optee->notif.lock);
112 INIT_LIST_HEAD(&optee->notif.db);
113 optee->notif.bitmap = bitmap_zalloc(max_key, GFP_KERNEL);
114 if (!optee->notif.bitmap)
117 optee->notif.max_key = max_key;
122 void optee_notif_uninit(struct optee *optee)
124 bitmap_free(optee->notif.bitmap);