obsw/bsp_z7/lwip/netif/xaxiemacif_fifo.c

367 lines
11 KiB
C

/*
* Copyright (C) 2010 - 2022 Xilinx, Inc.
* Copyright (C) 2022 - 2024 Advanced Micro Devices, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include "lwipopts.h"
#if !NO_SYS
#include "FreeRTOS.h"
#include "semphr.h"
#include "timers.h"
#include "lwip/sys.h"
#endif
#include "lwip/stats.h"
#include "netif/xadapter.h"
#include "netif/xaxiemacif.h"
#if XLWIP_CONFIG_INCLUDE_AXIETH_ON_ZYNQ == 1
#include "xscugic.h"
#else
#include "xintc_l.h"
#endif
#if XLWIP_CONFIG_INCLUDE_AXIETH_ON_ZYNQ == 1
#define AXIFIFO_INTR_PRIORITY_SET_IN_GIC 0xA0
#define AXIETH_INTR_PRIORITY_SET_IN_GIC 0xA0
#define TRIG_TYPE_RISING_EDGE_SENSITIVE 0x3
#define INTC_DIST_BASE_ADDR XPAR_SCUGIC_DIST_BASEADDR
#endif
#include "xstatus.h"
#include "xaxiemacif_fifo.h"
#include "xlwipconfig.h"
#if XPAR_INTC_0_HAS_FAST == 1
/*********** Function Prototypes *********************************************/
/*
* Function prototypes of the functions used for registering Fast
* Interrupt Handlers
*/
static void xllfifo_fastintr_handler(void) __attribute__ ((fast_interrupt));
static void xaxiemac_fasterror_handler(void) __attribute__ ((fast_interrupt));
/**************** Variable Declarations **************************************/
/** Variables for Fast Interrupt handlers ***/
struct xemac_s *xemac_fast;
xaxiemacif_s *xaxiemacif_fast;
#endif
#if !NO_SYS
extern u32 xInsideISR;
#endif
int xaxiemac_is_tx_space_available(xaxiemacif_s *emac)
{
return ((XLlFifo_TxVacancy(&emac->axififo) * 4) > XAE_MAX_FRAME_SIZE);
}
static void
xllfifo_recv_handler(struct xemac_s *xemac)
{
u32_t frame_length;
struct pbuf *p;
xaxiemacif_s *xaxiemacif = (xaxiemacif_s *)(xemac->state);
XLlFifo *llfifo = &xaxiemacif->axififo;
/* While there is data in the fifo ... */
while (XLlFifo_RxOccupancy(llfifo)) {
/* find packet length */
frame_length = XLlFifo_RxGetLen(llfifo);
/* allocate a pbuf */
p = pbuf_alloc(PBUF_RAW, frame_length, PBUF_POOL);
if (!p) {
char tmp_frame[XAE_MAX_FRAME_SIZE];
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif
/* receive and drop packet to keep data & len registers in sync */
XLlFifo_Read(llfifo, tmp_frame, frame_length);
continue;
}
/* receive packet */
XLlFifo_Read(llfifo, p->payload, frame_length);
#if ETH_PAD_SIZE
len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
#endif
/* store it in the receive queue, where it'll be processed by xemacif input thread */
if (pq_enqueue(xaxiemacif->recv_q, (void*)p) < 0) {
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif
pbuf_free(p);
continue;
}
#if !NO_SYS
sys_sem_signal(&xemac->sem_rx_data_available);
#endif
#if LINK_STATS
lwip_stats.link.recv++;
#endif
}
}
static void
fifo_error_handler(xaxiemacif_s *xaxiemacif, u32_t pending_intr)
{
XLlFifo *llfifo = &xaxiemacif->axififo;
if (pending_intr & XLLF_INT_RPURE_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("llfifo: Rx under-read error"));
}
if (pending_intr & XLLF_INT_RPORE_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("llfifo: Rx over-read error"));
}
if (pending_intr & XLLF_INT_RPUE_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("llfifo: Rx fifo empty"));
}
if (pending_intr & XLLF_INT_TPOE_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("llfifo: Tx fifo overrun"));
}
if (pending_intr & XLLF_INT_TSE_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("llfifo: Tx length mismatch"));
}
/* Reset the tx or rx side of the fifo as needed */
if (pending_intr & XLLF_INT_RXERROR_MASK) {
XLlFifo_IntClear(llfifo, XLLF_INT_RRC_MASK);
XLlFifo_RxReset(llfifo);
}
if (pending_intr & XLLF_INT_TXERROR_MASK) {
XLlFifo_IntClear(llfifo, XLLF_INT_TRC_MASK);
XLlFifo_TxReset(llfifo);
}
}
static void
xllfifo_intr_handler(struct xemac_s *xemac)
{
xaxiemacif_s *xaxiemacif = (xaxiemacif_s *)(xemac->state);
XLlFifo *llfifo = &xaxiemacif->axififo;
u32_t pending_fifo_intr = XLlFifo_IntPending(llfifo);
#if !NO_SYS
xInsideISR++;
#endif
while (pending_fifo_intr) {
if (pending_fifo_intr & XLLF_INT_RC_MASK) {
/* receive interrupt */
XLlFifo_IntClear(llfifo, XLLF_INT_RC_MASK);
xllfifo_recv_handler(xemac);
} else if (pending_fifo_intr & XLLF_INT_TC_MASK) {
/* tx intr */
XLlFifo_IntClear(llfifo, XLLF_INT_TC_MASK);
} else {
XLlFifo_IntClear(llfifo, XLLF_INT_ALL_MASK &
~(XLLF_INT_RC_MASK |
XLLF_INT_TC_MASK));
fifo_error_handler(xaxiemacif, pending_fifo_intr);
}
pending_fifo_intr = XLlFifo_IntPending(llfifo);
}
#if !NO_SYS
xInsideISR--;
#endif
}
XStatus init_axi_fifo(struct xemac_s *xemac)
{
xaxiemacif_s *xaxiemacif = (xaxiemacif_s *)(xemac->state);
#if XPAR_INTC_0_HAS_FAST == 1
xaxiemacif_fast = xaxiemacif;
xemac_fast = xemac;
#endif
struct xtopology_t *xtopologyp = &xtopology[xemac->topology_index];
/* initialize ll fifo */
XLlFifo_Initialize(&xaxiemacif->axififo,
XAxiEthernet_AxiDevBaseAddress(&xaxiemacif->axi_ethernet));
/* Clear any pending FIFO interrupts */
XLlFifo_IntClear(&xaxiemacif->axififo, XLLF_INT_ALL_MASK);
/* enable fifo interrupts */
XLlFifo_IntEnable(&xaxiemacif->axififo, XLLF_INT_ALL_MASK);
#if XLWIP_CONFIG_INCLUDE_AXIETH_ON_ZYNQ == 1
XScuGic_RegisterHandler(xtopologyp->scugic_baseaddr,
xaxiemacif->axi_ethernet.Config.TemacIntr,
(XInterruptHandler)xaxiemac_error_handler,
&xaxiemacif->axi_ethernet);
XScuGic_RegisterHandler(xtopologyp->scugic_baseaddr,
xaxiemacif->axi_ethernet.Config.AxiFifoIntr,
(XInterruptHandler)xllfifo_intr_handler,
xemac);
XScuGic_SetPriTrigTypeByDistAddr(INTC_DIST_BASE_ADDR,
xaxiemacif->axi_ethernet.Config.TemacIntr,
AXIETH_INTR_PRIORITY_SET_IN_GIC,
TRIG_TYPE_RISING_EDGE_SENSITIVE);
XScuGic_SetPriTrigTypeByDistAddr(INTC_DIST_BASE_ADDR,
xaxiemacif->axi_ethernet.Config.AxiFifoIntr,
AXIFIFO_INTR_PRIORITY_SET_IN_GIC,
TRIG_TYPE_RISING_EDGE_SENSITIVE);
XScuGic_EnableIntr(INTC_DIST_BASE_ADDR,
xaxiemacif->axi_ethernet.Config.TemacIntr);
XScuGic_EnableIntr(INTC_DIST_BASE_ADDR,
xaxiemacif->axi_ethernet.Config.AxiFifoIntr);
#else
#if NO_SYS
#if XPAR_INTC_0_HAS_FAST == 1
/* Register temac interrupt with interrupt controller */
XIntc_RegisterFastHandler(xtopologyp->intc_baseaddr,
xaxiemacif->axi_ethernet.Config.TemacIntr,
(XFastInterruptHandler)xaxiemac_fasterror_handler);
/* connect & enable FIFO interrupt */
XIntc_RegisterFastHandler(xtopologyp->intc_baseaddr,
xaxiemacif->axi_ethernet.Config.AxiFifoIntr,
(XFastInterruptHandler)xllfifo_fastintr_handler);
#else
/* Register temac interrupt with interrupt controller */
XIntc_RegisterHandler(xtopologyp->intc_baseaddr,
xaxiemacif->axi_ethernet.Config.TemacIntr,
(XInterruptHandler)xaxiemac_error_handler,
&xaxiemacif->axi_ethernet);
/* connect & enable FIFO interrupt */
XIntc_RegisterHandler(xtopologyp->intc_baseaddr,
xaxiemacif->axi_ethernet.Config.AxiFifoIntr,
(XInterruptHandler)xllfifo_intr_handler,
xemac);
#endif
/* Enable EMAC interrupts in the interrupt controller */
do {
/* read current interrupt enable mask */
unsigned int cur_mask = XIntc_In32(xtopologyp->intc_baseaddr + XIN_IER_OFFSET);
/* form new mask enabling SDMA & ll_temac interrupts */
cur_mask = cur_mask
| (1 << xaxiemacif->axi_ethernet.Config.AxiFifoIntr)
| (1 << xaxiemacif->axi_ethernet.Config.TemacIntr);
/* set new mask */
XIntc_EnableIntr(xtopologyp->intc_baseaddr, cur_mask);
} while (0);
#else
#if XPAR_INTC_0_HAS_FAST == 1
/* Register temac interrupt with interrupt controller */
XIntc_RegisterFastHandler(xtopologyp->intc_baseaddr,
xaxiemacif->axi_ethernet.Config.TemacIntr,
(XFastInterruptHandler)xaxiemac_fasterror_handler);
/* connect & enable FIFO interrupt */
XIntc_RegisterFastHandler(xtopologyp->intc_baseaddr,
xaxiemacif->axi_ethernet.Config.AxiFifoIntr,
(XFastInterruptHandler)xllfifo_fastintr_handler);
#else
/* Register temac interrupt with interrupt controller */
XIntc_RegisterHandler(xtopologyp->intc_baseaddr,
xaxiemacif->axi_ethernet.Config.TemacIntr,
(XInterruptHandler)xaxiemac_error_handler,
&xaxiemacif->axi_ethernet);
/* connect & enable FIFO interrupt */
XIntc_RegisterHandler(xtopologyp->intc_baseaddr,
xaxiemacif->axi_ethernet.Config.AxiFifoIntr,
(XInterruptHandler)xllfifo_intr_handler,
xemac);
#endif
/* Enable EMAC interrupts in the interrupt controller */
do {
/* read current interrupt enable mask */
unsigned int cur_mask = XIntc_In32(xtopologyp->intc_baseaddr + XIN_IER_OFFSET);
/* form new mask enabling SDMA & ll_temac interrupts */
cur_mask = cur_mask
| (1 << xaxiemacif->axi_ethernet.Config.AxiFifoIntr)
| (1 << xaxiemacif->axi_ethernet.Config.TemacIntr);
/* set new mask */
XIntc_EnableIntr(xtopologyp->intc_baseaddr, cur_mask);
} while (0);
#endif
#endif
return 0;
}
XStatus axififo_send(xaxiemacif_s *xaxiemacif, struct pbuf *p)
{
XLlFifo *llfifo = &xaxiemacif->axififo;
u32_t l = 0;
struct pbuf *q;
for(q = p; q != NULL; q = q->next) {
/* write frame data to FIFO */
XLlFifo_Write(llfifo, q->payload, q->len);
l += q->len;
}
/* initiate transmit */
XLlFifo_TxSetLen(llfifo, l);
return 0;
}
#if XPAR_INTC_0_HAS_FAST == 1
/*********** Fast Error Handler ********************************************/
void xaxiemac_fasterror_handler(void)
{
xaxiemac_error_handler(&xaxiemacif_fast->axi_ethernet);
}
/********** Fast Interrupt handler *****************************************/
void xllfifo_fastintr_handler(void)
{
xllfifo_intr_handler(xemac_fast);
}
#endif