@ -82,6 +82,7 @@
struct atmel_aes_caps {
bool has_dualbuff ;
bool has_cfb64 ;
bool has_ctr32 ;
u32 max_burst_size ;
} ;
@ -103,6 +104,15 @@ struct atmel_aes_ctx {
struct atmel_aes_base_ctx base ;
} ;
struct atmel_aes_ctr_ctx {
struct atmel_aes_base_ctx base ;
u32 iv [ AES_BLOCK_SIZE / sizeof ( u32 ) ] ;
size_t offset ;
struct scatterlist src [ 2 ] ;
struct scatterlist dst [ 2 ] ;
} ;
struct atmel_aes_reqctx {
unsigned long mode ;
} ;
@ -762,6 +772,96 @@ static int atmel_aes_start(struct atmel_aes_dev *dd)
atmel_aes_transfer_complete ) ;
}
static inline struct atmel_aes_ctr_ctx *
atmel_aes_ctr_ctx_cast ( struct atmel_aes_base_ctx * ctx )
{
return container_of ( ctx , struct atmel_aes_ctr_ctx , base ) ;
}
static int atmel_aes_ctr_transfer ( struct atmel_aes_dev * dd )
{
struct atmel_aes_ctr_ctx * ctx = atmel_aes_ctr_ctx_cast ( dd - > ctx ) ;
struct ablkcipher_request * req = ablkcipher_request_cast ( dd - > areq ) ;
struct scatterlist * src , * dst ;
u32 ctr , blocks ;
size_t datalen ;
bool use_dma , fragmented = false ;
/* Check for transfer completion. */
ctx - > offset + = dd - > total ;
if ( ctx - > offset > = req - > nbytes )
return atmel_aes_transfer_complete ( dd ) ;
/* Compute data length. */
datalen = req - > nbytes - ctx - > offset ;
blocks = DIV_ROUND_UP ( datalen , AES_BLOCK_SIZE ) ;
ctr = be32_to_cpu ( ctx - > iv [ 3 ] ) ;
if ( dd - > caps . has_ctr32 ) {
/* Check 32bit counter overflow. */
u32 start = ctr ;
u32 end = start + blocks - 1 ;
if ( end < start ) {
ctr | = 0xffffffff ;
datalen = AES_BLOCK_SIZE * - start ;
fragmented = true ;
}
} else {
/* Check 16bit counter overflow. */
u16 start = ctr & 0xffff ;
u16 end = start + ( u16 ) blocks - 1 ;
if ( blocks > > 16 | | end < start ) {
ctr | = 0xffff ;
datalen = AES_BLOCK_SIZE * ( 0x10000 - start ) ;
fragmented = true ;
}
}
use_dma = ( datalen > = ATMEL_AES_DMA_THRESHOLD ) ;
/* Jump to offset. */
src = scatterwalk_ffwd ( ctx - > src , req - > src , ctx - > offset ) ;
dst = ( ( req - > src = = req - > dst ) ? src :
scatterwalk_ffwd ( ctx - > dst , req - > dst , ctx - > offset ) ) ;
/* Configure hardware. */
atmel_aes_write_ctrl ( dd , use_dma , ctx - > iv ) ;
if ( unlikely ( fragmented ) ) {
/*
* Increment the counter manually to cope with the hardware
* counter overflow .
*/
ctx - > iv [ 3 ] = cpu_to_be32 ( ctr ) ;
crypto_inc ( ( u8 * ) ctx - > iv , AES_BLOCK_SIZE ) ;
}
if ( use_dma )
return atmel_aes_dma_start ( dd , src , dst , datalen ,
atmel_aes_ctr_transfer ) ;
return atmel_aes_cpu_start ( dd , src , dst , datalen ,
atmel_aes_ctr_transfer ) ;
}
static int atmel_aes_ctr_start ( struct atmel_aes_dev * dd )
{
struct atmel_aes_ctr_ctx * ctx = atmel_aes_ctr_ctx_cast ( dd - > ctx ) ;
struct ablkcipher_request * req = ablkcipher_request_cast ( dd - > areq ) ;
struct atmel_aes_reqctx * rctx = ablkcipher_request_ctx ( req ) ;
int err ;
atmel_aes_set_mode ( dd , rctx ) ;
err = atmel_aes_hw_init ( dd ) ;
if ( err )
return atmel_aes_complete ( dd , err ) ;
memcpy ( ctx - > iv , req - > info , AES_BLOCK_SIZE ) ;
ctx - > offset = 0 ;
dd - > total = 0 ;
return atmel_aes_ctr_transfer ( dd ) ;
}
static int atmel_aes_crypt ( struct ablkcipher_request * req , unsigned long mode )
{
struct atmel_aes_base_ctx * ctx ;
@ -919,6 +1019,16 @@ static int atmel_aes_cra_init(struct crypto_tfm *tfm)
return 0 ;
}
static int atmel_aes_ctr_cra_init ( struct crypto_tfm * tfm )
{
struct atmel_aes_ctx * ctx = crypto_tfm_ctx ( tfm ) ;
tfm - > crt_ablkcipher . reqsize = sizeof ( struct atmel_aes_reqctx ) ;
ctx - > base . start = atmel_aes_ctr_start ;
return 0 ;
}
static void atmel_aes_cra_exit ( struct crypto_tfm * tfm )
{
}
@ -1076,11 +1186,11 @@ static struct crypto_alg aes_algs[] = {
. cra_priority = ATMEL_AES_PRIORITY ,
. cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC ,
. cra_blocksize = 1 ,
. cra_ctxsize = sizeof ( struct atmel_aes_ctx ) ,
. cra_ctxsize = sizeof ( struct atmel_aes_ctr_ct x ) ,
. cra_alignmask = 0xf ,
. cra_type = & crypto_ablkcipher_type ,
. cra_module = THIS_MODULE ,
. cra_init = atmel_aes_cra_init ,
. cra_init = atmel_aes_ctr_c ra_init ,
. cra_exit = atmel_aes_cra_exit ,
. cra_u . ablkcipher = {
. min_keysize = AES_MIN_KEY_SIZE ,
@ -1262,6 +1372,7 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd)
{
dd - > caps . has_dualbuff = 0 ;
dd - > caps . has_cfb64 = 0 ;
dd - > caps . has_ctr32 = 0 ;
dd - > caps . max_burst_size = 1 ;
/* keep only major version number */
@ -1269,11 +1380,13 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd)
case 0x500 :
dd - > caps . has_dualbuff = 1 ;
dd - > caps . has_cfb64 = 1 ;
dd - > caps . has_ctr32 = 1 ;
dd - > caps . max_burst_size = 4 ;
break ;
case 0x200 :
dd - > caps . has_dualbuff = 1 ;
dd - > caps . has_cfb64 = 1 ;
dd - > caps . has_ctr32 = 1 ;
dd - > caps . max_burst_size = 4 ;
break ;
case 0x130 :