static U32 PDrvCryptoUpdateHashWithDMA(PUBLIC_CRYPTO_HASH_CONTEXT * pHashCtx, U8 * pData, U32 dataLength, U32 dmaUse) { /* * Note: The DMA only sees physical addresses ! */ U32 bufIn_phys = virt_to_phys(pData); U32 res = PUBLIC_CRYPTO_OPERATION_SUCCESS; U32 nHWAlgo = 0; U32 vInitValue = 0; U32 vDirectProcess = 0; if (pHashCtx->vNbBytesProcessed == 0) { vInitValue = 1; } nHWAlgo = DIGEST_CTRL_GET_ALGO(INREG32(&g_pSha1Md5Reg_t->CTRL)); dprintk(KERN_INFO "PDrvCryptoUpdateHASHWithDMA: Use=%u, Len=%u, In=0x%08x\n", (unsigned int)dmaUse, (unsigned int)dataLength, (unsigned int)bufIn_phys); if (dataLength == 0) { /* No need of setting the dma and crypto-processor */ dprintk(KERN_INFO "PDrvCryptoUpdateHASHWithDMA: Nothing to process\n"); return PUBLIC_CRYPTO_OPERATION_SUCCESS; } if (pData == 0) { dprintk(KERN_ERR "PDrvCryptoUpdateHASHWithDMA: bufIn_phys/bufOut_phys NULL\n"); return PUBLIC_CRYPTO_ERR_BAD_PARAMETERS; } /* Makes sure buffers are 4-bytes aligned */ if (!IS_4_BYTES_ALIGNED((int)bufIn_phys)) { dprintk(KERN_ERR "PDrvCryptoUpdateHASHWithDMA: bufIn_phys/Out not 4 bytes aligned\n"); return PUBLIC_CRYPTO_ERR_ALIGNMENT; } if (pHashCtx->vChunckIndex == 0) { vDirectProcess = 1; } if ((IS_4_BYTES_ALIGNED(HASH_CHUNK_BYTES_LENGTH-pHashCtx->vChunckIndex)) && (dataLength > HASH_CHUNK_BYTES_LENGTH-pHashCtx->vChunckIndex)) { /* Fill the chunk */ U32 vLengthToComplete = HASH_CHUNK_BYTES_LENGTH - pHashCtx->vChunckIndex; /* So we fill the chunk buffer with the new data to complete to HASH_CHUNK_BYTES_LENGTH */ memcpy(pHashCtx->pChunckBuffer + pHashCtx->vChunckIndex, pData, vLengthToComplete); pHashCtx->vChunckIndex = HASH_CHUNK_BYTES_LENGTH; pData += vLengthToComplete; dataLength -= vLengthToComplete; // Process the chunk first with no dma if (HASH_CHUNK_BYTES_LENGTH == HASH_BLOCK_BYTES_LENGTH) { res = static_Hash_HwPerform64bDigest((U32*)pHashCtx->pChunckBuffer, pHashCtx->vNbBytesProcessed, (HASH_CHUNK_BYTES_LENGTH << 5) | (vInitValue << 3) | (nHWAlgo << 1)); } else { res = static_Hash_HwPerformDmaDigest((U32*)pHashCtx->pChunckBuffer, pHashCtx->vNbBytesProcessed, (HASH_CHUNK_BYTES_LENGTH << 5) | (vInitValue << 3) | (nHWAlgo << 1), dmaUse); } if (res != PUBLIC_CRYPTO_OPERATION_SUCCESS) { return res; } vInitValue = 0; pHashCtx->vNbBytesProcessed+=HASH_CHUNK_BYTES_LENGTH; pHashCtx->vChunckIndex = 0; vDirectProcess = 1; } if ((vDirectProcess == 1) && (dataLength > HASH_BLOCK_BYTES_LENGTH)) { U32 vDmaProcessSize = dataLength & 0xFFFFFFC0; if (vDmaProcessSize == dataLength) { vDmaProcessSize = vDmaProcessSize - HASH_BLOCK_BYTES_LENGTH; // We keep one block for the final } res = static_Hash_HwPerformDmaDigest((U32*)pData, pHashCtx->vNbBytesProcessed, (vDmaProcessSize << 5) | (vInitValue << 3) | (nHWAlgo << 1), dmaUse); if (res != PUBLIC_CRYPTO_OPERATION_SUCCESS) { return res; } vInitValue = 0; pHashCtx->vNbBytesProcessed += vDmaProcessSize; pData += vDmaProcessSize; dataLength -= vDmaProcessSize; } /******************************** TO DO ******************************/ // Look if we can fill the chunk. If it is filled then process the dma // on the HASH_CHUNK_BYTES_LENGTH length. And put the remaining in the // chunk. Else put the remaining in the chunk and return the function. /*********************************************************************/ /* Is there any data in the chunk? If yes is it possible to make a HASH_CHUNK_BYTES_LENGTH buffer with the new data passed ? */ if ((pHashCtx->vChunckIndex != 0) && (pHashCtx->vChunckIndex + dataLength >= HASH_CHUNK_BYTES_LENGTH)) { U32 vLengthToComplete = HASH_CHUNK_BYTES_LENGTH - pHashCtx->vChunckIndex; /* So we fill the chunk buffer with the new data to complete to HASH_CHUNK_BYTES_LENGTH */ memcpy(pHashCtx->pChunckBuffer + pHashCtx->vChunckIndex, pData, vLengthToComplete); if (pHashCtx->vChunckIndex + dataLength == HASH_CHUNK_BYTES_LENGTH) { /* We'll keep some data for the final */ pHashCtx->vChunckIndex = HASH_CHUNK_BYTES_LENGTH; return PUBLIC_CRYPTO_OPERATION_SUCCESS; } /* Then we send this buffer to the hash hardware */ if (HASH_CHUNK_BYTES_LENGTH == HASH_BLOCK_BYTES_LENGTH) { res = static_Hash_HwPerform64bDigest((U32*)pHashCtx->pChunckBuffer, pHashCtx->vNbBytesProcessed, (HASH_CHUNK_BYTES_LENGTH << 5) | (vInitValue << 3) | (nHWAlgo << 1)); } else { res = static_Hash_HwPerformDmaDigest((U32*)pHashCtx->pChunckBuffer, pHashCtx->vNbBytesProcessed, (HASH_CHUNK_BYTES_LENGTH << 5) | (vInitValue << 3) | (nHWAlgo << 1), dmaUse); } vInitValue = 0; if (res != PUBLIC_CRYPTO_OPERATION_SUCCESS) { return res; } pHashCtx->vNbBytesProcessed += HASH_CHUNK_BYTES_LENGTH; /* We have flushed the chunk so it is empty now */ pHashCtx->vChunckIndex = 0; /* Then we have less data to proceed */ pData += vLengthToComplete; dataLength -= vLengthToComplete; } /* (2) We process all the HASH_CHUNK_BYTES_LENGTH buffer that we can */ /* Dirty patch to confirm : keep the last full block of HASH_CHUNK_BYTES_LENGTH for the final. We must keep some data for the final. To remove the patch replace > by >= */ while (dataLength > HASH_CHUNK_BYTES_LENGTH) { U8 pTempAlignedBuffer[HASH_CHUNK_BYTES_LENGTH]; /* * We process a HASH_CHUNK_BYTES_LENGTH buffer */ /* We copy the data to process to an aligned buffer !LINUX only ??! */ memcpy(pTempAlignedBuffer, pData, HASH_CHUNK_BYTES_LENGTH); /* Then we send this buffer to the hash hardware */ if (HASH_CHUNK_BYTES_LENGTH == HASH_BLOCK_BYTES_LENGTH) { res = static_Hash_HwPerform64bDigest((U32*)pTempAlignedBuffer, pHashCtx->vNbBytesProcessed, (HASH_CHUNK_BYTES_LENGTH << 5) | (vInitValue << 3) | (nHWAlgo << 1)); } else { res = static_Hash_HwPerformDmaDigest((U32*)pTempAlignedBuffer, pHashCtx->vNbBytesProcessed, (HASH_CHUNK_BYTES_LENGTH << 5) | (vInitValue << 3) | (nHWAlgo << 1), dmaUse); } vInitValue = 0; if (res != PUBLIC_CRYPTO_OPERATION_SUCCESS) { return res; } pHashCtx->vNbBytesProcessed += HASH_CHUNK_BYTES_LENGTH; /* Then we decrease the remaining data of HASH_CHUNK_BYTES_LENGTH */ pData += HASH_CHUNK_BYTES_LENGTH; dataLength -= HASH_CHUNK_BYTES_LENGTH; } /* (3) We look if we have some data that could not be processed yet because it is not large enough to fill a buffer of HASH_CHUNK_BYTES_LENGTH */ if (dataLength > 0) { if (pHashCtx->vChunckIndex + dataLength > HASH_CHUNK_BYTES_LENGTH) { /* Should never be in this case => Serious problem in the code !!! */ return PUBLIC_CRYPTO_ERR_BAD_PARAMETERS; } else { /* So we fill the chunk buffer with the new data */ memcpy(pHashCtx->pChunckBuffer + pHashCtx->vChunckIndex, pData, dataLength); pHashCtx->vChunckIndex += dataLength; } } dprintk(KERN_INFO "PDrvCryptoUpdateHASHWithDMA: Success\n"); return PUBLIC_CRYPTO_OPERATION_SUCCESS; }
static U32 PDrvCryptoUpdateDESWithDMA(PUBLIC_CRYPTO_DES_DES3_CONTEXT * pDesCtx, U8 * pSrc, U8 * pDest, U32 nbBlocks, U32 dmaUse) { /* * Note: The DMA only sees physical addresses ! */ U32 bufIn_phys = virt_to_phys(pSrc); U32 bufOut_phys = virt_to_phys(pDest); U32 dma_ch0 = OMAP3430_SMC_DMA_CH_0; U32 dma_ch1 = OMAP3430_SMC_DMA_CH_1; SCX_DMA_CHANNEL_PARAM ch0_parameters; SCX_DMA_CHANNEL_PARAM ch1_parameters; U32 nLength = nbBlocks * DES_BLOCK_SIZE; U32 returnCode; dprintk(KERN_INFO "PDrvCryptoUpdateDESWithDMA: Use=%u, Len=%u, In=0x%08x, Out=0x%08x\n", (unsigned int)dmaUse, (unsigned int)nLength, (unsigned int)bufIn_phys, (unsigned int)bufOut_phys); if (nLength == 0) { /* No need of setting the dma and crypto-processor */ dprintk(KERN_INFO "PDrvCryptoUpdateDESWithDMA: Nothing to process\n"); return PUBLIC_CRYPTO_OPERATION_SUCCESS; } if ((bufIn_phys == 0) || (bufOut_phys == 0)) { dprintk(KERN_ERR "PDrvCryptoUpdateDESWithDMA: bufIn_phys/bufOut_phys NULL\n"); return PUBLIC_CRYPTO_ERR_BAD_PARAMETERS; } /* Makes sure buffers are 4-bytes aligned */ if (!IS_4_BYTES_ALIGNED((int)bufIn_phys) || !IS_4_BYTES_ALIGNED((int)bufOut_phys)) { dprintk(KERN_ERR "PDrvCryptoUpdateDESWithDMA: bufIn_phys/Out not 4 bytes aligned\n"); return PUBLIC_CRYPTO_ERR_ALIGNMENT; } /* * Only one segment of the sg list to proceed --> no need of scatter gather algo */ /* Makes sure that if the dma channels that will need to be used are currently active, one can reprogram it (them) */ scxPublicDMADisableChannel(dma_ch0); scxPublicDMADisableChannel(dma_ch1); if (dmaUse == PUBLIC_CRYPTO_DMA_USE_IRQ) { /* Reset DMA int (DMA CTRL) - The DMA int (INT CTRL) is reset by the OS */ scxPublicDMADisableL3IRQ(); scxPublicDMAClearL3IRQ(); } /* DMA used for Input and Output */ OUTREG32(&g_pDESReg_t->DES_MASK, INREG32(&g_pDESReg_t->DES_MASK) | DES_MASK_DMA_REQ_OUT_EN_BIT | DES_MASK_DMA_REQ_IN_EN_BIT); /* DMA1: Mem -> DES */ ch0_parameters.data_type = DMA_CSDP_Srce_Endian_little | DMA_CSDP_Srce_Endian_Lock_off | DMA_CSDP_Dest_Endian_little | DMA_CSDP_Dest_Endian_Lock_off | DMA_CSDP_Write_Mode_none_posted | DMA_CSDP_Dest_Burst_off | DMA_CSDP_Dest_packed_off | DMA_CSDP_WR_Add_Trslt | DMA_CSDP_Src_Burst_off | DMA_CSDP_Src_packed_off | DMA_CSDP_RD_Add_Trslt | DMA_CSDP_Data_32b; ch0_parameters.elem_count = DMA_CEN_Elts_per_Frame_DES; ch0_parameters.frame_count = nbBlocks; ch0_parameters.src_amode = 1; /* post increment */ ch0_parameters.src_start = bufIn_phys; ch0_parameters.src_ei = DMA_CSEI_Default; ch0_parameters.src_fi = DMA_CSFI_Default; ch0_parameters.dst_amode = 0; /* const */ ch0_parameters.dst_start = DES1_REGS_HW_ADDR + 0x24; ch0_parameters.dst_ei = DMA_CDEI_Default; ch0_parameters.dst_fi = DMA_CDFI_Default; /* source frame index */ ch0_parameters.trigger = DMA_CCR_Mask_Channel(DMA_CCR_Channel_Mem2DES); ch0_parameters.sync_mode = 0x2; /* FS =1, BS=0 => An entire frame is transferred once a DMA request is made */ ch0_parameters.src_or_dst_synch = 0; /* Transfert is triggered by the Dest */ dprintk(KERN_INFO "PDrvCryptoUpdateDESWithDMA: scxPublicDMASetParams(ch0)\n"); scxPublicDMASetParams(dma_ch0, &ch0_parameters); dprintk(KERN_INFO "PDrvCryptoUpdateDESWithDMA: Start DMA channel %d\n", (unsigned int)dma_ch0); scxPublicDMAStart(dma_ch0, OMAP_DMA_DROP_IRQ); /* DMA2: DES -> Mem */ ch1_parameters.data_type = DMA_CSDP_Srce_Endian_little | DMA_CSDP_Srce_Endian_Lock_off | DMA_CSDP_Dest_Endian_little | DMA_CSDP_Dest_Endian_Lock_off | DMA_CSDP_Write_Mode_none_posted | DMA_CSDP_Dest_Burst_off | DMA_CSDP_Dest_packed_off | DMA_CSDP_WR_Add_Trslt | DMA_CSDP_Src_Burst_off | DMA_CSDP_Src_packed_off | DMA_CSDP_RD_Add_Trslt | DMA_CSDP_Data_32b; ch1_parameters.elem_count = DMA_CEN_Elts_per_Frame_DES; ch1_parameters.frame_count = nbBlocks; ch1_parameters.src_amode = 0; /* const */ ch1_parameters.src_start = DES1_REGS_HW_ADDR + 0x24; ch1_parameters.src_ei = DMA_CSEI_Default; ch1_parameters.src_fi = DMA_CSFI_Default; ch1_parameters.dst_amode = 1; /* post increment */ ch1_parameters.dst_start = bufOut_phys; ch1_parameters.dst_ei = DMA_CDEI_Default; ch1_parameters.dst_fi = DMA_CDFI_Default; /* source frame index */ ch1_parameters.trigger = DMA_CCR_Mask_Channel(DMA_CCR_Channel_DES2Mem); ch1_parameters.sync_mode = 0x2; /* FS =1, BS=0 => An entire frame is transferred once a DMA request is made */ ch1_parameters.src_or_dst_synch = 1; /* Transfert is triggered by the Src */ dprintk(KERN_INFO "PDrvCryptoUpdateDESWithDMA: scxPublicDMASetParams(ch1)\n"); scxPublicDMASetParams(dma_ch1, &ch1_parameters); if (dmaUse == PUBLIC_CRYPTO_DMA_USE_IRQ) { scxPublicDMAEnableL3IRQ(); } dprintk(KERN_INFO "PDrvCryptoUpdateDESWithDMA: Start DMA channel %d\n", (unsigned int)dma_ch1); scxPublicDMAStart(dma_ch1, OMAP_DMA_DROP_IRQ|OMAP_DMA_BLOCK_IRQ); /* * The input data may be in the cache only, * and the DMA is only working with physical addresses. * So flush the cache to have data coherency. */ v7_dma_flush_range((u32)pSrc, (u32)(pSrc + nLength)); /* Start operation */ OUTREG32(&g_pDESReg_t->DES_MASK, INREG32(&g_pDESReg_t->DES_MASK)|DES_MASK_START_BIT); if (dmaUse == PUBLIC_CRYPTO_DMA_USE_IRQ) { /* Suspends the process until the DMA IRQ occurs */ dprintk(KERN_INFO "PDrvCryptoUpdateDESWithDMA: Waiting for IRQ\n"); returnCode = scxPublicDMAWait(); } else { dprintk(KERN_INFO "PDrvCryptoUpdateDESWithDMA: Polling DMA\n"); returnCode = scxPublicDMAPoll(dma_ch1); } if (returnCode != PUBLIC_CRYPTO_OPERATION_SUCCESS) { dprintk(KERN_ERR "PDrvCryptoUpdateDESWithDMA: Timeout\n"); /* Do not exit function but clear properly the operation */ } if (dmaUse == PUBLIC_CRYPTO_DMA_USE_IRQ) { /* Acknoledge DMA interrupt */ scxPublicDMADisableL3IRQ(); } scxPublicDMAClearChannel(dma_ch1); /* * The dma transfert is complete */ /* Stop clocks */ OUTREG32(&g_pDESReg_t->DES_MASK, INREG32(&g_pDESReg_t->DES_MASK) &(~DES_MASK_START_BIT) ); /* Unset DMA synchronisation requests */ OUTREG32(&g_pDESReg_t->DES_MASK, INREG32(&g_pDESReg_t->DES_MASK) & (~DES_MASK_DMA_REQ_OUT_EN_BIT) & (~DES_MASK_DMA_REQ_IN_EN_BIT)); if (returnCode != PUBLIC_CRYPTO_OPERATION_SUCCESS) { dprintk(KERN_INFO "PDrvCryptoUpdateDESWithDMA: Error [0x%08x]\n", (unsigned int)returnCode); return returnCode; } /* * The output data are in the physical memory. * So invalidate the cache to have data coherency. */ v7_dma_inv_range((u32)pDest, (u32)(pDest + nLength)); dprintk(KERN_INFO "PDrvCryptoUpdateDESWithDMA: Success\n"); return PUBLIC_CRYPTO_OPERATION_SUCCESS; }