xref: /OK3568_Linux_fs/kernel/drivers/gpu/arm/bifrost/tests/kutf/kutf_resultset.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3  *
4  * (C) COPYRIGHT 2014, 2017, 2020-2021 ARM Limited. All rights reserved.
5  *
6  * This program is free software and is provided to you under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation, and any use by you of this program is subject to the terms
9  * of such GNU license.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you can access it online at
18  * http://www.gnu.org/licenses/gpl-2.0.html.
19  *
20  */
21 
22 /* Kernel UTF result management functions */
23 
24 #include <linux/list.h>
25 #include <linux/slab.h>
26 #include <linux/printk.h>
27 #include <linux/sched.h>
28 #include <linux/wait.h>
29 #include <linux/err.h>
30 
31 #include <kutf/kutf_suite.h>
32 #include <kutf/kutf_resultset.h>
33 
34 /* Lock to protect all result structures */
35 static DEFINE_SPINLOCK(kutf_result_lock);
36 
kutf_create_result_set(void)37 struct kutf_result_set *kutf_create_result_set(void)
38 {
39 	struct kutf_result_set *set;
40 
41 	set = kmalloc(sizeof(*set), GFP_KERNEL);
42 	if (!set) {
43 		pr_err("Failed to allocate resultset");
44 		goto fail_alloc;
45 	}
46 
47 	INIT_LIST_HEAD(&set->results);
48 	init_waitqueue_head(&set->waitq);
49 	set->flags = 0;
50 
51 	return set;
52 
53 fail_alloc:
54 	return NULL;
55 }
56 
kutf_add_result(struct kutf_context * context,enum kutf_result_status status,const char * message)57 int kutf_add_result(struct kutf_context *context,
58 		enum kutf_result_status status,
59 		const char *message)
60 {
61 	struct kutf_mempool *mempool = &context->fixture_pool;
62 	struct kutf_result_set *set = context->result_set;
63 	/* Create the new result */
64 	struct kutf_result *new_result;
65 
66 	BUG_ON(set == NULL);
67 
68 	new_result = kutf_mempool_alloc(mempool, sizeof(*new_result));
69 	if (!new_result) {
70 		pr_err("Result allocation failed\n");
71 		return -ENOMEM;
72 	}
73 
74 	INIT_LIST_HEAD(&new_result->node);
75 	new_result->status = status;
76 	new_result->message = message;
77 
78 	spin_lock(&kutf_result_lock);
79 
80 	list_add_tail(&new_result->node, &set->results);
81 
82 	spin_unlock(&kutf_result_lock);
83 
84 	wake_up(&set->waitq);
85 
86 	return 0;
87 }
88 
kutf_destroy_result_set(struct kutf_result_set * set)89 void kutf_destroy_result_set(struct kutf_result_set *set)
90 {
91 	if (!list_empty(&set->results))
92 		pr_err("%s: Unread results from test\n", __func__);
93 
94 	kfree(set);
95 }
96 
kutf_has_result(struct kutf_result_set * set)97 static bool kutf_has_result(struct kutf_result_set *set)
98 {
99 	bool has_result;
100 
101 	spin_lock(&kutf_result_lock);
102 	if (set->flags & KUTF_RESULT_SET_WAITING_FOR_INPUT)
103 		/* Pretend there are results if waiting for input */
104 		has_result = true;
105 	else
106 		has_result = !list_empty(&set->results);
107 	spin_unlock(&kutf_result_lock);
108 
109 	return has_result;
110 }
111 
kutf_remove_result(struct kutf_result_set * set)112 struct kutf_result *kutf_remove_result(struct kutf_result_set *set)
113 {
114 	struct kutf_result *result = NULL;
115 	int ret;
116 
117 	do {
118 		ret = wait_event_interruptible(set->waitq,
119 				kutf_has_result(set));
120 
121 		if (ret)
122 			return ERR_PTR(ret);
123 
124 		spin_lock(&kutf_result_lock);
125 
126 		if (!list_empty(&set->results)) {
127 			result = list_first_entry(&set->results,
128 					struct kutf_result,
129 					node);
130 			list_del(&result->node);
131 		} else if (set->flags & KUTF_RESULT_SET_WAITING_FOR_INPUT) {
132 			/* Return a fake result */
133 			static struct kutf_result waiting = {
134 				.status = KUTF_RESULT_USERDATA_WAIT
135 			};
136 			result = &waiting;
137 		}
138 		/* If result == NULL then there was a race with the event
139 		 * being removed between the check in kutf_has_result and
140 		 * the lock being obtained. In this case we retry
141 		 */
142 
143 		spin_unlock(&kutf_result_lock);
144 	} while (result == NULL);
145 
146 	return result;
147 }
148 
kutf_set_waiting_for_input(struct kutf_result_set * set)149 void kutf_set_waiting_for_input(struct kutf_result_set *set)
150 {
151 	spin_lock(&kutf_result_lock);
152 	set->flags |= KUTF_RESULT_SET_WAITING_FOR_INPUT;
153 	spin_unlock(&kutf_result_lock);
154 
155 	wake_up(&set->waitq);
156 }
157 
kutf_clear_waiting_for_input(struct kutf_result_set * set)158 void kutf_clear_waiting_for_input(struct kutf_result_set *set)
159 {
160 	spin_lock(&kutf_result_lock);
161 	set->flags &= ~KUTF_RESULT_SET_WAITING_FOR_INPUT;
162 	spin_unlock(&kutf_result_lock);
163 }
164