Linux Audio

Check our new training course

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}