Commit b8840098b70c11d70c29263e0765f103e6cbe55e

Authored by Sonic Zhang
Committed by Herbert Xu
1 parent a482b081a2

crypto: bfin_crc - CRC hardware driver for BF60x family processors.

The CRC peripheral is a hardware block used to compute the CRC of the block
of data. This is based on a CRC32 engine which computes the CRC value of 32b
data words presented to it. For data words of < 32b in size, this driver
pack 0 automatically into 32b data units. This driver implements the async
hash crypto framework API.

Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Showing 3 changed files with 789 additions and 1 deletions Side-by-side Diff

drivers/crypto/Kconfig
... ... @@ -325,5 +325,12 @@
325 325 source "drivers/crypto/ux500/Kconfig"
326 326 endif # if CRYPTO_DEV_UX500
327 327  
  328 +config CRYPTO_DEV_BFIN_CRC
  329 + tristate "Support for Blackfin CRC hardware"
  330 + depends on BF60x
  331 + help
  332 + Newer Blackfin processors have CRC hardware. Select this if you
  333 + want to use the Blackfin CRC module.
  334 +
328 335 endif # CRYPTO_HW
drivers/crypto/Makefile
... ... @@ -15,4 +15,5 @@
15 15 obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
16 16 obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
17 17 obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
  18 +obj-$(CONFIG_CRYPTO_DEV_BFIN_CRC) += bfin_crc.o
drivers/crypto/bfin_crc.c
  1 +/*
  2 + * Cryptographic API.
  3 + *
  4 + * Support Blackfin CRC HW acceleration.
  5 + *
  6 + * Copyright 2012 Analog Devices Inc.
  7 + *
  8 + * Licensed under the GPL-2.
  9 + */
  10 +
  11 +#include <linux/err.h>
  12 +#include <linux/device.h>
  13 +#include <linux/module.h>
  14 +#include <linux/init.h>
  15 +#include <linux/errno.h>
  16 +#include <linux/interrupt.h>
  17 +#include <linux/kernel.h>
  18 +#include <linux/irq.h>
  19 +#include <linux/io.h>
  20 +#include <linux/platform_device.h>
  21 +#include <linux/scatterlist.h>
  22 +#include <linux/dma-mapping.h>
  23 +#include <linux/delay.h>
  24 +#include <linux/unaligned/access_ok.h>
  25 +#include <linux/crypto.h>
  26 +#include <linux/cryptohash.h>
  27 +#include <crypto/scatterwalk.h>
  28 +#include <crypto/algapi.h>
  29 +#include <crypto/hash.h>
  30 +#include <crypto/internal/hash.h>
  31 +
  32 +#include <asm/blackfin.h>
  33 +#include <asm/bfin_crc.h>
  34 +#include <asm/dma.h>
  35 +#include <asm/portmux.h>
  36 +
  37 +#define CRC_CCRYPTO_QUEUE_LENGTH 5
  38 +
  39 +#define DRIVER_NAME "bfin-hmac-crc"
  40 +#define CHKSUM_DIGEST_SIZE 4
  41 +#define CHKSUM_BLOCK_SIZE 1
  42 +
  43 +#define CRC_MAX_DMA_DESC 100
  44 +
  45 +#define CRC_CRYPTO_STATE_UPDATE 1
  46 +#define CRC_CRYPTO_STATE_FINALUPDATE 2
  47 +#define CRC_CRYPTO_STATE_FINISH 3
  48 +
  49 +struct bfin_crypto_crc {
  50 + struct list_head list;
  51 + struct device *dev;
  52 + spinlock_t lock;
  53 +
  54 + int irq;
  55 + int dma_ch;
  56 + u32 poly;
  57 + volatile struct crc_register *regs;
  58 +
  59 + struct ahash_request *req; /* current request in operation */
  60 + struct dma_desc_array *sg_cpu; /* virt addr of sg dma descriptors */
  61 + dma_addr_t sg_dma; /* phy addr of sg dma descriptors */
  62 + u8 *sg_mid_buf;
  63 +
  64 + struct tasklet_struct done_task;
  65 + struct crypto_queue queue; /* waiting requests */
  66 +
  67 + u8 busy:1; /* crc device in operation flag */
  68 +};
  69 +
  70 +static struct bfin_crypto_crc_list {
  71 + struct list_head dev_list;
  72 + spinlock_t lock;
  73 +} crc_list;
  74 +
  75 +struct bfin_crypto_crc_reqctx {
  76 + struct bfin_crypto_crc *crc;
  77 +
  78 + unsigned int total; /* total request bytes */
  79 + size_t sg_buflen; /* bytes for this update */
  80 + unsigned int sg_nents;
  81 + struct scatterlist *sg; /* sg list head for this update*/
  82 + struct scatterlist bufsl[2]; /* chained sg list */
  83 +
  84 + size_t bufnext_len;
  85 + size_t buflast_len;
  86 + u8 bufnext[CHKSUM_DIGEST_SIZE]; /* extra bytes for next udpate */
  87 + u8 buflast[CHKSUM_DIGEST_SIZE]; /* extra bytes from last udpate */
  88 +
  89 + u8 flag;
  90 +};
  91 +
  92 +struct bfin_crypto_crc_ctx {
  93 + struct bfin_crypto_crc *crc;
  94 + u32 key;
  95 +};
  96 +
  97 +
  98 +/*
  99 + * derive number of elements in scatterlist
  100 + */
  101 +static int sg_count(struct scatterlist *sg_list)
  102 +{
  103 + struct scatterlist *sg = sg_list;
  104 + int sg_nents = 1;
  105 +
  106 + if (sg_list == NULL)
  107 + return 0;
  108 +
  109 + while (!sg_is_last(sg)) {
  110 + sg_nents++;
  111 + sg = scatterwalk_sg_next(sg);
  112 + }
  113 +
  114 + return sg_nents;
  115 +}
  116 +
  117 +/*
  118 + * get element in scatter list by given index
  119 + */
  120 +static struct scatterlist *sg_get(struct scatterlist *sg_list, unsigned int nents,
  121 + unsigned int index)
  122 +{
  123 + struct scatterlist *sg = NULL;
  124 + int i;
  125 +
  126 + for_each_sg(sg_list, sg, nents, i)
  127 + if (i == index)
  128 + break;
  129 +
  130 + return sg;
  131 +}
  132 +
  133 +static int bfin_crypto_crc_init_hw(struct bfin_crypto_crc *crc, u32 key)
  134 +{
  135 + crc->regs->datacntrld = 0;
  136 + crc->regs->control = MODE_CALC_CRC << OPMODE_OFFSET;
  137 + crc->regs->curresult = key;
  138 +
  139 + /* setup CRC interrupts */
  140 + crc->regs->status = CMPERRI | DCNTEXPI;
  141 + crc->regs->intrenset = CMPERRI | DCNTEXPI;
  142 + SSYNC();
  143 +
  144 + return 0;
  145 +}
  146 +
  147 +static int bfin_crypto_crc_init(struct ahash_request *req)
  148 +{
  149 + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
  150 + struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
  151 + struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
  152 + struct bfin_crypto_crc *crc;
  153 +
  154 + dev_dbg(crc->dev, "crc_init\n");
  155 + spin_lock_bh(&crc_list.lock);
  156 + list_for_each_entry(crc, &crc_list.dev_list, list) {
  157 + crc_ctx->crc = crc;
  158 + break;
  159 + }
  160 + spin_unlock_bh(&crc_list.lock);
  161 +
  162 + if (sg_count(req->src) > CRC_MAX_DMA_DESC) {
  163 + dev_dbg(crc->dev, "init: requested sg list is too big > %d\n",
  164 + CRC_MAX_DMA_DESC);
  165 + return -EINVAL;
  166 + }
  167 +
  168 + ctx->crc = crc;
  169 + ctx->bufnext_len = 0;
  170 + ctx->buflast_len = 0;
  171 + ctx->sg_buflen = 0;
  172 + ctx->total = 0;
  173 + ctx->flag = 0;
  174 +
  175 + /* init crc results */
  176 + put_unaligned_le32(crc_ctx->key, req->result);
  177 +
  178 + dev_dbg(crc->dev, "init: digest size: %d\n",
  179 + crypto_ahash_digestsize(tfm));
  180 +
  181 + return bfin_crypto_crc_init_hw(crc, crc_ctx->key);
  182 +}
  183 +
  184 +static void bfin_crypto_crc_config_dma(struct bfin_crypto_crc *crc)
  185 +{
  186 + struct scatterlist *sg;
  187 + struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(crc->req);
  188 + int i = 0, j = 0;
  189 + unsigned long dma_config;
  190 + unsigned int dma_count;
  191 + unsigned int dma_addr;
  192 + unsigned int mid_dma_count = 0;
  193 + int dma_mod;
  194 +
  195 + dma_map_sg(crc->dev, ctx->sg, ctx->sg_nents, DMA_TO_DEVICE);
  196 +
  197 + for_each_sg(ctx->sg, sg, ctx->sg_nents, j) {
  198 + dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 | DMAEN | PSIZE_32;
  199 + dma_addr = sg_dma_address(sg);
  200 + /* deduce extra bytes in last sg */
  201 + if (sg_is_last(sg))
  202 + dma_count = sg_dma_len(sg) - ctx->bufnext_len;
  203 + else
  204 + dma_count = sg_dma_len(sg);
  205 +
  206 + if (mid_dma_count) {
  207 + /* Append last middle dma buffer to 4 bytes with first
  208 + bytes in current sg buffer. Move addr of current
  209 + sg and deduce the length of current sg.
  210 + */
  211 + memcpy(crc->sg_mid_buf +((i-1) << 2) + mid_dma_count,
  212 + (void *)dma_addr,
  213 + CHKSUM_DIGEST_SIZE - mid_dma_count);
  214 + dma_addr += CHKSUM_DIGEST_SIZE - mid_dma_count;
  215 + dma_count -= CHKSUM_DIGEST_SIZE - mid_dma_count;
  216 + }
  217 + /* chop current sg dma len to multiple of 32 bits */
  218 + mid_dma_count = dma_count % 4;
  219 + dma_count &= ~0x3;
  220 +
  221 + if (dma_addr % 4 == 0) {
  222 + dma_config |= WDSIZE_32;
  223 + dma_count >>= 2;
  224 + dma_mod = 4;
  225 + } else if (dma_addr % 2 == 0) {
  226 + dma_config |= WDSIZE_16;
  227 + dma_count >>= 1;
  228 + dma_mod = 2;
  229 + } else {
  230 + dma_config |= WDSIZE_8;
  231 + dma_mod = 1;
  232 + }
  233 +
  234 + crc->sg_cpu[i].start_addr = dma_addr;
  235 + crc->sg_cpu[i].cfg = dma_config;
  236 + crc->sg_cpu[i].x_count = dma_count;
  237 + crc->sg_cpu[i].x_modify = dma_mod;
  238 + dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, "
  239 + "cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n",
  240 + i, crc->sg_cpu[i].start_addr,
  241 + crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count,
  242 + crc->sg_cpu[i].x_modify);
  243 + i++;
  244 +
  245 + if (mid_dma_count) {
  246 + /* copy extra bytes to next middle dma buffer */
  247 + dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 |
  248 + DMAEN | PSIZE_32 | WDSIZE_32;
  249 + memcpy(crc->sg_mid_buf + (i << 2),
  250 + (void *)(dma_addr + (dma_count << 2)),
  251 + mid_dma_count);
  252 + /* setup new dma descriptor for next middle dma */
  253 + crc->sg_cpu[i].start_addr = dma_map_single(crc->dev,
  254 + crc->sg_mid_buf + (i << 2),
  255 + CHKSUM_DIGEST_SIZE, DMA_TO_DEVICE);
  256 + crc->sg_cpu[i].cfg = dma_config;
  257 + crc->sg_cpu[i].x_count = 1;
  258 + crc->sg_cpu[i].x_modify = CHKSUM_DIGEST_SIZE;
  259 + dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, "
  260 + "cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n",
  261 + i, crc->sg_cpu[i].start_addr,
  262 + crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count,
  263 + crc->sg_cpu[i].x_modify);
  264 + i++;
  265 + }
  266 + }
  267 +
  268 + dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 | DMAEN | PSIZE_32 | WDSIZE_32;
  269 + /* For final update req, append the buffer for next update as well*/
  270 + if (ctx->bufnext_len && (ctx->flag == CRC_CRYPTO_STATE_FINALUPDATE ||
  271 + ctx->flag == CRC_CRYPTO_STATE_FINISH)) {
  272 + crc->sg_cpu[i].start_addr = dma_map_single(crc->dev, ctx->bufnext,
  273 + CHKSUM_DIGEST_SIZE, DMA_TO_DEVICE);
  274 + crc->sg_cpu[i].cfg = dma_config;
  275 + crc->sg_cpu[i].x_count = 1;
  276 + crc->sg_cpu[i].x_modify = CHKSUM_DIGEST_SIZE;
  277 + dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, "
  278 + "cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n",
  279 + i, crc->sg_cpu[i].start_addr,
  280 + crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count,
  281 + crc->sg_cpu[i].x_modify);
  282 + i++;
  283 + }
  284 +
  285 + if (i == 0)
  286 + return;
  287 +
  288 + flush_dcache_range((unsigned int)crc->sg_cpu,
  289 + (unsigned int)crc->sg_cpu +
  290 + i * sizeof(struct dma_desc_array));
  291 +
  292 + /* Set the last descriptor to stop mode */
  293 + crc->sg_cpu[i - 1].cfg &= ~(DMAFLOW | NDSIZE);
  294 + crc->sg_cpu[i - 1].cfg |= DI_EN;
  295 + set_dma_curr_desc_addr(crc->dma_ch, (unsigned long *)crc->sg_dma);
  296 + set_dma_x_count(crc->dma_ch, 0);
  297 + set_dma_x_modify(crc->dma_ch, 0);
  298 + SSYNC();
  299 + set_dma_config(crc->dma_ch, dma_config);
  300 +}
  301 +
  302 +static int bfin_crypto_crc_handle_queue(struct bfin_crypto_crc *crc,
  303 + struct ahash_request *req)
  304 +{
  305 + struct crypto_async_request *async_req, *backlog;
  306 + struct bfin_crypto_crc_reqctx *ctx;
  307 + struct scatterlist *sg;
  308 + int ret = 0;
  309 + int nsg, i, j;
  310 + unsigned int nextlen;
  311 + unsigned long flags;
  312 +
  313 + spin_lock_irqsave(&crc->lock, flags);
  314 + if (req)
  315 + ret = ahash_enqueue_request(&crc->queue, req);
  316 + if (crc->busy) {
  317 + spin_unlock_irqrestore(&crc->lock, flags);
  318 + return ret;
  319 + }
  320 + backlog = crypto_get_backlog(&crc->queue);
  321 + async_req = crypto_dequeue_request(&crc->queue);
  322 + if (async_req)
  323 + crc->busy = 1;
  324 + spin_unlock_irqrestore(&crc->lock, flags);
  325 +
  326 + if (!async_req)
  327 + return ret;
  328 +
  329 + if (backlog)
  330 + backlog->complete(backlog, -EINPROGRESS);
  331 +
  332 + req = ahash_request_cast(async_req);
  333 + crc->req = req;
  334 + ctx = ahash_request_ctx(req);
  335 + ctx->sg = NULL;
  336 + ctx->sg_buflen = 0;
  337 + ctx->sg_nents = 0;
  338 +
  339 + dev_dbg(crc->dev, "handling new req, flag=%u, nbytes: %d\n",
  340 + ctx->flag, req->nbytes);
  341 +
  342 + if (ctx->flag == CRC_CRYPTO_STATE_FINISH) {
  343 + if (ctx->bufnext_len == 0) {
  344 + crc->busy = 0;
  345 + return 0;
  346 + }
  347 +
  348 + /* Pack last crc update buffer to 32bit */
  349 + memset(ctx->bufnext + ctx->bufnext_len, 0,
  350 + CHKSUM_DIGEST_SIZE - ctx->bufnext_len);
  351 + } else {
  352 + /* Pack small data which is less than 32bit to buffer for next update. */
  353 + if (ctx->bufnext_len + req->nbytes < CHKSUM_DIGEST_SIZE) {
  354 + memcpy(ctx->bufnext + ctx->bufnext_len,
  355 + sg_virt(req->src), req->nbytes);
  356 + ctx->bufnext_len += req->nbytes;
  357 + if (ctx->flag == CRC_CRYPTO_STATE_FINALUPDATE &&
  358 + ctx->bufnext_len) {
  359 + goto finish_update;
  360 + } else {
  361 + crc->busy = 0;
  362 + return 0;
  363 + }
  364 + }
  365 +
  366 + if (ctx->bufnext_len) {
  367 + /* Chain in extra bytes of last update */
  368 + ctx->buflast_len = ctx->bufnext_len;
  369 + memcpy(ctx->buflast, ctx->bufnext, ctx->buflast_len);
  370 +
  371 + nsg = ctx->sg_buflen ? 2 : 1;
  372 + sg_init_table(ctx->bufsl, nsg);
  373 + sg_set_buf(ctx->bufsl, ctx->buflast, ctx->buflast_len);
  374 + if (nsg > 1)
  375 + scatterwalk_sg_chain(ctx->bufsl, nsg,
  376 + req->src);
  377 + ctx->sg = ctx->bufsl;
  378 + } else
  379 + ctx->sg = req->src;
  380 +
  381 + /* Chop crc buffer size to multiple of 32 bit */
  382 + nsg = ctx->sg_nents = sg_count(ctx->sg);
  383 + ctx->sg_buflen = ctx->buflast_len + req->nbytes;
  384 + ctx->bufnext_len = ctx->sg_buflen % 4;
  385 + ctx->sg_buflen &= ~0x3;
  386 +
  387 + if (ctx->bufnext_len) {
  388 + /* copy extra bytes to buffer for next update */
  389 + memset(ctx->bufnext, 0, CHKSUM_DIGEST_SIZE);
  390 + nextlen = ctx->bufnext_len;
  391 + for (i = nsg - 1; i >= 0; i--) {
  392 + sg = sg_get(ctx->sg, nsg, i);
  393 + j = min(nextlen, sg_dma_len(sg));
  394 + memcpy(ctx->bufnext + nextlen - j,
  395 + sg_virt(sg) + sg_dma_len(sg) - j, j);
  396 + if (j == sg_dma_len(sg))
  397 + ctx->sg_nents--;
  398 + nextlen -= j;
  399 + if (nextlen == 0)
  400 + break;
  401 + }
  402 + }
  403 + }
  404 +
  405 +finish_update:
  406 + if (ctx->bufnext_len && (ctx->flag == CRC_CRYPTO_STATE_FINALUPDATE ||
  407 + ctx->flag == CRC_CRYPTO_STATE_FINISH))
  408 + ctx->sg_buflen += CHKSUM_DIGEST_SIZE;
  409 +
  410 + /* set CRC data count before start DMA */
  411 + crc->regs->datacnt = ctx->sg_buflen >> 2;
  412 +
  413 + /* setup and enable CRC DMA */
  414 + bfin_crypto_crc_config_dma(crc);
  415 +
  416 + /* finally kick off CRC operation */
  417 + crc->regs->control |= BLKEN;
  418 + SSYNC();
  419 +
  420 + return -EINPROGRESS;
  421 +}
  422 +
  423 +static int bfin_crypto_crc_update(struct ahash_request *req)
  424 +{
  425 + struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
  426 +
  427 + if (!req->nbytes)
  428 + return 0;
  429 +
  430 + dev_dbg(ctx->crc->dev, "crc_update\n");
  431 + ctx->total += req->nbytes;
  432 + ctx->flag = CRC_CRYPTO_STATE_UPDATE;
  433 +
  434 + return bfin_crypto_crc_handle_queue(ctx->crc, req);
  435 +}
  436 +
  437 +static int bfin_crypto_crc_final(struct ahash_request *req)
  438 +{
  439 + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
  440 + struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
  441 + struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
  442 +
  443 + dev_dbg(ctx->crc->dev, "crc_final\n");
  444 + ctx->flag = CRC_CRYPTO_STATE_FINISH;
  445 + crc_ctx->key = 0;
  446 +
  447 + return bfin_crypto_crc_handle_queue(ctx->crc, req);
  448 +}
  449 +
  450 +static int bfin_crypto_crc_finup(struct ahash_request *req)
  451 +{
  452 + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
  453 + struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
  454 + struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
  455 +
  456 + dev_dbg(ctx->crc->dev, "crc_finishupdate\n");
  457 + ctx->total += req->nbytes;
  458 + ctx->flag = CRC_CRYPTO_STATE_FINALUPDATE;
  459 + crc_ctx->key = 0;
  460 +
  461 + return bfin_crypto_crc_handle_queue(ctx->crc, req);
  462 +}
  463 +
  464 +static int bfin_crypto_crc_digest(struct ahash_request *req)
  465 +{
  466 + int ret;
  467 +
  468 + ret = bfin_crypto_crc_init(req);
  469 + if (ret)
  470 + return ret;
  471 +
  472 + return bfin_crypto_crc_finup(req);
  473 +}
  474 +
  475 +static int bfin_crypto_crc_setkey(struct crypto_ahash *tfm, const u8 *key,
  476 + unsigned int keylen)
  477 +{
  478 + struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
  479 +
  480 + dev_dbg(crc_ctx->crc->dev, "crc_setkey\n");
  481 + if (keylen != CHKSUM_DIGEST_SIZE) {
  482 + crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
  483 + return -EINVAL;
  484 + }
  485 +
  486 + crc_ctx->key = get_unaligned_le32(key);
  487 +
  488 + return 0;
  489 +}
  490 +
  491 +static int bfin_crypto_crc_cra_init(struct crypto_tfm *tfm)
  492 +{
  493 + struct bfin_crypto_crc_ctx *crc_ctx = crypto_tfm_ctx(tfm);
  494 +
  495 + crc_ctx->key = 0;
  496 + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
  497 + sizeof(struct bfin_crypto_crc_reqctx));
  498 +
  499 + return 0;
  500 +}
  501 +
  502 +static void bfin_crypto_crc_cra_exit(struct crypto_tfm *tfm)
  503 +{
  504 +}
  505 +
  506 +static struct ahash_alg algs = {
  507 + .init = bfin_crypto_crc_init,
  508 + .update = bfin_crypto_crc_update,
  509 + .final = bfin_crypto_crc_final,
  510 + .finup = bfin_crypto_crc_finup,
  511 + .digest = bfin_crypto_crc_digest,
  512 + .setkey = bfin_crypto_crc_setkey,
  513 + .halg.digestsize = CHKSUM_DIGEST_SIZE,
  514 + .halg.base = {
  515 + .cra_name = "hmac(crc32)",
  516 + .cra_driver_name = DRIVER_NAME,
  517 + .cra_priority = 100,
  518 + .cra_flags = CRYPTO_ALG_TYPE_AHASH |
  519 + CRYPTO_ALG_ASYNC,
  520 + .cra_blocksize = CHKSUM_BLOCK_SIZE,
  521 + .cra_ctxsize = sizeof(struct bfin_crypto_crc_ctx),
  522 + .cra_alignmask = 3,
  523 + .cra_module = THIS_MODULE,
  524 + .cra_init = bfin_crypto_crc_cra_init,
  525 + .cra_exit = bfin_crypto_crc_cra_exit,
  526 + }
  527 +};
  528 +
  529 +static void bfin_crypto_crc_done_task(unsigned long data)
  530 +{
  531 + struct bfin_crypto_crc *crc = (struct bfin_crypto_crc *)data;
  532 +
  533 + bfin_crypto_crc_handle_queue(crc, NULL);
  534 +}
  535 +
  536 +static irqreturn_t bfin_crypto_crc_handler(int irq, void *dev_id)
  537 +{
  538 + struct bfin_crypto_crc *crc = dev_id;
  539 +
  540 + if (crc->regs->status & DCNTEXP) {
  541 + crc->regs->status = DCNTEXP;
  542 + SSYNC();
  543 +
  544 + /* prepare results */
  545 + put_unaligned_le32(crc->regs->result, crc->req->result);
  546 +
  547 + crc->regs->control &= ~BLKEN;
  548 + crc->busy = 0;
  549 +
  550 + if (crc->req->base.complete)
  551 + crc->req->base.complete(&crc->req->base, 0);
  552 +
  553 + tasklet_schedule(&crc->done_task);
  554 +
  555 + return IRQ_HANDLED;
  556 + } else
  557 + return IRQ_NONE;
  558 +}
  559 +
  560 +#ifdef CONFIG_PM
  561 +/**
  562 + * bfin_crypto_crc_suspend - suspend crc device
  563 + * @pdev: device being suspended
  564 + * @state: requested suspend state
  565 + */
  566 +static int bfin_crypto_crc_suspend(struct platform_device *pdev, pm_message_t state)
  567 +{
  568 + struct bfin_crypto_crc *crc = platform_get_drvdata(pdev);
  569 + int i = 100000;
  570 +
  571 + while ((crc->regs->control & BLKEN) && --i)
  572 + cpu_relax();
  573 +
  574 + if (i == 0)
  575 + return -EBUSY;
  576 +
  577 + return 0;
  578 +}
  579 +#else
  580 +# define bfin_crypto_crc_suspend NULL
  581 +#endif
  582 +
  583 +#define bfin_crypto_crc_resume NULL
  584 +
  585 +/**
  586 + * bfin_crypto_crc_probe - Initialize module
  587 + *
  588 + */
  589 +static int __devinit bfin_crypto_crc_probe(struct platform_device *pdev)
  590 +{
  591 + struct device *dev = &pdev->dev;
  592 + struct resource *res;
  593 + struct bfin_crypto_crc *crc;
  594 + unsigned int timeout = 100000;
  595 + int ret;
  596 +
  597 + crc = kzalloc(sizeof(*crc), GFP_KERNEL);
  598 + if (!crc) {
  599 + dev_err(&pdev->dev, "fail to malloc bfin_crypto_crc\n");
  600 + return -ENOMEM;
  601 + }
  602 +
  603 + crc->dev = dev;
  604 +
  605 + INIT_LIST_HEAD(&crc->list);
  606 + spin_lock_init(&crc->lock);
  607 + tasklet_init(&crc->done_task, bfin_crypto_crc_done_task, (unsigned long)crc);
  608 + crypto_init_queue(&crc->queue, CRC_CCRYPTO_QUEUE_LENGTH);
  609 +
  610 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  611 + if (res == NULL) {
  612 + dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
  613 + ret = -ENOENT;
  614 + goto out_error_free_mem;
  615 + }
  616 +
  617 + crc->regs = ioremap(res->start, resource_size(res));
  618 + if (!crc->regs) {
  619 + dev_err(&pdev->dev, "Cannot map CRC IO\n");
  620 + ret = -ENXIO;
  621 + goto out_error_free_mem;
  622 + }
  623 +
  624 + crc->irq = platform_get_irq(pdev, 0);
  625 + if (crc->irq < 0) {
  626 + dev_err(&pdev->dev, "No CRC DCNTEXP IRQ specified\n");
  627 + ret = -ENOENT;
  628 + goto out_error_unmap;
  629 + }
  630 +
  631 + ret = request_irq(crc->irq, bfin_crypto_crc_handler, IRQF_SHARED, dev_name(dev), crc);
  632 + if (ret) {
  633 + dev_err(&pdev->dev, "Unable to request blackfin crc irq\n");
  634 + goto out_error_unmap;
  635 + }
  636 +
  637 + res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
  638 + if (res == NULL) {
  639 + dev_err(&pdev->dev, "No CRC DMA channel specified\n");
  640 + ret = -ENOENT;
  641 + goto out_error_irq;
  642 + }
  643 + crc->dma_ch = res->start;
  644 +
  645 + ret = request_dma(crc->dma_ch, dev_name(dev));
  646 + if (ret) {
  647 + dev_err(&pdev->dev, "Unable to attach Blackfin CRC DMA channel\n");
  648 + goto out_error_irq;
  649 + }
  650 +
  651 + crc->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &crc->sg_dma, GFP_KERNEL);
  652 + if (crc->sg_cpu == NULL) {
  653 + ret = -ENOMEM;
  654 + goto out_error_dma;
  655 + }
  656 + /*
  657 + * need at most CRC_MAX_DMA_DESC sg + CRC_MAX_DMA_DESC middle +
  658 + * 1 last + 1 next dma descriptors
  659 + */
  660 + crc->sg_mid_buf = (u8 *)(crc->sg_cpu + ((CRC_MAX_DMA_DESC + 1) << 1));
  661 +
  662 + crc->regs->control = 0;
  663 + SSYNC();
  664 + crc->regs->poly = crc->poly = (u32)pdev->dev.platform_data;
  665 + SSYNC();
  666 +
  667 + while (!(crc->regs->status & LUTDONE) && (--timeout) > 0)
  668 + cpu_relax();
  669 +
  670 + if (timeout == 0)
  671 + dev_info(&pdev->dev, "init crc poly timeout\n");
  672 +
  673 + spin_lock(&crc_list.lock);
  674 + list_add(&crc->list, &crc_list.dev_list);
  675 + spin_unlock(&crc_list.lock);
  676 +
  677 + platform_set_drvdata(pdev, crc);
  678 +
  679 + ret = crypto_register_ahash(&algs);
  680 + if (ret) {
  681 + spin_lock(&crc_list.lock);
  682 + list_del(&crc->list);
  683 + spin_unlock(&crc_list.lock);
  684 + dev_err(&pdev->dev, "Cann't register crypto ahash device\n");
  685 + goto out_error_dma;
  686 + }
  687 +
  688 + dev_info(&pdev->dev, "initialized\n");
  689 +
  690 + return 0;
  691 +
  692 +out_error_dma:
  693 + if (crc->sg_cpu)
  694 + dma_free_coherent(&pdev->dev, PAGE_SIZE, crc->sg_cpu, crc->sg_dma);
  695 + free_dma(crc->dma_ch);
  696 +out_error_irq:
  697 + free_irq(crc->irq, crc->dev);
  698 +out_error_unmap:
  699 + iounmap((void *)crc->regs);
  700 +out_error_free_mem:
  701 + kfree(crc);
  702 +
  703 + return ret;
  704 +}
  705 +
  706 +/**
  707 + * bfin_crypto_crc_remove - Initialize module
  708 + *
  709 + */
  710 +static int __devexit bfin_crypto_crc_remove(struct platform_device *pdev)
  711 +{
  712 + struct bfin_crypto_crc *crc = platform_get_drvdata(pdev);
  713 +
  714 + if (!crc)
  715 + return -ENODEV;
  716 +
  717 + spin_lock(&crc_list.lock);
  718 + list_del(&crc->list);
  719 + spin_unlock(&crc_list.lock);
  720 +
  721 + crypto_unregister_ahash(&algs);
  722 + tasklet_kill(&crc->done_task);
  723 + iounmap((void *)crc->regs);
  724 + free_dma(crc->dma_ch);
  725 + if (crc->irq > 0)
  726 + free_irq(crc->irq, crc->dev);
  727 + kfree(crc);
  728 +
  729 + return 0;
  730 +}
  731 +
  732 +static struct platform_driver bfin_crypto_crc_driver = {
  733 + .probe = bfin_crypto_crc_probe,
  734 + .remove = __devexit_p(bfin_crypto_crc_remove),
  735 + .suspend = bfin_crypto_crc_suspend,
  736 + .resume = bfin_crypto_crc_resume,
  737 + .driver = {
  738 + .name = DRIVER_NAME,
  739 + .owner = THIS_MODULE,
  740 + },
  741 +};
  742 +
  743 +/**
  744 + * bfin_crypto_crc_mod_init - Initialize module
  745 + *
  746 + * Checks the module params and registers the platform driver.
  747 + * Real work is in the platform probe function.
  748 + */
  749 +static int __init bfin_crypto_crc_mod_init(void)
  750 +{
  751 + int ret;
  752 +
  753 + pr_info("Blackfin hardware CRC crypto driver\n");
  754 +
  755 + INIT_LIST_HEAD(&crc_list.dev_list);
  756 + spin_lock_init(&crc_list.lock);
  757 +
  758 + ret = platform_driver_register(&bfin_crypto_crc_driver);
  759 + if (ret) {
  760 + pr_info(KERN_ERR "unable to register driver\n");
  761 + return ret;
  762 + }
  763 +
  764 + return 0;
  765 +}
  766 +
  767 +/**
  768 + * bfin_crypto_crc_mod_exit - Deinitialize module
  769 + */
  770 +static void __exit bfin_crypto_crc_mod_exit(void)
  771 +{
  772 + platform_driver_unregister(&bfin_crypto_crc_driver);
  773 +}
  774 +
  775 +module_init(bfin_crypto_crc_mod_init);
  776 +module_exit(bfin_crypto_crc_mod_exit);
  777 +
  778 +MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
  779 +MODULE_DESCRIPTION("Blackfin CRC hardware crypto driver");
  780 +MODULE_LICENSE("GPL");