/** * * This function sets up the TX channel of a DMA engine to be ready for packet * transmission * * @param AxiDmaInstPtr is the instance pointer to 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_Bd BdTemplate; int Delay = 0; int Coalesce = 1; int Status; u32 BdCount; TxRingPtr = XAxiDma_GetTxRing(&AxiDma); /* Disable all TX interrupts before TxBD space setup */ XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* Set TX delay and coalesce */ XAxiDma_BdRingSetCoalesce(TxRingPtr, Coalesce, Delay); /* Setup TxBD space */ BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, TX_BD_SPACE_HIGH - TX_BD_SPACE_BASE + 1); Status = XAxiDma_BdRingCreate(TxRingPtr, TX_BD_SPACE_BASE, TX_BD_SPACE_BASE, XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "failed create BD ring in txsetup\r\n"); return XST_FAILURE; } /* * We create an all-zero BD as the template. */ XAxiDma_BdClear(&BdTemplate); Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "failed bdring clone in txsetup %d\r\n", Status); return XST_FAILURE; } /* Start the TX channel */ Status = XAxiDma_BdRingStart(TxRingPtr); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "failed start bdring txsetup %d\r\n", Status); return XST_FAILURE; } return XST_SUCCESS; }
int wlan_eth_dma_init() { int status; int bd_count; int i; u32 buf_addr; XAxiDma_Config *ETH_A_DMA_CFG_ptr; XAxiDma_Bd ETH_DMA_BD_Template; XAxiDma_BdRing *ETH_A_TxRing_ptr; XAxiDma_BdRing *ETH_A_RxRing_ptr; XAxiDma_Bd *first_bd_ptr; XAxiDma_Bd *cur_bd_ptr; packet_bd_list checkout; packet_bd* tx_queue; ETH_A_DMA_CFG_ptr = XAxiDma_LookupConfig(ETH_A_DMA_DEV_ID); status = XAxiDma_CfgInitialize(Ð_A_DMA_Instance, ETH_A_DMA_CFG_ptr); if(status != XST_SUCCESS) {xil_printf("Error in XAxiDma_CfgInitialize! Err = %d\n", status); return -1;} //Zero-out the template buffer descriptor XAxiDma_BdClear(Ð_DMA_BD_Template); //Fetch handles to the Tx and Rx BD rings ETH_A_TxRing_ptr = XAxiDma_GetTxRing(Ð_A_DMA_Instance); ETH_A_RxRing_ptr = XAxiDma_GetRxRing(Ð_A_DMA_Instance); //Disable all Tx/Rx DMA interrupts XAxiDma_BdRingIntDisable(ETH_A_TxRing_ptr, XAXIDMA_IRQ_ALL_MASK); XAxiDma_BdRingIntDisable(ETH_A_RxRing_ptr, XAXIDMA_IRQ_ALL_MASK); //Disable delays and coalescing (for now - these will be useful when we transition to interrupts) XAxiDma_BdRingSetCoalesce(ETH_A_TxRing_ptr, 1, 0); XAxiDma_BdRingSetCoalesce(ETH_A_RxRing_ptr, 1, 0); //Setup Tx/Rx buffer descriptor rings in memory status = XAxiDma_BdRingCreate(ETH_A_TxRing_ptr, ETH_A_TX_BD_SPACE_BASE, ETH_A_TX_BD_SPACE_BASE, XAXIDMA_BD_MINIMUM_ALIGNMENT, ETH_A_NUM_TX_BD); status |= XAxiDma_BdRingCreate(ETH_A_RxRing_ptr, ETH_A_RX_BD_SPACE_BASE, ETH_A_RX_BD_SPACE_BASE, XAXIDMA_BD_MINIMUM_ALIGNMENT, ETH_A_NUM_RX_BD); if(status != XST_SUCCESS) {xil_printf("Error creating DMA BD Rings! Err = %d\n", status); return -1;} //Populate each ring with empty buffer descriptors status = XAxiDma_BdRingClone(ETH_A_TxRing_ptr, Ð_DMA_BD_Template); status |= XAxiDma_BdRingClone(ETH_A_RxRing_ptr, Ð_DMA_BD_Template); if(status != XST_SUCCESS) {xil_printf("Error in XAxiDma_BdRingClone()! Err = %d\n", status); return -1;} //Start the DMA Tx channel // No Eth packets are transmitted until actual Tx BD's are pushed to the DMA hardware status = XAxiDma_BdRingStart(ETH_A_TxRing_ptr); //Initialize the Rx buffer descriptors bd_count = XAxiDma_BdRingGetFreeCnt(ETH_A_RxRing_ptr); if(bd_count != ETH_A_NUM_RX_BD) {xil_printf("Error in Eth Rx DMA init - not all Rx BDs were free at boot\n");} status = XAxiDma_BdRingAlloc(ETH_A_RxRing_ptr, bd_count, &first_bd_ptr); if(status != XST_SUCCESS) {xil_printf("Error in XAxiDma_BdRingAlloc()! Err = %d\n", status); return -1;} //Checkout ETH_A_NUM_RX_BD packet_bds queue_checkout(&checkout, ETH_A_NUM_RX_BD); if(checkout.length == ETH_A_NUM_RX_BD){ tx_queue = checkout.first; } else { xil_printf("Error during wlan_eth_dma_init: able to check out %d of %d packet_bds\n", checkout.length, ETH_A_NUM_RX_BD); return -1; } //Iterate over each Rx buffer descriptor cur_bd_ptr = first_bd_ptr; for(i = 0; i < bd_count; i++) { //Set the memory address for this BD's buffer buf_addr = (u32)((void*)((tx_packet_buffer*)(tx_queue->buf_ptr))->frame + sizeof(mac_header_80211) + sizeof(llc_header) - sizeof(ethernet_header)); status = XAxiDma_BdSetBufAddr(cur_bd_ptr, buf_addr); if(status != XST_SUCCESS) {xil_printf("XAxiDma_BdSetBufAddr failed (bd %d, addr 0x08x)! Err = %d\n", i, buf_addr, status); return -1;} //Set every Rx BD to max length (this assures 1 BD per Rx pkt) status = XAxiDma_BdSetLength(cur_bd_ptr, ETH_A_PKT_BUF_SIZE, ETH_A_RxRing_ptr->MaxTransferLen); if(status != XST_SUCCESS) {xil_printf("XAxiDma_BdSetLength failed (bd %d, addr 0x08x)! Err = %d\n", i, buf_addr, status); return -1;} //Rx BD's don't need control flags before use; DMA populates these post-Rx XAxiDma_BdSetCtrl(cur_bd_ptr, 0); //BD ID is arbitrary; use pointer to the packet_bd associated with this BD XAxiDma_BdSetId(cur_bd_ptr, (u32)tx_queue); //Update cur_bd_ptr to the next BD in the chain for the next iteration cur_bd_ptr = XAxiDma_BdRingNext(ETH_A_RxRing_ptr, cur_bd_ptr); //Traverse forward in the checked-out packet_bd list tx_queue = tx_queue->next; } //Push the Rx BD ring to hardware and start receiving status = XAxiDma_BdRingToHw(ETH_A_RxRing_ptr, bd_count, first_bd_ptr); //Enable Interrupts XAxiDma_BdRingIntEnable(ETH_A_RxRing_ptr, XAXIDMA_IRQ_ALL_MASK); status |= XAxiDma_BdRingStart(ETH_A_RxRing_ptr); if(status != XST_SUCCESS) {xil_printf("Error in XAxiDma_BdRingToHw/XAxiDma_BdRingStart(ETH_A_RxRing_ptr)! Err = %d\n", status); return -1;} return 0; }
/* * * 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 i; 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) { xdbg_printf(XDBG_DEBUG_ERROR, "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) { xdbg_printf(XDBG_DEBUG_ERROR, "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); Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "RX alloc BD failed %d\r\n", Status); return XST_FAILURE; } BdCurPtr = BdPtr; RxBufferPtr = RX_BUFFER_BASE; for (i = 0; i < FreeBdCount; i++) { Status = XAxiDma_BdSetBufAddr(BdCurPtr, RxBufferPtr); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "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, MAX_PKT_LEN); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "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); RxBufferPtr += MAX_PKT_LEN; BdCurPtr = XAxiDma_BdRingNext(RxRingPtr, BdCurPtr); } /* Clear the receive buffer, so we can verify data */ memset((void *)RX_BUFFER_BASE, 0, MAX_PKT_LEN); Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "RX submit hw failed %d\r\n", Status); return XST_FAILURE; } /* Start RX DMA channel */ Status = XAxiDma_BdRingStart(RxRingPtr); if (Status != XST_SUCCESS) { xdbg_printf(XDBG_DEBUG_ERROR, "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; }