2 * Copyright (c) 2010-2013 Xilinx, Inc. All rights reserved.
5 * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
6 * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
7 * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
8 * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
9 * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
10 * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
11 * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
12 * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
13 * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
14 * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
15 * AND FITNESS FOR A PARTICULAR PURPOSE.
20 #include "lwip/stats.h"
22 #include "lwip/inet_chksum.h"
24 #include "netif/xadapter.h"
25 #include "netif/xemacpsif.h"
28 #include "xlwipconfig.h"
29 #include "xparameters.h"
30 #include "xparameters_ps.h"
31 #include "xil_exception.h"
42 /*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c
43 *** to run it on a PEEP board
46 #define INTC_BASE_ADDR XPAR_SCUGIC_CPU_BASEADDR
47 #define INTC_DIST_BASE_ADDR XPAR_SCUGIC_DIST_BASEADDR
49 /* Byte alignment of BDs */
50 #define BD_ALIGNMENT (XEMACPS_DMABD_MINIMUM_ALIGNMENT*2)
52 static int tx_pbufs_storage[XLWIP_CONFIG_N_TX_DESC];
53 static int rx_pbufs_storage[XLWIP_CONFIG_N_RX_DESC];
55 static int EmacIntrNum;
59 extern BaseType_t xInsideISR;
62 #define XEMACPS_BD_TO_INDEX(ringptr, bdptr) \
63 (((u32)bdptr - (u32)(ringptr)->BaseBdAddr) / (ringptr)->Separation)
66 int is_tx_space_available(xemacpsif_s *emac)
68 XEmacPs_BdRing *txring;
71 txring = &(XEmacPs_GetTxRing(&emac->emacps));
73 /* tx space is available as long as there are valid BD's */
74 freecnt = XEmacPs_BdRingGetFreeCnt(txring);
78 void process_sent_bds(XEmacPs_BdRing *txring)
81 XEmacPs_Bd *CurBdPntr;
84 int n_pbufs_freed = 0;
90 /* obtain processed BD's */
91 n_bds = XEmacPs_BdRingFromHwTx(txring,
92 XLWIP_CONFIG_N_TX_DESC, &txbdset);
96 /* free the processed BD's */
97 n_pbufs_freed = n_bds;
99 while (n_pbufs_freed > 0) {
100 BdIndex = XEMACPS_BD_TO_INDEX(txring, CurBdPntr);
101 Temp = (unsigned int *)CurBdPntr;
105 if (BdIndex == (XLWIP_CONFIG_N_TX_DESC - 1)) {
109 p = (struct pbuf *)tx_pbufs_storage[BdIndex];
113 tx_pbufs_storage[BdIndex] = 0;
114 CurBdPntr = XEmacPs_BdRingNext(txring, CurBdPntr);
119 Status = XEmacPs_BdRingFree(txring, n_bds, txbdset);
120 if (Status != XST_SUCCESS) {
121 LWIP_DEBUGF(NETIF_DEBUG, ("Failure while freeing in Tx Done ISR\r\n"));
127 void emacps_send_handler(void *arg)
129 struct xemac_s *xemac;
130 xemacpsif_s *xemacpsif;
131 XEmacPs_BdRing *TxRingPtr;
133 #ifdef OS_IS_FREERTOS
136 xemac = (struct xemac_s *)(arg);
137 xemacpsif = (xemacpsif_s *)(xemac->state);
138 TxRingPtr = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
139 regval = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_TXSR_OFFSET);
140 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,XEMACPS_TXSR_OFFSET, regval);
142 /* If Transmit done interrupt is asserted, process completed BD's */
143 process_sent_bds(TxRingPtr);
144 #ifdef OS_IS_FREERTOS
149 XStatus emacps_sgsend(xemacpsif_s *xemacpsif, struct pbuf *p)
153 XEmacPs_Bd *txbdset, *txbd, *last_txbd = NULL;
154 XEmacPs_Bd *temp_txbd;
156 XEmacPs_BdRing *txring;
157 unsigned int BdIndex;
161 mtcpsr(lev | 0x000000C0);
164 while((XEmacPs_ReadReg((xemacpsif->emacps).Config.BaseAddress,
165 XEMACPS_TXSR_OFFSET)) & 0x08);
167 txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
169 /* first count the number of pbufs */
170 for (q = p, n_pbufs = 0; q != NULL; q = q->next)
173 /* obtain as many BD's */
174 Status = XEmacPs_BdRingAlloc(txring, n_pbufs, &txbdset);
175 if (Status != XST_SUCCESS) {
177 LWIP_DEBUGF(NETIF_DEBUG, ("sgsend: Error allocating TxBD\r\n"));
181 for(q = p, txbd = txbdset; q != NULL; q = q->next) {
182 BdIndex = XEMACPS_BD_TO_INDEX(txring, txbd);
183 if (tx_pbufs_storage[BdIndex] != 0) {
185 LWIP_DEBUGF(NETIF_DEBUG, ("PBUFS not available\r\n"));
189 /* Send the data from the pbuf to the interface, one pbuf at a
190 time. The size of the data in each pbuf is kept in the ->len
192 Xil_DCacheFlushRange((unsigned int)q->payload, (unsigned)q->len);
194 XEmacPs_BdSetAddressTx(txbd, (u32)q->payload);
195 if (q->len > (XEMACPS_MAX_FRAME_SIZE - 18))
196 XEmacPs_BdSetLength(txbd, (XEMACPS_MAX_FRAME_SIZE - 18) & 0x3FFF);
198 XEmacPs_BdSetLength(txbd, q->len & 0x3FFF);
200 tx_pbufs_storage[BdIndex] = (int)q;
204 XEmacPs_BdClearLast(txbd);
206 txbd = XEmacPs_BdRingNext(txring, txbd);
208 XEmacPs_BdSetLast(last_txbd);
210 /* For fragmented packets, remember the 1st BD allocated for the 1st
211 packet fragment. The used bit for this BD should be cleared at the end
212 after clearing out used bits for other fragments. For packets without
213 just remember the allocated BD. */
216 txbd = XEmacPs_BdRingNext(txring, txbd);
218 for(; q != NULL; q = q->next) {
219 XEmacPs_BdClearTxUsed(txbd);
220 txbd = XEmacPs_BdRingNext(txring, txbd);
222 XEmacPs_BdClearTxUsed(temp_txbd);
225 Status = XEmacPs_BdRingToHw(txring, n_pbufs, txbdset);
226 if (Status != XST_SUCCESS) {
228 LWIP_DEBUGF(NETIF_DEBUG, ("sgsend: Error submitting TxBD\r\n"));
233 XEmacPs_WriteReg((xemacpsif->emacps).Config.BaseAddress,
234 XEMACPS_NWCTRL_OFFSET,
235 (XEmacPs_ReadReg((xemacpsif->emacps).Config.BaseAddress,
236 XEMACPS_NWCTRL_OFFSET) | XEMACPS_NWCTRL_STARTTX_MASK));
242 void setup_rx_bds(XEmacPs_BdRing *rxring)
247 unsigned int FreeBds;
248 unsigned int BdIndex;
251 FreeBds = XEmacPs_BdRingGetFreeCnt (rxring);
252 while (FreeBds > 0) {
254 Status = XEmacPs_BdRingAlloc(rxring, 1, &rxbd);
255 if (Status != XST_SUCCESS) {
256 LWIP_DEBUGF(NETIF_DEBUG, ("setup_rx_bds: Error allocating RxBD\r\n"));
259 BdIndex = XEMACPS_BD_TO_INDEX(rxring, rxbd);
260 Temp = (unsigned int *)rxbd;
262 if (BdIndex == (XLWIP_CONFIG_N_RX_DESC - 1)) {
268 p = pbuf_alloc(PBUF_RAW, XEMACPS_MAX_FRAME_SIZE, PBUF_POOL);
271 lwip_stats.link.memerr++;
272 lwip_stats.link.drop++;
274 LWIP_DEBUGF(NETIF_DEBUG, ("unable to alloc pbuf in recv_handler\r\n"));
275 XEmacPs_BdRingUnAlloc(rxring, 1, rxbd);
279 XEmacPs_BdSetAddressRx(rxbd, (u32)p->payload);
282 rx_pbufs_storage[BdIndex] = (int)p;
283 Status = XEmacPs_BdRingToHw(rxring, 1, rxbd);
284 if (Status != XST_SUCCESS) {
285 LWIP_DEBUGF(NETIF_DEBUG, ("Error committing RxBD to hardware: "));
286 if (Status == XST_DMA_SG_LIST_ERROR)
287 LWIP_DEBUGF(NETIF_DEBUG, ("XST_DMA_SG_LIST_ERROR: this function was called out of sequence with XEmacPs_BdRingAlloc()\r\n"));
290 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"));
297 void emacps_recv_handler(void *arg)
300 XEmacPs_Bd *rxbdset, *CurBdPtr;
301 struct xemac_s *xemac;
302 xemacpsif_s *xemacpsif;
303 XEmacPs_BdRing *rxring;
304 volatile int bd_processed;
306 unsigned int BdIndex;
309 xemac = (struct xemac_s *)(arg);
310 xemacpsif = (xemacpsif_s *)(xemac->state);
311 rxring = &XEmacPs_GetRxRing(&xemacpsif->emacps);
313 #ifdef OS_IS_FREERTOS
317 * If Reception done interrupt is asserted, call RX call back function
318 * to handle the processed BDs and then raise the according flag.
320 regval = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET);
321 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET, regval);
323 resetrx_on_no_rxdata(xemacpsif);
327 bd_processed = XEmacPs_BdRingFromHwRx(rxring, XLWIP_CONFIG_N_RX_DESC, &rxbdset);
329 if (bd_processed <= 0) {
333 for (k = 0, CurBdPtr=rxbdset; k < bd_processed; k++) {
335 BdIndex = XEMACPS_BD_TO_INDEX(rxring, CurBdPtr);
336 p = (struct pbuf *)rx_pbufs_storage[BdIndex];
339 * Adjust the buffer size to the actual number of bytes received.
341 rx_bytes = XEmacPs_BdGetLength(CurBdPtr);
342 pbuf_realloc(p, rx_bytes);
343 Xil_DCacheInvalidateRange((unsigned int)p->payload, (unsigned)XEMACPS_MAX_FRAME_SIZE);
344 /* store it in the receive queue,
345 * where it'll be processed by a different handler
347 if (pq_enqueue(xemacpsif->recv_q, (void*)p) < 0) {
349 lwip_stats.link.memerr++;
350 lwip_stats.link.drop++;
355 sys_sem_signal(&xemac->sem_rx_data_available);
358 CurBdPtr = XEmacPs_BdRingNext( rxring, CurBdPtr);
360 /* free up the BD's */
361 XEmacPs_BdRingFree(rxring, bd_processed, rxbdset);
362 setup_rx_bds(rxring);
365 #ifdef OS_IS_FREERTOS
371 void clean_dma_txdescs(struct xemac_s *xemac)
373 XEmacPs_Bd BdTemplate;
374 XEmacPs_BdRing *TxRingPtr;
375 xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
377 TxRingPtr = &XEmacPs_GetTxRing(&xemacpsif->emacps);
379 XEmacPs_BdClear(&BdTemplate);
380 XEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK);
383 * Create the TxBD ring
385 XEmacPs_BdRingCreate(TxRingPtr, (u32) xemacpsif->tx_bdspace,
386 (u32) xemacpsif->tx_bdspace, BD_ALIGNMENT,
387 XLWIP_CONFIG_N_TX_DESC);
388 XEmacPs_BdRingClone(TxRingPtr, &BdTemplate, XEMACPS_SEND);
392 XStatus init_dma(struct xemac_s *xemac)
394 XEmacPs_Bd BdTemplate;
395 XEmacPs_BdRing *RxRingPtr, *TxRingPtr;
400 unsigned int BdIndex;
401 char *endAdd = (char *) &_end;
403 * Align the BD starte address to 1 MB boundary.
405 char *endAdd_aligned = (char *)(((int)endAdd + 0x100000) & (~0xFFFFF));
406 xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
407 struct xtopology_t *xtopologyp = &xtopology[xemac->topology_index];
410 * The BDs need to be allocated in uncached memory. Hence the 1 MB
411 * address range that starts at address 0xFF00000 is made uncached
412 * by setting appropriate attributes in the translation table.
414 Xil_SetTlbAttributes((int)endAdd_aligned, 0xc02); // addr, attr
416 RxRingPtr = &XEmacPs_GetRxRing(&xemacpsif->emacps);
417 TxRingPtr = &XEmacPs_GetTxRing(&xemacpsif->emacps);
418 LWIP_DEBUGF(NETIF_DEBUG, ("RxRingPtr: 0x%08x\r\n", RxRingPtr));
419 LWIP_DEBUGF(NETIF_DEBUG, ("TxRingPtr: 0x%08x\r\n", TxRingPtr));
421 xemacpsif->rx_bdspace = (void *)endAdd_aligned;
423 * We allocate 65536 bytes for Rx BDs which can accomodate a
424 * maximum of 8192 BDs which is much more than any application
427 xemacpsif->tx_bdspace = (void *)(endAdd_aligned + 0x10000);
429 LWIP_DEBUGF(NETIF_DEBUG, ("rx_bdspace: 0x%08x\r\n", xemacpsif->rx_bdspace));
430 LWIP_DEBUGF(NETIF_DEBUG, ("tx_bdspace: 0x%08x\r\n", xemacpsif->tx_bdspace));
432 if (!xemacpsif->rx_bdspace || !xemacpsif->tx_bdspace) {
433 xil_printf("%s@%d: Error: Unable to allocate memory for TX/RX buffer descriptors",
441 * Setup a BD template for the Rx channel. This template will be copied to
442 * every RxBD. We will not have to explicitly set these again.
444 XEmacPs_BdClear(&BdTemplate);
447 * Create the RxBD ring
450 Status = XEmacPs_BdRingCreate(RxRingPtr, (u32) xemacpsif->rx_bdspace,
451 (u32) xemacpsif->rx_bdspace, BD_ALIGNMENT,
452 XLWIP_CONFIG_N_RX_DESC);
454 if (Status != XST_SUCCESS) {
455 LWIP_DEBUGF(NETIF_DEBUG, ("Error setting up RxBD space\r\n"));
459 Status = XEmacPs_BdRingClone(RxRingPtr, &BdTemplate, XEMACPS_RECV);
460 if (Status != XST_SUCCESS) {
461 LWIP_DEBUGF(NETIF_DEBUG, ("Error initializing RxBD space\r\n"));
465 XEmacPs_BdClear(&BdTemplate);
466 XEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK);
468 * Create the TxBD ring
470 Status = XEmacPs_BdRingCreate(TxRingPtr, (u32) xemacpsif->tx_bdspace,
471 (u32) xemacpsif->tx_bdspace, BD_ALIGNMENT,
472 XLWIP_CONFIG_N_TX_DESC);
474 if (Status != XST_SUCCESS) {
478 /* We reuse the bd template, as the same one will work for both rx and tx. */
479 Status = XEmacPs_BdRingClone(TxRingPtr, &BdTemplate, XEMACPS_SEND);
480 if (Status != XST_SUCCESS) {
485 * Allocate RX descriptors, 1 RxBD at a time.
487 for (i = 0; i < XLWIP_CONFIG_N_RX_DESC; i++) {
488 Status = XEmacPs_BdRingAlloc(RxRingPtr, 1, &rxbd);
489 if (Status != XST_SUCCESS) {
490 LWIP_DEBUGF(NETIF_DEBUG, ("init_dma: Error allocating RxBD\r\n"));
494 p = pbuf_alloc(PBUF_RAW, XEMACPS_MAX_FRAME_SIZE, PBUF_POOL);
497 lwip_stats.link.memerr++;
498 lwip_stats.link.drop++;
500 LWIP_DEBUGF(NETIF_DEBUG, ("unable to alloc pbuf in recv_handler\r\n"));
504 XEmacPs_BdSetAddressRx(rxbd, (u32)p->payload);
506 BdIndex = XEMACPS_BD_TO_INDEX(RxRingPtr, rxbd);
507 rx_pbufs_storage[BdIndex] = (int)p;
510 Status = XEmacPs_BdRingToHw(RxRingPtr, 1, rxbd);
511 if (Status != XST_SUCCESS) {
512 LWIP_DEBUGF(NETIF_DEBUG, ("Error: committing RxBD to HW\r\n"));
518 * Connect the device driver handler that will be called when an
519 * interrupt for the device occurs, the handler defined above performs
520 * the specific interrupt processing for the device.
522 XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,
523 (Xil_ExceptionHandler)XEmacPs_IntrHandler,
524 (void *)&xemacpsif->emacps);
526 * Enable the interrupt for emacps.
528 XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, (u32) xtopologyp->scugic_emac_intr);
529 EmacIntrNum = (u32) xtopologyp->scugic_emac_intr;
534 * resetrx_on_no_rxdata():
536 * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata
537 * called by the user.
538 * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.
539 * Under heavy Rx traffic because of the HW bug there are times when the Rx path
540 * becomes unresponsive. The workaround for it is to check for the Rx path for
541 * traffic (by reading the stats registers regularly). If the stats register
542 * does not increment for sometime (proving no Rx traffic), the function resets
547 void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)
549 unsigned long regctrl;
550 unsigned long tempcntr;
552 tempcntr = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET);
553 if ((!tempcntr) && (!(xemacpsif->last_rx_frms_cntr))) {
554 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
555 XEMACPS_NWCTRL_OFFSET);
556 regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);
557 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
558 XEMACPS_NWCTRL_OFFSET, regctrl);
559 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);
560 regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);
561 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);
563 xemacpsif->last_rx_frms_cntr = tempcntr;
566 void FreeTxRxPBufs(void)
571 for (Index = 0; Index < XLWIP_CONFIG_N_TX_DESC; Index++) {
572 if (tx_pbufs_storage[Index] != 0) {
573 p = (struct pbuf *)tx_pbufs_storage[Index];
575 tx_pbufs_storage[Index] = 0;
579 for (Index = 0; Index < XLWIP_CONFIG_N_RX_DESC; Index++) {
580 p = (struct pbuf *)rx_pbufs_storage[Index];
586 void FreeOnlyTxPBufs(void)
591 for (Index = 0; Index < XLWIP_CONFIG_N_TX_DESC; Index++) {
592 if (tx_pbufs_storage[Index] != 0) {
593 p = (struct pbuf *)tx_pbufs_storage[Index];
595 tx_pbufs_storage[Index] = 0;
600 void EmacDisableIntr(void)
602 XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, EmacIntrNum);
605 void EmacEnableIntr(void)
607 XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, EmacIntrNum);