void setup_rx_bds(xemacpsif_s *xemacpsif, XEmacPs_BdRing *rxring) { XEmacPs_Bd *rxbd; XStatus status; struct pbuf *p; u32_t freebds; u32_t bdindex; u32_t *temp; u32_t index = 0; if (xemacpsif->emacps.Config.BaseAddress != XPAR_XEMACPS_0_BASEADDR) { index = sizeof(s32_t) * XLWIP_CONFIG_N_RX_DESC; } freebds = XEmacPs_BdRingGetFreeCnt (rxring); while (freebds > 0) { freebds--; 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 printf("unable to alloc pbuf in recv_handler\r\n"); return; } status = XEmacPs_BdRingAlloc(rxring, 1, &rxbd); if (status != XST_SUCCESS) { LWIP_DEBUGF(NETIF_DEBUG, ("setup_rx_bds: Error allocating RxBD\r\n")); pbuf_free(p); return; } status = XEmacPs_BdRingToHw(rxring, 1, 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")); pbuf_free(p); XEmacPs_BdRingUnAlloc(rxring, 1, rxbd); return; } Xil_DCacheInvalidateRange((u32_t)p->payload, (u32_t)XEMACPS_MAX_FRAME_SIZE); bdindex = XEMACPS_BD_TO_INDEX(rxring, rxbd); temp = (u32_t *)rxbd; *temp = 0; if (bdindex == (XLWIP_CONFIG_N_RX_DESC - 1)) { *temp = 0x00000002; } temp++; *temp = 0; XEmacPs_BdSetAddressRx(rxbd, (u32_t)p->payload); rx_pbufs_storage[index + bdindex] = (s32_t)p; } }
void setup_rx_bds(XEmacPs_BdRing *rxring) { XEmacPs_Bd *rxbd; XStatus Status; struct pbuf *p; unsigned int FreeBds; unsigned int BdIndex; unsigned int *Temp; FreeBds = XEmacPs_BdRingGetFreeCnt (rxring); while (FreeBds > 0) { FreeBds--; Status = XEmacPs_BdRingAlloc(rxring, 1, &rxbd); if (Status != XST_SUCCESS) { LWIP_DEBUGF(NETIF_DEBUG, ("setup_rx_bds: Error allocating RxBD\r\n")); return; } BdIndex = XEMACPS_BD_TO_INDEX(rxring, rxbd); Temp = (unsigned int *)rxbd; *Temp = 0; if (BdIndex == (XLWIP_CONFIG_N_RX_DESC - 1)) { *Temp = 0x00000002; } Temp++; *Temp = 0; 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")); XEmacPs_BdRingUnAlloc(rxring, 1, rxbd); dsb(); return; } XEmacPs_BdSetAddressRx(rxbd, (u32)p->payload); dsb(); rx_pbufs_storage[BdIndex] = (int)p; Status = XEmacPs_BdRingToHw(rxring, 1, 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; } } }
XStatus init_dma(struct xemac_s *xemac) { XEmacPs_Bd bdtemplate; XEmacPs_BdRing *rxringptr, *txringptr; XEmacPs_Bd *rxbd; struct pbuf *p; XStatus status; s32_t i; u32_t bdindex; volatile u32_t tempaddress; xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state); struct xtopology_t *xtopologyp = &xtopology[xemac->topology_index]; /* * The BDs need to be allocated in uncached memory. Hence the 1 MB * address range allocated for Bd_Space is made uncached * by setting appropriate attributes in the translation table. * The Bd_Space is aligned to 1MB and has a size of 1 MB. This ensures * a reserved uncached area used only for BDs. */ if (bd_space_attr_set == 0) { Xil_SetTlbAttributes((s32_t)bd_space, 0xc02); // addr, attr bd_space_attr_set = 1; } rxringptr = &XEmacPs_GetRxRing(&xemacpsif->emacps); txringptr = &XEmacPs_GetTxRing(&xemacpsif->emacps); LWIP_DEBUGF(NETIF_DEBUG, ("rxringptr: 0x%08x\r\n", rxringptr)); LWIP_DEBUGF(NETIF_DEBUG, ("txringptr: 0x%08x\r\n", txringptr)); /* Allocate 64k for Rx and Tx bds each to take care of extreme cases */ tempaddress = (u32_t)&(bd_space[bd_space_index]); xemacpsif->rx_bdspace = (void *)tempaddress; bd_space_index += 0x10000; tempaddress = (u32_t)&(bd_space[bd_space_index]); xemacpsif->tx_bdspace = (void *)tempaddress; bd_space_index += 0x10000; LWIP_DEBUGF(NETIF_DEBUG, ("rx_bdspace: 0x%08x\r\n", xemacpsif->rx_bdspace)); LWIP_DEBUGF(NETIF_DEBUG, ("tx_bdspace: 0x%08x\r\n", xemacpsif->tx_bdspace)); if (!xemacpsif->rx_bdspace || !xemacpsif->tx_bdspace) { xil_printf("%s@%d: Error: Unable to allocate memory for TX/RX buffer descriptors", __FILE__, __LINE__); return ERR_IF; } /* * Setup RxBD space. * * 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. */ XEmacPs_BdClear(&bdtemplate); /* * Create the RxBD ring */ status = XEmacPs_BdRingCreate(rxringptr, (u32) xemacpsif->rx_bdspace, (u32) xemacpsif->rx_bdspace, BD_ALIGNMENT, XLWIP_CONFIG_N_RX_DESC); if (status != XST_SUCCESS) { LWIP_DEBUGF(NETIF_DEBUG, ("Error setting up RxBD space\r\n")); return ERR_IF; } status = XEmacPs_BdRingClone(rxringptr, &bdtemplate, XEMACPS_RECV); if (status != XST_SUCCESS) { LWIP_DEBUGF(NETIF_DEBUG, ("Error initializing RxBD space\r\n")); return ERR_IF; } XEmacPs_BdClear(&bdtemplate); XEmacPs_BdSetStatus(&bdtemplate, XEMACPS_TXBUF_USED_MASK); /* * Create the TxBD ring */ status = XEmacPs_BdRingCreate(txringptr, (u32) xemacpsif->tx_bdspace, (u32) xemacpsif->tx_bdspace, BD_ALIGNMENT, XLWIP_CONFIG_N_TX_DESC); if (status != XST_SUCCESS) { return ERR_IF; } /* We reuse the bd template, as the same one will work for both rx and tx. */ status = XEmacPs_BdRingClone(txringptr, &bdtemplate, XEMACPS_SEND); if (status != XST_SUCCESS) { return ERR_IF; } /* * Allocate RX descriptors, 1 RxBD at a time. */ for (i = 0; i < XLWIP_CONFIG_N_RX_DESC; i++) { 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 printf("unable to alloc pbuf in init_dma\r\n"); return ERR_IF; } status = XEmacPs_BdRingAlloc(rxringptr, 1, &rxbd); if (status != XST_SUCCESS) { LWIP_DEBUGF(NETIF_DEBUG, ("init_dma: Error allocating RxBD\r\n")); pbuf_free(p); return ERR_IF; } /* Enqueue to HW */ status = XEmacPs_BdRingToHw(rxringptr, 1, rxbd); if (status != XST_SUCCESS) { LWIP_DEBUGF(NETIF_DEBUG, ("Error: committing RxBD to HW\r\n")); pbuf_free(p); XEmacPs_BdRingUnAlloc(rxringptr, 1, rxbd); return ERR_IF; } Xil_DCacheInvalidateRange((u32_t)p->payload, (u32_t)XEMACPS_MAX_FRAME_SIZE); XEmacPs_BdSetAddressRx(rxbd, (u32_t)p->payload); bdindex = XEMACPS_BD_TO_INDEX(rxringptr, rxbd); rx_pbufs_storage[bdindex] = (s32_t)p; } /* * Connect the device driver handler that will be called when an * interrupt for the device occurs, the handler defined above performs * the specific interrupt processing for the device. */ XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr, (Xil_ExceptionHandler)XEmacPs_IntrHandler, (void *)&xemacpsif->emacps); /* * Enable the interrupt for emacps. */ XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, (u32) xtopologyp->scugic_emac_intr); emac_intr_num = (u32) xtopologyp->scugic_emac_intr; return 0; }