/* * * This function sets up RX channel of the DMA engine to be ready for packet * reception * * @param AxiDmaInstPtr is the pointer to the instance of the DMA engine. * * @return - XST_SUCCESS if the setup is successful. * - XST_FAILURE if fails. * * @note None. * ******************************************************************************/ static int RxSetup(XAxiDma * AxiDmaInstPtr) { XAxiDma_BdRing *RxRingPtr; int Status; XAxiDma_Bd BdTemplate; XAxiDma_Bd *BdPtr; XAxiDma_Bd *BdCurPtr; int BdCount; int FreeBdCount; u32 RxBufferPtr; u32 RxBdSpacePtr; int Index; int RingIndex; RxBufferPtr = RX_BUFFER_BASE; RxBdSpacePtr = RX_BD_SPACE_BASE; for (RingIndex = 0; RingIndex < AxiDmaInstPtr->RxNumChannels; RingIndex++) { RxRingPtr = XAxiDma_GetRxIndexRing(&AxiDma, RingIndex); /* Disable all RX interrupts before RxBD space setup */ XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* Setup Rx BD space */ BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, RX_BD_SPACE_HIGH - RX_BD_SPACE_BASE + 1); Status = XAxiDma_BdRingCreate(RxRingPtr, RxBdSpacePtr, RxBdSpacePtr, XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount); if (Status != XST_SUCCESS) { xil_printf("Rx bd create failed with %d\r\n", Status); return XST_FAILURE; } /* * Setup a BD template for the Rx channel. Then copy it * to every RX BD. */ XAxiDma_BdClear(&BdTemplate); Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate); if (Status != XST_SUCCESS) { xil_printf("Rx bd clone failed with %d\r\n", Status); return XST_FAILURE; } /* Attach buffers to RxBD ring so we are ready to receive packets */ FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr); Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr); if (Status != XST_SUCCESS) { xil_printf("Rx bd alloc failed with %d\r\n", Status); return XST_FAILURE; } BdCurPtr = BdPtr; for (Index = 0; Index < FreeBdCount; Index++) { Status = XAxiDma_BdSetBufAddr(BdCurPtr, RxBufferPtr); if (Status != XST_SUCCESS) { xil_printf("Rx set buffer addr %x on BD %x failed %d\r\n", (unsigned int)RxBufferPtr, (unsigned int)BdCurPtr, Status); return XST_FAILURE; } Status = XAxiDma_BdSetLength(BdCurPtr, HSIZE, RxRingPtr->MaxTransferLen); if (Status != XST_SUCCESS) { xil_printf("Rx set length %d on BD %x failed %d\r\n", MAX_PKT_LEN, (unsigned int)BdCurPtr, Status); return XST_FAILURE; } /* Receive BDs do not need to set anything for the control * The hardware will set the SOF/EOF bits per stream status */ XAxiDma_BdSetCtrl(BdCurPtr, 0); XAxiDma_BdSetId(BdCurPtr, RxBufferPtr); XAxiDma_BdSetARCache(BdCurPtr, ARCACHE); XAxiDma_BdSetARUser(BdCurPtr, ARUSER); XAxiDma_BdSetVSize(BdCurPtr, VSIZE); XAxiDma_BdSetStride(BdCurPtr, STRIDE); RxBufferPtr += MAX_PKT_LEN; BdCurPtr = XAxiDma_BdRingNext(RxRingPtr, BdCurPtr); } /* * Set the coalescing threshold, so only one receive interrupt * occurs for this example * * If you would like to have multiple interrupts to happen, change * the COALESCING_COUNT to be a smaller value */ Status = XAxiDma_BdRingSetCoalesce(RxRingPtr, COALESCING_COUNT, DELAY_TIMER_COUNT); if (Status != XST_SUCCESS) { xil_printf("Rx set coalesce failed with %d\r\n", Status); return XST_FAILURE; } Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr); if (Status != XST_SUCCESS) { xil_printf("Rx ToHw failed with %d\r\n", Status); return XST_FAILURE; } /* Enable all RX interrupts */ XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* Start RX DMA channel */ Status = XAxiDma_UpdateBdRingCDesc(RxRingPtr); if (Status != XST_SUCCESS) { xil_printf("Failed bd start %x\r\n", Status); return XST_FAILURE; } RxBdSpacePtr += BdCount * sizeof(XAxiDma_Bd); } for (RingIndex = 0; RingIndex < AxiDmaInstPtr->RxNumChannels; RingIndex++) { RxRingPtr = XAxiDma_GetRxIndexRing(&AxiDma, RingIndex); Status = XAxiDma_StartBdRingHw(RxRingPtr); if (Status != XST_SUCCESS) { xil_printf("Rx start BD ring failed with %d\r\n", Status); return XST_FAILURE; } } return XST_SUCCESS; }
/** * * This function sets up RX channel of the DMA engine to be ready for packet * reception * * @param AxiDmaInstPtr is the pointer to the instance of the DMA engine. * * @return XST_SUCCESS if the setup is successful, XST_FAILURE otherwise. * * @note None. * ******************************************************************************/ static int RxSetup(XAxiDma * AxiDmaInstPtr) { XAxiDma_BdRing *RxRingPtr; int Delay = 0; int Coalesce = 1; int Status; XAxiDma_Bd BdTemplate; XAxiDma_Bd *BdPtr; XAxiDma_Bd *BdCurPtr; u32 BdCount; u32 FreeBdCount; u32 RxBufferPtr; int Index; RxRingPtr = XAxiDma_GetRxRing(&AxiDma); /* Disable all RX interrupts before RxBD space setup */ XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* Set delay and coalescing */ XAxiDma_BdRingSetCoalesce(RxRingPtr, Coalesce, Delay); /* Setup Rx BD space */ BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, RX_BD_SPACE_HIGH - RX_BD_SPACE_BASE + 1); Status = XAxiDma_BdRingCreate(RxRingPtr, RX_BD_SPACE_BASE, RX_BD_SPACE_BASE, XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount); if (Status != XST_SUCCESS) { xil_printf("RX create BD ring failed %d\r\n", Status); return XST_FAILURE; } /* * Setup an all-zero BD as the template for the Rx channel. */ XAxiDma_BdClear(&BdTemplate); Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate); if (Status != XST_SUCCESS) { xil_printf("RX clone BD failed %d\r\n", Status); return XST_FAILURE; } /* Attach buffers to RxBD ring so we are ready to receive packets */ FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr); //xil_printf("RxFreeBdCount %d", FreeBdCount); Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr); if (Status != XST_SUCCESS) { xil_printf("RX alloc BD failed %d\r\n", Status); return XST_FAILURE; } BdCurPtr = BdPtr; RxBufferPtr = RX_BUFFER_BASE; for (Index = 0; Index < FreeBdCount; Index++) { Status = XAxiDma_BdSetBufAddr(BdCurPtr, RxBufferPtr); if (Status != XST_SUCCESS) { xil_printf("Set buffer addr %x on BD %x failed %d\r\n", (unsigned int)RxBufferPtr, (unsigned int)BdCurPtr, Status); return XST_FAILURE; } // test_fix Status = XAxiDma_BdSetLength(BdCurPtr, MAX_PKT_LEN*2, RxRingPtr->MaxTransferLen); if (Status != XST_SUCCESS) { xil_printf("Rx set length %d on BD %x failed %d\r\n", MAX_PKT_LEN*2, (unsigned int)BdCurPtr, Status); return XST_FAILURE; } /* Receive BDs do not need to set anything for the control * The hardware will set the SOF/EOF bits per stream status */ XAxiDma_BdSetCtrl(BdCurPtr, 0); XAxiDma_BdSetId(BdCurPtr, RxBufferPtr); RxBufferPtr += MAX_PKT_LEN*2; BdCurPtr = XAxiDma_BdRingNext(RxRingPtr, BdCurPtr); } /* Clear the receive buffer, so we can verify data */ memset((void *)RX_BUFFER_BASE, 0, MAX_PKT_LEN*128); Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr); if (Status != XST_SUCCESS) { xil_printf("RX submit hw failed %d\r\n", Status); return XST_FAILURE; } /* Start RX DMA channel */ Status = XAxiDma_BdRingStart(RxRingPtr); if (Status != XST_SUCCESS) { xil_printf("RX start hw failed %d\r\n", Status); return XST_FAILURE; } return XST_SUCCESS; }
/* * * This function sets up the TX channel of a DMA engine to be ready for packet * transmission. * * @param AxiDmaInstPtr is the pointer to the instance of the DMA engine. * * @return - XST_SUCCESS if the setup is successful. * - XST_FAILURE otherwise. * * @note None. * ******************************************************************************/ static int TxSetup(XAxiDma * AxiDmaInstPtr) { XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(&AxiDma); XAxiDma_Bd BdTemplate; int Status; u32 BdCount; u32 TxBdSpacePtr = TX_BD_SPACE_BASE; /* Disable all TX interrupts before TxBD space setup */ XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* Setup TxBD space */ BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, (u32)TX_BD_SPACE_HIGH - (u32)TX_BD_SPACE_BASE + 1); Status = XAxiDma_BdRingCreate(TxRingPtr, TxBdSpacePtr, TxBdSpacePtr, XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount); if (Status != XST_SUCCESS) { xil_printf("Failed create BD ring\r\n"); return XST_FAILURE; } /* * Like the RxBD space, we create a template and set all BDs to be the * same as the template. The sender has to set up the BDs as needed. */ XAxiDma_BdClear(&BdTemplate); Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate); if (Status != XST_SUCCESS) { xil_printf("Failed clone BDs\r\n"); return XST_FAILURE; } /* * Set the coalescing threshold, so only one transmit interrupt * occurs for this example * * If you would like to have multiple interrupts to happen, change * the COALESCING_COUNT to be a smaller value */ Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, COALESCING_COUNT, DELAY_TIMER_COUNT); if (Status != XST_SUCCESS) { xil_printf("Failed set coalescing" " %d/%d\r\n",COALESCING_COUNT, DELAY_TIMER_COUNT); return XST_FAILURE; } /* Enable all TX interrupts */ XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* Start the TX channel */ Status = XAxiDma_UpdateBdRingCDesc(TxRingPtr); if (Status != XST_SUCCESS) { xil_printf("Failed bd start %x\r\n", Status); return XST_FAILURE; } Status = XAxiDma_StartBdRingHw(TxRingPtr); if (Status != XST_SUCCESS) { xil_printf("Failed bd start %x\r\n", Status); return XST_FAILURE; } return XST_SUCCESS; }
/** * * This function demonstrates the usage usage of the Axi Ethernet by sending * and receiving frames in interrupt driven SGDMA mode. * * * @param IntcInstancePtr is a pointer to the instance of the Intc * component. * @param AxiEthernetInstancePtr is a pointer to the instance of the * AxiEthernet component. * @param DmaInstancePtr is a pointer to the instance of the AXIDMA * component. * @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device , * typically XPAR_<AXIETHERNET_instance>_DEVICE_ID value from * xparameters.h. * @param AxiDmaDeviceId is Device ID of the Axi DMAA Device , * typically XPAR_<AXIDMA_instance>_DEVICE_ID value from * xparameters.h. * @param AxiEthernetIntrId is the Interrupt ID and is typically * XPAR_<INTC_instance>_<AXIETHERNET_instance>_VEC_ID * value from xparameters.h. * @param DmaRxIntrId is the interrupt id for DMA Rx and is typically * taken from XPAR_<AXIETHERNET_instance>_CONNECTED_DMARX_INTR * @param DmaTxIntrId is the interrupt id for DMA Tx and is typically * taken from XPAR_<AXIETHERNET_instance>_CONNECTED_DMATX_INTR * * @return -XST_SUCCESS to indicate success. * -XST_FAILURE to indicate failure. * * @note AxiDma hardware must be initialized before initializing * AxiEthernet. Since AxiDma reset line is connected to the * AxiEthernet reset line, a reset of AxiDma hardware during its * initialization would reset AxiEthernet. * ******************************************************************************/ int AxiEthernetExtVlanExample(INTC *IntcInstancePtr, XAxiEthernet *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr, u16 AxiEthernetDeviceId, u16 AxiDmaDeviceId, u16 AxiEthernetIntrId, u16 DmaRxIntrId, u16 DmaTxIntrId) { int Status; int LoopbackSpeed; XAxiEthernet_Config *MacCfgPtr; XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); XAxiDma_Bd BdTemplate; XAxiDma_Config* DmaConfig; /*************************************/ /* Setup device for first-time usage */ /*************************************/ /* * Get the configuration of AxiEthernet hardware. */ MacCfgPtr = XAxiEthernet_LookupConfig(AxiEthernetDeviceId); /* * Check if DMA is present or not. */ if(MacCfgPtr->AxiDevType != XPAR_AXI_DMA) { AxiEthernetUtilErrorTrap ("Device HW not configured for SGDMA mode\r\n"); return XST_FAILURE; } DmaConfig = XAxiDma_LookupConfig(AxiDmaDeviceId); /* * Initialize AXIDMA engine. AXIDMA engine must be initialized before * AxiEthernet. During AXIDMA engine initialization, AXIDMA hardware is * reset, and since AXIDMA reset line is connected to AxiEthernet, this * would ensure a reset of AxiEthernet. */ Status = XAxiDma_CfgInitialize(DmaInstancePtr, DmaConfig); if(Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error initializing DMA\r\n"); return XST_FAILURE; } /* * Initialize AxiEthernet hardware. */ Status = XAxiEthernet_CfgInitialize(AxiEthernetInstancePtr, MacCfgPtr, MacCfgPtr->BaseAddress); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error in initialize"); return XST_FAILURE; } /* * Set the MAC address */ Status = XAxiEthernet_SetMacAddress(AxiEthernetInstancePtr, AxiEthernetMAC); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting MAC address"); return XST_FAILURE; } /* * Setup RxBD space. * * We have already defined a properly aligned area of memory to store * RxBDs at the beginning of this source code file so just pass its * address into the function. No MMU is being used so the physical and * virtual addresses are the same. * * Setup a BD template for the Rx channel. This template will be copied * to every RxBD. We will not have to explicitly set these again. */ /* * Create the RxBD ring */ Status = XAxiDma_BdRingCreate(RxRingPtr, (u32) &RxBdSpace, (u32) &RxBdSpace, BD_ALIGNMENT, RXBD_CNT); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting up RxBD space"); return XST_FAILURE; } XAxiDma_BdClear(&BdTemplate); Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error initializing RxBD space"); return XST_FAILURE; } /* * Setup TxBD space. * * Like RxBD space, we have already defined a properly aligned area of * memory to use. */ /* * Create the TxBD ring */ Status = XAxiDma_BdRingCreate(TxRingPtr, (u32) &TxBdSpace, (u32) &TxBdSpace, BD_ALIGNMENT, TXBD_CNT); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting up TxBD space"); return XST_FAILURE; } /* * We reuse the bd template, as the same one will work for both rx and * tx. */ Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error initializing TxBD space"); return XST_FAILURE; } /* * Set PHY to loopback, speed depends on phy type. * MII is 100 and all others are 1000. */ if (XAxiEthernet_GetPhysicalInterface(AxiEthernetInstancePtr) == XAE_PHY_TYPE_MII){ LoopbackSpeed = AXIETHERNET_LOOPBACK_SPEED; } else { LoopbackSpeed = AXIETHERNET_LOOPBACK_SPEED_1G; } AxiEthernetUtilEnterLoopback(AxiEthernetInstancePtr, LoopbackSpeed); /* * Set PHY<-->MAC data clock */ Status = XAxiEthernet_SetOperatingSpeed(AxiEthernetInstancePtr, (u16)LoopbackSpeed); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Setting the operating speed of the MAC needs a delay. There * doesn't seem to be register to poll, so please consider this * during your application design. */ AxiEthernetUtilPhyDelay(2); /* * Connect to the interrupt controller and enable interrupts */ Status = AxiEthernetSetupIntrSystem(IntcInstancePtr, AxiEthernetInstancePtr, DmaInstancePtr, AxiEthernetIntrId, DmaRxIntrId, DmaTxIntrId); /****************************/ /* Run the example */ /****************************/ /* Run the new VLAN feature. Make sure HW has the capability */ if (XAxiEthernet_IsTxVlanTran(AxiEthernetInstancePtr) && XAxiEthernet_IsTxVlanStrp(AxiEthernetInstancePtr) && XAxiEthernet_IsTxVlanTag(AxiEthernetInstancePtr) && XAxiEthernet_IsRxVlanTran(AxiEthernetInstancePtr) && XAxiEthernet_IsRxVlanStrp(AxiEthernetInstancePtr) && XAxiEthernet_IsRxVlanTag(AxiEthernetInstancePtr)) { Status = AxiEthernetSgDmaIntrExtVlanExample (AxiEthernetInstancePtr,DmaInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } } /* * Disable the interrupts for the AxiEthernet device */ AxiEthernetDisableIntrSystem(IntcInstancePtr, AxiEthernetIntrId, DmaRxIntrId, DmaTxIntrId); /* * Stop the device */ XAxiEthernet_Stop(AxiEthernetInstancePtr); return XST_SUCCESS; }