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;
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"));
289 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"));
295 void emacps_recv_handler(void *arg)
298 XEmacPs_Bd *rxbdset, *CurBdPtr;
299 struct xemac_s *xemac;
300 xemacpsif_s *xemacpsif;
301 XEmacPs_BdRing *rxring;
302 volatile int bd_processed;
304 unsigned int BdIndex;
307 xemac = (struct xemac_s *)(arg);
308 xemacpsif = (xemacpsif_s *)(xemac->state);
309 rxring = &XEmacPs_GetRxRing(&xemacpsif->emacps);
311 #ifdef OS_IS_FREERTOS
315 * If Reception done interrupt is asserted, call RX call back function
316 * to handle the processed BDs and then raise the according flag.
318 regval = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET);
319 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET, regval);
321 resetrx_on_no_rxdata(xemacpsif);
325 bd_processed = XEmacPs_BdRingFromHwRx(rxring, XLWIP_CONFIG_N_RX_DESC, &rxbdset);
327 if (bd_processed <= 0) {
331 for (k = 0, CurBdPtr=rxbdset; k < bd_processed; k++) {
333 BdIndex = XEMACPS_BD_TO_INDEX(rxring, CurBdPtr);
334 p = (struct pbuf *)rx_pbufs_storage[BdIndex];
337 * Adjust the buffer size to the actual number of bytes received.
339 rx_bytes = XEmacPs_BdGetLength(CurBdPtr);
340 pbuf_realloc(p, rx_bytes);
341 Xil_DCacheInvalidateRange((unsigned int)p->payload, (unsigned)XEMACPS_MAX_FRAME_SIZE);
342 /* store it in the receive queue,
343 * where it'll be processed by a different handler
345 if (pq_enqueue(xemacpsif->recv_q, (void*)p) < 0) {
347 lwip_stats.link.memerr++;
348 lwip_stats.link.drop++;
353 sys_sem_signal(&xemac->sem_rx_data_available);
356 CurBdPtr = XEmacPs_BdRingNext( rxring, CurBdPtr);
358 /* free up the BD's */
359 XEmacPs_BdRingFree(rxring, bd_processed, rxbdset);
360 setup_rx_bds(rxring);
363 #ifdef OS_IS_FREERTOS
369 void clean_dma_txdescs(struct xemac_s *xemac)
371 XEmacPs_Bd BdTemplate;
372 XEmacPs_BdRing *TxRingPtr;
373 xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
375 TxRingPtr = &XEmacPs_GetTxRing(&xemacpsif->emacps);
377 XEmacPs_BdClear(&BdTemplate);
378 XEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK);
381 * Create the TxBD ring
383 XEmacPs_BdRingCreate(TxRingPtr, (u32) xemacpsif->tx_bdspace,
384 (u32) xemacpsif->tx_bdspace, BD_ALIGNMENT,
385 XLWIP_CONFIG_N_TX_DESC);
386 XEmacPs_BdRingClone(TxRingPtr, &BdTemplate, XEMACPS_SEND);
390 XStatus init_dma(struct xemac_s *xemac)
392 XEmacPs_Bd BdTemplate;
393 XEmacPs_BdRing *RxRingPtr, *TxRingPtr;
398 unsigned int BdIndex;
399 char *endAdd = &_end;
401 * Align the BD starte address to 1 MB boundary.
403 char *endAdd_aligned = (char *)(((int)endAdd + 0x100000) & (~0xFFFFF));
404 xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
405 struct xtopology_t *xtopologyp = &xtopology[xemac->topology_index];
408 * The BDs need to be allocated in uncached memory. Hence the 1 MB
409 * address range that starts at address 0xFF00000 is made uncached
410 * by setting appropriate attributes in the translation table.
412 Xil_SetTlbAttributes((int)endAdd_aligned, 0xc02); // addr, attr
414 RxRingPtr = &XEmacPs_GetRxRing(&xemacpsif->emacps);
415 TxRingPtr = &XEmacPs_GetTxRing(&xemacpsif->emacps);
416 LWIP_DEBUGF(NETIF_DEBUG, ("RxRingPtr: 0x%08x\r\n", RxRingPtr));
417 LWIP_DEBUGF(NETIF_DEBUG, ("TxRingPtr: 0x%08x\r\n", TxRingPtr));
419 xemacpsif->rx_bdspace = (void *)endAdd_aligned;
421 * We allocate 65536 bytes for Rx BDs which can accomodate a
422 * maximum of 8192 BDs which is much more than any application
425 xemacpsif->tx_bdspace = (void *)(endAdd_aligned + 0x10000);
427 LWIP_DEBUGF(NETIF_DEBUG, ("rx_bdspace: 0x%08x\r\n", xemacpsif->rx_bdspace));
428 LWIP_DEBUGF(NETIF_DEBUG, ("tx_bdspace: 0x%08x\r\n", xemacpsif->tx_bdspace));
430 if (!xemacpsif->rx_bdspace || !xemacpsif->tx_bdspace) {
431 xil_printf("%s@%d: Error: Unable to allocate memory for TX/RX buffer descriptors",
439 * Setup a BD template for the Rx channel. This template will be copied to
440 * every RxBD. We will not have to explicitly set these again.
442 XEmacPs_BdClear(&BdTemplate);
445 * Create the RxBD ring
448 Status = XEmacPs_BdRingCreate(RxRingPtr, (u32) xemacpsif->rx_bdspace,
449 (u32) xemacpsif->rx_bdspace, BD_ALIGNMENT,
450 XLWIP_CONFIG_N_RX_DESC);
452 if (Status != XST_SUCCESS) {
453 LWIP_DEBUGF(NETIF_DEBUG, ("Error setting up RxBD space\r\n"));
457 Status = XEmacPs_BdRingClone(RxRingPtr, &BdTemplate, XEMACPS_RECV);
458 if (Status != XST_SUCCESS) {
459 LWIP_DEBUGF(NETIF_DEBUG, ("Error initializing RxBD space\r\n"));
463 XEmacPs_BdClear(&BdTemplate);
464 XEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK);
466 * Create the TxBD ring
468 Status = XEmacPs_BdRingCreate(TxRingPtr, (u32) xemacpsif->tx_bdspace,
469 (u32) xemacpsif->tx_bdspace, BD_ALIGNMENT,
470 XLWIP_CONFIG_N_TX_DESC);
472 if (Status != XST_SUCCESS) {
476 /* We reuse the bd template, as the same one will work for both rx and tx. */
477 Status = XEmacPs_BdRingClone(TxRingPtr, &BdTemplate, XEMACPS_SEND);
478 if (Status != XST_SUCCESS) {
483 * Allocate RX descriptors, 1 RxBD at a time.
485 for (i = 0; i < XLWIP_CONFIG_N_RX_DESC; i++) {
486 Status = XEmacPs_BdRingAlloc(RxRingPtr, 1, &rxbd);
487 if (Status != XST_SUCCESS) {
488 LWIP_DEBUGF(NETIF_DEBUG, ("init_dma: Error allocating RxBD\r\n"));
492 p = pbuf_alloc(PBUF_RAW, XEMACPS_MAX_FRAME_SIZE, PBUF_POOL);
495 lwip_stats.link.memerr++;
496 lwip_stats.link.drop++;
498 LWIP_DEBUGF(NETIF_DEBUG, ("unable to alloc pbuf in recv_handler\r\n"));
502 XEmacPs_BdSetAddressRx(rxbd, (u32)p->payload);
504 BdIndex = XEMACPS_BD_TO_INDEX(RxRingPtr, rxbd);
505 rx_pbufs_storage[BdIndex] = (int)p;
508 Status = XEmacPs_BdRingToHw(RxRingPtr, 1, rxbd);
509 if (Status != XST_SUCCESS) {
510 LWIP_DEBUGF(NETIF_DEBUG, ("Error: committing RxBD to HW\r\n"));
516 * Connect the device driver handler that will be called when an
517 * interrupt for the device occurs, the handler defined above performs
518 * the specific interrupt processing for the device.
520 XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,
521 (Xil_ExceptionHandler)XEmacPs_IntrHandler,
522 (void *)&xemacpsif->emacps);
524 * Enable the interrupt for emacps.
526 XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, (u32) xtopologyp->scugic_emac_intr);
527 EmacIntrNum = (u32) xtopologyp->scugic_emac_intr;
532 * resetrx_on_no_rxdata():
534 * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata
535 * called by the user.
536 * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.
537 * Under heavy Rx traffic because of the HW bug there are times when the Rx path
538 * becomes unresponsive. The workaround for it is to check for the Rx path for
539 * traffic (by reading the stats registers regularly). If the stats register
540 * does not increment for sometime (proving no Rx traffic), the function resets
545 void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)
547 unsigned long regctrl;
548 unsigned long tempcntr;
550 tempcntr = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET);
551 if ((!tempcntr) && (!(xemacpsif->last_rx_frms_cntr))) {
552 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
553 XEMACPS_NWCTRL_OFFSET);
554 regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);
555 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
556 XEMACPS_NWCTRL_OFFSET, regctrl);
557 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);
558 regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);
559 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);
561 xemacpsif->last_rx_frms_cntr = tempcntr;
564 void FreeTxRxPBufs(void)
569 for (Index = 0; Index < XLWIP_CONFIG_N_TX_DESC; Index++) {
570 if (tx_pbufs_storage[Index] != 0) {
571 p = (struct pbuf *)tx_pbufs_storage[Index];
573 tx_pbufs_storage[Index] = 0;
577 for (Index = 0; Index < XLWIP_CONFIG_N_RX_DESC; Index++) {
578 p = (struct pbuf *)rx_pbufs_storage[Index];
584 void FreeOnlyTxPBufs(void)
589 for (Index = 0; Index < XLWIP_CONFIG_N_TX_DESC; Index++) {
590 if (tx_pbufs_storage[Index] != 0) {
591 p = (struct pbuf *)tx_pbufs_storage[Index];
593 tx_pbufs_storage[Index] = 0;
598 void EmacDisableIntr(void)
600 XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, EmacIntrNum);
603 void EmacEnableIntr(void)
605 XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, EmacIntrNum);