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