From b8db7431561e1b7555681ebb5810fa090c0bc5ce Mon Sep 17 00:00:00 2001 From: Mona Hossain Date: Thu, 17 Nov 2011 12:33:24 -0800 Subject: [PATCH] crypto: Fix Cipher Test Failures This patch fixes 2 issues that was causing cipher operation failure (1) Status register reflecting an SW_ERR (ACCESS_VIOL bit set) Status register needed to be cleared initially before starting any operation (2) Occasional failure observed in some cipher operation(s) (encryption and/or decryption) for modes that require reading in the CNTR IV register values after an operation is complete. These failures show up when doing a 3DES-CBC operation. But there is potential for it to raise its head when doing DES-CBC, AES-CBC or AES_XTS modes as well (since all of this modes require reading in the CNTR IV register). The CNTR IV register was being read after writing data to the IN FIFO. There is a potential for encryption (or decryption) operations to not have completed fully on all the data in the FIFO before the IV register is read, resulting in incorrect IV value. The fix is to read the CNTR IV register after the operation is guranteed to have completed sucessfully. This is done after reading data out of DATA OUT FIFO. Change-Id: Icef0d544ecb463cea4be978c3d2809049b92da05 Signed-off-by: Mona Hossain --- drivers/crypto/msm/qce40.c | 76 +++++++++++++++++++++----------------- drivers/crypto/msm/qce40.h | 6 +-- 2 files changed, 46 insertions(+), 36 deletions(-) diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c index 60a5aff1f56..d725851f6b4 100644 --- a/drivers/crypto/msm/qce40.c +++ b/drivers/crypto/msm/qce40.c @@ -208,6 +208,7 @@ static void _check_probe_done_call_back(struct msm_dmov_cmd *cmd_ptr, static int _init_ce_engine(struct qce_device *pce_dev) { + int status; /* Reset ce */ clk_reset(pce_dev->ce_core_clk, CLK_RESET_ASSERT); clk_reset(pce_dev->ce_core_clk, CLK_RESET_DEASSERT); @@ -223,6 +224,11 @@ static int _init_ce_engine(struct qce_device *pce_dev) /* Configure the CE Engine */ config_ce_engine(pce_dev); + /* + * Clear ACCESS_VIOL bit in CRYPTO_STATUS REGISTER + */ + status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG); + *((uint32_t *)(pce_dev->ce_dm.buffer.status)) = status & (~0x40000); /* * Ensure ce configuration is completed. */ @@ -474,12 +480,20 @@ static int _ce_setup_cipher_cmdrptrlist(struct qce_device *pce_dev, } } - if (creq->mode == QCE_MODE_CCM) + switch (creq->mode) { + case QCE_MODE_CCM: pce_dev->ce_dm.chan_ce_out_cmd->cmdptr = - cmdptrlist->aead_ce_out; - else + cmdptrlist->aead_ce_out; + break; + case QCE_MODE_ECB: pce_dev->ce_dm.chan_ce_out_cmd->cmdptr = - cmdptrlist->cipher_ce_out; + cmdptrlist->cipher_ce_out; + break; + default: + pce_dev->ce_dm.chan_ce_out_cmd->cmdptr = + cmdptrlist->cipher_ce_out_get_iv; + break; + } return 0; } @@ -1330,21 +1344,6 @@ static int _setup_cipher_cmdlists(struct qce_device *pce_dev, pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv); pscmd++; - pce_dev->ce_dm.cmdlist.get_cipher_aes_iv = pscmd; - pscmd->cmd = CMD_LC | CMD_SRC_SWAP_BYTES | - CMD_SRC_SWAP_SHORTS | CMD_MODE_SINGLE; - pscmd->src = (unsigned) (CRYPTO_CNTR0_IV0_REG + pce_dev->phy_iobase); - pscmd->len = CRYPTO_REG_SIZE * 4; - pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv); - pscmd++; - - pce_dev->ce_dm.cmdlist.get_cipher_aes_xts_iv = pscmd; - pscmd->cmd = CMD_LC | CMD_MODE_SINGLE; - pscmd->src = (unsigned) (CRYPTO_CNTR0_IV0_REG + pce_dev->phy_iobase); - pscmd->len = CRYPTO_REG_SIZE * 4; - pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv); - pscmd++; - pce_dev->ce_dm.cmdlist.set_cipher_des_iv = pscmd; pscmd->cmd = CMD_LC | CMD_SRC_SWAP_BYTES | CMD_SRC_SWAP_SHORTS | CMD_MODE_SINGLE; @@ -1353,11 +1352,11 @@ static int _setup_cipher_cmdlists(struct qce_device *pce_dev, pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv); pscmd++; - pce_dev->ce_dm.cmdlist.get_cipher_des_iv = pscmd; + pce_dev->ce_dm.cmdlist.get_cipher_iv = pscmd; pscmd->cmd = CMD_LC | CMD_SRC_SWAP_BYTES | CMD_SRC_SWAP_SHORTS | CMD_MODE_SINGLE; pscmd->src = (unsigned) (CRYPTO_CNTR0_IV0_REG + pce_dev->phy_iobase); - pscmd->len = CRYPTO_REG_SIZE * 2; + pscmd->len = CRYPTO_REG_SIZE * 4; pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.encr_cntr_iv); pscmd++; @@ -1613,6 +1612,14 @@ static int qce_setup_cmdlists(struct qce_device *pce_dev, pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.status); pscmd++; + /* CLEAR STATUS COMMAND LIST */ + pce_dev->ce_dm.cmdlist.clear_status = pscmd; + pscmd->cmd = CMD_LC | CMD_MODE_SINGLE | CMD_OCU; + pscmd->dst = (unsigned) (CRYPTO_STATUS_REG + pce_dev->phy_iobase); + pscmd->len = CRYPTO_REG_SIZE; + pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.status); + pscmd++; + /* SET GO_PROC REGISTERS COMMAND LIST */ pce_dev->ce_dm.cmdlist.set_go_proc = pscmd; pscmd->cmd = CMD_LC | CMD_MODE_SINGLE; @@ -1693,8 +1700,7 @@ static int _setup_cipher_cmdptrlists(struct qce_device *pce_dev, *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg); *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask); *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc); - *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in); - *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_iv); + *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in); cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16); cmdptrlist->cipher_aes_256_cbc_ctr = QCE_SET_CMD_PTR(cmd_ptr_vaddr); @@ -1706,8 +1712,7 @@ static int _setup_cipher_cmdptrlists(struct qce_device *pce_dev, *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg); *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask); *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc); - *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in); - *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_iv); + *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in); cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16); cmdptrlist->cipher_aes_128_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr); @@ -1743,8 +1748,7 @@ static int _setup_cipher_cmdptrlists(struct qce_device *pce_dev, *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_xts_du_size); *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask); *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc); - *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in); - *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_xts_iv); + *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in); cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16); cmdptrlist->cipher_aes_256_xts = QCE_SET_CMD_PTR(cmd_ptr_vaddr); @@ -1758,8 +1762,7 @@ static int _setup_cipher_cmdptrlists(struct qce_device *pce_dev, *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_xts_du_size); *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_mask); *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc); - *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in); - *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_aes_xts_iv); + *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in); cmd_ptr_vaddr = (uint32_t *)ALIGN(((unsigned int) cmd_ptr_vaddr), 16); cmdptrlist->cipher_des_cbc = QCE_SET_CMD_PTR(cmd_ptr_vaddr); @@ -1770,8 +1773,7 @@ static int _setup_cipher_cmdptrlists(struct qce_device *pce_dev, *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_des_iv); *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg); *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc); - *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in); - *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_des_iv); + *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in); cmd_ptr_vaddr = (uint32_t *)ALIGN(((unsigned int) cmd_ptr_vaddr), 16); cmdptrlist->cipher_des_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr); @@ -1792,8 +1794,7 @@ static int _setup_cipher_cmdptrlists(struct qce_device *pce_dev, *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_des_iv); *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg); *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_go_proc); - *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in); - *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_cipher_des_iv); + *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->ce_data_in); cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16); cmdptrlist->cipher_3des_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr); @@ -1810,6 +1811,14 @@ static int _setup_cipher_cmdptrlists(struct qce_device *pce_dev, *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_out); *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu); + + cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16); + cmdptrlist->cipher_ce_out_get_iv = QCE_SET_CMD_PTR(cmd_ptr_vaddr); + + *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_out); + *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_cipher_iv); + *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu); + *pvaddr = (unsigned char *) cmd_ptr_vaddr; return 0; @@ -2008,6 +2017,7 @@ static int qce_setup_cmdptrlists(struct qce_device *pce_dev, cmdptrlist->probe_ce_hw = QCE_SET_CMD_PTR(cmd_ptr_vaddr); *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_hw_version); + *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status); *cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu); *pvaddr = (unsigned char *) cmd_ptr_vaddr; diff --git a/drivers/crypto/msm/qce40.h b/drivers/crypto/msm/qce40.h index c9fbb17a3f8..809ba7f869f 100644 --- a/drivers/crypto/msm/qce40.h +++ b/drivers/crypto/msm/qce40.h @@ -117,6 +117,7 @@ struct ce_reg_buffers { /* CE Command lists */ struct ce_cmdlists { dmov_s *get_hw_version; + dmov_s *clear_status; dmov_s *get_status_ocu; dmov_s *set_cipher_cfg; @@ -132,10 +133,8 @@ struct ce_cmdlists { dmov_s *set_cipher_aes_iv; dmov_s *set_cipher_aes_xts_iv; - dmov_s *get_cipher_aes_iv; - dmov_s *get_cipher_aes_xts_iv; dmov_s *set_cipher_des_iv; - dmov_s *get_cipher_des_iv; + dmov_s *get_cipher_iv; dmov_s *set_cipher_mask; @@ -195,6 +194,7 @@ struct ce_cmdptrlists_ops { uint32_t aead_aes_256_ccm; uint32_t cipher_ce_out; + uint32_t cipher_ce_out_get_iv; uint32_t aead_ce_out; };