Loading...
Note: File does not exist in v3.1.
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
15struct notif_entry {
16 struct list_head link;
17 struct completion c;
18 u_int key;
19};
20
21static 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
32int 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);
82out:
83 spin_unlock_irqrestore(&optee->notif.lock, flags);
84
85 kfree(entry);
86
87 return rc;
88}
89
90int 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);
108out:
109 spin_unlock_irqrestore(&optee->notif.lock, flags);
110
111 return 0;
112}
113
114int 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
127void optee_notif_uninit(struct optee *optee)
128{
129 bitmap_free(optee->notif.bitmap);
130}