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