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