brintos

brintos / linux-shallow public Read only

0
0
Text · 2.6 KiB · 1970880 Raw
131 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2015-2021, Linaro Limited4 */5 6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt7 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 already51	 * 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 is60	 * 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}131