xref: /linux/drivers/tee/optee/notif.c (revision 6e7fd890f1d6ac83805409e9c346240de2705584)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2015-2021, Linaro Limited
4  */
5 
6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7 
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_core.h>
13 #include "optee_private.h"
14 
15 struct notif_entry {
16 	struct list_head link;
17 	struct completion c;
18 	u_int key;
19 };
20 
21 static bool have_key(struct optee *optee, u_int key)
22 {
23 	struct notif_entry *entry;
24 
25 	list_for_each_entry(entry, &optee->notif.db, link)
26 		if (entry->key == key)
27 			return true;
28 
29 	return false;
30 }
31 
32 int optee_notif_wait(struct optee *optee, u_int key, u32 timeout)
33 {
34 	unsigned long flags;
35 	struct notif_entry *entry;
36 	int rc = 0;
37 
38 	if (key > optee->notif.max_key)
39 		return -EINVAL;
40 
41 	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
42 	if (!entry)
43 		return -ENOMEM;
44 	init_completion(&entry->c);
45 	entry->key = key;
46 
47 	spin_lock_irqsave(&optee->notif.lock, flags);
48 
49 	/*
50 	 * If the bit is already set it means that the key has already
51 	 * been posted and we must not wait.
52 	 */
53 	if (test_bit(key, optee->notif.bitmap)) {
54 		clear_bit(key, optee->notif.bitmap);
55 		goto out;
56 	}
57 
58 	/*
59 	 * Check if someone is already waiting for this key. If there is
60 	 * it's a programming error.
61 	 */
62 	if (have_key(optee, key)) {
63 		rc = -EBUSY;
64 		goto out;
65 	}
66 
67 	list_add_tail(&entry->link, &optee->notif.db);
68 
69 	/*
70 	 * Unlock temporarily and wait for completion.
71 	 */
72 	spin_unlock_irqrestore(&optee->notif.lock, flags);
73 	if (timeout != 0) {
74 		if (!wait_for_completion_timeout(&entry->c, timeout))
75 			rc = -ETIMEDOUT;
76 	} else {
77 		wait_for_completion(&entry->c);
78 	}
79 	spin_lock_irqsave(&optee->notif.lock, flags);
80 
81 	list_del(&entry->link);
82 out:
83 	spin_unlock_irqrestore(&optee->notif.lock, flags);
84 
85 	kfree(entry);
86 
87 	return rc;
88 }
89 
90 int optee_notif_send(struct optee *optee, u_int key)
91 {
92 	unsigned long flags;
93 	struct notif_entry *entry;
94 
95 	if (key > optee->notif.max_key)
96 		return -EINVAL;
97 
98 	spin_lock_irqsave(&optee->notif.lock, flags);
99 
100 	list_for_each_entry(entry, &optee->notif.db, link)
101 		if (entry->key == key) {
102 			complete(&entry->c);
103 			goto out;
104 		}
105 
106 	/* Only set the bit in case there where nobody waiting */
107 	set_bit(key, optee->notif.bitmap);
108 out:
109 	spin_unlock_irqrestore(&optee->notif.lock, flags);
110 
111 	return 0;
112 }
113 
114 int optee_notif_init(struct optee *optee, u_int max_key)
115 {
116 	spin_lock_init(&optee->notif.lock);
117 	INIT_LIST_HEAD(&optee->notif.db);
118 	optee->notif.bitmap = bitmap_zalloc(max_key, GFP_KERNEL);
119 	if (!optee->notif.bitmap)
120 		return -ENOMEM;
121 
122 	optee->notif.max_key = max_key;
123 
124 	return 0;
125 }
126 
127 void optee_notif_uninit(struct optee *optee)
128 {
129 	bitmap_free(optee->notif.bitmap);
130 }
131