Print this page
5253 kmem_alloc/kmem_zalloc won't fail with KM_SLEEP
5254 getrbuf won't fail with KM_SLEEP
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/crypto/io/dca_rng.c
+++ new/usr/src/uts/common/crypto/io/dca_rng.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 (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 -#pragma ident "%Z%%M% %I% %E% SMI"
28 -
29 27 /*
30 28 * Deimos - cryptographic acceleration based upon Broadcom 582x.
31 29 */
32 30
33 31 #include <sys/types.h>
34 32 #include <sys/ddi.h>
35 33 #include <sys/sunddi.h>
36 34 #include <sys/kmem.h>
37 35 #include <sys/crypto/dca.h>
38 36 #include <sys/atomic.h>
39 37
40 38 /*
41 39 * Random number implementation.
42 40 */
43 41
44 42 static int dca_rngstart(dca_t *, dca_request_t *);
45 43 static void dca_rngdone(dca_request_t *, int);
46 44
47 45 static void dca_random_done();
48 46 int dca_random_buffer(dca_t *dca, caddr_t buf, int len);
49 47 int dca_random_init();
50 48 void dca_random_fini();
51 49
52 50 int
53 51 dca_rng(dca_t *dca, uchar_t *buf, size_t len, crypto_req_handle_t req)
54 52 {
55 53 dca_request_t *reqp;
56 54 int rv;
57 55 crypto_data_t *data;
58 56
59 57 if ((reqp = dca_getreq(dca, MCR2, 1)) == NULL) {
60 58 dca_error(dca, "unable to allocate request for RNG");
61 59 return (CRYPTO_HOST_MEMORY);
62 60 }
63 61
64 62 reqp->dr_kcf_req = req;
65 63
66 64 data = &reqp->dr_ctx.in_dup;
67 65 data->cd_format = CRYPTO_DATA_RAW;
68 66 data->cd_offset = 0;
69 67 data->cd_length = 0;
70 68 data->cd_raw.iov_base = (char *)buf;
71 69 data->cd_raw.iov_len = len;
72 70 reqp->dr_out = data;
73 71 reqp->dr_in = NULL;
74 72
75 73 rv = dca_rngstart(dca, reqp);
76 74 if (rv != CRYPTO_QUEUED) {
77 75 if (reqp->destroy)
78 76 dca_destroyreq(reqp);
79 77 else
80 78 dca_freereq(reqp);
81 79 }
82 80 return (rv);
83 81 }
84 82
85 83 int
86 84 dca_rngstart(dca_t *dca, dca_request_t *reqp)
87 85 {
88 86 uint16_t cmd;
89 87 size_t len;
90 88 uint16_t chunk;
91 89 crypto_data_t *out = reqp->dr_out;
92 90
93 91 if (dca->dca_flags & DCA_RNGSHA1) {
94 92 reqp->dr_job_stat = DS_RNGSHA1JOBS;
95 93 reqp->dr_byte_stat = DS_RNGSHA1BYTES;
96 94 cmd = CMD_RNGSHA1;
97 95 } else {
98 96 reqp->dr_job_stat = DS_RNGJOBS;
99 97 reqp->dr_byte_stat = DS_RNGBYTES;
100 98 cmd = CMD_RNGDIRECT;
101 99 }
102 100
103 101 len = out->cd_raw.iov_len - out->cd_length;
104 102 len = min(len, MAXPACKET & ~0xf);
105 103 chunk = ROUNDUP(len, sizeof (uint32_t));
106 104
107 105 if ((len < dca_mindma) ||
108 106 dca_sgcheck(dca, reqp->dr_out, DCA_SG_WALIGN)) {
109 107 reqp->dr_flags |= DR_SCATTER;
110 108 }
111 109
112 110 /* Try to do direct DMA. */
113 111 if (!(reqp->dr_flags & DR_SCATTER)) {
114 112 if (dca_bindchains(reqp, 0, len) != DDI_SUCCESS) {
115 113 return (CRYPTO_DEVICE_ERROR);
116 114 }
117 115 }
118 116
119 117 reqp->dr_in_paddr = 0;
120 118 reqp->dr_in_next = 0;
121 119 reqp->dr_in_len = 0;
122 120
123 121 /*
124 122 * Setup for scattering the result back out
125 123 * Using the pre-mapped buffers to store random numbers. Since the
126 124 * data buffer is a linked list, we need to transfer its head to MCR
127 125 */
128 126 if (reqp->dr_flags & DR_SCATTER) {
129 127 reqp->dr_out_paddr = reqp->dr_obuf_head.dc_buffer_paddr;
130 128 reqp->dr_out_next = reqp->dr_obuf_head.dc_next_paddr;
131 129 if (chunk > reqp->dr_obuf_head.dc_buffer_length)
132 130 reqp->dr_out_len = reqp->dr_obuf_head.dc_buffer_length;
133 131 else
134 132 reqp->dr_out_len = chunk;
135 133 }
136 134 reqp->dr_param.dp_rng.dr_chunklen = len;
137 135 reqp->dr_pkt_length = (uint16_t)chunk;
138 136 reqp->dr_callback = dca_rngdone;
139 137
140 138 /* write out the context structure */
141 139 PUTCTX16(reqp, CTX_LENGTH, CTX_RNG_LENGTH);
142 140 PUTCTX16(reqp, CTX_CMD, cmd);
143 141
144 142 /* schedule the work by doing a submit */
145 143 return (dca_start(dca, reqp, MCR2, 1));
146 144 }
147 145
148 146 void
149 147 dca_rngdone(dca_request_t *reqp, int errno)
150 148 {
151 149 if (errno == CRYPTO_SUCCESS) {
152 150
153 151 if (reqp->dr_flags & DR_SCATTER) {
154 152 (void) ddi_dma_sync(reqp->dr_obuf_dmah, 0,
155 153 reqp->dr_out_len, DDI_DMA_SYNC_FORKERNEL);
156 154 if (dca_check_dma_handle(reqp->dr_dca,
157 155 reqp->dr_obuf_dmah, DCA_FM_ECLASS_NONE) !=
158 156 DDI_SUCCESS) {
159 157 reqp->destroy = TRUE;
160 158 errno = CRYPTO_DEVICE_ERROR;
161 159 goto errout;
162 160 }
163 161 errno = dca_scatter(reqp->dr_obuf_kaddr,
164 162 reqp->dr_out, reqp->dr_param.dp_rng.dr_chunklen, 0);
165 163 if (errno != CRYPTO_SUCCESS) {
166 164 goto errout;
167 165 }
168 166 } else {
169 167 reqp->dr_out->cd_length +=
170 168 reqp->dr_param.dp_rng.dr_chunklen;
171 169 }
172 170
173 171 /*
174 172 * If there is more to do, then reschedule another
175 173 * pass.
176 174 */
177 175 if (reqp->dr_out->cd_length < reqp->dr_out->cd_raw.iov_len) {
178 176 errno = dca_rngstart(reqp->dr_dca, reqp);
179 177 if (errno == CRYPTO_QUEUED) {
180 178 return;
181 179 }
182 180 }
183 181 }
184 182
185 183 errout:
186 184
187 185 if (reqp->dr_kcf_req) {
188 186 /* notify framework that request is completed */
189 187 crypto_op_notification(reqp->dr_kcf_req, errno);
190 188 } else {
191 189 /* For internal random number generation */
192 190 dca_random_done(reqp->dr_dca);
193 191 }
194 192
195 193 DBG(NULL, DINTR,
196 194 "dca_rngdone: returning %d to the kef via crypto_op_notification",
197 195 errno);
198 196 if (reqp->destroy)
199 197 dca_destroyreq(reqp);
200 198 else
201 199 dca_freereq(reqp);
202 200 }
203 201
204 202 /*
205 203 * This gives a 32k random bytes per buffer. The two buffers will switch back
206 204 * and forth. When a buffer is used up, a request will be submitted to refill
207 205 * this buffer before switching to the other one
208 206 */
↓ open down ↓ |
170 lines elided |
↑ open up ↑ |
209 207
210 208 #define RANDOM_BUFFER_SIZE (1<<15)
211 209 #define DCA_RANDOM_MAX_WAIT 10000
212 210
213 211 int
214 212 dca_random_init(dca_t *dca)
215 213 {
216 214 /* Mutex for the local random number pool */
217 215 mutex_init(&dca->dca_random_lock, NULL, MUTEX_DRIVER, NULL);
218 216
219 - if ((dca->dca_buf1 = kmem_alloc(RANDOM_BUFFER_SIZE, KM_SLEEP)) ==
220 - NULL) {
221 - mutex_destroy(&dca->dca_random_lock);
222 - return (CRYPTO_FAILED);
223 - }
217 + dca->dca_buf1 = kmem_alloc(RANDOM_BUFFER_SIZE, KM_SLEEP);
224 218
225 - if ((dca->dca_buf2 = kmem_alloc(RANDOM_BUFFER_SIZE, KM_SLEEP)) ==
226 - NULL) {
227 - mutex_destroy(&dca->dca_random_lock);
228 - kmem_free(dca->dca_buf1, RANDOM_BUFFER_SIZE);
229 - return (CRYPTO_FAILED);
230 - }
219 + dca->dca_buf2 = kmem_alloc(RANDOM_BUFFER_SIZE, KM_SLEEP);
231 220
232 221 return (CRYPTO_SUCCESS);
233 222 }
234 223
235 224 void
236 225 dca_random_fini(dca_t *dca)
237 226 {
238 227 kmem_free(dca->dca_buf1, RANDOM_BUFFER_SIZE);
239 228 kmem_free(dca->dca_buf2, RANDOM_BUFFER_SIZE);
240 229 dca->dca_buf1 = dca->dca_buf2 = dca->dca_buf_ptr = NULL;
241 230 (void) mutex_destroy(&dca->dca_random_lock);
242 231 }
243 232
244 233 int
245 234 dca_random_buffer(dca_t *dca, caddr_t buf, int len)
246 235 {
247 236 int rv;
248 237 int i, j;
249 238 char *fill_buf;
250 239
251 240 mutex_enter(&dca->dca_random_lock);
252 241
253 242 if (dca->dca_buf_ptr == NULL) {
254 243 if (dca->dca_buf1 == NULL || dca->dca_buf2 == NULL) {
255 244 mutex_exit(&dca->dca_random_lock);
256 245 return (CRYPTO_FAILED);
257 246 }
258 247
259 248 /* Very first time. Let us fill the first buffer */
260 249 if (dca_rng(dca, (uchar_t *)dca->dca_buf1, RANDOM_BUFFER_SIZE,
261 250 NULL) != CRYPTO_QUEUED) {
262 251 mutex_exit(&dca->dca_random_lock);
263 252 return (CRYPTO_FAILED);
264 253 }
265 254
266 255 atomic_or_32(&dca->dca_random_filling, 0x1);
267 256
268 257 /* Pretend we are using buffer2 and it is empty */
269 258 dca->dca_buf_ptr = dca->dca_buf2;
270 259 dca->dca_index = RANDOM_BUFFER_SIZE;
271 260 }
272 261
273 262 i = 0;
274 263 while (i < len) {
275 264 if (dca->dca_index >= RANDOM_BUFFER_SIZE) {
276 265 j = 0;
277 266 while (dca->dca_random_filling) {
278 267 /* Only wait here at the first time */
279 268 delay(drv_usectohz(100));
280 269 if (j++ >= DCA_RANDOM_MAX_WAIT)
281 270 break;
282 271 }
283 272 DBG(NULL, DENTRY, "dca_random_buffer: j: %d", j);
284 273 if (j > DCA_RANDOM_MAX_WAIT) {
285 274 mutex_exit(&dca->dca_random_lock);
286 275 return (CRYPTO_FAILED);
287 276 }
288 277
289 278 /* switch to the other buffer */
290 279 if (dca->dca_buf_ptr == dca->dca_buf1) {
291 280 dca->dca_buf_ptr = dca->dca_buf2;
292 281 fill_buf = dca->dca_buf1;
293 282 } else {
294 283 dca->dca_buf_ptr = dca->dca_buf1;
295 284 fill_buf = dca->dca_buf2;
296 285 }
297 286
298 287 atomic_or_32(&dca->dca_random_filling, 0x1);
299 288 dca->dca_index = 0;
300 289
301 290 if ((rv = dca_rng(dca, (uchar_t *)fill_buf,
302 291 RANDOM_BUFFER_SIZE, NULL)) != CRYPTO_QUEUED) {
303 292 mutex_exit(&dca->dca_random_lock);
304 293 return (rv);
305 294 }
306 295 }
307 296
308 297 if (dca->dca_buf_ptr[dca->dca_index] != '\0')
309 298 buf[i++] = dca->dca_buf_ptr[dca->dca_index];
310 299
311 300 dca->dca_index++;
312 301 }
313 302
314 303 mutex_exit(&dca->dca_random_lock);
315 304
316 305 DBG(NULL, DENTRY, "dca_random_buffer: i: %d", i);
317 306 return (CRYPTO_SUCCESS);
318 307 }
319 308
320 309 static void
321 310 dca_random_done(dca_t *dca)
322 311 {
323 312 DBG(NULL, DENTRY, "dca_random_done");
324 313 atomic_and_32(&dca->dca_random_filling, 0x0);
325 314 }
↓ open down ↓ |
85 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX