int XAxiCdma_Transfer(XAxiCdma *InstancePtr, u32 SrcAddr, u32 DstAddr, int byte_Length, XAxiCdma_CallBackFn SimpleCallBack, void *CallbackRef) { int Status, CDMA_Status; Status = XAxiCdma_SimpleTransfer(InstancePtr, (u32) SrcAddr , (u32) DstAddr, byte_Length, NULL, NULL); if (Status != XST_SUCCESS) { CDMA_Status = XAxiCdma_GetError(InstancePtr); if (CDMA_Status != 0x0) { XAxiCdma_Reset(InstancePtr); //xil_xil_printf("Error Code = %x\r\r\n",CDMA_Status); } return XST_FAILURE; } while (XAxiCdma_IsBusy(InstancePtr)); // Wait CDMA_Status = XAxiCdma_GetError(InstancePtr); if (CDMA_Status != 0x0) { XAxiCdma_Reset(InstancePtr); //xil_xil_printf("Error Code = %x\r\r\n",CDMA_Status); return XST_FAILURE; } return XST_SUCCESS; }
void dma_reset(XAxiCdma * dma) { // Perform reset XAxiCdma_Reset(dma); // Wait for it to complete while (!XAxiCdma_ResetIsDone(dma)); }
/** * This function is the interrupt handler for the driver, it handles all the * interrupts. For the completion of a transfer that has a callback function, * the callback function is called. * * @param HandlerRef is a reference pointer passed to the interrupt * registration function. It will be a pointer to the driver * instance we are working on * * @return None * * @note If one transfer does not have all its submitted BDs completed * successfully,then a reset is needed to clean up the mess left * by that transfer.Otherwise, the wrong interrupt callback maybe * called for the following transfers. However, if you always use * the same interrupt callback for all the transfers, and you are * the only user of the DMA engine, then you do not have to worry * about this. *****************************************************************************/ void XAxiCdma_IntrHandler(void *HandlerRef) { XAxiCdma *InstancePtr; u32 Status; u32 Irq; u32 Error = 0x0; InstancePtr = (XAxiCdma *)HandlerRef; Status = XAxiCdma_ReadReg(InstancePtr->BaseAddr, XAXICDMA_SR_OFFSET); /* Check what interrupts have fired */ Irq = Status & XAXICDMA_XR_IRQ_ALL_MASK; if (Irq == 0x0) { xdbg_printf(XDBG_DEBUG_ERROR, "No interrupt for intr handler\r\n"); return; } /* Acknowledge the interrupt */ XAxiCdma_WriteReg(InstancePtr->BaseAddr, XAXICDMA_SR_OFFSET, Irq); /* Pass the interrupt and error status to the callback function * if the transfer has one */ /* If SimpleNotDone flag is set, then it is a simple transfer */ if (InstancePtr->SimpleNotDone) { if (InstancePtr->SimpleCallBackFn) { (InstancePtr->SimpleCallBackFn)( InstancePtr->SimpleCallBackRef, Irq, NULL); InstancePtr->SimpleCallBackFn = NULL; } InstancePtr->SimpleNotDone = 0; if (InstancePtr->SGWaiting) { XAxiCdma_BdRingStartTransfer(InstancePtr); } } else { /* SG transfer */ if (InstancePtr->SgHandlerHead != InstancePtr->SgHandlerTail) { int Tmp; XAxiCdma_IntrHandlerList Handler = InstancePtr->Handlers[InstancePtr->SgHandlerHead]; Tmp = Handler.NumBds; /* Caution: may have race condition here * * If an interrupt for another transfer happens * while in callback function, then the wrong callback * function may be called. */ Handler.CallBackFn(Handler.CallBackRef, Irq, &(Tmp)); InstancePtr->Handlers[InstancePtr->SgHandlerHead].NumBds = Tmp; /* Update the handler head if this transfer is done */ if (Tmp == 0) { Tmp = InstancePtr->SgHandlerHead + 1; if (Tmp == XAXICDMA_MAXIMUM_MAX_HANDLER) { Tmp = 0; } InstancePtr->SgHandlerHead = Tmp; } } else { xdbg_printf(XDBG_DEBUG_ERROR, "ERROR: SG transfer intr without handler\r\n"); } } /* If has error interrupt, hardware needs to be reset */ Error = Status & XAXICDMA_SR_ERR_ALL_MASK; if ((Irq & XAXICDMA_XR_IRQ_ERROR_MASK) && Error) { int TimeOut; TimeOut = XAXICDMA_RESET_LOOP_LIMIT; /* Need to reset the hardware to clear the errors */ XAxiCdma_Reset(InstancePtr); while (TimeOut) { if (XAxiCdma_ResetIsDone(InstancePtr)) { break; } TimeOut -= 1; } /* Reset failed */ if (!TimeOut) { /* Mark the driver/engine is not in working state */ InstancePtr->Initialized = 0; } /* In case of error, no further handling is needed * * User should check send/receive buffers to see what happened * as well as check the DMA engine registers */ return; } return; }
/** * This function initializes the driver. It should be called before any other * function calls to the driver. * * It sets up the driver according to the hardware build. It resets the * hardware at the end. * * @param InstancePtr is the driver instance that is working on * @param CfgPtr is the pointer to the hardware configuration structure * @param EffectiveAddr is the virtual address of the hardware instance. * If address translation is not in use, please use the physical * address * * @return * - XST_SUCCESS for success * - XST_INVALID_PARAM if word length is less than 4 * - XST_FAILURE for reset failure * * @note None. * *****************************************************************************/ u32 XAxiCdma_CfgInitialize(XAxiCdma *InstancePtr, XAxiCdma_Config *CfgPtr, u32 EffectiveAddr) { u32 RegValue; int TimeOut; /* Mark the driver is not in working state yet */ InstancePtr->Initialized = 0; InstancePtr->BaseAddr = EffectiveAddr; InstancePtr->HasDRE = CfgPtr->HasDRE; InstancePtr->IsLite = CfgPtr->IsLite; InstancePtr->WordLength = ((unsigned int)CfgPtr->DataWidth) >> 3; InstancePtr->AddrWidth = CfgPtr->AddrWidth; /* AXI CDMA supports 32 bits data width and up */ if (InstancePtr->WordLength < 4) { xdbg_printf(XDBG_DEBUG_ERROR, "Word length too short %d\r\n", InstancePtr->WordLength); return XST_INVALID_PARAM; } RegValue = XAxiCdma_ReadReg(CfgPtr->BaseAddress, XAXICDMA_SR_OFFSET); InstancePtr->SimpleOnlyBuild = !(RegValue & XAXICDMA_SR_SGINCLD_MASK); /* Lite mode only supports data_width * burst_len * * Lite mode is ignored if SG mode is selected */ if (InstancePtr->SimpleOnlyBuild && CfgPtr->IsLite) { InstancePtr->MaxTransLen = InstancePtr->WordLength * CfgPtr->BurstLen; } else { InstancePtr->MaxTransLen = XAXICDMA_MAX_TRANSFER_LEN; } TimeOut = XAXICDMA_RESET_LOOP_LIMIT; /* Reset the hardware */ XAxiCdma_Reset(InstancePtr); /* The hardware should be pretty quick on reset, the reset is only * slow if there is an active large transfer */ while (TimeOut) { if (XAxiCdma_ResetIsDone(InstancePtr)) { break; } TimeOut -= 1; } if (!TimeOut) { xdbg_printf(XDBG_DEBUG_ERROR, "Reset failed\r\n"); return XST_FAILURE; } /* Initialize the BD ring statistics, to prevent BD ring being used * before being created */ InstancePtr->AllBdCnt = 0; InstancePtr->FreeBdCnt = 0; InstancePtr->HwBdCnt = 0; InstancePtr->PreBdCnt = 0; InstancePtr->PostBdCnt = 0; /* Mark that the driver/engine is in working state now */ InstancePtr->Initialized = 1; return XST_SUCCESS; }
/** * This function transfers data from Source Address to Destination Address * using the AXI CDMA. * User has to specify the Source Address, Destination Address and Transfer * Length in AXICDMA_SRC_ADDR, AXICDMA_DEST_ADDR and AXICDMA_LENGTH defines * respectively. * * @param DeviceId is device ID of the XAxiCdma Device. * * @return - XST_SUCCESS if successful * - XST_FAILURE.if unsuccessful. * * @note If the hardware system is not built correctly, this function * may never return to the caller. * ******************************************************************************/ int DmaDataTransfer (u16 DeviceID) { int Status; volatile int Error; XAxiCdma_Config *ConfigPtr; Error = 0; /* * Make sure we have a valid addresses for Src and Dst. */ if (AXICDMA_SRC_ADDR == 0) { return XST_FAILURE; } if (AXICDMA_DEST_ADDR == 0) { return XST_FAILURE; } /* * Initialize the AXI CDMA IP. */ ConfigPtr = XAxiCdma_LookupConfig(DeviceID); if (ConfigPtr == NULL) { return XST_FAILURE; } Status = XAxiCdma_CfgInitialize(&CdmaInstance, ConfigPtr, ConfigPtr->BaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Reset the AXI CDMA device. */ XAxiCdma_Reset(&CdmaInstance); /* * Disable AXI CDMA Interrupts */ XAxiCdma_IntrDisable(&CdmaInstance, XAXICDMA_XR_IRQ_ALL_MASK); /* * Start Transferring Data from source to destination in polled mode */ XAxiCdma_SimpleTransfer (&CdmaInstance, AXICDMA_SRC_ADDR, AXICDMA_DEST_ADDR, AXICDMA_LENGTH, 0, 0); /* * Poll Status register waiting for either Completion or Error */ while (XAxiCdma_IsBusy(&CdmaInstance)); Error = XAxiCdma_GetError(&CdmaInstance); if (Error != 0x0) { xil_printf("AXI CDMA Transfer Error = %8.8x\r\n"); return XST_FAILURE; } xil_printf("AXI CDMA Transfer is Complete\r\n"); return XST_SUCCESS; }
/** * The example to do the scatter gather transfer through polling. * * @param DeviceId is the Device Id of the XAxiCdma instance * * @return * - XST_SUCCESS if example finishes successfully * - XST_FAILURE if error occurs * * @note None * ******************************************************************************/ int XAxiCdma_SgPollExample(u16 DeviceId) { XAxiCdma_Config *CfgPtr; int Status; u8 *SrcPtr; u8 *DstPtr; SrcPtr = (u8 *)TransmitBufferPtr; DstPtr = (u8 *)ReceiveBufferPtr; #ifdef __aarch64__ Xil_SetTlbAttributes(BD_SPACE_BASE, MARK_UNCACHEABLE); #endif /* Initialize the XAxiCdma device. */ CfgPtr = XAxiCdma_LookupConfig(DeviceId); if (!CfgPtr) { xdbg_printf(XDBG_DEBUG_ERROR, "Cannot find config structure for device %d\r\n", XPAR_AXICDMA_0_DEVICE_ID); return XST_FAILURE; } Status = XAxiCdma_CfgInitialize(&AxiCdmaInstance, CfgPtr, CfgPtr->BaseAddress); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "Initialization failed with %d\r\n", Status); return XST_FAILURE; } /* Setup the BD ring */ Status = SetupTransfer(&AxiCdmaInstance); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "Setup BD ring failed with %d\r\n", Status); return XST_FAILURE; } Done = 0; Error = 0; /* Start the DMA transfer */ Status = DoTransfer(&AxiCdmaInstance); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "Do transfer failed with %d\r\n", Status); return XST_FAILURE; } /* Wait until the DMA transfer is done or error occurs */ while ((CheckCompletion(&AxiCdmaInstance) < NUMBER_OF_BDS_TO_TRANSFER) && !Error) { /* Wait */ } if(Error) { int TimeOut = RESET_LOOP_COUNT; xdbg_printf(XDBG_DEBUG_ERROR, "Transfer has error %x\r\n", Error); /* Need to reset the hardware to restore to the correct state */ XAxiCdma_Reset(&AxiCdmaInstance); while (TimeOut) { if (XAxiCdma_ResetIsDone(&AxiCdmaInstance)) { break; } TimeOut -= 1; } /* Reset has failed, print a message to notify the user */ if (!TimeOut) { xdbg_printf(XDBG_DEBUG_ERROR, "Reset hardware failed with %d\r\n", Status); } return XST_FAILURE; } /* Transfer completed successfully, check data */ Status = CheckData(SrcPtr, DstPtr, MAX_PKT_LEN * NUMBER_OF_BDS_TO_TRANSFER); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "Check data failed for sg " "transfer\r\n"); return XST_FAILURE; } /* Test finishes successfully, return successfully */ return XST_SUCCESS; }
/* * This function does one simple transfer in polled mode * * @param InstancePtr is a pointer to the XAxiCdma instance * @param Length is the transfer length * @param Retries is how many times to retry on submission * * @return * - XST_SUCCESS if transfer is successful * - XST_FAILURE if either the transfer fails or the data has * error * * @note None * ******************************************************************************/ static int DoSimplePollTransfer(XAxiCdma *InstancePtr, int Length, int Retries) { int Index; u8 *SrcPtr; u8 *DestPtr; int Status; /* Initialize the source buffer bytes with a pattern and the * the destination buffer bytes to zero */ SrcPtr = (u8 *)SrcBuffer; DestPtr = (u8 *)DestBuffer; for (Index = 0; Index < BUFFER_BYTESIZE; Index++) { SrcPtr[Index] = Index & 0xFF; DestPtr[Index] = 0; } /* Flush the SrcBuffer before the DMA transfer, in case the Data Cache * is enabled */ Xil_DCacheFlushRange((u32)&SrcBuffer, Length); /* Try to start the DMA transfer */ while (Retries) { Retries -= 1; Status = XAxiCdma_SimpleTransfer(InstancePtr, (u32)SrcBuffer, (u32)DestBuffer, Length, NULL, NULL); if (Status == XST_SUCCESS) { break; } } /* Return failure if failed to submit the transfer */ if (!Retries) { return XST_FAILURE; } /* Wait until the DMA transfer is done */ while (XAxiCdma_IsBusy(InstancePtr)) { /* Wait */ } /* If the hardware has errors, this example fails * This is a poll example, no interrupt handler is involved. * Therefore, error conditions are not cleared by the driver. */ Error = XAxiCdma_GetError(InstancePtr); if (Error != 0x0) { int TimeOut = RESET_LOOP_COUNT; /* Need to reset the hardware to restore to the correct state */ XAxiCdma_Reset(InstancePtr); while (TimeOut) { if (XAxiCdma_ResetIsDone(InstancePtr)) { break; } TimeOut -= 1; } /* Reset has failed, print a message to notify the user */ return XST_FAILURE; } /* Transfer completes successfully, check data */ Status = CheckData(SrcPtr, DestPtr, Length); if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; }