Path: blob/master/drivers/crypto/amcc/crypto4xx_core.c
15111 views
/**1* AMCC SoC PPC4xx Crypto Driver2*3* Copyright (c) 2008 Applied Micro Circuits Corporation.4* All rights reserved. James Hsiao <[email protected]>5*6* This program is free software; you can redistribute it and/or modify7* it under the terms of the GNU General Public License as published by8* the Free Software Foundation; either version 2 of the License, or9* (at your option) any later version.10*11* This program is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14* GNU General Public License for more details.15*16* This file implements AMCC crypto offload Linux device driver for use with17* Linux CryptoAPI.18*/1920#include <linux/kernel.h>21#include <linux/interrupt.h>22#include <linux/spinlock_types.h>23#include <linux/random.h>24#include <linux/scatterlist.h>25#include <linux/crypto.h>26#include <linux/dma-mapping.h>27#include <linux/platform_device.h>28#include <linux/init.h>29#include <linux/of_platform.h>30#include <linux/slab.h>31#include <asm/dcr.h>32#include <asm/dcr-regs.h>33#include <asm/cacheflush.h>34#include <crypto/aes.h>35#include <crypto/sha.h>36#include "crypto4xx_reg_def.h"37#include "crypto4xx_core.h"38#include "crypto4xx_sa.h"3940#define PPC4XX_SEC_VERSION_STR "0.5"4142/**43* PPC4xx Crypto Engine Initialization Routine44*/45static void crypto4xx_hw_init(struct crypto4xx_device *dev)46{47union ce_ring_size ring_size;48union ce_ring_contol ring_ctrl;49union ce_part_ring_size part_ring_size;50union ce_io_threshold io_threshold;51u32 rand_num;52union ce_pe_dma_cfg pe_dma_cfg;5354writel(PPC4XX_BYTE_ORDER, dev->ce_base + CRYPTO4XX_BYTE_ORDER_CFG);55/* setup pe dma, include reset sg, pdr and pe, then release reset */56pe_dma_cfg.w = 0;57pe_dma_cfg.bf.bo_sgpd_en = 1;58pe_dma_cfg.bf.bo_data_en = 0;59pe_dma_cfg.bf.bo_sa_en = 1;60pe_dma_cfg.bf.bo_pd_en = 1;61pe_dma_cfg.bf.dynamic_sa_en = 1;62pe_dma_cfg.bf.reset_sg = 1;63pe_dma_cfg.bf.reset_pdr = 1;64pe_dma_cfg.bf.reset_pe = 1;65writel(pe_dma_cfg.w, dev->ce_base + CRYPTO4XX_PE_DMA_CFG);66/* un reset pe,sg and pdr */67pe_dma_cfg.bf.pe_mode = 0;68pe_dma_cfg.bf.reset_sg = 0;69pe_dma_cfg.bf.reset_pdr = 0;70pe_dma_cfg.bf.reset_pe = 0;71pe_dma_cfg.bf.bo_td_en = 0;72writel(pe_dma_cfg.w, dev->ce_base + CRYPTO4XX_PE_DMA_CFG);73writel(dev->pdr_pa, dev->ce_base + CRYPTO4XX_PDR_BASE);74writel(dev->pdr_pa, dev->ce_base + CRYPTO4XX_RDR_BASE);75writel(PPC4XX_PRNG_CTRL_AUTO_EN, dev->ce_base + CRYPTO4XX_PRNG_CTRL);76get_random_bytes(&rand_num, sizeof(rand_num));77writel(rand_num, dev->ce_base + CRYPTO4XX_PRNG_SEED_L);78get_random_bytes(&rand_num, sizeof(rand_num));79writel(rand_num, dev->ce_base + CRYPTO4XX_PRNG_SEED_H);80ring_size.w = 0;81ring_size.bf.ring_offset = PPC4XX_PD_SIZE;82ring_size.bf.ring_size = PPC4XX_NUM_PD;83writel(ring_size.w, dev->ce_base + CRYPTO4XX_RING_SIZE);84ring_ctrl.w = 0;85writel(ring_ctrl.w, dev->ce_base + CRYPTO4XX_RING_CTRL);86writel(PPC4XX_DC_3DES_EN, dev->ce_base + CRYPTO4XX_DEVICE_CTRL);87writel(dev->gdr_pa, dev->ce_base + CRYPTO4XX_GATH_RING_BASE);88writel(dev->sdr_pa, dev->ce_base + CRYPTO4XX_SCAT_RING_BASE);89part_ring_size.w = 0;90part_ring_size.bf.sdr_size = PPC4XX_SDR_SIZE;91part_ring_size.bf.gdr_size = PPC4XX_GDR_SIZE;92writel(part_ring_size.w, dev->ce_base + CRYPTO4XX_PART_RING_SIZE);93writel(PPC4XX_SD_BUFFER_SIZE, dev->ce_base + CRYPTO4XX_PART_RING_CFG);94io_threshold.w = 0;95io_threshold.bf.output_threshold = PPC4XX_OUTPUT_THRESHOLD;96io_threshold.bf.input_threshold = PPC4XX_INPUT_THRESHOLD;97writel(io_threshold.w, dev->ce_base + CRYPTO4XX_IO_THRESHOLD);98writel(0, dev->ce_base + CRYPTO4XX_PDR_BASE_UADDR);99writel(0, dev->ce_base + CRYPTO4XX_RDR_BASE_UADDR);100writel(0, dev->ce_base + CRYPTO4XX_PKT_SRC_UADDR);101writel(0, dev->ce_base + CRYPTO4XX_PKT_DEST_UADDR);102writel(0, dev->ce_base + CRYPTO4XX_SA_UADDR);103writel(0, dev->ce_base + CRYPTO4XX_GATH_RING_BASE_UADDR);104writel(0, dev->ce_base + CRYPTO4XX_SCAT_RING_BASE_UADDR);105/* un reset pe,sg and pdr */106pe_dma_cfg.bf.pe_mode = 1;107pe_dma_cfg.bf.reset_sg = 0;108pe_dma_cfg.bf.reset_pdr = 0;109pe_dma_cfg.bf.reset_pe = 0;110pe_dma_cfg.bf.bo_td_en = 0;111writel(pe_dma_cfg.w, dev->ce_base + CRYPTO4XX_PE_DMA_CFG);112/*clear all pending interrupt*/113writel(PPC4XX_INTERRUPT_CLR, dev->ce_base + CRYPTO4XX_INT_CLR);114writel(PPC4XX_INT_DESCR_CNT, dev->ce_base + CRYPTO4XX_INT_DESCR_CNT);115writel(PPC4XX_INT_DESCR_CNT, dev->ce_base + CRYPTO4XX_INT_DESCR_CNT);116writel(PPC4XX_INT_CFG, dev->ce_base + CRYPTO4XX_INT_CFG);117writel(PPC4XX_PD_DONE_INT, dev->ce_base + CRYPTO4XX_INT_EN);118}119120int crypto4xx_alloc_sa(struct crypto4xx_ctx *ctx, u32 size)121{122ctx->sa_in = dma_alloc_coherent(ctx->dev->core_dev->device, size * 4,123&ctx->sa_in_dma_addr, GFP_ATOMIC);124if (ctx->sa_in == NULL)125return -ENOMEM;126127ctx->sa_out = dma_alloc_coherent(ctx->dev->core_dev->device, size * 4,128&ctx->sa_out_dma_addr, GFP_ATOMIC);129if (ctx->sa_out == NULL) {130dma_free_coherent(ctx->dev->core_dev->device,131ctx->sa_len * 4,132ctx->sa_in, ctx->sa_in_dma_addr);133return -ENOMEM;134}135136memset(ctx->sa_in, 0, size * 4);137memset(ctx->sa_out, 0, size * 4);138ctx->sa_len = size;139140return 0;141}142143void crypto4xx_free_sa(struct crypto4xx_ctx *ctx)144{145if (ctx->sa_in != NULL)146dma_free_coherent(ctx->dev->core_dev->device, ctx->sa_len * 4,147ctx->sa_in, ctx->sa_in_dma_addr);148if (ctx->sa_out != NULL)149dma_free_coherent(ctx->dev->core_dev->device, ctx->sa_len * 4,150ctx->sa_out, ctx->sa_out_dma_addr);151152ctx->sa_in_dma_addr = 0;153ctx->sa_out_dma_addr = 0;154ctx->sa_len = 0;155}156157u32 crypto4xx_alloc_state_record(struct crypto4xx_ctx *ctx)158{159ctx->state_record = dma_alloc_coherent(ctx->dev->core_dev->device,160sizeof(struct sa_state_record),161&ctx->state_record_dma_addr, GFP_ATOMIC);162if (!ctx->state_record_dma_addr)163return -ENOMEM;164memset(ctx->state_record, 0, sizeof(struct sa_state_record));165166return 0;167}168169void crypto4xx_free_state_record(struct crypto4xx_ctx *ctx)170{171if (ctx->state_record != NULL)172dma_free_coherent(ctx->dev->core_dev->device,173sizeof(struct sa_state_record),174ctx->state_record,175ctx->state_record_dma_addr);176ctx->state_record_dma_addr = 0;177}178179/**180* alloc memory for the gather ring181* no need to alloc buf for the ring182* gdr_tail, gdr_head and gdr_count are initialized by this function183*/184static u32 crypto4xx_build_pdr(struct crypto4xx_device *dev)185{186int i;187struct pd_uinfo *pd_uinfo;188dev->pdr = dma_alloc_coherent(dev->core_dev->device,189sizeof(struct ce_pd) * PPC4XX_NUM_PD,190&dev->pdr_pa, GFP_ATOMIC);191if (!dev->pdr)192return -ENOMEM;193194dev->pdr_uinfo = kzalloc(sizeof(struct pd_uinfo) * PPC4XX_NUM_PD,195GFP_KERNEL);196if (!dev->pdr_uinfo) {197dma_free_coherent(dev->core_dev->device,198sizeof(struct ce_pd) * PPC4XX_NUM_PD,199dev->pdr,200dev->pdr_pa);201return -ENOMEM;202}203memset(dev->pdr, 0, sizeof(struct ce_pd) * PPC4XX_NUM_PD);204dev->shadow_sa_pool = dma_alloc_coherent(dev->core_dev->device,205256 * PPC4XX_NUM_PD,206&dev->shadow_sa_pool_pa,207GFP_ATOMIC);208if (!dev->shadow_sa_pool)209return -ENOMEM;210211dev->shadow_sr_pool = dma_alloc_coherent(dev->core_dev->device,212sizeof(struct sa_state_record) * PPC4XX_NUM_PD,213&dev->shadow_sr_pool_pa, GFP_ATOMIC);214if (!dev->shadow_sr_pool)215return -ENOMEM;216for (i = 0; i < PPC4XX_NUM_PD; i++) {217pd_uinfo = (struct pd_uinfo *) (dev->pdr_uinfo +218sizeof(struct pd_uinfo) * i);219220/* alloc 256 bytes which is enough for any kind of dynamic sa */221pd_uinfo->sa_va = dev->shadow_sa_pool + 256 * i;222pd_uinfo->sa_pa = dev->shadow_sa_pool_pa + 256 * i;223224/* alloc state record */225pd_uinfo->sr_va = dev->shadow_sr_pool +226sizeof(struct sa_state_record) * i;227pd_uinfo->sr_pa = dev->shadow_sr_pool_pa +228sizeof(struct sa_state_record) * i;229}230231return 0;232}233234static void crypto4xx_destroy_pdr(struct crypto4xx_device *dev)235{236if (dev->pdr != NULL)237dma_free_coherent(dev->core_dev->device,238sizeof(struct ce_pd) * PPC4XX_NUM_PD,239dev->pdr, dev->pdr_pa);240if (dev->shadow_sa_pool)241dma_free_coherent(dev->core_dev->device, 256 * PPC4XX_NUM_PD,242dev->shadow_sa_pool, dev->shadow_sa_pool_pa);243if (dev->shadow_sr_pool)244dma_free_coherent(dev->core_dev->device,245sizeof(struct sa_state_record) * PPC4XX_NUM_PD,246dev->shadow_sr_pool, dev->shadow_sr_pool_pa);247248kfree(dev->pdr_uinfo);249}250251static u32 crypto4xx_get_pd_from_pdr_nolock(struct crypto4xx_device *dev)252{253u32 retval;254u32 tmp;255256retval = dev->pdr_head;257tmp = (dev->pdr_head + 1) % PPC4XX_NUM_PD;258259if (tmp == dev->pdr_tail)260return ERING_WAS_FULL;261262dev->pdr_head = tmp;263264return retval;265}266267static u32 crypto4xx_put_pd_to_pdr(struct crypto4xx_device *dev, u32 idx)268{269struct pd_uinfo *pd_uinfo;270unsigned long flags;271272pd_uinfo = (struct pd_uinfo *)(dev->pdr_uinfo +273sizeof(struct pd_uinfo) * idx);274spin_lock_irqsave(&dev->core_dev->lock, flags);275if (dev->pdr_tail != PPC4XX_LAST_PD)276dev->pdr_tail++;277else278dev->pdr_tail = 0;279pd_uinfo->state = PD_ENTRY_FREE;280spin_unlock_irqrestore(&dev->core_dev->lock, flags);281282return 0;283}284285static struct ce_pd *crypto4xx_get_pdp(struct crypto4xx_device *dev,286dma_addr_t *pd_dma, u32 idx)287{288*pd_dma = dev->pdr_pa + sizeof(struct ce_pd) * idx;289290return dev->pdr + sizeof(struct ce_pd) * idx;291}292293/**294* alloc memory for the gather ring295* no need to alloc buf for the ring296* gdr_tail, gdr_head and gdr_count are initialized by this function297*/298static u32 crypto4xx_build_gdr(struct crypto4xx_device *dev)299{300dev->gdr = dma_alloc_coherent(dev->core_dev->device,301sizeof(struct ce_gd) * PPC4XX_NUM_GD,302&dev->gdr_pa, GFP_ATOMIC);303if (!dev->gdr)304return -ENOMEM;305306memset(dev->gdr, 0, sizeof(struct ce_gd) * PPC4XX_NUM_GD);307308return 0;309}310311static inline void crypto4xx_destroy_gdr(struct crypto4xx_device *dev)312{313dma_free_coherent(dev->core_dev->device,314sizeof(struct ce_gd) * PPC4XX_NUM_GD,315dev->gdr, dev->gdr_pa);316}317318/*319* when this function is called.320* preemption or interrupt must be disabled321*/322u32 crypto4xx_get_n_gd(struct crypto4xx_device *dev, int n)323{324u32 retval;325u32 tmp;326if (n >= PPC4XX_NUM_GD)327return ERING_WAS_FULL;328329retval = dev->gdr_head;330tmp = (dev->gdr_head + n) % PPC4XX_NUM_GD;331if (dev->gdr_head > dev->gdr_tail) {332if (tmp < dev->gdr_head && tmp >= dev->gdr_tail)333return ERING_WAS_FULL;334} else if (dev->gdr_head < dev->gdr_tail) {335if (tmp < dev->gdr_head || tmp >= dev->gdr_tail)336return ERING_WAS_FULL;337}338dev->gdr_head = tmp;339340return retval;341}342343static u32 crypto4xx_put_gd_to_gdr(struct crypto4xx_device *dev)344{345unsigned long flags;346347spin_lock_irqsave(&dev->core_dev->lock, flags);348if (dev->gdr_tail == dev->gdr_head) {349spin_unlock_irqrestore(&dev->core_dev->lock, flags);350return 0;351}352353if (dev->gdr_tail != PPC4XX_LAST_GD)354dev->gdr_tail++;355else356dev->gdr_tail = 0;357358spin_unlock_irqrestore(&dev->core_dev->lock, flags);359360return 0;361}362363static inline struct ce_gd *crypto4xx_get_gdp(struct crypto4xx_device *dev,364dma_addr_t *gd_dma, u32 idx)365{366*gd_dma = dev->gdr_pa + sizeof(struct ce_gd) * idx;367368return (struct ce_gd *) (dev->gdr + sizeof(struct ce_gd) * idx);369}370371/**372* alloc memory for the scatter ring373* need to alloc buf for the ring374* sdr_tail, sdr_head and sdr_count are initialized by this function375*/376static u32 crypto4xx_build_sdr(struct crypto4xx_device *dev)377{378int i;379struct ce_sd *sd_array;380381/* alloc memory for scatter descriptor ring */382dev->sdr = dma_alloc_coherent(dev->core_dev->device,383sizeof(struct ce_sd) * PPC4XX_NUM_SD,384&dev->sdr_pa, GFP_ATOMIC);385if (!dev->sdr)386return -ENOMEM;387388dev->scatter_buffer_size = PPC4XX_SD_BUFFER_SIZE;389dev->scatter_buffer_va =390dma_alloc_coherent(dev->core_dev->device,391dev->scatter_buffer_size * PPC4XX_NUM_SD,392&dev->scatter_buffer_pa, GFP_ATOMIC);393if (!dev->scatter_buffer_va) {394dma_free_coherent(dev->core_dev->device,395sizeof(struct ce_sd) * PPC4XX_NUM_SD,396dev->sdr, dev->sdr_pa);397return -ENOMEM;398}399400sd_array = dev->sdr;401402for (i = 0; i < PPC4XX_NUM_SD; i++) {403sd_array[i].ptr = dev->scatter_buffer_pa +404dev->scatter_buffer_size * i;405}406407return 0;408}409410static void crypto4xx_destroy_sdr(struct crypto4xx_device *dev)411{412if (dev->sdr != NULL)413dma_free_coherent(dev->core_dev->device,414sizeof(struct ce_sd) * PPC4XX_NUM_SD,415dev->sdr, dev->sdr_pa);416417if (dev->scatter_buffer_va != NULL)418dma_free_coherent(dev->core_dev->device,419dev->scatter_buffer_size * PPC4XX_NUM_SD,420dev->scatter_buffer_va,421dev->scatter_buffer_pa);422}423424/*425* when this function is called.426* preemption or interrupt must be disabled427*/428static u32 crypto4xx_get_n_sd(struct crypto4xx_device *dev, int n)429{430u32 retval;431u32 tmp;432433if (n >= PPC4XX_NUM_SD)434return ERING_WAS_FULL;435436retval = dev->sdr_head;437tmp = (dev->sdr_head + n) % PPC4XX_NUM_SD;438if (dev->sdr_head > dev->gdr_tail) {439if (tmp < dev->sdr_head && tmp >= dev->sdr_tail)440return ERING_WAS_FULL;441} else if (dev->sdr_head < dev->sdr_tail) {442if (tmp < dev->sdr_head || tmp >= dev->sdr_tail)443return ERING_WAS_FULL;444} /* the head = tail, or empty case is already take cared */445dev->sdr_head = tmp;446447return retval;448}449450static u32 crypto4xx_put_sd_to_sdr(struct crypto4xx_device *dev)451{452unsigned long flags;453454spin_lock_irqsave(&dev->core_dev->lock, flags);455if (dev->sdr_tail == dev->sdr_head) {456spin_unlock_irqrestore(&dev->core_dev->lock, flags);457return 0;458}459if (dev->sdr_tail != PPC4XX_LAST_SD)460dev->sdr_tail++;461else462dev->sdr_tail = 0;463spin_unlock_irqrestore(&dev->core_dev->lock, flags);464465return 0;466}467468static inline struct ce_sd *crypto4xx_get_sdp(struct crypto4xx_device *dev,469dma_addr_t *sd_dma, u32 idx)470{471*sd_dma = dev->sdr_pa + sizeof(struct ce_sd) * idx;472473return (struct ce_sd *)(dev->sdr + sizeof(struct ce_sd) * idx);474}475476static u32 crypto4xx_fill_one_page(struct crypto4xx_device *dev,477dma_addr_t *addr, u32 *length,478u32 *idx, u32 *offset, u32 *nbytes)479{480u32 len;481482if (*length > dev->scatter_buffer_size) {483memcpy(phys_to_virt(*addr),484dev->scatter_buffer_va +485*idx * dev->scatter_buffer_size + *offset,486dev->scatter_buffer_size);487*offset = 0;488*length -= dev->scatter_buffer_size;489*nbytes -= dev->scatter_buffer_size;490if (*idx == PPC4XX_LAST_SD)491*idx = 0;492else493(*idx)++;494*addr = *addr + dev->scatter_buffer_size;495return 1;496} else if (*length < dev->scatter_buffer_size) {497memcpy(phys_to_virt(*addr),498dev->scatter_buffer_va +499*idx * dev->scatter_buffer_size + *offset, *length);500if ((*offset + *length) == dev->scatter_buffer_size) {501if (*idx == PPC4XX_LAST_SD)502*idx = 0;503else504(*idx)++;505*nbytes -= *length;506*offset = 0;507} else {508*nbytes -= *length;509*offset += *length;510}511512return 0;513} else {514len = (*nbytes <= dev->scatter_buffer_size) ?515(*nbytes) : dev->scatter_buffer_size;516memcpy(phys_to_virt(*addr),517dev->scatter_buffer_va +518*idx * dev->scatter_buffer_size + *offset,519len);520*offset = 0;521*nbytes -= len;522523if (*idx == PPC4XX_LAST_SD)524*idx = 0;525else526(*idx)++;527528return 0;529}530}531532static void crypto4xx_copy_pkt_to_dst(struct crypto4xx_device *dev,533struct ce_pd *pd,534struct pd_uinfo *pd_uinfo,535u32 nbytes,536struct scatterlist *dst)537{538dma_addr_t addr;539u32 this_sd;540u32 offset;541u32 len;542u32 i;543u32 sg_len;544struct scatterlist *sg;545546this_sd = pd_uinfo->first_sd;547offset = 0;548i = 0;549550while (nbytes) {551sg = &dst[i];552sg_len = sg->length;553addr = dma_map_page(dev->core_dev->device, sg_page(sg),554sg->offset, sg->length, DMA_TO_DEVICE);555556if (offset == 0) {557len = (nbytes <= sg->length) ? nbytes : sg->length;558while (crypto4xx_fill_one_page(dev, &addr, &len,559&this_sd, &offset, &nbytes))560;561if (!nbytes)562return;563i++;564} else {565len = (nbytes <= (dev->scatter_buffer_size - offset)) ?566nbytes : (dev->scatter_buffer_size - offset);567len = (sg->length < len) ? sg->length : len;568while (crypto4xx_fill_one_page(dev, &addr, &len,569&this_sd, &offset, &nbytes))570;571if (!nbytes)572return;573sg_len -= len;574if (sg_len) {575addr += len;576while (crypto4xx_fill_one_page(dev, &addr,577&sg_len, &this_sd, &offset, &nbytes))578;579}580i++;581}582}583}584585static u32 crypto4xx_copy_digest_to_dst(struct pd_uinfo *pd_uinfo,586struct crypto4xx_ctx *ctx)587{588struct dynamic_sa_ctl *sa = (struct dynamic_sa_ctl *) ctx->sa_in;589struct sa_state_record *state_record =590(struct sa_state_record *) pd_uinfo->sr_va;591592if (sa->sa_command_0.bf.hash_alg == SA_HASH_ALG_SHA1) {593memcpy((void *) pd_uinfo->dest_va, state_record->save_digest,594SA_HASH_ALG_SHA1_DIGEST_SIZE);595}596597return 0;598}599600static void crypto4xx_ret_sg_desc(struct crypto4xx_device *dev,601struct pd_uinfo *pd_uinfo)602{603int i;604if (pd_uinfo->num_gd) {605for (i = 0; i < pd_uinfo->num_gd; i++)606crypto4xx_put_gd_to_gdr(dev);607pd_uinfo->first_gd = 0xffffffff;608pd_uinfo->num_gd = 0;609}610if (pd_uinfo->num_sd) {611for (i = 0; i < pd_uinfo->num_sd; i++)612crypto4xx_put_sd_to_sdr(dev);613614pd_uinfo->first_sd = 0xffffffff;615pd_uinfo->num_sd = 0;616}617}618619static u32 crypto4xx_ablkcipher_done(struct crypto4xx_device *dev,620struct pd_uinfo *pd_uinfo,621struct ce_pd *pd)622{623struct crypto4xx_ctx *ctx;624struct ablkcipher_request *ablk_req;625struct scatterlist *dst;626dma_addr_t addr;627628ablk_req = ablkcipher_request_cast(pd_uinfo->async_req);629ctx = crypto_tfm_ctx(ablk_req->base.tfm);630631if (pd_uinfo->using_sd) {632crypto4xx_copy_pkt_to_dst(dev, pd, pd_uinfo, ablk_req->nbytes,633ablk_req->dst);634} else {635dst = pd_uinfo->dest_va;636addr = dma_map_page(dev->core_dev->device, sg_page(dst),637dst->offset, dst->length, DMA_FROM_DEVICE);638}639crypto4xx_ret_sg_desc(dev, pd_uinfo);640if (ablk_req->base.complete != NULL)641ablk_req->base.complete(&ablk_req->base, 0);642643return 0;644}645646static u32 crypto4xx_ahash_done(struct crypto4xx_device *dev,647struct pd_uinfo *pd_uinfo)648{649struct crypto4xx_ctx *ctx;650struct ahash_request *ahash_req;651652ahash_req = ahash_request_cast(pd_uinfo->async_req);653ctx = crypto_tfm_ctx(ahash_req->base.tfm);654655crypto4xx_copy_digest_to_dst(pd_uinfo,656crypto_tfm_ctx(ahash_req->base.tfm));657crypto4xx_ret_sg_desc(dev, pd_uinfo);658/* call user provided callback function x */659if (ahash_req->base.complete != NULL)660ahash_req->base.complete(&ahash_req->base, 0);661662return 0;663}664665static u32 crypto4xx_pd_done(struct crypto4xx_device *dev, u32 idx)666{667struct ce_pd *pd;668struct pd_uinfo *pd_uinfo;669670pd = dev->pdr + sizeof(struct ce_pd)*idx;671pd_uinfo = dev->pdr_uinfo + sizeof(struct pd_uinfo)*idx;672if (crypto_tfm_alg_type(pd_uinfo->async_req->tfm) ==673CRYPTO_ALG_TYPE_ABLKCIPHER)674return crypto4xx_ablkcipher_done(dev, pd_uinfo, pd);675else676return crypto4xx_ahash_done(dev, pd_uinfo);677}678679/**680* Note: Only use this function to copy items that is word aligned.681*/682void crypto4xx_memcpy_le(unsigned int *dst,683const unsigned char *buf,684int len)685{686u8 *tmp;687for (; len >= 4; buf += 4, len -= 4)688*dst++ = cpu_to_le32(*(unsigned int *) buf);689690tmp = (u8 *)dst;691switch (len) {692case 3:693*tmp++ = 0;694*tmp++ = *(buf+2);695*tmp++ = *(buf+1);696*tmp++ = *buf;697break;698case 2:699*tmp++ = 0;700*tmp++ = 0;701*tmp++ = *(buf+1);702*tmp++ = *buf;703break;704case 1:705*tmp++ = 0;706*tmp++ = 0;707*tmp++ = 0;708*tmp++ = *buf;709break;710default:711break;712}713}714715static void crypto4xx_stop_all(struct crypto4xx_core_device *core_dev)716{717crypto4xx_destroy_pdr(core_dev->dev);718crypto4xx_destroy_gdr(core_dev->dev);719crypto4xx_destroy_sdr(core_dev->dev);720dev_set_drvdata(core_dev->device, NULL);721iounmap(core_dev->dev->ce_base);722kfree(core_dev->dev);723kfree(core_dev);724}725726void crypto4xx_return_pd(struct crypto4xx_device *dev,727u32 pd_entry, struct ce_pd *pd,728struct pd_uinfo *pd_uinfo)729{730/* irq should be already disabled */731dev->pdr_head = pd_entry;732pd->pd_ctl.w = 0;733pd->pd_ctl_len.w = 0;734pd_uinfo->state = PD_ENTRY_FREE;735}736737/*738* derive number of elements in scatterlist739* Shamlessly copy from talitos.c740*/741static int get_sg_count(struct scatterlist *sg_list, int nbytes)742{743struct scatterlist *sg = sg_list;744int sg_nents = 0;745746while (nbytes) {747sg_nents++;748if (sg->length > nbytes)749break;750nbytes -= sg->length;751sg = sg_next(sg);752}753754return sg_nents;755}756757static u32 get_next_gd(u32 current)758{759if (current != PPC4XX_LAST_GD)760return current + 1;761else762return 0;763}764765static u32 get_next_sd(u32 current)766{767if (current != PPC4XX_LAST_SD)768return current + 1;769else770return 0;771}772773u32 crypto4xx_build_pd(struct crypto_async_request *req,774struct crypto4xx_ctx *ctx,775struct scatterlist *src,776struct scatterlist *dst,777unsigned int datalen,778void *iv, u32 iv_len)779{780struct crypto4xx_device *dev = ctx->dev;781dma_addr_t addr, pd_dma, sd_dma, gd_dma;782struct dynamic_sa_ctl *sa;783struct scatterlist *sg;784struct ce_gd *gd;785struct ce_pd *pd;786u32 num_gd, num_sd;787u32 fst_gd = 0xffffffff;788u32 fst_sd = 0xffffffff;789u32 pd_entry;790unsigned long flags;791struct pd_uinfo *pd_uinfo = NULL;792unsigned int nbytes = datalen, idx;793unsigned int ivlen = 0;794u32 gd_idx = 0;795796/* figure how many gd is needed */797num_gd = get_sg_count(src, datalen);798if (num_gd == 1)799num_gd = 0;800801/* figure how many sd is needed */802if (sg_is_last(dst) || ctx->is_hash) {803num_sd = 0;804} else {805if (datalen > PPC4XX_SD_BUFFER_SIZE) {806num_sd = datalen / PPC4XX_SD_BUFFER_SIZE;807if (datalen % PPC4XX_SD_BUFFER_SIZE)808num_sd++;809} else {810num_sd = 1;811}812}813814/*815* The follow section of code needs to be protected816* The gather ring and scatter ring needs to be consecutive817* In case of run out of any kind of descriptor, the descriptor818* already got must be return the original place.819*/820spin_lock_irqsave(&dev->core_dev->lock, flags);821if (num_gd) {822fst_gd = crypto4xx_get_n_gd(dev, num_gd);823if (fst_gd == ERING_WAS_FULL) {824spin_unlock_irqrestore(&dev->core_dev->lock, flags);825return -EAGAIN;826}827}828if (num_sd) {829fst_sd = crypto4xx_get_n_sd(dev, num_sd);830if (fst_sd == ERING_WAS_FULL) {831if (num_gd)832dev->gdr_head = fst_gd;833spin_unlock_irqrestore(&dev->core_dev->lock, flags);834return -EAGAIN;835}836}837pd_entry = crypto4xx_get_pd_from_pdr_nolock(dev);838if (pd_entry == ERING_WAS_FULL) {839if (num_gd)840dev->gdr_head = fst_gd;841if (num_sd)842dev->sdr_head = fst_sd;843spin_unlock_irqrestore(&dev->core_dev->lock, flags);844return -EAGAIN;845}846spin_unlock_irqrestore(&dev->core_dev->lock, flags);847848pd_uinfo = (struct pd_uinfo *)(dev->pdr_uinfo +849sizeof(struct pd_uinfo) * pd_entry);850pd = crypto4xx_get_pdp(dev, &pd_dma, pd_entry);851pd_uinfo->async_req = req;852pd_uinfo->num_gd = num_gd;853pd_uinfo->num_sd = num_sd;854855if (iv_len || ctx->is_hash) {856ivlen = iv_len;857pd->sa = pd_uinfo->sa_pa;858sa = (struct dynamic_sa_ctl *) pd_uinfo->sa_va;859if (ctx->direction == DIR_INBOUND)860memcpy(sa, ctx->sa_in, ctx->sa_len * 4);861else862memcpy(sa, ctx->sa_out, ctx->sa_len * 4);863864memcpy((void *) sa + ctx->offset_to_sr_ptr,865&pd_uinfo->sr_pa, 4);866867if (iv_len)868crypto4xx_memcpy_le(pd_uinfo->sr_va, iv, iv_len);869} else {870if (ctx->direction == DIR_INBOUND) {871pd->sa = ctx->sa_in_dma_addr;872sa = (struct dynamic_sa_ctl *) ctx->sa_in;873} else {874pd->sa = ctx->sa_out_dma_addr;875sa = (struct dynamic_sa_ctl *) ctx->sa_out;876}877}878pd->sa_len = ctx->sa_len;879if (num_gd) {880/* get first gd we are going to use */881gd_idx = fst_gd;882pd_uinfo->first_gd = fst_gd;883pd_uinfo->num_gd = num_gd;884gd = crypto4xx_get_gdp(dev, &gd_dma, gd_idx);885pd->src = gd_dma;886/* enable gather */887sa->sa_command_0.bf.gather = 1;888idx = 0;889src = &src[0];890/* walk the sg, and setup gather array */891while (nbytes) {892sg = &src[idx];893addr = dma_map_page(dev->core_dev->device, sg_page(sg),894sg->offset, sg->length, DMA_TO_DEVICE);895gd->ptr = addr;896gd->ctl_len.len = sg->length;897gd->ctl_len.done = 0;898gd->ctl_len.ready = 1;899if (sg->length >= nbytes)900break;901nbytes -= sg->length;902gd_idx = get_next_gd(gd_idx);903gd = crypto4xx_get_gdp(dev, &gd_dma, gd_idx);904idx++;905}906} else {907pd->src = (u32)dma_map_page(dev->core_dev->device, sg_page(src),908src->offset, src->length, DMA_TO_DEVICE);909/*910* Disable gather in sa command911*/912sa->sa_command_0.bf.gather = 0;913/*914* Indicate gather array is not used915*/916pd_uinfo->first_gd = 0xffffffff;917pd_uinfo->num_gd = 0;918}919if (ctx->is_hash || sg_is_last(dst)) {920/*921* we know application give us dst a whole piece of memory922* no need to use scatter ring.923* In case of is_hash, the icv is always at end of src data.924*/925pd_uinfo->using_sd = 0;926pd_uinfo->first_sd = 0xffffffff;927pd_uinfo->num_sd = 0;928pd_uinfo->dest_va = dst;929sa->sa_command_0.bf.scatter = 0;930if (ctx->is_hash)931pd->dest = virt_to_phys((void *)dst);932else933pd->dest = (u32)dma_map_page(dev->core_dev->device,934sg_page(dst), dst->offset,935dst->length, DMA_TO_DEVICE);936} else {937struct ce_sd *sd = NULL;938u32 sd_idx = fst_sd;939nbytes = datalen;940sa->sa_command_0.bf.scatter = 1;941pd_uinfo->using_sd = 1;942pd_uinfo->dest_va = dst;943pd_uinfo->first_sd = fst_sd;944pd_uinfo->num_sd = num_sd;945sd = crypto4xx_get_sdp(dev, &sd_dma, sd_idx);946pd->dest = sd_dma;947/* setup scatter descriptor */948sd->ctl.done = 0;949sd->ctl.rdy = 1;950/* sd->ptr should be setup by sd_init routine*/951idx = 0;952if (nbytes >= PPC4XX_SD_BUFFER_SIZE)953nbytes -= PPC4XX_SD_BUFFER_SIZE;954else955nbytes = 0;956while (nbytes) {957sd_idx = get_next_sd(sd_idx);958sd = crypto4xx_get_sdp(dev, &sd_dma, sd_idx);959/* setup scatter descriptor */960sd->ctl.done = 0;961sd->ctl.rdy = 1;962if (nbytes >= PPC4XX_SD_BUFFER_SIZE)963nbytes -= PPC4XX_SD_BUFFER_SIZE;964else965/*966* SD entry can hold PPC4XX_SD_BUFFER_SIZE,967* which is more than nbytes, so done.968*/969nbytes = 0;970}971}972973sa->sa_command_1.bf.hash_crypto_offset = 0;974pd->pd_ctl.w = ctx->pd_ctl;975pd->pd_ctl_len.w = 0x00400000 | (ctx->bypass << 24) | datalen;976pd_uinfo->state = PD_ENTRY_INUSE;977wmb();978/* write any value to push engine to read a pd */979writel(1, dev->ce_base + CRYPTO4XX_INT_DESCR_RD);980return -EINPROGRESS;981}982983/**984* Algorithm Registration Functions985*/986static int crypto4xx_alg_init(struct crypto_tfm *tfm)987{988struct crypto_alg *alg = tfm->__crt_alg;989struct crypto4xx_alg *amcc_alg = crypto_alg_to_crypto4xx_alg(alg);990struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);991992ctx->dev = amcc_alg->dev;993ctx->sa_in = NULL;994ctx->sa_out = NULL;995ctx->sa_in_dma_addr = 0;996ctx->sa_out_dma_addr = 0;997ctx->sa_len = 0;998999switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {1000default:1001tfm->crt_ablkcipher.reqsize = sizeof(struct crypto4xx_ctx);1002break;1003case CRYPTO_ALG_TYPE_AHASH:1004crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),1005sizeof(struct crypto4xx_ctx));1006break;1007}10081009return 0;1010}10111012static void crypto4xx_alg_exit(struct crypto_tfm *tfm)1013{1014struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);10151016crypto4xx_free_sa(ctx);1017crypto4xx_free_state_record(ctx);1018}10191020int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,1021struct crypto4xx_alg_common *crypto_alg,1022int array_size)1023{1024struct crypto4xx_alg *alg;1025int i;1026int rc = 0;10271028for (i = 0; i < array_size; i++) {1029alg = kzalloc(sizeof(struct crypto4xx_alg), GFP_KERNEL);1030if (!alg)1031return -ENOMEM;10321033alg->alg = crypto_alg[i];1034alg->dev = sec_dev;10351036switch (alg->alg.type) {1037case CRYPTO_ALG_TYPE_AHASH:1038rc = crypto_register_ahash(&alg->alg.u.hash);1039break;10401041default:1042rc = crypto_register_alg(&alg->alg.u.cipher);1043break;1044}10451046if (rc) {1047list_del(&alg->entry);1048kfree(alg);1049} else {1050list_add_tail(&alg->entry, &sec_dev->alg_list);1051}1052}10531054return 0;1055}10561057static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)1058{1059struct crypto4xx_alg *alg, *tmp;10601061list_for_each_entry_safe(alg, tmp, &sec_dev->alg_list, entry) {1062list_del(&alg->entry);1063switch (alg->alg.type) {1064case CRYPTO_ALG_TYPE_AHASH:1065crypto_unregister_ahash(&alg->alg.u.hash);1066break;10671068default:1069crypto_unregister_alg(&alg->alg.u.cipher);1070}1071kfree(alg);1072}1073}10741075static void crypto4xx_bh_tasklet_cb(unsigned long data)1076{1077struct device *dev = (struct device *)data;1078struct crypto4xx_core_device *core_dev = dev_get_drvdata(dev);1079struct pd_uinfo *pd_uinfo;1080struct ce_pd *pd;1081u32 tail;10821083while (core_dev->dev->pdr_head != core_dev->dev->pdr_tail) {1084tail = core_dev->dev->pdr_tail;1085pd_uinfo = core_dev->dev->pdr_uinfo +1086sizeof(struct pd_uinfo)*tail;1087pd = core_dev->dev->pdr + sizeof(struct ce_pd) * tail;1088if ((pd_uinfo->state == PD_ENTRY_INUSE) &&1089pd->pd_ctl.bf.pe_done &&1090!pd->pd_ctl.bf.host_ready) {1091pd->pd_ctl.bf.pe_done = 0;1092crypto4xx_pd_done(core_dev->dev, tail);1093crypto4xx_put_pd_to_pdr(core_dev->dev, tail);1094pd_uinfo->state = PD_ENTRY_FREE;1095} else {1096/* if tail not done, break */1097break;1098}1099}1100}11011102/**1103* Top Half of isr.1104*/1105static irqreturn_t crypto4xx_ce_interrupt_handler(int irq, void *data)1106{1107struct device *dev = (struct device *)data;1108struct crypto4xx_core_device *core_dev = dev_get_drvdata(dev);11091110if (core_dev->dev->ce_base == 0)1111return 0;11121113writel(PPC4XX_INTERRUPT_CLR,1114core_dev->dev->ce_base + CRYPTO4XX_INT_CLR);1115tasklet_schedule(&core_dev->tasklet);11161117return IRQ_HANDLED;1118}11191120/**1121* Supported Crypto Algorithms1122*/1123struct crypto4xx_alg_common crypto4xx_alg[] = {1124/* Crypto AES modes */1125{ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .u.cipher = {1126.cra_name = "cbc(aes)",1127.cra_driver_name = "cbc-aes-ppc4xx",1128.cra_priority = CRYPTO4XX_CRYPTO_PRIORITY,1129.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,1130.cra_blocksize = AES_BLOCK_SIZE,1131.cra_ctxsize = sizeof(struct crypto4xx_ctx),1132.cra_type = &crypto_ablkcipher_type,1133.cra_init = crypto4xx_alg_init,1134.cra_exit = crypto4xx_alg_exit,1135.cra_module = THIS_MODULE,1136.cra_u = {1137.ablkcipher = {1138.min_keysize = AES_MIN_KEY_SIZE,1139.max_keysize = AES_MAX_KEY_SIZE,1140.ivsize = AES_IV_SIZE,1141.setkey = crypto4xx_setkey_aes_cbc,1142.encrypt = crypto4xx_encrypt,1143.decrypt = crypto4xx_decrypt,1144}1145}1146}},1147};11481149/**1150* Module Initialization Routine1151*/1152static int __init crypto4xx_probe(struct platform_device *ofdev)1153{1154int rc;1155struct resource res;1156struct device *dev = &ofdev->dev;1157struct crypto4xx_core_device *core_dev;11581159rc = of_address_to_resource(ofdev->dev.of_node, 0, &res);1160if (rc)1161return -ENODEV;11621163if (of_find_compatible_node(NULL, NULL, "amcc,ppc460ex-crypto")) {1164mtdcri(SDR0, PPC460EX_SDR0_SRST,1165mfdcri(SDR0, PPC460EX_SDR0_SRST) | PPC460EX_CE_RESET);1166mtdcri(SDR0, PPC460EX_SDR0_SRST,1167mfdcri(SDR0, PPC460EX_SDR0_SRST) & ~PPC460EX_CE_RESET);1168} else if (of_find_compatible_node(NULL, NULL,1169"amcc,ppc405ex-crypto")) {1170mtdcri(SDR0, PPC405EX_SDR0_SRST,1171mfdcri(SDR0, PPC405EX_SDR0_SRST) | PPC405EX_CE_RESET);1172mtdcri(SDR0, PPC405EX_SDR0_SRST,1173mfdcri(SDR0, PPC405EX_SDR0_SRST) & ~PPC405EX_CE_RESET);1174} else if (of_find_compatible_node(NULL, NULL,1175"amcc,ppc460sx-crypto")) {1176mtdcri(SDR0, PPC460SX_SDR0_SRST,1177mfdcri(SDR0, PPC460SX_SDR0_SRST) | PPC460SX_CE_RESET);1178mtdcri(SDR0, PPC460SX_SDR0_SRST,1179mfdcri(SDR0, PPC460SX_SDR0_SRST) & ~PPC460SX_CE_RESET);1180} else {1181printk(KERN_ERR "Crypto Function Not supported!\n");1182return -EINVAL;1183}11841185core_dev = kzalloc(sizeof(struct crypto4xx_core_device), GFP_KERNEL);1186if (!core_dev)1187return -ENOMEM;11881189dev_set_drvdata(dev, core_dev);1190core_dev->ofdev = ofdev;1191core_dev->dev = kzalloc(sizeof(struct crypto4xx_device), GFP_KERNEL);1192if (!core_dev->dev)1193goto err_alloc_dev;11941195core_dev->dev->core_dev = core_dev;1196core_dev->device = dev;1197spin_lock_init(&core_dev->lock);1198INIT_LIST_HEAD(&core_dev->dev->alg_list);1199rc = crypto4xx_build_pdr(core_dev->dev);1200if (rc)1201goto err_build_pdr;12021203rc = crypto4xx_build_gdr(core_dev->dev);1204if (rc)1205goto err_build_gdr;12061207rc = crypto4xx_build_sdr(core_dev->dev);1208if (rc)1209goto err_build_sdr;12101211/* Init tasklet for bottom half processing */1212tasklet_init(&core_dev->tasklet, crypto4xx_bh_tasklet_cb,1213(unsigned long) dev);12141215/* Register for Crypto isr, Crypto Engine IRQ */1216core_dev->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);1217rc = request_irq(core_dev->irq, crypto4xx_ce_interrupt_handler, 0,1218core_dev->dev->name, dev);1219if (rc)1220goto err_request_irq;12211222core_dev->dev->ce_base = of_iomap(ofdev->dev.of_node, 0);1223if (!core_dev->dev->ce_base) {1224dev_err(dev, "failed to of_iomap\n");1225goto err_iomap;1226}12271228/* need to setup pdr, rdr, gdr and sdr before this */1229crypto4xx_hw_init(core_dev->dev);12301231/* Register security algorithms with Linux CryptoAPI */1232rc = crypto4xx_register_alg(core_dev->dev, crypto4xx_alg,1233ARRAY_SIZE(crypto4xx_alg));1234if (rc)1235goto err_start_dev;12361237return 0;12381239err_start_dev:1240iounmap(core_dev->dev->ce_base);1241err_iomap:1242free_irq(core_dev->irq, dev);1243irq_dispose_mapping(core_dev->irq);1244tasklet_kill(&core_dev->tasklet);1245err_request_irq:1246crypto4xx_destroy_sdr(core_dev->dev);1247err_build_sdr:1248crypto4xx_destroy_gdr(core_dev->dev);1249err_build_gdr:1250crypto4xx_destroy_pdr(core_dev->dev);1251err_build_pdr:1252kfree(core_dev->dev);1253err_alloc_dev:1254kfree(core_dev);12551256return rc;1257}12581259static int __exit crypto4xx_remove(struct platform_device *ofdev)1260{1261struct device *dev = &ofdev->dev;1262struct crypto4xx_core_device *core_dev = dev_get_drvdata(dev);12631264free_irq(core_dev->irq, dev);1265irq_dispose_mapping(core_dev->irq);12661267tasklet_kill(&core_dev->tasklet);1268/* Un-register with Linux CryptoAPI */1269crypto4xx_unregister_alg(core_dev->dev);1270/* Free all allocated memory */1271crypto4xx_stop_all(core_dev);12721273return 0;1274}12751276static const struct of_device_id crypto4xx_match[] = {1277{ .compatible = "amcc,ppc4xx-crypto",},1278{ },1279};12801281static struct platform_driver crypto4xx_driver = {1282.driver = {1283.name = "crypto4xx",1284.owner = THIS_MODULE,1285.of_match_table = crypto4xx_match,1286},1287.probe = crypto4xx_probe,1288.remove = crypto4xx_remove,1289};12901291static int __init crypto4xx_init(void)1292{1293return platform_driver_register(&crypto4xx_driver);1294}12951296static void __exit crypto4xx_exit(void)1297{1298platform_driver_unregister(&crypto4xx_driver);1299}13001301module_init(crypto4xx_init);1302module_exit(crypto4xx_exit);13031304MODULE_LICENSE("GPL");1305MODULE_AUTHOR("James Hsiao <[email protected]>");1306MODULE_DESCRIPTION("Driver for AMCC PPC4xx crypto accelerator");1307130813091310