| 1 | /* |
| 2 | * A loadable module that benchmarks the OCF crypto speed from kernel space. |
| 3 | * |
| 4 | * Copyright (C) 2004-2010 David McCullough <david_mccullough@mcafee.com> |
| 5 | * |
| 6 | * LICENSE TERMS |
| 7 | * |
| 8 | * The free distribution and use of this software in both source and binary |
| 9 | * form is allowed (with or without changes) provided that: |
| 10 | * |
| 11 | * 1. distributions of this source code include the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer; |
| 13 | * |
| 14 | * 2. distributions in binary form include the above copyright |
| 15 | * notice, this list of conditions and the following disclaimer |
| 16 | * in the documentation and/or other associated materials; |
| 17 | * |
| 18 | * 3. the copyright holder's name is not used to endorse products |
| 19 | * built using this software without specific written permission. |
| 20 | * |
| 21 | * ALTERNATIVELY, provided that this notice is retained in full, this product |
| 22 | * may be distributed under the terms of the GNU General Public License (GPL), |
| 23 | * in which case the provisions of the GPL apply INSTEAD OF those given above. |
| 24 | * |
| 25 | * DISCLAIMER |
| 26 | * |
| 27 | * This software is provided 'as is' with no explicit or implied warranties |
| 28 | * in respect of its properties, including, but not limited to, correctness |
| 29 | * and/or fitness for purpose. |
| 30 | */ |
| 31 | |
| 32 | |
| 33 | #include <linux/version.h> |
| 34 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) |
| 35 | #include <linux/config.h> |
| 36 | #endif |
| 37 | #include <linux/module.h> |
| 38 | #include <linux/init.h> |
| 39 | #include <linux/list.h> |
| 40 | #include <linux/slab.h> |
| 41 | #include <linux/wait.h> |
| 42 | #include <linux/sched.h> |
| 43 | #include <linux/spinlock.h> |
| 44 | #include <linux/interrupt.h> |
| 45 | #include <cryptodev.h> |
| 46 | |
| 47 | #ifdef I_HAVE_AN_XSCALE_WITH_INTEL_SDK |
| 48 | #define BENCH_IXP_ACCESS_LIB 1 |
| 49 | #endif |
| 50 | #ifdef BENCH_IXP_ACCESS_LIB |
| 51 | #include <IxTypes.h> |
| 52 | #include <IxOsBuffMgt.h> |
| 53 | #include <IxNpeDl.h> |
| 54 | #include <IxCryptoAcc.h> |
| 55 | #include <IxQMgr.h> |
| 56 | #include <IxOsServices.h> |
| 57 | #include <IxOsCacheMMU.h> |
| 58 | #endif |
| 59 | |
| 60 | /* |
| 61 | * support for access lib version 1.4 |
| 62 | */ |
| 63 | #ifndef IX_MBUF_PRIV |
| 64 | #define IX_MBUF_PRIV(x) ((x)->priv) |
| 65 | #endif |
| 66 | |
| 67 | /* |
| 68 | * the number of simultaneously active requests |
| 69 | */ |
| 70 | static int request_q_len = 40; |
| 71 | module_param(request_q_len, int, 0); |
| 72 | MODULE_PARM_DESC(request_q_len, "Number of outstanding requests"); |
| 73 | |
| 74 | /* |
| 75 | * how many requests we want to have processed |
| 76 | */ |
| 77 | static int request_num = 1024; |
| 78 | module_param(request_num, int, 0); |
| 79 | MODULE_PARM_DESC(request_num, "run for at least this many requests"); |
| 80 | |
| 81 | /* |
| 82 | * the size of each request |
| 83 | */ |
| 84 | static int request_size = 1488; |
| 85 | module_param(request_size, int, 0); |
| 86 | MODULE_PARM_DESC(request_size, "size of each request"); |
| 87 | |
| 88 | /* |
| 89 | * OCF batching of requests |
| 90 | */ |
| 91 | static int request_batch = 1; |
| 92 | module_param(request_batch, int, 0); |
| 93 | MODULE_PARM_DESC(request_batch, "enable OCF request batching"); |
| 94 | |
| 95 | /* |
| 96 | * OCF immediate callback on completion |
| 97 | */ |
| 98 | static int request_cbimm = 1; |
| 99 | module_param(request_cbimm, int, 0); |
| 100 | MODULE_PARM_DESC(request_cbimm, "enable OCF immediate callback on completion"); |
| 101 | |
| 102 | /* |
| 103 | * a structure for each request |
| 104 | */ |
| 105 | typedef struct { |
| 106 | struct work_struct work; |
| 107 | #ifdef BENCH_IXP_ACCESS_LIB |
| 108 | IX_MBUF mbuf; |
| 109 | #endif |
| 110 | unsigned char *buffer; |
| 111 | } request_t; |
| 112 | |
| 113 | static request_t *requests; |
| 114 | |
| 115 | static spinlock_t ocfbench_counter_lock; |
| 116 | static int outstanding; |
| 117 | static int total; |
| 118 | |
| 119 | /*************************************************************************/ |
| 120 | /* |
| 121 | * OCF benchmark routines |
| 122 | */ |
| 123 | |
| 124 | static uint64_t ocf_cryptoid; |
| 125 | static unsigned long jstart, jstop; |
| 126 | |
| 127 | static int ocf_init(void); |
| 128 | static int ocf_cb(struct cryptop *crp); |
| 129 | static void ocf_request(void *arg); |
| 130 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
| 131 | static void ocf_request_wq(struct work_struct *work); |
| 132 | #endif |
| 133 | |
| 134 | static int |
| 135 | ocf_init(void) |
| 136 | { |
| 137 | int error; |
| 138 | struct cryptoini crie, cria; |
| 139 | struct cryptodesc crda, crde; |
| 140 | |
| 141 | memset(&crie, 0, sizeof(crie)); |
| 142 | memset(&cria, 0, sizeof(cria)); |
| 143 | memset(&crde, 0, sizeof(crde)); |
| 144 | memset(&crda, 0, sizeof(crda)); |
| 145 | |
| 146 | cria.cri_alg = CRYPTO_SHA1_HMAC; |
| 147 | cria.cri_klen = 20 * 8; |
| 148 | cria.cri_key = "0123456789abcdefghij"; |
| 149 | |
| 150 | //crie.cri_alg = CRYPTO_3DES_CBC; |
| 151 | crie.cri_alg = CRYPTO_AES_CBC; |
| 152 | crie.cri_klen = 24 * 8; |
| 153 | crie.cri_key = "0123456789abcdefghijklmn"; |
| 154 | |
| 155 | crie.cri_next = &cria; |
| 156 | |
| 157 | error = crypto_newsession(&ocf_cryptoid, &crie, |
| 158 | CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE); |
| 159 | if (error) { |
| 160 | printk("crypto_newsession failed %d\n", error); |
| 161 | return -1; |
| 162 | } |
| 163 | return 0; |
| 164 | } |
| 165 | |
| 166 | static int |
| 167 | ocf_cb(struct cryptop *crp) |
| 168 | { |
| 169 | request_t *r = (request_t *) crp->crp_opaque; |
| 170 | unsigned long flags; |
| 171 | |
| 172 | if (crp->crp_etype) |
| 173 | printk("Error in OCF processing: %d\n", crp->crp_etype); |
| 174 | crypto_freereq(crp); |
| 175 | crp = NULL; |
| 176 | |
| 177 | /* do all requests but take at least 1 second */ |
| 178 | spin_lock_irqsave(&ocfbench_counter_lock, flags); |
| 179 | total++; |
| 180 | if (total > request_num && jstart + HZ < jiffies) { |
| 181 | outstanding--; |
| 182 | spin_unlock_irqrestore(&ocfbench_counter_lock, flags); |
| 183 | return 0; |
| 184 | } |
| 185 | spin_unlock_irqrestore(&ocfbench_counter_lock, flags); |
| 186 | |
| 187 | schedule_work(&r->work); |
| 188 | return 0; |
| 189 | } |
| 190 | |
| 191 | |
| 192 | static void |
| 193 | ocf_request(void *arg) |
| 194 | { |
| 195 | request_t *r = arg; |
| 196 | struct cryptop *crp = crypto_getreq(2); |
| 197 | struct cryptodesc *crde, *crda; |
| 198 | unsigned long flags; |
| 199 | |
| 200 | if (!crp) { |
| 201 | spin_lock_irqsave(&ocfbench_counter_lock, flags); |
| 202 | outstanding--; |
| 203 | spin_unlock_irqrestore(&ocfbench_counter_lock, flags); |
| 204 | return; |
| 205 | } |
| 206 | |
| 207 | crde = crp->crp_desc; |
| 208 | crda = crde->crd_next; |
| 209 | |
| 210 | crda->crd_skip = 0; |
| 211 | crda->crd_flags = 0; |
| 212 | crda->crd_len = request_size; |
| 213 | crda->crd_inject = request_size; |
| 214 | crda->crd_alg = CRYPTO_SHA1_HMAC; |
| 215 | crda->crd_key = "0123456789abcdefghij"; |
| 216 | crda->crd_klen = 20 * 8; |
| 217 | |
| 218 | crde->crd_skip = 0; |
| 219 | crde->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_ENCRYPT; |
| 220 | crde->crd_len = request_size; |
| 221 | crde->crd_inject = request_size; |
| 222 | //crde->crd_alg = CRYPTO_3DES_CBC; |
| 223 | crde->crd_alg = CRYPTO_AES_CBC; |
| 224 | crde->crd_key = "0123456789abcdefghijklmn"; |
| 225 | crde->crd_klen = 24 * 8; |
| 226 | |
| 227 | crp->crp_ilen = request_size + 64; |
| 228 | crp->crp_flags = 0; |
| 229 | if (request_batch) |
| 230 | crp->crp_flags |= CRYPTO_F_BATCH; |
| 231 | if (request_cbimm) |
| 232 | crp->crp_flags |= CRYPTO_F_CBIMM; |
| 233 | crp->crp_buf = (caddr_t) r->buffer; |
| 234 | crp->crp_callback = ocf_cb; |
| 235 | crp->crp_sid = ocf_cryptoid; |
| 236 | crp->crp_opaque = (caddr_t) r; |
| 237 | crypto_dispatch(crp); |
| 238 | } |
| 239 | |
| 240 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
| 241 | static void |
| 242 | ocf_request_wq(struct work_struct *work) |
| 243 | { |
| 244 | request_t *r = container_of(work, request_t, work); |
| 245 | ocf_request(r); |
| 246 | } |
| 247 | #endif |
| 248 | |
| 249 | static void |
| 250 | ocf_done(void) |
| 251 | { |
| 252 | crypto_freesession(ocf_cryptoid); |
| 253 | } |
| 254 | |
| 255 | /*************************************************************************/ |
| 256 | #ifdef BENCH_IXP_ACCESS_LIB |
| 257 | /*************************************************************************/ |
| 258 | /* |
| 259 | * CryptoAcc benchmark routines |
| 260 | */ |
| 261 | |
| 262 | static IxCryptoAccCtx ixp_ctx; |
| 263 | static UINT32 ixp_ctx_id; |
| 264 | static IX_MBUF ixp_pri; |
| 265 | static IX_MBUF ixp_sec; |
| 266 | static int ixp_registered = 0; |
| 267 | |
| 268 | static void ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, |
| 269 | IxCryptoAccStatus status); |
| 270 | static void ixp_perform_cb(UINT32 ctx_id, IX_MBUF *sbufp, IX_MBUF *dbufp, |
| 271 | IxCryptoAccStatus status); |
| 272 | static void ixp_request(void *arg); |
| 273 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
| 274 | static void ixp_request_wq(struct work_struct *work); |
| 275 | #endif |
| 276 | |
| 277 | static int |
| 278 | ixp_init(void) |
| 279 | { |
| 280 | IxCryptoAccStatus status; |
| 281 | |
| 282 | ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_3DES; |
| 283 | ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; |
| 284 | ixp_ctx.cipherCtx.cipherKeyLen = 24; |
| 285 | ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64; |
| 286 | ixp_ctx.cipherCtx.cipherInitialVectorLen = IX_CRYPTO_ACC_DES_IV_64; |
| 287 | memcpy(ixp_ctx.cipherCtx.key.cipherKey, "0123456789abcdefghijklmn", 24); |
| 288 | |
| 289 | ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_SHA1; |
| 290 | ixp_ctx.authCtx.authDigestLen = 12; |
| 291 | ixp_ctx.authCtx.aadLen = 0; |
| 292 | ixp_ctx.authCtx.authKeyLen = 20; |
| 293 | memcpy(ixp_ctx.authCtx.key.authKey, "0123456789abcdefghij", 20); |
| 294 | |
| 295 | ixp_ctx.useDifferentSrcAndDestMbufs = 0; |
| 296 | ixp_ctx.operation = IX_CRYPTO_ACC_OP_ENCRYPT_AUTH ; |
| 297 | |
| 298 | IX_MBUF_MLEN(&ixp_pri) = IX_MBUF_PKT_LEN(&ixp_pri) = 128; |
| 299 | IX_MBUF_MDATA(&ixp_pri) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); |
| 300 | IX_MBUF_MLEN(&ixp_sec) = IX_MBUF_PKT_LEN(&ixp_sec) = 128; |
| 301 | IX_MBUF_MDATA(&ixp_sec) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); |
| 302 | |
| 303 | status = ixCryptoAccCtxRegister(&ixp_ctx, &ixp_pri, &ixp_sec, |
| 304 | ixp_register_cb, ixp_perform_cb, &ixp_ctx_id); |
| 305 | |
| 306 | if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) { |
| 307 | while (!ixp_registered) |
| 308 | schedule(); |
| 309 | return ixp_registered < 0 ? -1 : 0; |
| 310 | } |
| 311 | |
| 312 | printk("ixp: ixCryptoAccCtxRegister failed %d\n", status); |
| 313 | return -1; |
| 314 | } |
| 315 | |
| 316 | static void |
| 317 | ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, IxCryptoAccStatus status) |
| 318 | { |
| 319 | if (bufp) { |
| 320 | IX_MBUF_MLEN(bufp) = IX_MBUF_PKT_LEN(bufp) = 0; |
| 321 | kfree(IX_MBUF_MDATA(bufp)); |
| 322 | IX_MBUF_MDATA(bufp) = NULL; |
| 323 | } |
| 324 | |
| 325 | if (IX_CRYPTO_ACC_STATUS_WAIT == status) |
| 326 | return; |
| 327 | if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) |
| 328 | ixp_registered = 1; |
| 329 | else |
| 330 | ixp_registered = -1; |
| 331 | } |
| 332 | |
| 333 | static void |
| 334 | ixp_perform_cb( |
| 335 | UINT32 ctx_id, |
| 336 | IX_MBUF *sbufp, |
| 337 | IX_MBUF *dbufp, |
| 338 | IxCryptoAccStatus status) |
| 339 | { |
| 340 | request_t *r = NULL; |
| 341 | unsigned long flags; |
| 342 | |
| 343 | /* do all requests but take at least 1 second */ |
| 344 | spin_lock_irqsave(&ocfbench_counter_lock, flags); |
| 345 | total++; |
| 346 | if (total > request_num && jstart + HZ < jiffies) { |
| 347 | outstanding--; |
| 348 | spin_unlock_irqrestore(&ocfbench_counter_lock, flags); |
| 349 | return; |
| 350 | } |
| 351 | |
| 352 | if (!sbufp || !(r = IX_MBUF_PRIV(sbufp))) { |
| 353 | printk("crappo %p %p\n", sbufp, r); |
| 354 | outstanding--; |
| 355 | spin_unlock_irqrestore(&ocfbench_counter_lock, flags); |
| 356 | return; |
| 357 | } |
| 358 | spin_unlock_irqrestore(&ocfbench_counter_lock, flags); |
| 359 | |
| 360 | schedule_work(&r->work); |
| 361 | } |
| 362 | |
| 363 | static void |
| 364 | ixp_request(void *arg) |
| 365 | { |
| 366 | request_t *r = arg; |
| 367 | IxCryptoAccStatus status; |
| 368 | unsigned long flags; |
| 369 | |
| 370 | memset(&r->mbuf, 0, sizeof(r->mbuf)); |
| 371 | IX_MBUF_MLEN(&r->mbuf) = IX_MBUF_PKT_LEN(&r->mbuf) = request_size + 64; |
| 372 | IX_MBUF_MDATA(&r->mbuf) = r->buffer; |
| 373 | IX_MBUF_PRIV(&r->mbuf) = r; |
| 374 | status = ixCryptoAccAuthCryptPerform(ixp_ctx_id, &r->mbuf, NULL, |
| 375 | 0, request_size, 0, request_size, request_size, r->buffer); |
| 376 | if (IX_CRYPTO_ACC_STATUS_SUCCESS != status) { |
| 377 | printk("status1 = %d\n", status); |
| 378 | spin_lock_irqsave(&ocfbench_counter_lock, flags); |
| 379 | outstanding--; |
| 380 | spin_unlock_irqrestore(&ocfbench_counter_lock, flags); |
| 381 | return; |
| 382 | } |
| 383 | return; |
| 384 | } |
| 385 | |
| 386 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
| 387 | static void |
| 388 | ixp_request_wq(struct work_struct *work) |
| 389 | { |
| 390 | request_t *r = container_of(work, request_t, work); |
| 391 | ixp_request(r); |
| 392 | } |
| 393 | #endif |
| 394 | |
| 395 | static void |
| 396 | ixp_done(void) |
| 397 | { |
| 398 | /* we should free the session here but I am lazy :-) */ |
| 399 | } |
| 400 | |
| 401 | /*************************************************************************/ |
| 402 | #endif /* BENCH_IXP_ACCESS_LIB */ |
| 403 | /*************************************************************************/ |
| 404 | |
| 405 | int |
| 406 | ocfbench_init(void) |
| 407 | { |
| 408 | int i; |
| 409 | unsigned long mbps; |
| 410 | unsigned long flags; |
| 411 | |
| 412 | printk("Crypto Speed tests\n"); |
| 413 | |
| 414 | requests = kmalloc(sizeof(request_t) * request_q_len, GFP_KERNEL); |
| 415 | if (!requests) { |
| 416 | printk("malloc failed\n"); |
| 417 | return -EINVAL; |
| 418 | } |
| 419 | |
| 420 | for (i = 0; i < request_q_len; i++) { |
| 421 | /* +64 for return data */ |
| 422 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
| 423 | INIT_WORK(&requests[i].work, ocf_request_wq); |
| 424 | #else |
| 425 | INIT_WORK(&requests[i].work, ocf_request, &requests[i]); |
| 426 | #endif |
| 427 | requests[i].buffer = kmalloc(request_size + 128, GFP_DMA); |
| 428 | if (!requests[i].buffer) { |
| 429 | printk("malloc failed\n"); |
| 430 | return -EINVAL; |
| 431 | } |
| 432 | memset(requests[i].buffer, '0' + i, request_size + 128); |
| 433 | } |
| 434 | |
| 435 | /* |
| 436 | * OCF benchmark |
| 437 | */ |
| 438 | printk("OCF: testing ...\n"); |
| 439 | if (ocf_init() == -1) |
| 440 | return -EINVAL; |
| 441 | |
| 442 | spin_lock_init(&ocfbench_counter_lock); |
| 443 | total = outstanding = 0; |
| 444 | jstart = jiffies; |
| 445 | for (i = 0; i < request_q_len; i++) { |
| 446 | spin_lock_irqsave(&ocfbench_counter_lock, flags); |
| 447 | outstanding++; |
| 448 | spin_unlock_irqrestore(&ocfbench_counter_lock, flags); |
| 449 | ocf_request(&requests[i]); |
| 450 | } |
| 451 | while (outstanding > 0) |
| 452 | schedule(); |
| 453 | jstop = jiffies; |
| 454 | |
| 455 | mbps = 0; |
| 456 | if (jstop > jstart) { |
| 457 | mbps = (unsigned long) total * (unsigned long) request_size * 8; |
| 458 | mbps /= ((jstop - jstart) * 1000) / HZ; |
| 459 | } |
| 460 | printk("OCF: %d requests of %d bytes in %d jiffies (%d.%03d Mbps)\n", |
| 461 | total, request_size, (int)(jstop - jstart), |
| 462 | ((int)mbps) / 1000, ((int)mbps) % 1000); |
| 463 | ocf_done(); |
| 464 | |
| 465 | #ifdef BENCH_IXP_ACCESS_LIB |
| 466 | /* |
| 467 | * IXP benchmark |
| 468 | */ |
| 469 | printk("IXP: testing ...\n"); |
| 470 | ixp_init(); |
| 471 | total = outstanding = 0; |
| 472 | jstart = jiffies; |
| 473 | for (i = 0; i < request_q_len; i++) { |
| 474 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
| 475 | INIT_WORK(&requests[i].work, ixp_request_wq); |
| 476 | #else |
| 477 | INIT_WORK(&requests[i].work, ixp_request, &requests[i]); |
| 478 | #endif |
| 479 | spin_lock_irqsave(&ocfbench_counter_lock, flags); |
| 480 | outstanding++; |
| 481 | spin_unlock_irqrestore(&ocfbench_counter_lock, flags); |
| 482 | ixp_request(&requests[i]); |
| 483 | } |
| 484 | while (outstanding > 0) |
| 485 | schedule(); |
| 486 | jstop = jiffies; |
| 487 | |
| 488 | mbps = 0; |
| 489 | if (jstop > jstart) { |
| 490 | mbps = (unsigned long) total * (unsigned long) request_size * 8; |
| 491 | mbps /= ((jstop - jstart) * 1000) / HZ; |
| 492 | } |
| 493 | printk("IXP: %d requests of %d bytes in %d jiffies (%d.%03d Mbps)\n", |
| 494 | total, request_size, jstop - jstart, |
| 495 | ((int)mbps) / 1000, ((int)mbps) % 1000); |
| 496 | ixp_done(); |
| 497 | #endif /* BENCH_IXP_ACCESS_LIB */ |
| 498 | |
| 499 | for (i = 0; i < request_q_len; i++) |
| 500 | kfree(requests[i].buffer); |
| 501 | kfree(requests); |
| 502 | return -EINVAL; /* always fail to load so it can be re-run quickly ;-) */ |
| 503 | } |
| 504 | |
| 505 | static void __exit ocfbench_exit(void) |
| 506 | { |
| 507 | } |
| 508 | |
| 509 | module_init(ocfbench_init); |
| 510 | module_exit(ocfbench_exit); |
| 511 | |
| 512 | MODULE_LICENSE("BSD"); |
| 513 | MODULE_AUTHOR("David McCullough <david_mccullough@mcafee.com>"); |
| 514 | MODULE_DESCRIPTION("Benchmark various in-kernel crypto speeds"); |
| 515 | |