/** * Enqueue a set of BDs to hardware that were previously allocated by * XEmacPs_BdRingAlloc(). Once this function returns, the argument BD set goes * under hardware control. Any changes made to these BDs after this point will * corrupt the BD list leading to data corruption and system instability. * * The set will be rejected if the last BD of the set does not mark the end of * a packet (see XEmacPs_BdSetLast()). * * @param RingPtr is a pointer to the instance to be worked on. * @param NumBd is the number of BDs in the set. * @param BdSetPtr is the first BD of the set to commit to hardware. * * @return * - XST_SUCCESS if the set of BDs was accepted and enqueued to hardware. * - XST_FAILURE if the set of BDs was rejected because the last BD of the set * did not have its "last" bit set. * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with * XEmacPs_BdRingAlloc(). * * @note This function should not be preempted by another XEmacPs_Bd function * call that modifies the BD space. It is the caller's responsibility to * provide a mutual exclusion mechanism. * *****************************************************************************/ int XEmacPs_BdRingToHw(XEmacPs_BdRing * RingPtr, unsigned NumBd, XEmacPs_Bd * BdSetPtr) { XEmacPs_Bd *CurBdPtr; unsigned i; /* if no bds to process, simply return. */ if (0 == NumBd) return (XST_SUCCESS); /* Make sure we are in sync with XEmacPs_BdRingAlloc() */ if ((RingPtr->PreCnt < NumBd) || (RingPtr->PreHead != BdSetPtr)) { return (XST_DMA_SG_LIST_ERROR); } CurBdPtr = BdSetPtr; for (i = 0; i < NumBd; i++) { XEMACPS_CACHE_FLUSH(CurBdPtr); CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr); } /* Adjust ring pointers & counters */ XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PreHead, NumBd); RingPtr->PreCnt -= NumBd; RingPtr->HwTail = CurBdPtr; RingPtr->HwCnt += NumBd; return (XST_SUCCESS); }
/** * Enqueue a set of BDs to hardware that were previously allocated by * XEmacPs_BdRingAlloc(). Once this function returns, the argument BD set goes * under hardware control. Any changes made to these BDs after this point will * corrupt the BD list leading to data corruption and system instability. * * The set will be rejected if the last BD of the set does not mark the end of * a packet (see XEmacPs_BdSetLast()). * * @param RingPtr is a pointer to the instance to be worked on. * @param NumBd is the number of BDs in the set. * @param BdSetPtr is the first BD of the set to commit to hardware. * * @return * - XST_SUCCESS if the set of BDs was accepted and enqueued to hardware. * - XST_FAILURE if the set of BDs was rejected because the last BD of the set * did not have its "last" bit set. * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with * XEmacPs_BdRingAlloc(). * * @note This function should not be preempted by another XEmacPs_Bd function * call that modifies the BD space. It is the caller's responsibility to * provide a mutual exclusion mechanism. * *****************************************************************************/ LONG XEmacPs_BdRingToHw(XEmacPs_BdRing * RingPtr, u32 NumBd, XEmacPs_Bd * BdSetPtr) { XEmacPs_Bd *CurBdPtr; u32 i; LONG Status; /* if no bds to process, simply return. */ if (0U == NumBd){ Status = (LONG)(XST_SUCCESS); } else { /* Make sure we are in sync with XEmacPs_BdRingAlloc() */ if ((RingPtr->PreCnt < NumBd) || (RingPtr->PreHead != BdSetPtr)) { Status = (LONG)(XST_DMA_SG_LIST_ERROR); } else { CurBdPtr = BdSetPtr; for (i = 0U; i < NumBd; i++) { CurBdPtr = (XEmacPs_Bd *)((void *)XEmacPs_BdRingNext(RingPtr, CurBdPtr)); } /* Adjust ring pointers & counters */ XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PreHead, NumBd); RingPtr->PreCnt -= NumBd; RingPtr->HwTail = CurBdPtr; RingPtr->HwCnt += NumBd; Status = (LONG)(XST_SUCCESS); } } return Status; }
void _setup_rx_bds(XEmacPs_BdRing *rxring) { XEmacPs_Bd *rxbd, *CurBdPtr; int n_bds, i; XStatus Status; struct pbuf *p; u32 BdSts; unsigned int FreeBds, k; unsigned int BdIndex; unsigned int *Temp; FreeBds = XEmacPs_BdRingGetFreeCnt (rxring); Status = XEmacPs_BdRingAlloc(rxring, FreeBds, &rxbd); if (Status != XST_SUCCESS) { LWIP_DEBUGF(NETIF_DEBUG, ("setup_rx_bds: Error allocating RxBD\r\n")); return; } for (k = 0, CurBdPtr = rxbd; k < FreeBds; k++) { p = pbuf_alloc(PBUF_RAW, XEMACPS_MAX_FRAME_SIZE, PBUF_POOL); if (!p) { #if LINK_STATS lwip_stats.link.memerr++; lwip_stats.link.drop++; #endif LWIP_DEBUGF(NETIF_DEBUG, ("unable to alloc pbuf in recv_handler\r\n")); return; } BdIndex = XEMACPS_BD_TO_INDEX(rxring, CurBdPtr); Temp = (unsigned int *)CurBdPtr; *Temp = 0; if (BdIndex == (XLWIP_CONFIG_N_RX_DESC - 1)) { *Temp = 0x00000002; } Temp++; *Temp = 0; XEmacPs_BdSetAddressRx(CurBdPtr, (u32)p->payload); dsb(); rx_pbufs_storage[BdIndex] = (int)p; CurBdPtr = XEmacPs_BdRingNext (rxring, CurBdPtr); /* Enqueue to HW */ } Status = XEmacPs_BdRingToHw(rxring, FreeBds, rxbd); if (Status != XST_SUCCESS) { LWIP_DEBUGF(NETIF_DEBUG, ("Error committing RxBD to hardware: ")); if (Status == XST_DMA_SG_LIST_ERROR) LWIP_DEBUGF(NETIF_DEBUG, ("XST_DMA_SG_LIST_ERROR: this function was called out of sequence with XEmacPs_BdRingAlloc()\r\n")); else LWIP_DEBUGF(NETIF_DEBUG, ("set of BDs was rejected because the first BD did not have its start-of-packet bit set, or the last BD did not have its end-of-packet bit set, or any one of the BD set has 0 as length value\r\n")); return; } }
void process_sent_bds(xemacpsif_s *xemacpsif, XEmacPs_BdRing *txring) { XEmacPs_Bd *txbdset; XEmacPs_Bd *curbdpntr; s32_t n_bds; XStatus status; s32_t n_pbufs_freed = 0; u32_t bdindex; struct pbuf *p; u32_t *temp; u32_t index = 0; if (xemacpsif->emacps.Config.BaseAddress != XPAR_XEMACPS_0_BASEADDR) { index = sizeof(s32_t) * XLWIP_CONFIG_N_TX_DESC; } while (1) { /* obtain processed BD's */ n_bds = XEmacPs_BdRingFromHwTx(txring, XLWIP_CONFIG_N_TX_DESC, &txbdset); if (n_bds == 0) { return; } /* free the processed BD's */ n_pbufs_freed = n_bds; curbdpntr = txbdset; while (n_pbufs_freed > 0) { bdindex = XEMACPS_BD_TO_INDEX(txring, curbdpntr); temp = (u32_t *)curbdpntr; *temp = 0; temp++; *temp = 0x80000000; if (bdindex == (XLWIP_CONFIG_N_TX_DESC - 1)) { *temp = 0xC0000000; } p = (struct pbuf *)tx_pbufs_storage[index + bdindex]; if (p != NULL) { pbuf_free(p); } tx_pbufs_storage[index + bdindex] = 0; curbdpntr = XEmacPs_BdRingNext(txring, curbdpntr); n_pbufs_freed--; dsb(); } status = XEmacPs_BdRingFree(txring, n_bds, txbdset); if (status != XST_SUCCESS) { LWIP_DEBUGF(NETIF_DEBUG, ("Failure while freeing in Tx Done ISR\r\n")); } } return; }
void process_sent_bds(XEmacPs_BdRing *txring) { XEmacPs_Bd *txbdset; XEmacPs_Bd *CurBdPntr; int n_bds; XStatus Status; int n_pbufs_freed = 0; unsigned int BdIndex; struct pbuf *p; unsigned int *Temp; while (1) { /* obtain processed BD's */ n_bds = XEmacPs_BdRingFromHwTx(txring, XLWIP_CONFIG_N_TX_DESC, &txbdset); if (n_bds == 0) { return; } /* free the processed BD's */ n_pbufs_freed = n_bds; CurBdPntr = txbdset; while (n_pbufs_freed > 0) { BdIndex = XEMACPS_BD_TO_INDEX(txring, CurBdPntr); Temp = (unsigned int *)CurBdPntr; *Temp = 0; Temp++; *Temp = 0x80000000; if (BdIndex == (XLWIP_CONFIG_N_TX_DESC - 1)) { *Temp = 0xC0000000; } p = (struct pbuf *)tx_pbufs_storage[BdIndex]; if(p != NULL) { pbuf_free(p); } tx_pbufs_storage[BdIndex] = 0; CurBdPntr = XEmacPs_BdRingNext(txring, CurBdPntr); n_pbufs_freed--; dsb(); } Status = XEmacPs_BdRingFree(txring, n_bds, txbdset); if (Status != XST_SUCCESS) { LWIP_DEBUGF(NETIF_DEBUG, ("Failure while freeing in Tx Done ISR\r\n")); } } return; }
void emacps_recv_handler(void *arg) { struct pbuf *p; XEmacPs_Bd *rxbdset, *curbdptr; struct xemac_s *xemac; xemacpsif_s *xemacpsif; XEmacPs_BdRing *rxring; volatile s32_t bd_processed; s32_t rx_bytes, k; u32_t bdindex; u32_t regval; xemac = (struct xemac_s *)(arg); xemacpsif = (xemacpsif_s *)(xemac->state); rxring = &XEmacPs_GetRxRing(&xemacpsif->emacps); #ifdef OS_IS_FREERTOS xInsideISR++; #endif /* * If Reception done interrupt is asserted, call RX call back function * to handle the processed BDs and then raise the according flag. */ regval = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET); XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET, regval); resetrx_on_no_rxdata(xemacpsif); while(1) { bd_processed = XEmacPs_BdRingFromHwRx(rxring, XLWIP_CONFIG_N_RX_DESC, &rxbdset); if (bd_processed <= 0) { break; } for (k = 0, curbdptr=rxbdset; k < bd_processed; k++) { bdindex = XEMACPS_BD_TO_INDEX(rxring, curbdptr); p = (struct pbuf *)rx_pbufs_storage[bdindex]; /* * Adjust the buffer size to the actual number of bytes received. */ rx_bytes = XEmacPs_BdGetLength(curbdptr); pbuf_realloc(p, rx_bytes); /* store it in the receive queue, * where it'll be processed by a different handler */ if (pq_enqueue(xemacpsif->recv_q, (void*)p) < 0) { #if LINK_STATS lwip_stats.link.memerr++; lwip_stats.link.drop++; #endif pbuf_free(p); } else { #if !NO_SYS sys_sem_signal(&xemac->sem_rx_data_available); #endif } curbdptr = XEmacPs_BdRingNext( rxring, curbdptr); } /* free up the BD's */ XEmacPs_BdRingFree(rxring, bd_processed, rxbdset); setup_rx_bds(rxring); } #ifdef OS_IS_FREERTOS xInsideISR--; #endif return; }
XStatus emacps_sgsend(xemacpsif_s *xemacpsif, struct pbuf *p) { struct pbuf *q; s32_t n_pbufs; XEmacPs_Bd *txbdset, *txbd, *last_txbd = NULL; XEmacPs_Bd *temp_txbd; XStatus status; XEmacPs_BdRing *txring; u32_t bdindex; u32_t lev; lev = mfcpsr(); mtcpsr(lev | 0x000000C0); txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps)); /* first count the number of pbufs */ for (q = p, n_pbufs = 0; q != NULL; q = q->next) n_pbufs++; /* obtain as many BD's */ status = XEmacPs_BdRingAlloc(txring, n_pbufs, &txbdset); if (status != XST_SUCCESS) { mtcpsr(lev); LWIP_DEBUGF(NETIF_DEBUG, ("sgsend: Error allocating TxBD\r\n")); return XST_FAILURE; } for(q = p, txbd = txbdset; q != NULL; q = q->next) { bdindex = XEMACPS_BD_TO_INDEX(txring, txbd); if (tx_pbufs_storage[bdindex] != 0) { mtcpsr(lev); LWIP_DEBUGF(NETIF_DEBUG, ("PBUFS not available\r\n")); return XST_FAILURE; } /* Send the data from the pbuf to the interface, one pbuf at a time. The size of the data in each pbuf is kept in the ->len variable. */ Xil_DCacheFlushRange((u32_t)q->payload, (u32_t)q->len); XEmacPs_BdSetAddressTx(txbd, (u32)q->payload); if (q->len > (XEMACPS_MAX_FRAME_SIZE - 18)) XEmacPs_BdSetLength(txbd, (XEMACPS_MAX_FRAME_SIZE - 18) & 0x3FFF); else XEmacPs_BdSetLength(txbd, q->len & 0x3FFF); tx_pbufs_storage[bdindex] = (s32_t)q; pbuf_ref(q); last_txbd = txbd; XEmacPs_BdClearLast(txbd); txbd = XEmacPs_BdRingNext(txring, txbd); } XEmacPs_BdSetLast(last_txbd); /* For fragmented packets, remember the 1st BD allocated for the 1st packet fragment. The used bit for this BD should be cleared at the end after clearing out used bits for other fragments. For packets without just remember the allocated BD. */ temp_txbd = txbdset; txbd = txbdset; txbd = XEmacPs_BdRingNext(txring, txbd); q = p->next; for(; q != NULL; q = q->next) { XEmacPs_BdClearTxUsed(txbd); txbd = XEmacPs_BdRingNext(txring, txbd); } XEmacPs_BdClearTxUsed(temp_txbd); status = XEmacPs_BdRingToHw(txring, n_pbufs, txbdset); if (status != XST_SUCCESS) { mtcpsr(lev); LWIP_DEBUGF(NETIF_DEBUG, ("sgsend: Error submitting TxBD\r\n")); return XST_FAILURE; } /* Start transmit */ XEmacPs_WriteReg((xemacpsif->emacps).Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, (XEmacPs_ReadReg((xemacpsif->emacps).Config.BaseAddress, XEMACPS_NWCTRL_OFFSET) | XEMACPS_NWCTRL_STARTTX_MASK)); mtcpsr(lev); return status; }
/** * Returns a set of BD(s) that have been processed by hardware. The returned * BDs may be examined to determine the outcome of the DMA transaction(s). * Once the BDs have been examined, the user must call XEmacPs_BdRingFree() * in the same order which they were retrieved here. Example: * * <pre> * NumBd = XEmacPs_BdRingFromHwRx(MyRingPtr, MaxBd, &MyBdSet); * * if (NumBd == 0) * { * // hardware has nothing ready for us yet * } * * CurBd = MyBdSet; * for (i=0; i<NumBd; i++) * { * // Examine CurBd for post processing..... * * // Onto next BD * CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd); * } * * XEmacPs_BdRingFree(MyRingPtr, NumBd, MyBdSet); // Return list * } * </pre> * * A more advanced use of this function may allocate multiple sets of BDs. * They must be retrieved from hardware and freed in the correct sequence: * <pre> * // Legal * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1); * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1); * * // Legal * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1); * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2); * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1); * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2); * * // Not legal * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1); * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2); * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2); * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1); * </pre> * * If hardware has only partially completed a packet spanning multiple BDs, * then none of the BDs for that packet will be included in the results. * * @param RingPtr is a pointer to the instance to be worked on. * @param BdLimit is the maximum number of BDs to return in the set. * @param BdSetPtr is an output parameter, it points to the first BD available * for examination. * * @return * The number of BDs processed by hardware. A value of 0 indicates that no * data is available. No more than BdLimit BDs will be returned. * * @note Treat BDs returned by this function as read-only. * * @note This function should not be preempted by another XEmacPs_Bd function * call that modifies the BD space. It is the caller's responsibility to * provide a mutual exclusion mechanism. * *****************************************************************************/ unsigned XEmacPs_BdRingFromHwRx(XEmacPs_BdRing * RingPtr, unsigned BdLimit, XEmacPs_Bd ** BdSetPtr) { XEmacPs_Bd *CurBdPtr; u32 BdStr = 0; unsigned BdCount; unsigned BdPartialCount; CurBdPtr = RingPtr->HwHead; BdCount = 0; BdPartialCount = 0; /* If no BDs in work group, then there's nothing to search */ if (RingPtr->HwCnt == 0) { *BdSetPtr = NULL; return (0); } /* Starting at HwHead, keep moving forward in the list until: * - A BD is encountered with its new/used bit set which means * hardware has completed processing of that BD. * - RingPtr->HwTail is reached and RingPtr->HwCnt is reached. * - The number of requested BDs has been processed */ while (BdCount < BdLimit) { /* Read the status */ XEMACPS_CACHE_INVALIDATE(CurBdPtr); BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET); if (!(XEmacPs_BdIsRxNew(CurBdPtr))) { break; } BdCount++; /* hardware has processed this BD so check the "last" bit. If * it is clear, then there are more BDs for the current packet. * Keep a count of these partial packet BDs. */ if (BdStr & XEMACPS_RXBUF_EOF_MASK) { BdPartialCount = 0; } else { BdPartialCount++; } /* Move on to next BD in work group */ CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr); } /* Subtract off any partial packet BDs found */ BdCount -= BdPartialCount; /* If BdCount is non-zero then BDs were found to return. Set return * parameters, update pointers and counters, return success */ if (BdCount > 0) { *BdSetPtr = RingPtr->HwHead; RingPtr->HwCnt -= BdCount; RingPtr->PostCnt += BdCount; XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount); return (BdCount); } else { *BdSetPtr = NULL; return (0); } }
XStatus emacps_sgsend(xemacpsif_s *xemacpsif, struct pbuf *p) { struct pbuf *q; int n_pbufs; XEmacPs_Bd *txbdset, *txbd, *last_txbd = NULL; XStatus Status; XEmacPs_BdRing *txring; unsigned int BdIndex; unsigned int lev; lev = mfcpsr(); mtcpsr(lev | 0x000000C0); #ifdef PEEP while((XEmacPs_ReadReg((xemacpsif->emacps).Config.BaseAddress, XEMACPS_TXSR_OFFSET)) & 0x08); #endif txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps)); /* first count the number of pbufs */ for (q = p, n_pbufs = 0; q != NULL; q = q->next) n_pbufs++; /* obtain as many BD's */ Status = XEmacPs_BdRingAlloc(txring, n_pbufs, &txbdset); if (Status != XST_SUCCESS) { mtcpsr(lev); LWIP_DEBUGF(NETIF_DEBUG, ("sgsend: Error allocating TxBD\r\n")); return ERR_IF; } for(q = p, txbd = txbdset; q != NULL; q = q->next) { BdIndex = XEMACPS_BD_TO_INDEX(txring, txbd); if (tx_pbufs_storage[BdIndex] != 0) { mtcpsr(lev); LWIP_DEBUGF(NETIF_DEBUG, ("PBUFS not available\r\n")); return ERR_IF; } /* Send the data from the pbuf to the interface, one pbuf at a time. The size of the data in each pbuf is kept in the ->len variable. */ Xil_DCacheFlushRange((unsigned int)q->payload, (unsigned)q->len); XEmacPs_BdSetAddressTx(txbd, (u32)q->payload); if (q->len > (XEMACPS_MAX_FRAME_SIZE - 18)) XEmacPs_BdSetLength(txbd, (XEMACPS_MAX_FRAME_SIZE - 18) & 0x3FFF); else XEmacPs_BdSetLength(txbd, q->len & 0x3FFF); tx_pbufs_storage[BdIndex] = (int)q; pbuf_ref(q); last_txbd = txbd; XEmacPs_BdClearLast(txbd); dsb(); txbd = XEmacPs_BdRingNext(txring, txbd); } XEmacPs_BdSetLast(last_txbd); dsb(); for(q = p, txbd = txbdset; q != NULL; q = q->next) { XEmacPs_BdClearTxUsed(txbd); txbd = XEmacPs_BdRingNext(txring, txbd); } dsb(); Status = XEmacPs_BdRingToHw(txring, n_pbufs, txbdset); if (Status != XST_SUCCESS) { mtcpsr(lev); LWIP_DEBUGF(NETIF_DEBUG, ("sgsend: Error submitting TxBD\r\n")); return ERR_IF; } dsb(); /* Start transmit */ XEmacPs_WriteReg((xemacpsif->emacps).Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, (XEmacPs_ReadReg((xemacpsif->emacps).Config.BaseAddress, XEMACPS_NWCTRL_OFFSET) | XEMACPS_NWCTRL_STARTTX_MASK)); dsb(); mtcpsr(lev); return Status; }
/** * * This function demonstrates the usage of the EMACPS by sending and * receiving a single frame in DMA interrupt mode. * The source packet will be described by two descriptors. It will be * received into a buffer described by a single descriptor. * * @param EmacPsInstancePtr is a pointer to the instance of the EmacPs * driver. * * @return XST_SUCCESS to indicate success, otherwise XST_FAILURE. * * @note None. * *****************************************************************************/ int EmacPsDmaSingleFrameIntrExample(XEmacPs *EmacPsInstancePtr) { int Status; u32 PayloadSize = 1000; u32 NumRxBuf = 0; XEmacPs_Bd *Bd1Ptr; XEmacPs_Bd *Bd2Ptr; XEmacPs_Bd *BdRxPtr; /* * Clear variables shared with callbacks */ FramesRx = 0; FramesTx = 0; DeviceErrors = 0; /* * Calculate the frame length (not including FCS) */ TxFrameLength = XEMACPS_HDR_SIZE + PayloadSize; /* * Setup packet to be transmitted */ EmacPsUtilFrameHdrFormatMAC(&TxFrame, EmacPsMAC); EmacPsUtilFrameHdrFormatType(&TxFrame, PayloadSize); EmacPsUtilFrameSetPayloadData(&TxFrame, PayloadSize); Xil_DCacheFlushRange((u32)&TxFrame, TxFrameLength); /* * Clear out receive packet memory area */ EmacPsUtilFrameMemClear(&RxFrame); Xil_DCacheFlushRange((u32)&RxFrame, TxFrameLength); /* * Allocate RxBDs since we do not know how many BDs will be used * in advance, use RXBD_CNT here. */ Status = XEmacPs_BdRingAlloc(& (XEmacPs_GetRxRing(EmacPsInstancePtr)), 1, &BdRxPtr); if (Status != XST_SUCCESS) { EmacPsUtilErrorTrap("Error allocating RxBD"); return XST_FAILURE; } /* * Setup the BD. The XEmacPs_BdRingClone() call will mark the * "wrap" field for last RxBD. Setup buffer address to associated * BD. */ XEmacPs_BdSetAddressRx(BdRxPtr, &RxFrame); /* * Enqueue to HW */ Status = XEmacPs_BdRingToHw(&(XEmacPs_GetRxRing(EmacPsInstancePtr)), 1, BdRxPtr); if (Status != XST_SUCCESS) { EmacPsUtilErrorTrap("Error committing RxBD to HW"); return XST_FAILURE; } /* * Allocate, setup, and enqueue 2 TxBDs. The first BD will * describe the first 32 bytes of TxFrame and the rest of BDs * will describe the rest of the frame. * * The function below will allocate 2 adjacent BDs with Bd1Ptr * being set as the lead BD. */ Status = XEmacPs_BdRingAlloc(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), 2, &Bd1Ptr); if (Status != XST_SUCCESS) { EmacPsUtilErrorTrap("Error allocating TxBD"); return XST_FAILURE; } /* * Setup first TxBD */ XEmacPs_BdSetAddressTx(Bd1Ptr, &TxFrame); XEmacPs_BdSetLength(Bd1Ptr, FIRST_FRAGMENT_SIZE); XEmacPs_BdClearTxUsed(Bd1Ptr); XEmacPs_BdClearLast(Bd1Ptr); /* * Setup second TxBD */ Bd2Ptr = XEmacPs_BdRingNext(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), Bd1Ptr); XEmacPs_BdSetAddressTx(Bd2Ptr, (u32) (&TxFrame) + FIRST_FRAGMENT_SIZE); XEmacPs_BdSetLength(Bd2Ptr, TxFrameLength - FIRST_FRAGMENT_SIZE); XEmacPs_BdClearTxUsed(Bd2Ptr); XEmacPs_BdSetLast(Bd2Ptr); /* * Enqueue to HW */ Status = XEmacPs_BdRingToHw(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), 2, Bd1Ptr); if (Status != XST_SUCCESS) { EmacPsUtilErrorTrap("Error committing TxBD to HW"); return XST_FAILURE; } /* * Start the device */ XEmacPs_Start(EmacPsInstancePtr); /* Start transmit */ XEmacPs_Transmit(EmacPsInstancePtr); /* * Wait for transmission to complete */ while (!FramesTx); /* * Now that the frame has been sent, post process our TxBDs. * Since we have only submitted 2 to hardware, then there should * be only 2 ready for post processing. */ if (XEmacPs_BdRingFromHwTx(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), 2, &Bd1Ptr) == 0) { EmacPsUtilErrorTrap ("TxBDs were not ready for post processing"); return XST_FAILURE; } /* * Examine the TxBDs. * * There isn't much to do. The only thing to check would be DMA * exception bits. But this would also be caught in the error * handler. So we just return these BDs to the free list. */ Status = XEmacPs_BdRingFree(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), 2, Bd1Ptr); if (Status != XST_SUCCESS) { EmacPsUtilErrorTrap("Error freeing up TxBDs"); return XST_FAILURE; } /* * Wait for Rx indication */ while (!FramesRx); /* * Now that the frame has been received, post process our RxBD. * Since we have submitted to hardware, then there should be only 1 * ready for post processing. */ NumRxBuf = XEmacPs_BdRingFromHwRx(&(XEmacPs_GetRxRing (EmacPsInstancePtr)), 1, &BdRxPtr); if (0 == NumRxBuf) { EmacPsUtilErrorTrap("RxBD was not ready for post processing"); return XST_FAILURE; } /* * There is no device status to check. If there was a DMA error, * it should have been reported to the error handler. Check the * receive lengthi against the transmitted length, then verify * the data. */ if ((XEmacPs_BdGetLength(BdRxPtr)) != TxFrameLength) { EmacPsUtilErrorTrap("Length mismatch"); return XST_FAILURE; } if (EmacPsUtilFrameVerify(&TxFrame, &RxFrame) != 0) { EmacPsUtilErrorTrap("Data mismatch"); return XST_FAILURE; } /* * Return the RxBD back to the channel for later allocation. Free * the exact number we just post processed. */ Status = XEmacPs_BdRingFree(&(XEmacPs_GetRxRing(EmacPsInstancePtr)), NumRxBuf, BdRxPtr); if (Status != XST_SUCCESS) { EmacPsUtilErrorTrap("Error freeing up RxBDs"); return XST_FAILURE; } /* * Finished this example. If everything worked correctly, all TxBDs * and RxBDs should be free for allocation. Stop the device. */ XEmacPs_Stop(EmacPsInstancePtr); return XST_SUCCESS; }
void emacps_recv_handler(void *arg) { struct pbuf *p; unsigned irq_status, i; XEmacPs_Bd *rxbdset, *CurBdPtr; struct xemac_s *xemac; xemacpsif_s *xemacpsif; XEmacPs_BdRing *rxring; volatile int bd_processed; int rx_bytes, k; unsigned int BdIndex; xemac = (struct xemac_s *)(arg); xemacpsif = (xemacpsif_s *)(xemac->state); rxring = &XEmacPs_GetRxRing(&xemacpsif->emacps); #ifdef OS_IS_FREERTOS xInsideISR++; #endif /* * If Reception done interrupt is asserted, call RX call back function * to handle the processed BDs and then raise the according flag. */ while(1) { bd_processed = XEmacPs_BdRingFromHwRx(rxring, XLWIP_CONFIG_N_RX_DESC, &rxbdset); if (bd_processed <= 0) { #ifdef OS_IS_FREERTOS xInsideISR--; #endif return; } for (k = 0, CurBdPtr=rxbdset; k < bd_processed; k++) { BdIndex = XEMACPS_BD_TO_INDEX(rxring, CurBdPtr); p = (struct pbuf *)rx_pbufs_storage[BdIndex]; /* * Adjust the buffer size to the actual number of bytes received. */ rx_bytes = XEmacPs_BdGetLength(CurBdPtr); pbuf_realloc(p, rx_bytes); Xil_DCacheInvalidateRange((unsigned int)p->payload, (unsigned)XEMACPS_MAX_FRAME_SIZE); /* store it in the receive queue, * where it'll be processed by a different handler */ if (pq_enqueue(xemacpsif->recv_q, (void*)p) < 0) { #if LINK_STATS lwip_stats.link.memerr++; lwip_stats.link.drop++; #endif pbuf_free(p); } else { #if !NO_SYS sys_sem_signal(&xemac->sem_rx_data_available); #endif } CurBdPtr = XEmacPs_BdRingNext( rxring, CurBdPtr); } /* free up the BD's */ XEmacPs_BdRingFree(rxring, bd_processed, rxbdset); _setup_rx_bds(rxring); } return; }
/** * Returns a set of BD(s) that have been processed by hardware. The returned * BDs may be examined to determine the outcome of the DMA transaction(s). * Once the BDs have been examined, the user must call XEmacPs_BdRingFree() * in the same order which they were retrieved here. Example: * * <pre> * NumBd = XEmacPs_BdRingFromHwTx(MyRingPtr, MaxBd, &MyBdSet), * if (NumBd == 0) * { * * hardware has nothing ready for us yet* * } * * CurBd = MyBdSet, * for (i=0; i<NumBd; i++) * { * * Examine CurBd for post processing *..... * * * Onto next BD * * CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd), * } * * XEmacPs_BdRingFree(MyRingPtr, NumBd, MyBdSet), *Return list* * } * </pre> * * A more advanced use of this function may allocate multiple sets of BDs. * They must be retrieved from hardware and freed in the correct sequence: * <pre> * * Legal * * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1), * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1), * * * Legal * * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1), * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2), * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1), * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2), * * * Not legal * * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1), * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2), * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2), * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1), * </pre> * * If hardware has only partially completed a packet spanning multiple BDs, * then none of the BDs for that packet will be included in the results. * * @param RingPtr is a pointer to the instance to be worked on. * @param BdLimit is the maximum number of BDs to return in the set. * @param BdSetPtr is an output parameter, it points to the first BD available * for examination. * * @return * The number of BDs processed by hardware. A value of 0 indicates that no * data is available. No more than BdLimit BDs will be returned. * * @note Treat BDs returned by this function as read-only. * * @note This function should not be preempted by another XEmacPs_Bd function * call that modifies the BD space. It is the caller's responsibility to * provide a mutual exclusion mechanism. * *****************************************************************************/ u32 XEmacPs_BdRingFromHwTx(XEmacPs_BdRing * RingPtr, u32 BdLimit, XEmacPs_Bd ** BdSetPtr) { XEmacPs_Bd *CurBdPtr; u32 BdStr = 0U; u32 BdCount; u32 BdPartialCount; u32 Sop = 0U; u32 Status; u32 BdLimitLoc = BdLimit; CurBdPtr = RingPtr->HwHead; BdCount = 0U; BdPartialCount = 0U; /* If no BDs in work group, then there's nothing to search */ if (RingPtr->HwCnt == 0x00000000U) { *BdSetPtr = NULL; Status = 0U; } else { if (BdLimitLoc > RingPtr->HwCnt){ BdLimitLoc = RingPtr->HwCnt; } /* Starting at HwHead, keep moving forward in the list until: * - A BD is encountered with its new/used bit set which means * hardware has not completed processing of that BD. * - RingPtr->HwTail is reached and RingPtr->HwCnt is reached. * - The number of requested BDs has been processed */ while (BdCount < BdLimitLoc) { /* Read the status */ if(CurBdPtr != NULL){ BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET); } if ((Sop == 0x00000000U) && ((BdStr & XEMACPS_TXBUF_USED_MASK)!=0x00000000U)){ Sop = 1U; } if (Sop == 0x00000001U) { BdCount++; BdPartialCount++; } /* hardware has processed this BD so check the "last" bit. * If it is clear, then there are more BDs for the current * packet. Keep a count of these partial packet BDs. */ if ((Sop == 0x00000001U) && ((BdStr & XEMACPS_TXBUF_LAST_MASK)!=0x00000000U)) { Sop = 0U; BdPartialCount = 0U; } /* Move on to next BD in work group */ CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr); } /* Subtract off any partial packet BDs found */ BdCount -= BdPartialCount; /* If BdCount is non-zero then BDs were found to return. Set return * parameters, update pointers and counters, return success */ if (BdCount > 0x00000000U) { *BdSetPtr = RingPtr->HwHead; RingPtr->HwCnt -= BdCount; RingPtr->PostCnt += BdCount; XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount); Status = (BdCount); } else { *BdSetPtr = NULL; Status = 0U; } } return Status; }