Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.19 130 lines 2.6 kB view raw
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}