blob: 910fcd697006a521eebc0395556e6ea996cf8018 [file] [log] [blame]
/*****************************************************************************
* Copyright Statement:
* --------------------
* This software is protected by Copyright and the information contained
* herein is confidential. The software may not be copied and the information
* contained herein may not be used or disclosed except with the written
* permission of MediaTek Inc. (C) 2013
*
* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
* NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
* SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
*
* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
* LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
* RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
* THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
*
*****************************************************************************/
/*****************************************************************************
*
* Filename:
* ---------
* drv_soe.c
*
* Description:
* ------------
* SOE Driver
*
* Author:
* -------
* -------
*
*============================================================================
* HISTORY
* Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
*------------------------------------------------------------------------------
* removed!
* removed!
* removed!
*
* removed!
* removed!
*
* removed!
* removed!
*
* removed!
* removed!
*
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
*
* removed!
* removed!
*
* removed!
* removed!
*
* removed!
* removed!
*
*
*------------------------------------------------------------------------------
* Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
*============================================================================
*****************************************************************************/
/*******************************************************************************
* Include header files
*******************************************************************************/
#include "kal_general_types.h"
#include "sleepdrv_interface.h"
#include "drvpdn.h"
#include "ex_public.h"
#include "drv_soe_reg.h"
#include "drv_soe_key.h"
#include "drv_soe_bm.h"
#include "drv_soe_engine.h"
#ifdef SOE_CHB_MODE
#define SOE_GPD_CHK SOE_CHK_32
#else
#define SOE_GPD_CHK SOE_CHK_28
#endif
#define SOE_BD_CHK SOE_CHK_16
#if 0 //defined(ATEST_ENABLE)
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
#else
#define DRV_MSG(level, fmt...)
#endif
#if defined(ATEST_ENABLE)
kal_uint32 drv_soe_dbg_frc[5];
kal_uint32 drv_soe_frc_start[5], drv_soe_frc_end[5];
extern kal_uint32 drv_sm_getCurFRC(void);
#define DRV_DBG_FRC_INIT(t) drv_soe_dbg_frc[t]=0
#define DRV_DBG_FRC_START(t) do{ drv_soe_frc_start[t] = drv_sm_getCurFRC(); \
}while(0)
#define DRV_DBG_FRC_END(t) do{ drv_soe_frc_end[t] = drv_sm_getCurFRC(); \
drv_soe_dbg_frc[t] += (drv_soe_frc_end[t] - drv_soe_frc_start[t]); \
}while(0)
#else
#define DRV_DBG_FRC_INIT(t)
#define DRV_DBG_FRC_START(t)
#define DRV_DBG_FRC_END(t)
#endif
//#define DRV_DISABLE_IRQ
/*******************************************************************************
* global variable definitions
*******************************************************************************/
static kal_bool drv_inited = KAL_FALSE;
static kal_enhmutexid drv_soe_locker;
static kal_eventgrpid drv_soe_egid;
#ifdef ATEST_ENABLE
static void (*drv_soe_lisr_handler_cb)(kal_uint32 vector) = NULL;
#endif
kal_bool drv_soe_irq_en = KAL_TRUE;
/*******************************************************************************
* SOE register dump
*******************************************************************************/
EX_BBREG_DUMP soe_reg_dump;
const kal_uint32 soe_reg_dump_regions[] = {
SOE_BASE, 0xC0, 4,
SOE_BASE+0x200, 0xB0, 4,
SOE_BASE+0x8000, 0x10, 4,
};
static void drv_soe_register_bbreg_dump(void)
{
soe_reg_dump.regions = (kal_uint32*)soe_reg_dump_regions;
soe_reg_dump.num = sizeof(soe_reg_dump_regions) / (sizeof(kal_uint32) * 3);
soe_reg_dump.bbreg_dump_callback = NULL;
EX_REGISTER_BBREG_DUMP(&soe_reg_dump);
}
/*******************************************************************************
* Function definitions
*******************************************************************************/
static kal_uint8 drv_soe_calc_chksum(kal_uint8 *data, kal_uint16 len)
{
kal_uint8 *uDataPtr, ckSum;
kal_uint16 i;
*(data + 1) = 0x0;
uDataPtr = data;
ckSum = 0;
for (i = 0; i < len; i++)
ckSum += *(uDataPtr + i);
return 0xFF - ckSum;
}
static void drv_soe_set_reg(kal_uint32 reg, kal_uint32 mask, kal_uint32 val, kal_uint32 offset)
{
kal_uint32 tmp;
tmp = SOE_REG(reg);
tmp &= (~mask);
tmp |= (val << offset);
SOE_REG(SOE_CR) = tmp;
}
void drv_soe_lisr(kal_uint32 irq_id)
{
kal_uint32 intr_status;
#ifdef ATEST_ENABLE
if(drv_soe_lisr_handler_cb != NULL) {
drv_soe_lisr_handler_cb(irq_id);
return;
}
#endif
intr_status = SOE_REG(SOE_L2ISAR);
SOE_REG(SOE_L2ISAR) = intr_status;
#if defined(MT6297)
intr_status |= (SOE_REG(SOE_ASYM_STATUS_REG7) << 8);
#endif
Data_Sync_Barrier();
IRQClearInt(SOE_IRQ);
Data_Sync_Barrier();
kal_set_eg_events(drv_soe_egid, intr_status, KAL_OR);
}
#ifdef ATEST_ENABLE
void drv_soe_reg_interrupt(void (*handler)(kal_uint32 vector))
{
drv_soe_lisr_handler_cb = handler;
}
#endif
void drv_soe_init(void)
{
if(drv_inited) {
return;
}
drv_soe_locker = kal_create_enh_mutex("SOEMtx");
if(!drv_soe_locker) ASSERT(0);
drv_soe_egid = kal_create_event_group("SOEEvt");
if(!drv_soe_egid) ASSERT(0);
//move to interface/service/config/kal_config/xxx_isr_config.h
//IRQ_Register_LISR(SOE_IRQ, drv_soe_lisr, "SOE handler");
//IRQSensitivity(SOE_IRQ, KAL_TRUE);
IRQClearInt(SOE_IRQ);
IRQUnmask(SOE_IRQ);
drv_inited = KAL_TRUE;
DRV_DBG_FRC_INIT(0);
DRV_DBG_FRC_INIT(1);
drv_soe_register_bbreg_dump();
}
static kal_uint32 drv_soe_gen_key_attr(drv_soe_key_attr_t *key_attr, sec_key_t *key_table)
{
#ifdef SOE_CHB_MODE
kal_uint32 kindex2;
#endif
kal_uint32 i, kindex = 0;
kal_bool extKey = KAL_TRUE;
//Get valid key index
for(i=0; i < SOE_DRV_KEY_ENTRY_MAX; i++) {
if(!SECK_GET_VALID(key_table[i])) {
kindex = i;
#ifdef SOE_CHB_MODE
kindex2 = (i + 1);
#endif
break;
}
}
if(i == (SOE_KEY_ENTRY_MAX + 1)) {
return 1;
}
if (key_attr->mode == SECK_CHB) {
key_attr->en = SECK_DEC;
}
if((kal_uint32)key_attr->key >= (kal_uint32)key_table &&
(kal_uint32)key_attr->key < ((kal_uint32)key_table + sizeof(sec_key_t))) {
extKey = KAL_FALSE;
}
else {
memset(&key_table[kindex], 0, sizeof(sec_key_t));
}
SECK_SET_VALID(key_table[kindex]);
key_attr->idx = (kindex + 1);
if (key_attr->en == SECK_ENC) {
SECK_SET_ENC(key_table[kindex]);
}
else {
SECK_SET_DEC(key_table[kindex]);
}
if (key_attr->mode == SECK_CHB) {
SECK_SET_MODE(key_table[kindex], SECK_AES);
}
else {
SECK_SET_MODE(key_table[kindex], key_attr->mode);
}
SECK_SET_OPT(key_table[kindex], key_attr->opt);
SECK_SET_ALG(key_table[kindex], key_attr->alg);
if (key_attr->mode == SECK_DES && key_attr->opt == SECK_OPT_3DES) {
SECK_SET_3DES(key_table[kindex], key_attr->desmode);
}
#if defined(SOE_MD97_HW)
if (key_attr->mode == SECK_RC5) {
rc5_para_t rc5_para;
rc5_para.pack.keylen = key_attr->var_key.rc5_len;
rc5_para.pack.block = key_attr->ops_para.rc5_attr.word_size / SECK_RC5_WORD_SIZE_BIT_INC;
rc5_para.pack.round = key_attr->ops_para.rc5_attr.rounds / SECK_RC5_ROUND_INC ;
SECK_SET_RC5_ATTR(key_table[kindex], rc5_para.p);
}
if (key_attr->mode == SECK_IDEA && key_attr->opt == SECK_OPT_3IDEA) {
SECK_SET_3IDEA(key_table[kindex], key_attr->ideamode);
}
if (key_attr->mode == SECK_CAST5 || key_attr->mode == SECK_CAST6 || key_attr->mode == SECK_BLOWFISH) {
SECK_SET_VAR_KEYLEN(key_table[kindex], key_attr->keylen);
}
if ((key_attr->mode == SECK_HASH || key_attr->mode == SECK_HMAC) && (key_attr->alg == SECK_ALG_TIGER))
{
tiger_para_t tiger_para;
tiger_para.pack.bits = key_attr->ops_para.tiger_attr.bits;
tiger_para.pack.rounds = key_attr->ops_para.tiger_attr.rounds;
SECK_SET_TIGER_ATTR(key_table[kindex], tiger_para.p);
}
#endif
/*MSG(MSG_INFO, "%s mod = %d\r\n", __FUNCTION__, attr->mode);*/
if (key_attr->key && extKey) {
SECK_SET_KEY(key_table[kindex], key_attr->key, key_attr->keylen);
}
SOE_CACHE_STORE(&key_table[kindex], sizeof(sec_key_t));
#ifdef SOE_CHB_MODE
if (key_attr->mode == SECK_CHB) {
if(extKey) {
memset(&key_table[kindex2], 0, sizeof(sec_key_t));
}
SECK_SET_VALID(key_table[kindex2]);
key_attr->idx2 = (kindex2 + 1);
if (key_attr->en == SECK_ENC) {
SECK_SET_ENC(key_table[kindex2]);
}
else {
SECK_SET_DEC(key_table[kindex2]);
}
SECK_SET_MODE(key_table[kindex2], SECK_HMAC);
SECK_SET_OPT(key_table[kindex2], key_attr->opt2);
SECK_SET_ALG(key_table[kindex2], key_attr->alg2);
if (key_attr->key2 && extKey) {
SECK_SET_KEY(key_table[kindex2], key_attr->key2, key_attr->keylen2);
}
SOE_CACHE_STORE(&key_table[kindex2], sizeof(sec_key_t));
}
#endif
return 0;
}
static kal_uint32 drv_soe_list_init(drv_soe_list_attr_t *attr)
{
kal_uint16 i, type;
gpd_t *gpd_now = NULL, *gpd_new;
bd_t *bd_now = NULL, *bd_new;
drv_soe_gpd_attr_t *gpd_attr;
drv_soe_key_attr_t *key_attr;
kal_uint32 len;
kal_uint8 *buf;
for (i = 0; i < attr->gpdnum; i++) {
/* reset variable */
gpd_attr = &attr->gpd[i];
key_attr = &attr->key[i];
bd_now = NULL;
gpd_new = gpd_attr->gpd;
if (gpd_now != NULL) {
SOE_SET_NEXT(gpd_now, virt_to_phys(gpd_new));
SOE_SET_CHKSUM(gpd_now, SOE_GPD_CHK);
}
memset(gpd_new, 0, GPD_SIZE);
SOE_SET_FLAGS_HWO(gpd_new);
if (gpd_attr->bd == NULL) {
SOE_CLR_FLAGS_BDP(gpd_new);
} else {
SOE_SET_FLAGS_BDP(gpd_new);
}
SOE_CLR_FORMAT_VR(gpd_new);
if(!SOE_IS_DYNA_DRAM((kal_uint32)gpd_attr->outbuf, gpd_attr->outlen)) {
return DRV_SOE_ERR_INVALID_PTR;
}
if(query_is_cached_ram((kal_uint32)gpd_attr->outbuf, gpd_attr->outlen)) {
SOE_CACHE_STORE(gpd_attr->outbuf, gpd_attr->outlen);
SOE_CACHE_INVALIDATE(gpd_attr->outbuf, gpd_attr->outlen);
gpd_attr->outbuf = (kal_uint8*)virt_to_phys(gpd_attr->outbuf);
}
SOE_SET_BUF_LEN(gpd_new, gpd_attr->buflen);
SOE_SET_OUTPTR(gpd_new, gpd_attr->outbuf);
if(gpd_attr->icblen) {
if(!SOE_IS_DYNA_DRAM((kal_uint32)gpd_attr->icb, gpd_attr->icblen)) {
return DRV_SOE_ERR_INVALID_PTR;
}
if(query_is_cached_ram((kal_uint32)gpd_attr->icb, gpd_attr->icblen)) {
SOE_CACHE_STORE(gpd_attr->icb, gpd_attr->icblen);
gpd_attr->icb = (kal_uint8*)virt_to_phys(gpd_attr->icb);
}
SOE_SET_ICBPTR(gpd_new, gpd_attr->icb);
if(key_attr->alg == SECK_ALG_CBC) {
#if defined(SOE_MD97_HW) && !defined(MT6297)
SOE_SET_FORMAT_UI(gpd_new);
#else
/* Apollo is not ready for using UI with new algorithms */
do {
if(key_attr->mode == SECK_DES || key_attr->mode == SECK_AES)
SOE_SET_FORMAT_UI(gpd_new);
}while(0);
#endif
}
}
else {
SOE_SET_ICBPTR(gpd_new, gpd_attr->outbuf); //dummy ptr
}
if(gpd_attr->icvlen) {
if(!SOE_IS_DYNA_DRAM((kal_uint32)gpd_attr->icv, gpd_attr->icvlen)) {
return DRV_SOE_ERR_INVALID_PTR;
}
if(query_is_cached_ram((kal_uint32)gpd_attr->icv, gpd_attr->icvlen)) {
SOE_CACHE_STORE(gpd_attr->icv, gpd_attr->icvlen);
SOE_CACHE_INVALIDATE(gpd_attr->icv, gpd_attr->icvlen);
gpd_attr->icv = (kal_uint8*)virt_to_phys(gpd_attr->icv);
}
SOE_SET_ICVPTR(gpd_new, gpd_attr->icv);
}
else {
SOE_SET_ICVPTR(gpd_new, gpd_attr->outbuf); //dummy ptr
}
SOE_SET_KEY_IDX(gpd_new, gpd_attr->keyidx);
#ifdef SOE_CHB_MODE
SOE_SET_KEY_IDX2(gpd_new, gpd_attr->keyidx2);
SOE_SET_CIPHER_OFFSET(gpd_new, gpd_attr->cipher_offset);
if (key_attr->mode == SECK_CHB) {
SOE_SET_FORMAT_CHB(gpd_new);
}
else {
SOE_CLR_FORMAT_CHB(gpd_new);
}
#endif
if (gpd_attr->bd == NULL) {
/* No BD, set data ptr */
if(!SOE_IS_DYNA_DRAM((kal_uint32)gpd_attr->inbuf, gpd_attr->inlen)) {
return DRV_SOE_ERR_INVALID_PTR;
}
if(query_is_cached_ram((kal_uint32)gpd_attr->inbuf, gpd_attr->inlen)) {
SOE_CACHE_STORE(gpd_attr->inbuf, gpd_attr->inlen);
gpd_attr->inbuf = (kal_uint8*)virt_to_phys(gpd_attr->inbuf);
}
SOE_SET_DATA(gpd_new, gpd_attr->inbuf);
} else {
/* Generate BDs */
for (type = 0; type < 2; type++) {
if(key_attr->alg == SECK_ALG_XCBC) {
// XCBC
buf = type ? gpd_attr->inbuf : gpd_attr->icb;
len = type ? gpd_attr->inlen : gpd_attr->icblen;
}
else {
// CCM/GCM
buf = type ? gpd_attr->inbuf : gpd_attr->abuf;
len = type ? gpd_attr->inlen : gpd_attr->alen;
}
if(!SOE_IS_DYNA_DRAM((kal_uint32)buf, len)) {
return DRV_SOE_ERR_INVALID_PTR;
}
if(query_is_cached_ram((kal_uint32)buf, len)) {
SOE_CACHE_STORE(buf, len);
buf = (kal_uint8*)virt_to_phys(buf);
}
bd_new = &gpd_attr->bd[type];
/* set data ptr */
memset(bd_new, 0, BD_SIZE);
BD_SET_DATA(bd_new, buf);
BD_SET_BUF_LEN(bd_new, len);
/* set list */
if (bd_now == NULL) {
SOE_SET_BD(gpd_new, virt_to_phys(bd_new));
} else {
if(!len)
BD_SET_FLAGS_EOL(bd_now);
BD_SET_NEXT(bd_now, virt_to_phys(bd_new));
BD_SET_CHKSUM(bd_now, SOE_BD_CHK);
SOE_CACHE_STORE(bd_now, BD_SIZE);
}
if (type == 1) { /* last BD */
BD_SET_FLAGS_EOL(bd_new);
}
bd_now = bd_new;
}
BD_SET_CHKSUM(bd_now, SOE_BD_CHK);
SOE_CACHE_STORE(bd_now, BD_SIZE);
}
SOE_SET_CHKSUM(gpd_new, SOE_GPD_CHK);
SOE_CACHE_STORE(gpd_new, GPD_SIZE);
gpd_now = gpd_new;
}
/* link last GPD */
gpd_new = (gpd_t *)&gpd_now[1];
SOE_SET_NEXT(gpd_now, virt_to_phys(gpd_new));
SOE_SET_FLAGS_INT(gpd_now);
SOE_SET_CHKSUM(gpd_now, SOE_GPD_CHK);
SOE_CACHE_STORE(gpd_now, GPD_SIZE);
memset(gpd_new, 0, GPD_SIZE);
SOE_CACHE_STORE(gpd_new, GPD_SIZE);
return 0;
}
static kal_uint32 drv_soe_gen_gpd_attr(drv_soe_gpd_attr_t *attr, drv_soe_key_attr_t *key)
{
kal_uint32 err = 0;
// check keylen and datalen
switch(key->mode) {
case SECK_NULL:
err = 0;
break;
case SECK_HMAC:
switch(key->alg) {
case SECK_ALG_MD5:
case SECK_ALG_SHA1:
case SECK_ALG_SHA256:
#if defined(SOE_MD97_HW)
case SECK_ALG_TIGER:
#endif
if(key->keylen != 64) err = DRV_SOE_ERR_KEYLEN;
break;
case SECK_ALG_SHA384:
case SECK_ALG_SHA512:
if(key->keylen != 128) err = DRV_SOE_ERR_KEYLEN;
break;
default:
err = DRV_SOE_ERR_ALG;
break;
}
//following check as HASH
case SECK_HASH:
if(attr->inlen > 65535) err = DRV_SOE_ERR_INLEN;
#if defined(SOE_MD97_HW)
if(key->alg > SECK_ALG_TIGER) err = DRV_SOE_ERR_ALG;
#else
if(key->alg > SECK_ALG_SHA512) err = DRV_SOE_ERR_ALG;
#endif
switch(key->alg) {
case SECK_ALG_MD5:
if(attr->outlen != 16) err = DRV_SOE_ERR_OUTLEN;
break;
case SECK_ALG_SHA1:
if(attr->outlen != 20) err = DRV_SOE_ERR_OUTLEN;
break;
case SECK_ALG_SHA256:
if(attr->outlen != 32) err = DRV_SOE_ERR_OUTLEN;
break;
case SECK_ALG_SHA384:
if(attr->outlen != 48) err = DRV_SOE_ERR_OUTLEN;
break;
case SECK_ALG_SHA512:
if(attr->outlen != 64) err = DRV_SOE_ERR_OUTLEN;
break;
#if defined(SOE_MD97_HW)
case SECK_ALG_TIGER:
if(attr->outlen != 16 && attr->outlen != 24 && attr->outlen != 32) err = DRV_SOE_ERR_OUTLEN;
break;
#endif
default:
err = DRV_SOE_ERR_ALG;
break;
}
break;
case SECK_DES:
if(key->opt > SECK_OPT_3DES) err = DRV_SOE_ERR_OPT;
if(key->alg > SECK_ALG_CBC) err = DRV_SOE_ERR_ALG;
if(!(attr->inlen == 8 || (attr->inlen >= 16 && attr->inlen <= 65528))) err = DRV_SOE_ERR_INLEN;
if(attr->inlen != attr->outlen) err = DRV_SOE_ERR_OUTLEN;
if(key->opt == SECK_OPT_DES && key->keylen != 8) err = DRV_SOE_ERR_KEYLEN;
if(key->opt == SECK_OPT_3DES && key->keylen != 24) err = DRV_SOE_ERR_KEYLEN;
if(key->alg == SECK_ALG_CBC && attr->icblen != 8) err = DRV_SOE_ERR_ICBLEN;
break;
case SECK_AES:
if(key->alg != SECK_ALG_XCBC && key->alg != SECK_ALG_CMAC) {
if(key->opt > SECK_AES_256) err = DRV_SOE_ERR_OPT;
if(attr->inlen != attr->outlen) err = DRV_SOE_ERR_OUTLEN;
}
else {
if(key->opt > SECK_AES_128) err = DRV_SOE_ERR_OPT;
if(attr->inlen > 65535) err = DRV_SOE_ERR_INLEN;
if(key->en == SECK_DEC && attr->icvlen != 16) err = DRV_SOE_ERR_ICVLEN;
}
switch(key->alg) {
case SECK_ALG_CBC:
if(attr->icblen != 16) err = DRV_SOE_ERR_ICBLEN;
//following check as ECB
case SECK_ALG_ECB:
if(!(attr->inlen == 16 || (attr->inlen >= 32 && attr->inlen <= 65520))) err = DRV_SOE_ERR_INLEN;
break;
case SECK_ALG_CTR:
if(attr->inlen == 0 || attr->inlen > 65535) {
err = DRV_SOE_ERR_INLEN;
}
if(attr->icblen != 16) err = DRV_SOE_ERR_ICBLEN;
break;
case SECK_ALG_CCM:
case SECK_ALG_GCM:
//check in next stage
default:
break;
}
break;
#if defined(SOE_MD97_HW)
case SECK_RC5:
if(key->opt != 0) err = DRV_SOE_ERR_OPT;
if(key->alg > SECK_ALG_CBC) err = DRV_SOE_ERR_ALG;
if(!(attr->inlen == 8 || (attr->inlen >= 16 && attr->inlen <= 65528))) err = DRV_SOE_ERR_INLEN;
if(attr->inlen != attr->outlen) err = DRV_SOE_ERR_OUTLEN;
if(key->alg == SECK_ALG_CBC && (attr->icblen != 4 && attr->icblen != 8 && attr->icblen != 16)) err = DRV_SOE_ERR_ICBLEN;
if(key->keylen == 0 /*|| key->keylen > 255 */) err = DRV_SOE_ERR_KEYLEN;
break;
case SECK_IDEA:
if(key->opt > SECK_OPT_3IDEA) err = DRV_SOE_ERR_OPT;
if(key->alg > SECK_ALG_CBC) err = DRV_SOE_ERR_ALG;
if(!(attr->inlen == 8 || (attr->inlen >= 16 && attr->inlen <= 65528))) err = DRV_SOE_ERR_INLEN;
if(attr->inlen != attr->outlen) err = DRV_SOE_ERR_OUTLEN;
if(key->opt == SECK_OPT_IDEA && key->keylen != 16) err = DRV_SOE_ERR_KEYLEN;
if(key->opt == SECK_OPT_3IDEA && key->keylen != 48) err = DRV_SOE_ERR_KEYLEN;
if(key->alg == SECK_ALG_CBC && attr->icblen != 8) err = DRV_SOE_ERR_ICBLEN;
break;
case SECK_CAST5:
if(key->opt != 0) err = DRV_SOE_ERR_OPT;
if(key->alg > SECK_ALG_CBC) err = DRV_SOE_ERR_ALG;
if(!(attr->inlen == 8 || (attr->inlen >= 16 && attr->inlen <= 65528))) err = DRV_SOE_ERR_INLEN;
if(attr->inlen != attr->outlen) err = DRV_SOE_ERR_OUTLEN;
if(key->alg == SECK_ALG_CBC && attr->icblen != 8) err = DRV_SOE_ERR_ICBLEN;
if(key->keylen < 5 || key->keylen > 16) err = DRV_SOE_ERR_KEYLEN;
break;
case SECK_CAST6:
if(key->opt != 0) err = DRV_SOE_ERR_OPT;
if(key->alg > SECK_ALG_CBC) err = DRV_SOE_ERR_ALG;
if(!(attr->inlen == 16 || (attr->inlen >= 32 && attr->inlen <= 65520))) err = DRV_SOE_ERR_INLEN;
if(attr->inlen != attr->outlen) err = DRV_SOE_ERR_OUTLEN;
if(key->alg == SECK_ALG_CBC && attr->icblen != 16) err = DRV_SOE_ERR_ICBLEN;
if(key->keylen < 16 || key->keylen > 32 || (key->keylen & 3) != 0) err = DRV_SOE_ERR_KEYLEN;
break;
case SECK_BLOWFISH:
if(key->opt != 0) err = DRV_SOE_ERR_OPT;
if(key->alg > SECK_ALG_CBC) err = DRV_SOE_ERR_ALG;
if(!(attr->inlen == 8 || (attr->inlen >= 16 && attr->inlen <= 65528))) err = DRV_SOE_ERR_INLEN;
if(attr->inlen != attr->outlen) err = DRV_SOE_ERR_OUTLEN;
if(key->alg == SECK_ALG_CBC && attr->icblen != 8) err = DRV_SOE_ERR_ICBLEN;
if(key->keylen < 4 || key->keylen > 56) err = DRV_SOE_ERR_KEYLEN;
break;
case SECK_CHB:
if (key->opt != SECK_AES_128) err = DRV_SOE_ERR_OPT;
if (key->alg != SECK_ALG_CBC) err = DRV_SOE_ERR_ALG;
if (key->alg2 > SECK_ALG_SHA256) err = 3;
break;
case SECK_RSADH:
if (key->opt != 0) err = DRV_SOE_ERR_OPT;
if (key->alg > SECK_ALG_MODEXP) err = DRV_SOE_ERR_ALG;
break;
case SECK_ECC:
if (key->opt != 0) err = DRV_SOE_ERR_OPT;
if (key->alg > SECK_ALG_PADD) err = DRV_SOE_ERR_ALG;
break;
#endif
default:
err = DRV_SOE_ERR_MODE;
}
//check CHB mode
if (key->mode != SECK_CHB) {
if ((key->mode == SECK_AES) && (key->alg == SECK_ALG_CCM || key->alg == SECK_ALG_GCM)) {
attr->buflen = attr->inlen;
if((attr->inlen + attr->alen) > 65535) {
err = DRV_SOE_ERR_CHBLEN;
}
}
else {
attr->alen = 0;
}
}
else {
attr->alen = 0;
}
if(err) {
DRV_MSG(MSG_INFO, "%s err: %x\r\n", __FUNCTION__, err);
return err;
}
//assign keyidx
attr->keyidx = key->idx;
if (key->mode == SECK_CHB) {
attr->keyidx2 = key->idx2;
}
DRV_MSG(MSG_INFO, "%s keyidx:%d keyidx2:%d\r\n", __FUNCTION__, attr->keyidx, attr->keyidx2);
return 0;
}
kal_uint32 drv_soe_gen_attr(drv_soe_ctrl_struct_t *ctrl)
{
drv_soe_list_attr_t *attr = &ctrl->list_attr;
kal_uint32 i, idx, ret;
DRV_DBG_FRC_START(0);
// check ptr
if(ctrl->gpd == NULL || ctrl->key == NULL) {
return DRV_SOE_ERR_INVALID_PTR;
}
if(!SOE_IS_DYNA_DRAM((kal_uint32)ctrl->gpd, sizeof(gpd_t))) {
return DRV_SOE_ERR_INVALID_PTR;
}
if(!SOE_IS_DYNA_DRAM((kal_uint32)ctrl->key, sizeof(sec_key_t))) {
return DRV_SOE_ERR_INVALID_PTR;
}
// set key table
for(i = 0, idx = 0; i < attr->gpdnum; i++) {
if(idx == (SOE_DRV_GPD_MAX + 1)) {
return DRV_SOE_ERR_GPD_OVERFLOW;
}
ret = drv_soe_gen_key_attr(&attr->key[i], ctrl->key);
if(ret) {
DRV_MSG(MSG_INFO, "%s gen_key err: %x\r\n", __FUNCTION__, ret);
return ret;
}
if(attr->gpd[i].alen > 0) {
ret = attr->key[i].idx - 1;
SECK_SET_ADATA(ctrl->key[ret], attr->gpd[i].alen);
SOE_CACHE_STORE(&ctrl->key[ret], sizeof(sec_key_t));
}
memset(&ctrl->gpd[idx], 0, sizeof(gpd_t));
attr->gpd[i].gpd = &ctrl->gpd[idx++];
ret = drv_soe_gen_gpd_attr(&attr->gpd[i], &attr->key[i]);
if(ret) {
DRV_MSG(MSG_INFO, "%s gen_gpd err: %x\r\n", __FUNCTION__, ret);
return ret;
}
if(attr->gpd[i].alen || (attr->key[i].mode == SECK_AES && attr->key[i].alg == SECK_ALG_XCBC && attr->gpd[i].icblen) ) {
memset(&ctrl->gpd[idx], 0, sizeof(gpd_t));
attr->gpd[i].bd = (bd_t*)&ctrl->gpd[attr->gpdnum + idx];
}
}
ret = drv_soe_list_init(attr);
#ifdef ATEST_ENABLE
if(!ret)
ctrl->r_gpd_cnt += attr->gpdnum;
#endif
DRV_DBG_FRC_END(0);
return ret;
}
kal_uint32 drv_soe_update_attr(drv_soe_ctrl_struct_t *ctrl)
{
drv_soe_list_attr_t *attr = &ctrl->list_attr;
kal_uint32 ret;
DRV_DBG_FRC_START(0);
// check ctrl
if(!SOE_GET_NEXT(ctrl->gpd)) {
return DRV_SOE_ERR_INVALID_GPD;
}
// update GPD
ret = drv_soe_list_init(attr);
#ifdef ATEST_ENABLE
if(!ret)
ctrl->r_gpd_cnt += attr->gpdnum;
#endif
DRV_DBG_FRC_END(0);
return ret;
}
kal_uint32 drv_soe_trigger(gpd_t *pGpd, sec_key_t *pKey)
{
kal_uint32 err = 0;
kal_uint32 event_group = 0;
kal_uint32 soe_timeout_ticks;
gpd_t *last_gpd = pGpd;
//check GPD/KEY
if(last_gpd == NULL || pKey == NULL) return DRV_SOE_ERR_INVALID_PTR;
if((kal_uint32)last_gpd & 0x3) return DRV_SOE_ERR_INVALID_PTR;
if((kal_uint32)pKey & 0x3) return DRV_SOE_ERR_INVALID_PTR;
if(!SOE_IS_DYNA_DRAM((kal_uint32)pGpd, sizeof(gpd_t))) return DRV_SOE_ERR_INVALID_PTR;
pKey = (sec_key_t*)((kal_uint32)pKey - sizeof(sec_key_t));
if(!SOE_IS_DYNA_DRAM((kal_uint32)pKey, sizeof(sec_key_t))) return DRV_SOE_ERR_INVALID_PTR;
while(SOE_IS_FLAGS_HWO(last_gpd)) {
if(!SECK_GET_VALID(pKey[last_gpd->keyidx])) return DRV_SOE_ERR_INVALID_KEY;
if(last_gpd->pnext == NULL) return DRV_SOE_ERR_INVALID_PNEXT;
if(last_gpd->icbptr == NULL) return DRV_SOE_ERR_INVALID_ICB;
if(last_gpd->icvptr == NULL) return DRV_SOE_ERR_INVALID_ICV;
last_gpd = last_gpd->pnext;
}
if(last_gpd == pGpd) return DRV_SOE_ERR_INVALID_GPD;
DRV_DBG_FRC_START(0);
//check drv init
if(!drv_inited) {
drv_soe_init();
}
//mutex lock
kal_take_enh_mutex(drv_soe_locker);
SleepDrv_LockSleep(SLEEP_CTL_SOE, SMP);
PDN_CLR(PDN_SOE);
//check SOE status
Data_Mem_Barrier();
if(SOE_REG(SOE_QCSR) & SOQ_STAT) {
err = DRV_SOE_ERR_STAT_BUSY;
goto EngineError;
}
//unmask irq
#ifndef DRV_DISABLE_IRQ
if(drv_soe_irq_en) {
SOE_REG(SOE_L2ISAR) = 0xFFFFFFFF;
SOE_REG(SOE_L2IMCR) = 0xFFFFFFFF;
IRQClearInt(SOE_IRQ);
IRQUnmask(SOE_IRQ);
}
#endif
//config SOE
#if defined(MT6297)
SOE_REG(SOE_ASYM_STATUS_REG7) = 0xFFFFFFFF;
#endif
SOE_REG(SOE_CR) = (SOE_CS_EN | SOE_CSALL_EN);
drv_soe_set_reg(SOE_CR, SOE_DMA_MODE, SOE_DMA_MODE, SOE_DMA_MODE_BITS);
if(query_is_cached_ram((kal_uint32)pKey, sizeof(sec_key_t))) {
SOE_REG(SOE_KTSAR) = virt_to_phys(pKey);
}
else {
SOE_REG(SOE_KTSAR) = (kal_uint32)pKey;
}
if(query_is_cached_ram((kal_uint32)pGpd, sizeof(gpd_t))) {
SOE_REG(SOE_QSAR) = virt_to_phys(pGpd);
}
else {
SOE_REG(SOE_QSAR) = (kal_uint32)pGpd;
}
//start queue
Data_Mem_Barrier();
DRV_DBG_FRC_START(1);
SOE_REG(SOE_QCSR) = SOQ_START;
Data_Sync_Barrier();
//wait done
#ifndef DRV_DISABLE_IRQ
if(drv_soe_irq_en) {
kal_retrieve_eg_events(drv_soe_egid, (SO_ERROR_MASK | SO_DONE), KAL_OR_CONSUME, &event_group, KAL_SUSPEND);
}
else
#endif
{
soe_timeout_ticks = drv_get_current_time();
while(SOE_REG(SOE_QCSR) & SOQ_STAT) {
if(drv_get_duration_ms(soe_timeout_ticks) > 8000) {
DRV_DBG_FRC_END(1);
err = DRV_SOE_ERR_STAT_BUSY;
goto EngineError;
}
}
event_group = SOE_REG(SOE_L2ISAR);
#if defined(MT6297)
event_group |= (SOE_REG(SOE_ASYM_STATUS_REG7) << 8);
#endif
}
DRV_DBG_FRC_END(1);
if(event_group & SO_GPD_CSERR) err = DRV_SOE_ERR_GPD_CSERR;
if(event_group & SO_BD_CSERR) err = DRV_SOE_ERR_BD_CSERR;
if(event_group & SO_LENERR) err = DRV_SOE_ERR_LENERR;
if(event_group & SO_KTERR) err = DRV_SOE_ERR_KTERR;
if(SOE_IS_FORMAT_VR(pGpd)) err = DRV_SOE_ERR_VRERR;
if(event_group & SO_ASYM_ERROR_MASK) err = DRV_SOE_ERR_ASYMERR;
if(err) goto EngineError;
SOE_REG(SOE_L2IMSR) = 0xFFFFFFFF;
Data_Sync_Barrier();
EngineError:
PDN_SET(PDN_SOE);
SleepDrv_UnlockSleep(SLEEP_CTL_SOE, SMP);
kal_give_enh_mutex(drv_soe_locker);
DRV_DBG_FRC_END(0);
return err;
}
void drv_soe_cache_ctrl(kal_bool clean, kal_bool invalidate, kal_uint32 addr, kal_uint32 ln)
{
if(clean)
SOE_CACHE_STORE(addr, ln);
if(invalidate)
SOE_CACHE_INVALIDATE(addr, ln);
}
void* drv_soe_memcpy(kal_uint8 *dst, kal_uint8 *src, kal_uint32 ln)
{
return memcpy((kal_uint8*)virt_to_phys(dst), \
(kal_uint8*)virt_to_phys(src), \
ln);
}
//Call from devdrv_common.c Drv_Init_Phase2()
void SOE_Drv_Init(void)
{
drv_soe_init();
PDN_SET(PDN_SOE);
}