xref: /illumos-gate/usr/src/uts/common/crypto/api/kcf_cbufcall.c (revision 0fb96ba1f1ce26ff8b286f8f928769a6afcb00a6)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * crypto_bufcall(9F) group of routines.
29  */
30 
31 #include <sys/types.h>
32 #include <sys/sunddi.h>
33 #include <sys/callb.h>
34 #include <sys/ksynch.h>
35 #include <sys/systm.h>
36 #include <sys/taskq_impl.h>
37 #include <sys/crypto/api.h>
38 #include <sys/crypto/sched_impl.h>
39 
40 /*
41  * All pending crypto bufcalls are put on a list. cbuf_list_lock
42  * protects changes to this list.
43  *
44  * The following locking order is maintained in the code - The
45  * global cbuf_list_lock followed by the individual lock
46  * in a crypto bufcall structure (kc_lock).
47  */
48 kmutex_t	cbuf_list_lock;
49 kcondvar_t	cbuf_list_cv;	/* cv the service thread waits on */
50 static kcf_cbuf_elem_t *cbuf_list_head;
51 static kcf_cbuf_elem_t *cbuf_list_tail;
52 
53 /*
54  * Allocate and return a handle to be used for crypto_bufcall().
55  * Can be called from user context only.
56  */
57 crypto_bc_t
58 crypto_bufcall_alloc(void)
59 {
60 	kcf_cbuf_elem_t *cbufp;
61 
62 	cbufp = kmem_zalloc(sizeof (kcf_cbuf_elem_t), KM_SLEEP);
63 	mutex_init(&cbufp->kc_lock, NULL, MUTEX_DEFAULT, NULL);
64 	cv_init(&cbufp->kc_cv, NULL, CV_DEFAULT, NULL);
65 	cbufp->kc_state = CBUF_FREE;
66 
67 	return (cbufp);
68 }
69 
70 /*
71  * Free the handle if possible. Returns CRYPTO_SUCCESS if the handle
72  * is freed. Else it returns CRYPTO_BUSY.
73  *
74  * The client should do a crypto_unbufcall() if it receives a
75  * CRYPTO_BUSY.
76  *
77  * Can be called both from user and interrupt context.
78  */
79 int
80 crypto_bufcall_free(crypto_bc_t bc)
81 {
82 	kcf_cbuf_elem_t *cbufp = (kcf_cbuf_elem_t *)bc;
83 
84 	mutex_enter(&cbufp->kc_lock);
85 	if (cbufp->kc_state != CBUF_FREE) {
86 		mutex_exit(&cbufp->kc_lock);
87 		return (CRYPTO_BUSY);
88 	}
89 	mutex_exit(&cbufp->kc_lock);
90 
91 	mutex_destroy(&cbufp->kc_lock);
92 	cv_destroy(&cbufp->kc_cv);
93 	kmem_free(cbufp, sizeof (kcf_cbuf_elem_t));
94 
95 	return (CRYPTO_SUCCESS);
96 }
97 
98 /*
99  * Schedule func() to be called when queue space is available to
100  * submit a crypto request.
101  *
102  * Can be called both from user and interrupt context.
103  */
104 int
105 crypto_bufcall(crypto_bc_t bc, void (*func)(void *arg), void *arg)
106 {
107 	kcf_cbuf_elem_t *cbufp;
108 
109 	cbufp = (kcf_cbuf_elem_t *)bc;
110 	if (cbufp == NULL || func == NULL) {
111 		return (CRYPTO_ARGUMENTS_BAD);
112 	}
113 
114 	mutex_enter(&cbuf_list_lock);
115 	mutex_enter(&cbufp->kc_lock);
116 	if (cbufp->kc_state != CBUF_FREE) {
117 		mutex_exit(&cbufp->kc_lock);
118 		mutex_exit(&cbuf_list_lock);
119 		return (CRYPTO_BUSY);
120 	}
121 
122 	cbufp->kc_state = CBUF_WAITING;
123 	cbufp->kc_func = func;
124 	cbufp->kc_arg = arg;
125 	cbufp->kc_prev = cbufp->kc_next = NULL;
126 
127 	if (cbuf_list_head == NULL) {
128 		cbuf_list_head = cbuf_list_tail = cbufp;
129 	} else {
130 		cbuf_list_tail->kc_next = cbufp;
131 		cbufp->kc_prev = cbuf_list_tail;
132 		cbuf_list_tail = cbufp;
133 	}
134 
135 	/*
136 	 * Signal the crypto_bufcall_service thread to start
137 	 * working on this crypto bufcall request.
138 	 */
139 	cv_signal(&cbuf_list_cv);
140 	mutex_exit(&cbufp->kc_lock);
141 	mutex_exit(&cbuf_list_lock);
142 
143 	return (CRYPTO_SUCCESS);
144 }
145 
146 /*
147  * Cancel a pending crypto bufcall request. If the bufcall
148  * is currently executing, we wait till it is complete.
149  *
150  * Can only be called from user context.
151  */
152 int
153 crypto_unbufcall(crypto_bc_t bc)
154 {
155 	kcf_cbuf_elem_t *cbufp = (kcf_cbuf_elem_t *)bc;
156 
157 	mutex_enter(&cbuf_list_lock);
158 	mutex_enter(&cbufp->kc_lock);
159 
160 	if (cbufp->kc_state == CBUF_WAITING) {
161 		kcf_cbuf_elem_t *nextp = cbufp->kc_next;
162 		kcf_cbuf_elem_t *prevp = cbufp->kc_prev;
163 
164 		if (nextp != NULL)
165 			nextp->kc_prev = prevp;
166 		else
167 			cbuf_list_tail = prevp;
168 
169 		if (prevp != NULL)
170 			prevp->kc_next = nextp;
171 		else
172 			cbuf_list_head = nextp;
173 		cbufp->kc_state = CBUF_FREE;
174 	} else if (cbufp->kc_state == CBUF_RUNNING) {
175 		mutex_exit(&cbuf_list_lock);
176 		/*
177 		 * crypto_bufcall_service thread is working
178 		 * on this element. We will wait for that
179 		 * thread to signal us when done.
180 		 */
181 		while (cbufp->kc_state == CBUF_RUNNING)
182 			cv_wait(&cbufp->kc_cv, &cbufp->kc_lock);
183 		mutex_exit(&cbufp->kc_lock);
184 
185 		return (CRYPTO_SUCCESS);
186 	}
187 
188 	mutex_exit(&cbufp->kc_lock);
189 	mutex_exit(&cbuf_list_lock);
190 
191 	return (CRYPTO_SUCCESS);
192 }
193 
194 /*
195  * We sample the number of jobs. We do not hold the lock
196  * as it is not necessary to get the exact count.
197  */
198 #define	KCF_GSWQ_AVAIL	(gswq->gs_maxjobs - gswq->gs_njobs)
199 
200 /*
201  * One queue space each for init, update, and final.
202  */
203 #define	GSWQ_MINFREE	3
204 
205 /*
206  * Go through the list of crypto bufcalls and do the necessary
207  * callbacks.
208  */
209 static void
210 kcf_run_cbufcalls(void)
211 {
212 	kcf_cbuf_elem_t *cbufp;
213 	int count;
214 
215 	mutex_enter(&cbuf_list_lock);
216 
217 	/*
218 	 * Get estimate of available queue space from KCF_GSWQ_AVAIL.
219 	 * We can call 'n' crypto bufcall callback functions where
220 	 * n * GSWQ_MINFREE <= available queue space.
221 	 *
222 	 * TO DO - Extend the check to taskqs of hardware providers.
223 	 * For now, we handle only the software providers.
224 	 */
225 	count = KCF_GSWQ_AVAIL;
226 	while ((cbufp = cbuf_list_head) != NULL) {
227 		if (GSWQ_MINFREE <= count) {
228 			count -= GSWQ_MINFREE;
229 			mutex_enter(&cbufp->kc_lock);
230 			cbuf_list_head = cbufp->kc_next;
231 			cbufp->kc_state = CBUF_RUNNING;
232 			mutex_exit(&cbufp->kc_lock);
233 			mutex_exit(&cbuf_list_lock);
234 
235 			(*cbufp->kc_func)(cbufp->kc_arg);
236 
237 			mutex_enter(&cbufp->kc_lock);
238 			cbufp->kc_state = CBUF_FREE;
239 			cv_broadcast(&cbufp->kc_cv);
240 			mutex_exit(&cbufp->kc_lock);
241 
242 			mutex_enter(&cbuf_list_lock);
243 		} else {
244 			/*
245 			 * There is not enough queue space in this
246 			 * round. We bail out and try again
247 			 * later.
248 			 */
249 			break;
250 		}
251 	}
252 	if (cbuf_list_head == NULL)
253 		cbuf_list_tail = NULL;
254 
255 	mutex_exit(&cbuf_list_lock);
256 }
257 
258 /*
259  * Background processing of crypto bufcalls.
260  */
261 void
262 crypto_bufcall_service(void)
263 {
264 	callb_cpr_t	cprinfo;
265 
266 	CALLB_CPR_INIT(&cprinfo, &cbuf_list_lock, callb_generic_cpr,
267 	    "crypto_bufcall_service");
268 
269 	mutex_enter(&cbuf_list_lock);
270 
271 	for (;;) {
272 		if (cbuf_list_head != NULL && KCF_GSWQ_AVAIL >= GSWQ_MINFREE) {
273 			mutex_exit(&cbuf_list_lock);
274 			kcf_run_cbufcalls();
275 			mutex_enter(&cbuf_list_lock);
276 		}
277 
278 		if (cbuf_list_head != NULL) {
279 			/*
280 			 * Wait 30 seconds for queue space to become available.
281 			 * This number is reasonable as it does not cause
282 			 * much CPU overhead. We could wait on a condition
283 			 * variable and the global software dequeue routine can
284 			 * signal us. But, it adds overhead to that routine
285 			 * which we want to avoid. Also, the client is prepared
286 			 * to wait any way.
287 			 */
288 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
289 			mutex_exit(&cbuf_list_lock);
290 			delay(30 * drv_usectohz(1000000));
291 			mutex_enter(&cbuf_list_lock);
292 			CALLB_CPR_SAFE_END(&cprinfo, &cbuf_list_lock);
293 		}
294 
295 		/* Wait for new work to arrive */
296 		if (cbuf_list_head == NULL) {
297 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
298 			cv_wait(&cbuf_list_cv, &cbuf_list_lock);
299 			CALLB_CPR_SAFE_END(&cprinfo, &cbuf_list_lock);
300 		}
301 	}
302 }
303