0001
0002
0003
0004
0005
0006 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0007
0008 #include <linux/arm-smccc.h>
0009 #include <linux/errno.h>
0010 #include <linux/slab.h>
0011 #include <linux/spinlock.h>
0012 #include <linux/tee_drv.h>
0013 #include "optee_private.h"
0014
0015 struct notif_entry {
0016 struct list_head link;
0017 struct completion c;
0018 u_int key;
0019 };
0020
0021 static bool have_key(struct optee *optee, u_int key)
0022 {
0023 struct notif_entry *entry;
0024
0025 list_for_each_entry(entry, &optee->notif.db, link)
0026 if (entry->key == key)
0027 return true;
0028
0029 return false;
0030 }
0031
0032 int optee_notif_wait(struct optee *optee, u_int key)
0033 {
0034 unsigned long flags;
0035 struct notif_entry *entry;
0036 int rc = 0;
0037
0038 if (key > optee->notif.max_key)
0039 return -EINVAL;
0040
0041 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
0042 if (!entry)
0043 return -ENOMEM;
0044 init_completion(&entry->c);
0045 entry->key = key;
0046
0047 spin_lock_irqsave(&optee->notif.lock, flags);
0048
0049
0050
0051
0052
0053 if (test_bit(key, optee->notif.bitmap)) {
0054 clear_bit(key, optee->notif.bitmap);
0055 goto out;
0056 }
0057
0058
0059
0060
0061
0062 if (have_key(optee, key)) {
0063 rc = -EBUSY;
0064 goto out;
0065 }
0066
0067 list_add_tail(&entry->link, &optee->notif.db);
0068
0069
0070
0071
0072 spin_unlock_irqrestore(&optee->notif.lock, flags);
0073 wait_for_completion(&entry->c);
0074 spin_lock_irqsave(&optee->notif.lock, flags);
0075
0076 list_del(&entry->link);
0077 out:
0078 spin_unlock_irqrestore(&optee->notif.lock, flags);
0079
0080 kfree(entry);
0081
0082 return rc;
0083 }
0084
0085 int optee_notif_send(struct optee *optee, u_int key)
0086 {
0087 unsigned long flags;
0088 struct notif_entry *entry;
0089
0090 if (key > optee->notif.max_key)
0091 return -EINVAL;
0092
0093 spin_lock_irqsave(&optee->notif.lock, flags);
0094
0095 list_for_each_entry(entry, &optee->notif.db, link)
0096 if (entry->key == key) {
0097 complete(&entry->c);
0098 goto out;
0099 }
0100
0101
0102 set_bit(key, optee->notif.bitmap);
0103 out:
0104 spin_unlock_irqrestore(&optee->notif.lock, flags);
0105
0106 return 0;
0107 }
0108
0109 int optee_notif_init(struct optee *optee, u_int max_key)
0110 {
0111 spin_lock_init(&optee->notif.lock);
0112 INIT_LIST_HEAD(&optee->notif.db);
0113 optee->notif.bitmap = bitmap_zalloc(max_key, GFP_KERNEL);
0114 if (!optee->notif.bitmap)
0115 return -ENOMEM;
0116
0117 optee->notif.max_key = max_key;
0118
0119 return 0;
0120 }
0121
0122 void optee_notif_uninit(struct optee *optee)
0123 {
0124 bitmap_free(optee->notif.bitmap);
0125 }