Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}