| /***************************************************************************** |
| * 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); |
| } |