summaryrefslogtreecommitdiff
path: root/embeddedsw/ThirdParty/sw_services/lwip211/src
diff options
context:
space:
mode:
Diffstat (limited to 'embeddedsw/ThirdParty/sw_services/lwip211/src')
-rw-r--r--embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xadapter.h87
-rw-r--r--embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xemacpsif.h166
-rw-r--r--embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xpqueue.h54
-rw-r--r--embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xtopology.h60
-rw-r--r--embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xadapter.c425
-rw-r--r--embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemac_ieee_reg.h101
-rw-r--r--embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif.c795
-rw-r--r--embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif_dma.c930
-rw-r--r--embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif_hw.c276
-rw-r--r--embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif_physpeed.c1037
-rw-r--r--embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xpqueue.c93
11 files changed, 4024 insertions, 0 deletions
diff --git a/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xadapter.h b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xadapter.h
new file mode 100644
index 0000000..4d32b7f
--- /dev/null
+++ b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xadapter.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 - 2021 Xilinx, 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.
+ *
+ */
+
+#ifndef __XADAPTER_H_
+#define __XADAPTER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "lwipopts.h"
+
+#if !NO_SYS
+#include "lwip/sys.h"
+#endif
+
+#include "lwip/netif.h"
+#include "lwip/ip.h"
+
+#include "netif/xtopology.h"
+
+struct xemac_s {
+ enum xemac_types type;
+ int topology_index;
+ void *state;
+#if !NO_SYS
+ sys_sem_t sem_rx_data_available;
+#if defined(__arm__) && !defined(ARMR5)
+ TimerHandle_t xTimer;
+#endif
+#endif
+};
+
+enum ethernet_link_status {
+ ETH_LINK_UNDEFINED = 0,
+ ETH_LINK_UP,
+ ETH_LINK_DOWN,
+ ETH_LINK_NEGOTIATING
+};
+
+void eth_link_detect(struct netif *netif);
+void lwip_raw_init();
+int xemacif_input(struct netif *netif);
+void xemacif_input_thread(struct netif *netif);
+struct netif * xemac_add(struct netif *netif,
+ ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw,
+ unsigned char *mac_ethernet_address,
+ UINTPTR mac_baseaddr);
+#if defined (__arm__) || defined (__aarch64__)
+void xemacpsif_resetrx_on_no_rxdata(struct netif *netif);
+#endif
+
+/* global lwip debug variable used for debugging */
+extern int lwip_runtime_debug;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xemacpsif.h b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xemacpsif.h
new file mode 100644
index 0000000..f108920
--- /dev/null
+++ b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xemacpsif.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2010 - 2019 Xilinx, 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.
+ *
+ */
+
+#ifndef __NETIF_XEMACPSIF_H__
+#define __NETIF_XEMACPSIF_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "xlwipconfig.h"
+#include "lwip/netif.h"
+#include "netif/etharp.h"
+#include "lwip/sys.h"
+#include "netif/xadapter.h"
+
+#include "xstatus.h"
+#include "sleep.h"
+#include "xparameters.h"
+#include "xparameters_ps.h" /* defines XPAR values */
+#include "xil_types.h"
+#include "xil_assert.h"
+#include "xil_io.h"
+#include "xil_exception.h"
+#include "xpseudo_asm.h"
+#include "xil_cache.h"
+#include "xil_printf.h"
+#include "xscugic.h"
+#include "xemacps.h" /* defines XEmacPs API */
+
+#include "netif/xpqueue.h"
+#include "xlwipconfig.h"
+
+#if defined (__aarch64__) && (EL1_NONSECURE == 1)
+#include "xil_smc.h"
+#endif
+
+#define ZYNQ_EMACPS_0_BASEADDR 0xE000B000
+#define ZYNQ_EMACPS_1_BASEADDR 0xE000C000
+
+#define ZYNQMP_EMACPS_0_BASEADDR 0xFF0B0000
+#define ZYNQMP_EMACPS_1_BASEADDR 0xFF0C0000
+#define ZYNQMP_EMACPS_2_BASEADDR 0xFF0D0000
+#define ZYNQMP_EMACPS_3_BASEADDR 0xFF0E0000
+
+#define CRL_APB_GEM0_REF_CTRL 0xFF5E0050
+#define CRL_APB_GEM1_REF_CTRL 0xFF5E0054
+#define CRL_APB_GEM2_REF_CTRL 0xFF5E0058
+#define CRL_APB_GEM3_REF_CTRL 0xFF5E005C
+
+#define CRL_APB_GEM_DIV0_MASK 0x00003F00
+#define CRL_APB_GEM_DIV0_SHIFT 8
+#define CRL_APB_GEM_DIV1_MASK 0x003F0000
+#define CRL_APB_GEM_DIV1_SHIFT 16
+
+#define VERSAL_EMACPS_0_BASEADDR 0xFF0C0000
+#define VERSAL_EMACPS_1_BASEADDR 0xFF0D0000
+
+#define VERSAL_CRL_GEM0_REF_CTRL 0xFF5E0118
+#define VERSAL_CRL_GEM1_REF_CTRL 0xFF5E011C
+
+#define VERSAL_CRL_GEM_DIV_MASK 0x0003FF00
+#define VERSAL_CRL_APB_GEM_DIV_SHIFT 8
+
+#if defined (ARMR5) || (__aarch64__) || (ARMA53_32) || (__MICROBLAZE__)
+#if defined (USE_JUMBO_FRAMES)
+#define ZYNQMP_USE_JUMBO
+#endif
+#endif
+
+#define GEM_VERSION_ZYNQMP 7
+#define GEM_VERSION_VERSAL 0x107
+
+#define MAX_FRAME_SIZE_JUMBO (XEMACPS_MTU_JUMBO + XEMACPS_HDR_SIZE + XEMACPS_TRL_SIZE)
+
+void xemacpsif_setmac(u32_t index, u8_t *addr);
+u8_t* xemacpsif_getmac(u32_t index);
+err_t xemacpsif_init(struct netif *netif);
+s32_t xemacpsif_input(struct netif *netif);
+
+/* xaxiemacif_hw.c */
+void xemacps_error_handler(XEmacPs * Temac);
+
+/* structure within each netif, encapsulating all information required for
+ * using a particular temac instance
+ */
+typedef struct {
+ XEmacPs emacps;
+
+ /* queue to store overflow packets */
+ pq_queue_t *recv_q;
+ pq_queue_t *send_q;
+
+ /* pointers to memory holding buffer descriptors (used only with SDMA) */
+ void *rx_bdspace;
+ void *tx_bdspace;
+
+ unsigned int last_rx_frms_cntr;
+
+} xemacpsif_s;
+
+extern xemacpsif_s xemacpsif;
+
+s32_t is_tx_space_available(xemacpsif_s *emac);
+
+/* xemacpsif_dma.c */
+
+void process_sent_bds(xemacpsif_s *xemacpsif, XEmacPs_BdRing *txring);
+u32_t phy_setup_emacps (XEmacPs *xemacpsp, u32_t phy_addr);
+void detect_phy(XEmacPs *xemacpsp);
+void emacps_send_handler(void *arg);
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+XStatus emacps_sgsend(xemacpsif_s *xemacpsif, struct pbuf *p,
+ u32_t block_till_tx_complete, u32_t *to_block_index);
+#else
+XStatus emacps_sgsend(xemacpsif_s *xemacpsif, struct pbuf *p);
+#endif
+void emacps_recv_handler(void *arg);
+void emacps_error_handler(void *arg,u8 Direction, u32 ErrorWord);
+void setup_rx_bds(xemacpsif_s *xemacpsif, XEmacPs_BdRing *rxring);
+void HandleTxErrors(struct xemac_s *xemac);
+void HandleEmacPsError(struct xemac_s *xemac);
+XEmacPs_Config *xemacps_lookup_config(unsigned mac_base);
+void init_emacps(xemacpsif_s *xemacps, struct netif *netif);
+void setup_isr (struct xemac_s *xemac);
+XStatus init_dma(struct xemac_s *xemac);
+void start_emacps (xemacpsif_s *xemacps);
+void free_txrx_pbufs(xemacpsif_s *xemacpsif);
+void free_onlytx_pbufs(xemacpsif_s *xemacpsif);
+void init_emacps_on_error (xemacpsif_s *xemacps, struct netif *netif);
+void clean_dma_txdescs(struct xemac_s *xemac);
+void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif);
+void reset_dma(struct xemac_s *xemac);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __NETIF_XAXIEMACIF_H__ */
diff --git a/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xpqueue.h b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xpqueue.h
new file mode 100644
index 0000000..132f02f
--- /dev/null
+++ b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xpqueue.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 - 2019 Xilinx, 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.
+ *
+ */
+
+#ifndef __LWIP_PBUF_QUEUE_H_
+#define __LWIP_PBUF_QUEUE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PQ_QUEUE_SIZE 4096
+
+typedef struct {
+ void *data[PQ_QUEUE_SIZE];
+ int head, tail, len;
+} pq_queue_t;
+
+pq_queue_t* pq_create_queue();
+int pq_enqueue(pq_queue_t *q, void *p);
+void* pq_dequeue(pq_queue_t *q);
+int pq_qlength(pq_queue_t *q);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xtopology.h b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xtopology.h
new file mode 100644
index 0000000..51718f1
--- /dev/null
+++ b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/include/netif/xtopology.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2007 - 2019 Xilinx, 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.
+ *
+ */
+
+#ifndef __XTOPOLOGY_H_
+#define __XTOPOLOGY_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "xil_types.h"
+
+enum xemac_types { xemac_type_unknown = -1, xemac_type_xps_emaclite, xemac_type_xps_ll_temac, xemac_type_axi_ethernet, xemac_type_emacps };
+
+struct xtopology_t {
+ UINTPTR emac_baseaddr;
+ enum xemac_types emac_type;
+ UINTPTR intc_baseaddr;
+ unsigned intc_emac_intr; /* valid only for xemac_type_xps_emaclite */
+ UINTPTR scugic_baseaddr; /* valid only for Zynq */
+ unsigned scugic_emac_intr; /* valid only for GEM */
+};
+
+extern int xtopology_n_emacs;
+extern struct xtopology_t xtopology[];
+
+int xtopology_find_index(unsigned base);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xadapter.c b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xadapter.c
new file mode 100644
index 0000000..9594ff5
--- /dev/null
+++ b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xadapter.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2007 - 2021 Xilinx, 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"
+#include "xlwipconfig.h"
+#include "xemac_ieee_reg.h"
+
+#if !NO_SYS
+#endif
+
+#include "lwip/mem.h"
+#include "lwip/stats.h"
+#include "lwip/sys.h"
+#include "lwip/ip.h"
+#include "lwip/tcp.h"
+#include "lwip/udp.h"
+#include "lwip/priv/tcp_priv.h"
+
+#include "netif/etharp.h"
+#include "netif/xadapter.h"
+
+#ifdef XLWIP_CONFIG_INCLUDE_EMACLITE
+#include "netif/xemacliteif.h"
+#endif
+
+#ifdef XLWIP_CONFIG_INCLUDE_AXI_ETHERNET
+#include "netif/xaxiemacif.h"
+#endif
+
+#ifdef XLWIP_CONFIG_INCLUDE_GEM
+#include "netif/xemacpsif.h"
+#endif
+
+#if !NO_SYS
+#include "lwip/tcpip.h"
+
+#define THREAD_STACKSIZE 256
+#define LINK_DETECT_THREAD_INTERVAL 1000 /* one second */
+
+void link_detect_thread(void *p);
+#endif
+
+/* global lwip debug variable used for debugging */
+int lwip_runtime_debug = 0;
+
+enum ethernet_link_status eth_link_status = ETH_LINK_UNDEFINED;
+u32_t phyaddrforemac;
+
+void
+lwip_raw_init()
+{
+ ip_init(); /* Doesn't do much, it should be called to handle future changes. */
+#if LWIP_UDP
+ udp_init(); /* Clears the UDP PCB list. */
+#endif
+#if LWIP_TCP
+ tcp_init(); /* Clears the TCP PCB list and clears some internal TCP timers. */
+ /* Note: you must call tcp_fasttmr() and tcp_slowtmr() at the */
+ /* predefined regular intervals after this initialization. */
+#endif
+}
+
+static enum xemac_types
+find_mac_type(unsigned base)
+{
+ int i;
+
+ for (i = 0; i < xtopology_n_emacs; i++) {
+ if (xtopology[i].emac_baseaddr == base)
+ return xtopology[i].emac_type;
+ }
+
+ return xemac_type_unknown;
+}
+
+int
+xtopology_find_index(unsigned base)
+{
+ int i;
+
+ for (i = 0; i < xtopology_n_emacs; i++) {
+ if (xtopology[i].emac_baseaddr == base)
+ return i;
+ }
+
+ return -1;
+}
+
+/*
+ * xemac_add: this is a wrapper around lwIP's netif_add function.
+ * The objective is to provide portability between the different Xilinx MAC's
+ * This function can be used to add both xps_ethernetlite and xps_ll_temac
+ * based interfaces
+ */
+struct netif *
+xemac_add(struct netif *netif,
+ ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw,
+ unsigned char *mac_ethernet_address,
+ UINTPTR mac_baseaddr)
+{
+ int i;
+
+#if !NO_SYS
+ /* Start thread to detect link periodically for Hot Plug autodetect */
+ sys_thread_new("link_detect_thread", link_detect_thread, netif,
+ THREAD_STACKSIZE, tskIDLE_PRIORITY);
+#endif
+
+ /* set mac address */
+ netif->hwaddr_len = 6;
+ for (i = 0; i < 6; i++)
+ netif->hwaddr[i] = mac_ethernet_address[i];
+
+ /* initialize based on MAC type */
+ switch (find_mac_type(mac_baseaddr)) {
+ case xemac_type_xps_emaclite:
+#ifdef XLWIP_CONFIG_INCLUDE_EMACLITE
+ return netif_add(netif, ipaddr, netmask, gw,
+ (void*)mac_baseaddr,
+ xemacliteif_init,
+#if NO_SYS
+ ethernet_input
+#else
+ tcpip_input
+#endif
+ );
+#else
+ return NULL;
+#endif
+ case xemac_type_axi_ethernet:
+#ifdef XLWIP_CONFIG_INCLUDE_AXI_ETHERNET
+ return netif_add(netif, ipaddr, netmask, gw,
+ (void*)mac_baseaddr,
+ xaxiemacif_init,
+#if NO_SYS
+ ethernet_input
+#else
+ tcpip_input
+#endif
+ );
+#else
+ return NULL;
+#endif
+#if defined (__arm__) || defined (__aarch64__)
+ case xemac_type_emacps:
+#ifdef XLWIP_CONFIG_INCLUDE_GEM
+ return netif_add(netif, ipaddr, netmask, gw,
+ (void*)mac_baseaddr,
+ xemacpsif_init,
+#if NO_SYS
+ ethernet_input
+#else
+ tcpip_input
+#endif
+
+ );
+#endif
+#endif
+ default:
+ xil_printf("unable to determine type of EMAC with baseaddress 0x%08x\r\n",
+ mac_baseaddr);
+ return NULL;
+ }
+}
+
+#if !NO_SYS
+/*
+ * The input thread calls lwIP to process any received packets.
+ * This thread waits until a packet is received (sem_rx_data_available),
+ * and then calls xemacif_input which processes 1 packet at a time.
+ */
+void
+xemacif_input_thread(struct netif *netif)
+{
+ struct xemac_s *emac = (struct xemac_s *)netif->state;
+ while (1) {
+ /* sleep until there are packets to process
+ * This semaphore is set by the packet receive interrupt
+ * routine.
+ */
+ sys_sem_wait(&emac->sem_rx_data_available);
+
+ /* move all received packets to lwIP */
+ xemacif_input(netif);
+ }
+}
+#endif
+
+int
+xemacif_input(struct netif *netif)
+{
+ struct xemac_s *emac = (struct xemac_s *)netif->state;
+
+ int n_packets = 0;
+
+ switch (emac->type) {
+ case xemac_type_xps_emaclite:
+#ifdef XLWIP_CONFIG_INCLUDE_EMACLITE
+ n_packets = xemacliteif_input(netif);
+ break;
+#else
+ print("incorrect configuration: xps_ethernetlite drivers not present?");
+ while(1);
+ return 0;
+#endif
+ case xemac_type_axi_ethernet:
+#ifdef XLWIP_CONFIG_INCLUDE_AXI_ETHERNET
+ n_packets = xaxiemacif_input(netif);
+ break;
+#else
+ print("incorrect configuration: axi_ethernet drivers not present?");
+ while(1);
+ return 0;
+#endif
+#if defined (__arm__) || defined (__aarch64__)
+ case xemac_type_emacps:
+#ifdef XLWIP_CONFIG_INCLUDE_GEM
+ n_packets = xemacpsif_input(netif);
+ break;
+#else
+ xil_printf("incorrect configuration: ps7_ethernet drivers not present?\r\n");
+ while(1);
+ return 0;
+#endif
+#endif
+ default:
+ print("incorrect configuration: unknown temac type");
+ while(1);
+ return 0;
+ }
+
+ return n_packets;
+}
+
+#if defined(XLWIP_CONFIG_INCLUDE_GEM)
+static u32_t phy_link_detect(XEmacPs *xemacp, u32_t phy_addr)
+{
+ u16_t status;
+
+ /* Read Phy Status register twice to get the confirmation of the current
+ * link status.
+ */
+ XEmacPs_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ XEmacPs_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+
+ if (status & IEEE_STAT_LINK_STATUS)
+ return 1;
+ return 0;
+}
+#elif defined(XLWIP_CONFIG_INCLUDE_AXI_ETHERNET)
+static u32_t phy_link_detect(XAxiEthernet *xemacp, u32_t phy_addr)
+{
+ u16_t status;
+
+ /* Read Phy Status register twice to get the confirmation of the current
+ * link status.
+ */
+ XAxiEthernet_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ XAxiEthernet_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+
+ if (status & IEEE_STAT_LINK_STATUS)
+ return 1;
+ return 0;
+}
+#elif defined(XLWIP_CONFIG_INCLUDE_EMACLITE)
+static u32_t phy_link_detect(XEmacLite *xemacp, u32_t phy_addr)
+{
+ u16_t status;
+
+ /* Read Phy Status register twice to get the confirmation of the current
+ * link status.
+ */
+ XEmacLite_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ XEmacLite_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+
+ if (status & IEEE_STAT_LINK_STATUS)
+ return 1;
+ return 0;
+}
+#endif
+
+#if defined(XLWIP_CONFIG_INCLUDE_GEM)
+static u32_t phy_autoneg_status(XEmacPs *xemacp, u32_t phy_addr)
+{
+ u16_t status;
+
+ /* Read Phy Status register twice to get the confirmation of the current
+ * link status.
+ */
+ XEmacPs_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ XEmacPs_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+
+ if (status & IEEE_STAT_AUTONEGOTIATE_COMPLETE)
+ return 1;
+ return 0;
+}
+#elif defined(XLWIP_CONFIG_INCLUDE_AXI_ETHERNET)
+static u32_t phy_autoneg_status(XAxiEthernet *xemacp, u32_t phy_addr)
+{
+ u16_t status;
+
+ /* Read Phy Status register twice to get the confirmation of the current
+ * link status.
+ */
+ XAxiEthernet_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ XAxiEthernet_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+
+ if (status & IEEE_STAT_AUTONEGOTIATE_COMPLETE)
+ return 1;
+ return 0;
+}
+#elif defined(XLWIP_CONFIG_INCLUDE_EMACLITE)
+static u32_t phy_autoneg_status(XEmacLite *xemacp, u32_t phy_addr)
+{
+ u16_t status;
+
+ /* Read Phy Status register twice to get the confirmation of the current
+ * link status.
+ */
+ XEmacLite_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ XEmacLite_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+
+ if (status & IEEE_STAT_AUTONEGOTIATE_COMPLETE)
+ return 1;
+ return 0;
+}
+#endif
+
+void eth_link_detect(struct netif *netif)
+{
+ u32_t link_speed, phy_link_status;
+ struct xemac_s *xemac = (struct xemac_s *)(netif->state);
+
+#if defined(XLWIP_CONFIG_INCLUDE_GEM)
+ xemacpsif_s *xemacs = (xemacpsif_s *)(xemac->state);
+ XEmacPs *xemacp = &xemacs->emacps;
+#elif defined(XLWIP_CONFIG_INCLUDE_AXI_ETHERNET)
+ xaxiemacif_s *xemacs = (xaxiemacif_s *)(xemac->state);
+ XAxiEthernet *xemacp = &xemacs->axi_ethernet;
+#elif defined(XLWIP_CONFIG_INCLUDE_EMACLITE)
+ xemacliteif_s *xemacs = (xemacliteif_s *)(xemac->state);
+ XEmacLite *xemacp = xemacs->instance;
+#endif
+
+ if ((xemacp->IsReady != (u32)XIL_COMPONENT_IS_READY) ||
+ (eth_link_status == ETH_LINK_UNDEFINED))
+ return;
+
+ phy_link_status = phy_link_detect(xemacp, phyaddrforemac);
+
+ if ((eth_link_status == ETH_LINK_UP) && (!phy_link_status))
+ eth_link_status = ETH_LINK_DOWN;
+
+ switch (eth_link_status) {
+ case ETH_LINK_UNDEFINED:
+ case ETH_LINK_UP:
+ return;
+ case ETH_LINK_DOWN:
+ netif_set_link_down(netif);
+ eth_link_status = ETH_LINK_NEGOTIATING;
+ xil_printf("Ethernet Link down\r\n");
+ break;
+ case ETH_LINK_NEGOTIATING:
+ if (phy_link_status &&
+ phy_autoneg_status(xemacp, phyaddrforemac)) {
+
+ /* Initiate Phy setup to get link speed */
+#if defined(XLWIP_CONFIG_INCLUDE_GEM)
+ link_speed = phy_setup_emacps(xemacp,
+ phyaddrforemac);
+ XEmacPs_SetOperatingSpeed(xemacp, link_speed);
+#elif defined(XLWIP_CONFIG_INCLUDE_AXI_ETHERNET)
+ link_speed = phy_setup_axiemac(xemacp);
+ XAxiEthernet_SetOperatingSpeed(xemacp,
+ link_speed);
+#endif
+ netif_set_link_up(netif);
+ eth_link_status = ETH_LINK_UP;
+ xil_printf("Ethernet Link up\r\n");
+ }
+ break;
+ }
+}
+
+#if !NO_SYS
+void link_detect_thread(void *p)
+{
+ struct netif *netif = (struct netif *) p;
+
+ while (1) {
+ /* Call eth_link_detect() every second to detect Ethernet link
+ * change.
+ */
+ eth_link_detect(netif);
+ vTaskDelay(LINK_DETECT_THREAD_INTERVAL / portTICK_RATE_MS);
+ }
+}
+#endif
diff --git a/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemac_ieee_reg.h b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemac_ieee_reg.h
new file mode 100644
index 0000000..4c240a9
--- /dev/null
+++ b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemac_ieee_reg.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2018 - 2019 Xilinx, 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.
+ *
+ */
+
+#ifndef __XEMAC_IEEE_REGS_H_
+#define __XEMAC_IEEE_REGS_H_
+
+/* Advertisement control register. */
+#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
+#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
+#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
+#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
+#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
+#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
+#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
+#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
+#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
+
+
+#define ADVERTISE_100_AND_10 (ADVERTISE_10FULL | ADVERTISE_100FULL | \
+ ADVERTISE_10HALF | ADVERTISE_100HALF)
+#define ADVERTISE_100 (ADVERTISE_100FULL | ADVERTISE_100HALF)
+#define ADVERTISE_10 (ADVERTISE_10FULL | ADVERTISE_10HALF)
+
+#define ADVERTISE_1000 0x0300
+
+
+#define IEEE_CONTROL_REG_OFFSET 0
+#define IEEE_STATUS_REG_OFFSET 1
+#define IEEE_AUTONEGO_ADVERTISE_REG 4
+#define IEEE_PARTNER_ABILITIES_1_REG_OFFSET 5
+#define IEEE_PARTNER_ABILITIES_2_REG_OFFSET 8
+#define IEEE_PARTNER_ABILITIES_3_REG_OFFSET 10
+#define IEEE_1000_ADVERTISE_REG_OFFSET 9
+#define IEEE_MMD_ACCESS_CONTROL_REG 13
+#define IEEE_MMD_ACCESS_ADDRESS_DATA_REG 14
+#define IEEE_COPPER_SPECIFIC_CONTROL_REG 16
+#define IEEE_SPECIFIC_STATUS_REG 17
+#define IEEE_COPPER_SPECIFIC_STATUS_REG_2 19
+#define IEEE_EXT_PHY_SPECIFIC_CONTROL_REG 20
+#define IEEE_CONTROL_REG_MAC 21
+#define IEEE_PAGE_ADDRESS_REGISTER 22
+
+#define IEEE_CTRL_1GBPS_LINKSPEED_MASK 0x2040
+#define IEEE_CTRL_LINKSPEED_MASK 0x0040
+#define IEEE_CTRL_LINKSPEED_1000M 0x0040
+#define IEEE_CTRL_LINKSPEED_100M 0x2000
+#define IEEE_CTRL_LINKSPEED_10M 0x0000
+#define IEEE_CTRL_FULL_DUPLEX 0x100
+#define IEEE_CTRL_RESET_MASK 0x8000
+#define IEEE_CTRL_AUTONEGOTIATE_ENABLE 0x1000
+#define IEEE_STAT_AUTONEGOTIATE_CAPABLE 0x0008
+#define IEEE_STAT_AUTONEGOTIATE_COMPLETE 0x0020
+#define IEEE_STAT_AUTONEGOTIATE_RESTART 0x0200
+#define IEEE_STAT_LINK_STATUS 0x0004
+#define IEEE_STAT_1GBPS_EXTENSIONS 0x0100
+#define IEEE_AN1_ABILITY_MASK 0x1FE0
+#define IEEE_AN3_ABILITY_MASK_1GBPS 0x0C00
+#define IEEE_AN1_ABILITY_MASK_100MBPS 0x0380
+#define IEEE_AN1_ABILITY_MASK_10MBPS 0x0060
+#define IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK 0x0030
+
+#define IEEE_SPEED_MASK 0xC000
+#define IEEE_SPEED_1000 0x8000
+#define IEEE_SPEED_100 0x4000
+
+#define IEEE_ASYMMETRIC_PAUSE_MASK 0x0800
+#define IEEE_PAUSE_MASK 0x0400
+#define IEEE_AUTONEG_ERROR_MASK 0x8000
+
+#define IEEE_MMD_ACCESS_CTRL_DEVAD_MASK 0x1F
+#define IEEE_MMD_ACCESS_CTRL_PIDEVAD_MASK 0x801F
+#define IEEE_MMD_ACCESS_CTRL_NOPIDEVAD_MASK 0x401F
+
+#endif /* __XEMAC_IEEE_REGS_H_ */
diff --git a/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif.c b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif.c
new file mode 100644
index 0000000..1bf3abb
--- /dev/null
+++ b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif.c
@@ -0,0 +1,795 @@
+/*
+ * Copyright (C) 2010 - 2021 Xilinx, 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 <stdio.h>
+#include <string.h>
+
+#include <xparameters.h>
+#include "lwipopts.h"
+#include "xlwipconfig.h"
+#include "lwip/opt.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/pbuf.h"
+#include "lwip/sys.h"
+#include "lwip/stats.h"
+#include "lwip/igmp.h"
+
+#include "netif/etharp.h"
+#include "netif/xemacpsif.h"
+#include "netif/xadapter.h"
+#include "netif/xpqueue.h"
+#include "xparameters.h"
+#include "xscugic.h"
+#include "xemacps.h"
+
+#if LWIP_IPV6
+#include "lwip/ethip6.h"
+#endif
+
+
+/* Define those to better describe your network interface. */
+#define IFNAME0 't'
+#define IFNAME1 'e'
+
+#if LWIP_IGMP
+static err_t xemacpsif_mac_filter_update (struct netif *netif,
+ ip_addr_t *group, u8_t action);
+
+static u8_t xemacps_mcast_entry_mask = 0;
+#endif
+
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+static err_t xemacpsif_mld6_mac_filter_update (struct netif *netif,
+ ip_addr_t *group, u8_t action);
+
+static u8_t xemacps_mld6_mcast_entry_mask;
+#endif
+
+XEmacPs_Config *mac_config;
+struct netif *NetIf;
+
+#if !NO_SYS
+#if defined(__arm__) && !defined(ARMR5)
+int32_t lExpireCounter = 0;
+#define RESETRXTIMEOUT 10
+#endif
+#endif
+
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+extern volatile u32_t notifyinfo[4*XLWIP_CONFIG_N_TX_DESC];
+#endif
+
+/*
+ * this function is always called with interrupts off
+ * this function also assumes that there are available BD's
+ */
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+static err_t _unbuffered_low_level_output(xemacpsif_s *xemacpsif,
+ struct pbuf *p, u32_t block_till_tx_complete, u32_t *to_block_index )
+#else
+static err_t _unbuffered_low_level_output(xemacpsif_s *xemacpsif,
+ struct pbuf *p)
+#endif
+{
+ XStatus status = 0;
+ err_t err = ERR_MEM;
+
+#if ETH_PAD_SIZE
+ pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
+#endif
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+ if (block_till_tx_complete == 1) {
+ status = emacps_sgsend(xemacpsif, p, 1, to_block_index);
+ } else {
+ status = emacps_sgsend(xemacpsif, p, 0, to_block_index);
+ }
+#else
+ status = emacps_sgsend(xemacpsif, p);
+#endif
+ if (status != XST_SUCCESS) {
+#if LINK_STATS
+ lwip_stats.link.drop++;
+#endif
+ } else {
+ err = ERR_OK;
+ }
+
+#if ETH_PAD_SIZE
+ pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
+#endif
+
+#if LINK_STATS
+ lwip_stats.link.xmit++;
+#endif /* LINK_STATS */
+
+ return err;
+
+}
+
+/*
+ * low_level_output():
+ *
+ * Should do the actual transmission of the packet. The packet is
+ * contained in the pbuf that is passed to the function. This pbuf
+ * might be chained.
+ *
+ */
+
+static err_t low_level_output(struct netif *netif, struct pbuf *p)
+{
+ err_t err = ERR_MEM;
+ s32_t freecnt;
+ XEmacPs_BdRing *txring;
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+ u32_t notfifyblocksleepcntr;
+ u32_t to_block_index;
+#endif
+
+ SYS_ARCH_DECL_PROTECT(lev);
+ struct xemac_s *xemac = (struct xemac_s *)(netif->state);
+ xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
+
+ SYS_ARCH_PROTECT(lev);
+ /* check if space is available to send */
+ freecnt = is_tx_space_available(xemacpsif);
+ if (freecnt <= 5) {
+ txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
+ process_sent_bds(xemacpsif, txring);
+ }
+
+ if (is_tx_space_available(xemacpsif)) {
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+ if (netif_is_opt_block_tx_set(netif, NETIF_ENABLE_BLOCKING_TX_FOR_PACKET)) {
+ err = _unbuffered_low_level_output(xemacpsif, p, 1, &to_block_index);
+ } else {
+ err = _unbuffered_low_level_output(xemacpsif, p, 0, &to_block_index);
+ }
+#else
+ err = _unbuffered_low_level_output(xemacpsif, p);
+#endif
+ } else {
+#if LINK_STATS
+ lwip_stats.link.drop++;
+#endif
+ printf("pack dropped, no space\r\n");
+ SYS_ARCH_UNPROTECT(lev);
+ goto return_pack_dropped;
+ }
+ SYS_ARCH_UNPROTECT(lev);
+
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+ if (netif_is_opt_block_tx_set(netif, NETIF_ENABLE_BLOCKING_TX_FOR_PACKET)) {
+ /* Wait for approx 1 second before timing out */
+ notfifyblocksleepcntr = 900000;
+ while(notifyinfo[to_block_index] == 1) {
+ usleep(1);
+ notfifyblocksleepcntr--;
+ if (notfifyblocksleepcntr <= 0) {
+ err = ERR_TIMEOUT;
+ break;
+ }
+ }
+ }
+ netif_clear_opt_block_tx(netif, NETIF_ENABLE_BLOCKING_TX_FOR_PACKET);
+#endif
+return_pack_dropped:
+ return err;
+}
+
+/*
+ * low_level_input():
+ *
+ * Should allocate a pbuf and transfer the bytes of the incoming
+ * packet from the interface into the pbuf.
+ *
+ */
+static struct pbuf * low_level_input(struct netif *netif)
+{
+ struct xemac_s *xemac = (struct xemac_s *)(netif->state);
+ xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
+ struct pbuf *p;
+
+ /* see if there is data to process */
+ if (pq_qlength(xemacpsif->recv_q) == 0)
+ return NULL;
+
+ /* return one packet from receive q */
+ p = (struct pbuf *)pq_dequeue(xemacpsif->recv_q);
+ return p;
+}
+
+/*
+ * xemacpsif_output():
+ *
+ * This function is called by the TCP/IP stack when an IP packet
+ * should be sent. It calls the function called low_level_output() to
+ * do the actual transmission of the packet.
+ *
+ */
+
+static err_t xemacpsif_output(struct netif *netif, struct pbuf *p,
+ const ip_addr_t *ipaddr)
+{
+ /* resolve hardware address, then send (or queue) packet */
+ return etharp_output(netif, p, ipaddr);
+}
+
+/*
+ * xemacpsif_input():
+ *
+ * This function should be called when a packet is ready to be read
+ * from the interface. It uses the function low_level_input() that
+ * should handle the actual reception of bytes from the network
+ * interface.
+ *
+ * Returns the number of packets read (max 1 packet on success,
+ * 0 if there are no packets)
+ *
+ */
+
+s32_t xemacpsif_input(struct netif *netif)
+{
+ struct eth_hdr *ethhdr;
+ struct pbuf *p;
+ SYS_ARCH_DECL_PROTECT(lev);
+
+#if !NO_SYS
+ while (1)
+#endif
+ {
+ /* move received packet into a new pbuf */
+ SYS_ARCH_PROTECT(lev);
+ p = low_level_input(netif);
+ SYS_ARCH_UNPROTECT(lev);
+
+ /* no packet could be read, silently ignore this */
+ if (p == NULL) {
+ return 0;
+ }
+
+ /* points to packet payload, which starts with an Ethernet header */
+ ethhdr = p->payload;
+
+ #if LINK_STATS
+ lwip_stats.link.recv++;
+ #endif /* LINK_STATS */
+
+ switch (htons(ethhdr->type)) {
+ /* IP or ARP packet? */
+ case ETHTYPE_IP:
+ case ETHTYPE_ARP:
+ #if LWIP_IPV6
+ /*IPv6 Packet?*/
+ case ETHTYPE_IPV6:
+ #endif
+ #if PPPOE_SUPPORT
+ /* PPPoE packet? */
+ case ETHTYPE_PPPOEDISC:
+ case ETHTYPE_PPPOE:
+ #endif /* PPPOE_SUPPORT */
+ /* full packet send to tcpip_thread to process */
+ if (netif->input(p, netif) != ERR_OK) {
+ LWIP_DEBUGF(NETIF_DEBUG, ("xemacpsif_input: IP input error\r\n"));
+ pbuf_free(p);
+ p = NULL;
+ }
+ break;
+
+ default:
+ pbuf_free(p);
+ p = NULL;
+ break;
+ }
+ }
+
+ return 1;
+}
+
+#if !NO_SYS
+#if defined(__arm__) && !defined(ARMR5)
+void vTimerCallback( TimerHandle_t pxTimer )
+{
+ /* Do something if the pxTimer parameter is NULL */
+ configASSERT(pxTimer);
+
+ lExpireCounter++;
+ /* If the timer has expired 100 times then reset RX */
+ if(lExpireCounter >= RESETRXTIMEOUT) {
+ lExpireCounter = 0;
+ xemacpsif_resetrx_on_no_rxdata(NetIf);
+ }
+}
+#endif
+#endif
+
+static err_t low_level_init(struct netif *netif)
+{
+ UINTPTR mac_address = (UINTPTR)(netif->state);
+ struct xemac_s *xemac;
+ xemacpsif_s *xemacpsif;
+ u32 dmacrreg;
+
+ s32_t status = XST_SUCCESS;
+
+ NetIf = netif;
+
+ xemacpsif = mem_malloc(sizeof *xemacpsif);
+ if (xemacpsif == NULL) {
+ LWIP_DEBUGF(NETIF_DEBUG, ("xemacpsif_init: out of memory\r\n"));
+ return ERR_MEM;
+ }
+
+ xemac = mem_malloc(sizeof *xemac);
+ if (xemac == NULL) {
+ LWIP_DEBUGF(NETIF_DEBUG, ("xemacpsif_init: out of memory\r\n"));
+ return ERR_MEM;
+ }
+
+ xemac->state = (void *)xemacpsif;
+ xemac->topology_index = xtopology_find_index(mac_address);
+ xemac->type = xemac_type_emacps;
+
+ xemacpsif->send_q = NULL;
+ xemacpsif->recv_q = pq_create_queue();
+ if (!xemacpsif->recv_q)
+ return ERR_MEM;
+
+ /* maximum transfer unit */
+#ifdef ZYNQMP_USE_JUMBO
+ netif->mtu = XEMACPS_MTU_JUMBO - XEMACPS_HDR_SIZE;
+#else
+ netif->mtu = XEMACPS_MTU - XEMACPS_HDR_SIZE;
+#endif
+
+#if LWIP_IGMP
+ netif->igmp_mac_filter = xemacpsif_mac_filter_update;
+#endif
+
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+ netif->mld_mac_filter = xemacpsif_mld6_mac_filter_update;
+#endif
+
+ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP |
+ NETIF_FLAG_LINK_UP;
+
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+ netif->flags |= NETIF_FLAG_MLD6;
+#endif
+
+#if LWIP_IGMP
+ netif->flags |= NETIF_FLAG_IGMP;
+#endif
+
+#if !NO_SYS
+ sys_sem_new(&xemac->sem_rx_data_available, 0);
+#endif
+ /* obtain config of this emac */
+ mac_config = (XEmacPs_Config *)xemacps_lookup_config((unsigned)(UINTPTR)netif->state);
+
+#if defined (__aarch64__) && (EL1_NONSECURE == 1)
+ /* Request device to indicate that this library is using it */
+ if (mac_config->BaseAddress == VERSAL_EMACPS_0_BASEADDR) {
+ Xil_Smc(PM_REQUEST_DEVICE_SMC_FID, DEV_GEM_0, 1, 0, 100, 1, 0, 0);
+ }
+ if (mac_config->BaseAddress == VERSAL_EMACPS_0_BASEADDR) {
+ Xil_Smc(PM_REQUEST_DEVICE_SMC_FID, DEV_GEM_1, 1, 0, 100, 1, 0, 0);
+ }
+#endif
+
+ status = XEmacPs_CfgInitialize(&xemacpsif->emacps, mac_config,
+ mac_config->BaseAddress);
+ if (status != XST_SUCCESS) {
+ xil_printf("In %s:EmacPs Configuration Failed....\r\n", __func__);
+ }
+
+ /* initialize the mac */
+ init_emacps(xemacpsif, netif);
+
+ dmacrreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_DMACR_OFFSET);
+ dmacrreg = dmacrreg | (0x00000010);
+ XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_DMACR_OFFSET, dmacrreg);
+#if !NO_SYS
+#if defined(__arm__) && !defined(ARMR5)
+ /* Freertos tick is 10ms by default; set period to the same */
+ xemac->xTimer = xTimerCreate("Timer", 10, pdTRUE, ( void * ) 1, vTimerCallback);
+ if (xemac->xTimer == NULL) {
+ xil_printf("In %s:Timer creation failed....\r\n", __func__);
+ } else {
+ if(xTimerStart(xemac->xTimer, 0) != pdPASS) {
+ xil_printf("In %s:Timer start failed....\r\n", __func__);
+ }
+ }
+#endif
+#endif
+ setup_isr(xemac);
+ init_dma(xemac);
+ start_emacps(xemacpsif);
+
+ /* replace the state in netif (currently the emac baseaddress)
+ * with the mac instance pointer.
+ */
+ netif->state = (void *)xemac;
+
+ return ERR_OK;
+}
+
+void HandleEmacPsError(struct xemac_s *xemac)
+{
+ xemacpsif_s *xemacpsif;
+ s32_t status = XST_SUCCESS;
+ u32 dmacrreg;
+
+ SYS_ARCH_DECL_PROTECT(lev);
+ SYS_ARCH_PROTECT(lev);
+
+ xemacpsif = (xemacpsif_s *)(xemac->state);
+ free_txrx_pbufs(xemacpsif);
+ status = XEmacPs_CfgInitialize(&xemacpsif->emacps, mac_config,
+ mac_config->BaseAddress);
+ if (status != XST_SUCCESS) {
+ xil_printf("In %s:EmacPs Configuration Failed....\r\n", __func__);
+ }
+ /* initialize the mac */
+ init_emacps_on_error(xemacpsif, NetIf);
+ dmacrreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_DMACR_OFFSET);
+ dmacrreg = dmacrreg | (0x01000000);
+ XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_DMACR_OFFSET, dmacrreg);
+ setup_isr(xemac);
+ init_dma(xemac);
+ start_emacps(xemacpsif);
+
+ SYS_ARCH_UNPROTECT(lev);
+}
+
+void HandleTxErrors(struct xemac_s *xemac)
+{
+ xemacpsif_s *xemacpsif;
+ u32 netctrlreg;
+
+ SYS_ARCH_DECL_PROTECT(lev);
+ SYS_ARCH_PROTECT(lev);
+ xemacpsif = (xemacpsif_s *)(xemac->state);
+ netctrlreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET);
+ netctrlreg = netctrlreg & (~XEMACPS_NWCTRL_TXEN_MASK);
+ XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET, netctrlreg);
+ free_onlytx_pbufs(xemacpsif);
+
+ clean_dma_txdescs(xemac);
+ netctrlreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET);
+ netctrlreg = netctrlreg | (XEMACPS_NWCTRL_TXEN_MASK);
+ XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET, netctrlreg);
+ SYS_ARCH_UNPROTECT(lev);
+}
+
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+static u8_t xemacpsif_ip6_addr_ismulticast(ip6_addr_t* ip_addr)
+{
+ if(ip6_addr_ismulticast_linklocal(ip_addr)||
+ ip6_addr_ismulticast_iflocal(ip_addr) ||
+ ip6_addr_ismulticast_adminlocal(ip_addr)||
+ ip6_addr_ismulticast_sitelocal(ip_addr) ||
+ ip6_addr_ismulticast_orglocal(ip_addr) ||
+ ip6_addr_ismulticast_global(ip_addr)) {
+ /*Return TRUE if IPv6 is Multicast type*/
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static void xemacpsif_mld6_mac_hash_update (struct netif *netif, u8_t *ip_addr,
+ u8_t action)
+{
+ u8_t multicast_mac_addr[6];
+ struct xemac_s *xemac = (struct xemac_s *) (netif->state);
+ xemacpsif_s *xemacpsif = (xemacpsif_s *) (xemac->state);
+ XEmacPs_BdRing *txring;
+ txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
+
+ multicast_mac_addr[0] = LL_IP6_MULTICAST_ADDR_0;
+ multicast_mac_addr[1] = LL_IP6_MULTICAST_ADDR_1;
+ multicast_mac_addr[2] = ip_addr[12];
+ multicast_mac_addr[3] = ip_addr[13];
+ multicast_mac_addr[4] = ip_addr[14];
+ multicast_mac_addr[5] = ip_addr[15];
+
+ /* Wait till all sent packets are acknowledged from HW */
+ while(txring->HwCnt);
+
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ SYS_ARCH_PROTECT(lev);
+
+ /* Stop Ethernet */
+ XEmacPs_Stop(&xemacpsif->emacps);
+
+ if (action == NETIF_ADD_MAC_FILTER) {
+ /* Set Mulitcast mac address in hash table */
+ XEmacPs_SetHash(&xemacpsif->emacps, multicast_mac_addr);
+
+ } else if (action == NETIF_DEL_MAC_FILTER) {
+ /* Remove Mulitcast mac address in hash table */
+ XEmacPs_DeleteHash(&xemacpsif->emacps, multicast_mac_addr);
+ }
+
+ /* Reset DMA */
+ reset_dma(xemac);
+
+ /* Start Ethernet */
+ XEmacPs_Start(&xemacpsif->emacps);
+
+ SYS_ARCH_UNPROTECT(lev);
+}
+
+static err_t xemacpsif_mld6_mac_filter_update (struct netif *netif, ip_addr_t *group,
+ u8_t action)
+{
+ u8_t temp_mask;
+ unsigned int i;
+ u8_t * ip_addr = (u8_t *) group;
+
+ if(!(xemacpsif_ip6_addr_ismulticast((ip6_addr_t*) ip_addr))) {
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("%s: The requested MAC address is not a multicast address.\r\n", __func__)); LWIP_DEBUGF(NETIF_DEBUG,
+ ("Multicast address add operation failure !!\r\n"));
+ return ERR_ARG;
+ }
+ if (action == NETIF_ADD_MAC_FILTER) {
+ for (i = 0; i < XEMACPS_MAX_MAC_ADDR; i++) {
+ temp_mask = (0x01) << i;
+ if ((xemacps_mld6_mcast_entry_mask & temp_mask) == temp_mask) {
+ continue;
+ }
+ xemacps_mld6_mcast_entry_mask |= temp_mask;
+
+ /* Update mac address in hash table */
+ xemacpsif_mld6_mac_hash_update(netif, ip_addr, action);
+
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("%s: Multicast MAC address successfully added.\r\n", __func__));
+
+ return ERR_OK;
+ }
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("%s: No multicast address registers left.\r\n", __func__));
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("Multicast MAC address add operation failure !!\r\n"));
+ return ERR_MEM;
+ } else if (action == NETIF_DEL_MAC_FILTER) {
+ for (i = 0; i < XEMACPS_MAX_MAC_ADDR; i++) {
+ temp_mask = (0x01) << i;
+ if ((xemacps_mld6_mcast_entry_mask & temp_mask) != temp_mask) {
+ continue;
+ }
+ xemacps_mld6_mcast_entry_mask &= (~temp_mask);
+
+ /* Update mac address in hash table */
+ xemacpsif_mld6_mac_hash_update(netif, ip_addr, action);
+
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("%s: Multicast MAC address successfully removed.\r\n", __func__));
+
+ return ERR_OK;
+ }
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("%s: No multicast address registers present with\r\n", __func__));
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("the requested Multicast MAC address.\r\n"));
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("Multicast MAC address removal failure!!.\r\n"));
+ return ERR_MEM;
+ }
+ return ERR_ARG;
+}
+#endif
+
+#if LWIP_IGMP
+static void xemacpsif_mac_hash_update (struct netif *netif, u8_t *ip_addr,
+ u8_t action)
+{
+ u8_t multicast_mac_addr[6];
+ struct xemac_s *xemac = (struct xemac_s *) (netif->state);
+ xemacpsif_s *xemacpsif = (xemacpsif_s *) (xemac->state);
+ XEmacPs_BdRing *txring;
+ txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
+
+ multicast_mac_addr[0] = 0x01;
+ multicast_mac_addr[1] = 0x00;
+ multicast_mac_addr[2] = 0x5E;
+ multicast_mac_addr[3] = ip_addr[1] & 0x7F;
+ multicast_mac_addr[4] = ip_addr[2];
+ multicast_mac_addr[5] = ip_addr[3];
+
+ /* Wait till all sent packets are acknowledged from HW */
+ while(txring->HwCnt);
+
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ SYS_ARCH_PROTECT(lev);
+
+ /* Stop Ethernet */
+ XEmacPs_Stop(&xemacpsif->emacps);
+
+ if (action == IGMP_ADD_MAC_FILTER) {
+ /* Set Mulitcast mac address in hash table */
+ XEmacPs_SetHash(&xemacpsif->emacps, multicast_mac_addr);
+
+ } else if (action == IGMP_DEL_MAC_FILTER) {
+ /* Remove Mulitcast mac address in hash table */
+ XEmacPs_DeleteHash(&xemacpsif->emacps, multicast_mac_addr);
+ }
+
+ /* Reset DMA */
+ reset_dma(xemac);
+
+ /* Start Ethernet */
+ XEmacPs_Start(&xemacpsif->emacps);
+
+ SYS_ARCH_UNPROTECT(lev);
+}
+
+static err_t xemacpsif_mac_filter_update (struct netif *netif, ip_addr_t *group,
+ u8_t action)
+{
+ u8_t temp_mask;
+ unsigned int i;
+ u8_t * ip_addr = (u8_t *) group;
+
+ if ((ip_addr[0] < 224) && (ip_addr[0] > 239)) {
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("%s: The requested MAC address is not a multicast address.\r\n", __func__));
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("Multicast address add operation failure !!\r\n"));
+
+ return ERR_ARG;
+ }
+
+ if (action == IGMP_ADD_MAC_FILTER) {
+
+ for (i = 0; i < XEMACPS_MAX_MAC_ADDR; i++) {
+ temp_mask = (0x01) << i;
+ if ((xemacps_mcast_entry_mask & temp_mask) == temp_mask) {
+ continue;
+ }
+ xemacps_mcast_entry_mask |= temp_mask;
+
+ /* Update mac address in hash table */
+ xemacpsif_mac_hash_update(netif, ip_addr, action);
+
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("%s: Multicast MAC address successfully added.\r\n", __func__));
+
+ return ERR_OK;
+ }
+ if (i == XEMACPS_MAX_MAC_ADDR) {
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("%s: No multicast address registers left.\r\n", __func__));
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("Multicast MAC address add operation failure !!\r\n"));
+
+ return ERR_MEM;
+ }
+ } else if (action == IGMP_DEL_MAC_FILTER) {
+ for (i = 0; i < XEMACPS_MAX_MAC_ADDR; i++) {
+ temp_mask = (0x01) << i;
+ if ((xemacps_mcast_entry_mask & temp_mask) != temp_mask) {
+ continue;
+ }
+ xemacps_mcast_entry_mask &= (~temp_mask);
+
+ /* Update mac address in hash table */
+ xemacpsif_mac_hash_update(netif, ip_addr, action);
+
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("%s: Multicast MAC address successfully removed.\r\n", __func__));
+
+ return ERR_OK;
+ }
+ if (i == XEMACPS_MAX_MAC_ADDR) {
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("%s: No multicast address registers present with\r\n", __func__));
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("the requested Multicast MAC address.\r\n"));
+ LWIP_DEBUGF(NETIF_DEBUG,
+ ("Multicast MAC address removal failure!!.\r\n"));
+
+ return ERR_MEM;
+ }
+ }
+ return ERR_OK;
+}
+#endif
+
+/*
+ * xemacpsif_init():
+ *
+ * Should be called at the beginning of the program to set up the
+ * network interface. It calls the function low_level_init() to do the
+ * actual setup of the hardware.
+ *
+ */
+
+err_t xemacpsif_init(struct netif *netif)
+{
+#if LWIP_SNMP
+ /* ifType ethernetCsmacd(6) @see RFC1213 */
+ netif->link_type = 6;
+ /* your link speed here */
+ netif->link_speed = ;
+ netif->ts = 0;
+ netif->ifinoctets = 0;
+ netif->ifinucastpkts = 0;
+ netif->ifinnucastpkts = 0;
+ netif->ifindiscards = 0;
+ netif->ifoutoctets = 0;
+ netif->ifoutucastpkts = 0;
+ netif->ifoutnucastpkts = 0;
+ netif->ifoutdiscards = 0;
+#endif
+
+ netif->name[0] = IFNAME0;
+ netif->name[1] = IFNAME1;
+ netif->output = xemacpsif_output;
+ netif->linkoutput = low_level_output;
+#if LWIP_IPV6
+ netif->output_ip6 = ethip6_output;
+#endif
+
+ low_level_init(netif);
+ return ERR_OK;
+}
+
+/*
+ * xemacpsif_resetrx_on_no_rxdata():
+ *
+ * Should be called by the user at regular intervals, typically
+ * from a timer (100 msecond). This is to provide a SW workaround
+ * for the HW bug (SI #692601). Please refer to the function header
+ * for the function resetrx_on_no_rxdata in xemacpsif_dma.c to
+ * know more about the SI.
+ *
+ */
+
+void xemacpsif_resetrx_on_no_rxdata(struct netif *netif)
+{
+ struct xemac_s *xemac = (struct xemac_s *)(netif->state);
+ xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
+
+ resetrx_on_no_rxdata(xemacpsif);
+}
diff --git a/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif_dma.c b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif_dma.c
new file mode 100644
index 0000000..2da3566
--- /dev/null
+++ b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif_dma.c
@@ -0,0 +1,930 @@
+/*
+ * Copyright (C) 2010 - 2021 Xilinx, 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"
+#include "lwip/stats.h"
+#include "lwip/sys.h"
+#include "lwip/inet_chksum.h"
+
+#include "netif/xadapter.h"
+#include "netif/xemacpsif.h"
+#include "xstatus.h"
+
+#include "xlwipconfig.h"
+#include "xparameters.h"
+#include "xparameters_ps.h"
+#include "xil_exception.h"
+#include "xil_mmu.h"
+#if defined (ARMR5)
+#include "xreg_cortexr5.h"
+#endif
+#ifdef CONFIG_XTRACE
+#include "xtrace.h"
+#endif
+#if !NO_SYS
+#include "FreeRTOS.h"
+#include "semphr.h"
+#include "timers.h"
+#endif
+
+
+#define INTC_BASE_ADDR XPAR_SCUGIC_0_CPU_BASEADDR
+#define INTC_DIST_BASE_ADDR XPAR_SCUGIC_0_DIST_BASEADDR
+
+/* Byte alignment of BDs */
+#define BD_ALIGNMENT (XEMACPS_DMABD_MINIMUM_ALIGNMENT*2)
+
+/* A max of 4 different ethernet interfaces are supported */
+static UINTPTR tx_pbufs_storage[4*XLWIP_CONFIG_N_TX_DESC];
+static UINTPTR rx_pbufs_storage[4*XLWIP_CONFIG_N_RX_DESC];
+
+static s32_t emac_intr_num;
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+volatile u32_t notifyinfo[4*XLWIP_CONFIG_N_TX_DESC];
+#endif
+
+/******************************************************************************
+ * Each BD is of 8 bytes of size and the BDs (BD chain) need to be put
+ * at uncached memory location. If they are not put at uncached
+ * locations, the user needs to flush or invalidate for each BD/packet.
+ * However, the flush or invalidate can happen over a cache line which can
+ * span multiple BDs. This means a flush or invalidate of one BD can actually
+ * flush/invalidate multiple BDs adjacent to the targeted BD.Assuming that
+ * the user and hardware both update the BD fields, this operation from user
+ * can potentially overwrite the updates done by hardware or user.
+ * To avoid this, it is always safe to put the BD chains for Rx and tx side
+ * at uncached memory location.
+ *
+ * The Xilinx standalone BSP for Cortex A9 implements only primary page tables.
+ * Each table entry corresponds to 1 MB of address map. This means, if a memory
+ * region has to be made uncached, the minimum granularity will be of 1 MB.
+ *
+ * The implementation below allocates a 1 MB of u8 array aligned to 1 MB.
+ * This ensures that this array is put at 1 MB aligned memory (e.g. 0x1200000)
+ * and accupies memory of 1 MB. The init_dma function then changes 1 MB of this
+ * region to make it uncached (strongly ordered).
+ * This increases the bss section of the program significantly and can be a
+ * wastage of memory. The reason beings, BDs will hardly occupy few KBs of
+ * memory and the rest of 1 MB of memory will be unused.
+ *
+ * If a program uses other peripherals that have DMAs/bus masters and need
+ * uncached memory, they may also end of following the same approach. This
+ * definitely aggravates the memory wastage issue. To avoid all this, the user
+ * can create a new 1 MB section in the linker script and reserve it for such
+ * use cases that need uncached memory location. They can then have their own
+ * memory allocation logic in their application that allocates uncached memory
+ * from this 1 MB location. For such a case, changes need to be done in this
+ * file and appropriate uncached memory allocated through other means can be
+ * used.
+ *
+ * The present implementation here allocates 1 MB of uncached memory. It
+ * reserves of 64 KB of memory for each BD chain. 64 KB of memory means 8192 of
+ * BDs for each BD chain which is more than enough for any application.
+ * Assuming that both emac0 and emac1 are present, 256 KB of memory is allocated
+ * for BDs. The rest 768 KB of memory is just unused.
+ *********************************************************************************/
+
+#if defined __aarch64__
+u8_t bd_space[0x200000] __attribute__ ((aligned (0x200000)));
+#else
+u8_t bd_space[0x100000] __attribute__ ((aligned (0x100000)));
+#endif
+static volatile u32_t bd_space_index = 0;
+static volatile u32_t bd_space_attr_set = 0;
+
+#if !NO_SYS
+long xInsideISR = 0;
+#endif
+
+#define XEMACPS_BD_TO_INDEX(ringptr, bdptr) \
+ (((UINTPTR)bdptr - (UINTPTR)(ringptr)->BaseBdAddr) / (ringptr)->Separation)
+
+
+s32_t is_tx_space_available(xemacpsif_s *emac)
+{
+ XEmacPs_BdRing *txring;
+ s32_t freecnt = 0;
+
+ txring = &(XEmacPs_GetTxRing(&emac->emacps));
+
+ /* tx space is available as long as there are valid BD's */
+ freecnt = XEmacPs_BdRingGetFreeCnt(txring);
+ return freecnt;
+}
+
+
+static inline
+u32_t get_base_index_txpbufsstorage (xemacpsif_s *xemacpsif)
+{
+ u32_t index;
+#ifdef XPAR_XEMACPS_0_BASEADDR
+ if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
+ index = 0;
+ }
+#endif
+#ifdef XPAR_XEMACPS_1_BASEADDR
+ if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_1_BASEADDR) {
+ index = XLWIP_CONFIG_N_TX_DESC;
+ }
+#endif
+#ifdef XPAR_XEMACPS_2_BASEADDR
+ if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_2_BASEADDR) {
+ index = 2 * XLWIP_CONFIG_N_TX_DESC;
+ }
+#endif
+#ifdef XPAR_XEMACPS_3_BASEADDR
+ if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_3_BASEADDR) {
+ index = 3 * XLWIP_CONFIG_N_TX_DESC;
+ }
+#endif
+ return index;
+}
+
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+static inline
+u32_t get_base_index_tasknotifyinfo (xemacpsif_s *xemacpsif)
+{
+ u32_t index;
+#ifdef XPAR_XEMACPS_0_BASEADDR
+ if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
+ index = 0;
+ }
+#endif
+#ifdef XPAR_XEMACPS_1_BASEADDR
+ if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_1_BASEADDR) {
+ index = XLWIP_CONFIG_N_TX_DESC;
+ }
+#endif
+#ifdef XPAR_XEMACPS_2_BASEADDR
+ if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_2_BASEADDR) {
+ index = 2 * XLWIP_CONFIG_N_TX_DESC;
+ }
+#endif
+#ifdef XPAR_XEMACPS_3_BASEADDR
+ if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_3_BASEADDR) {
+ index = 3 * XLWIP_CONFIG_N_TX_DESC;
+ }
+#endif
+ return index;
+}
+#endif
+
+static inline
+u32_t get_base_index_rxpbufsstorage (xemacpsif_s *xemacpsif)
+{
+ u32_t index;
+#ifdef XPAR_XEMACPS_0_BASEADDR
+ if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
+ index = 0;
+ }
+#endif
+#ifdef XPAR_XEMACPS_1_BASEADDR
+ if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_1_BASEADDR) {
+ index = XLWIP_CONFIG_N_RX_DESC;
+ }
+#endif
+#ifdef XPAR_XEMACPS_2_BASEADDR
+ if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_2_BASEADDR) {
+ index = 2 * XLWIP_CONFIG_N_RX_DESC;
+ }
+#endif
+#ifdef XPAR_XEMACPS_3_BASEADDR
+ if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_3_BASEADDR) {
+ index = 3 * XLWIP_CONFIG_N_RX_DESC;
+ }
+#endif
+ return index;
+}
+
+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 *temp;
+ u32_t index;
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+ u32_t tx_task_notifier_index;
+#endif
+
+ index = get_base_index_txpbufsstorage (xemacpsif);
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+ tx_task_notifier_index = get_base_index_tasknotifyinfo (xemacpsif);
+#endif
+
+ 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 *)curbdpntr;
+ *temp = 0;
+ temp++;
+ if (bdindex == (XLWIP_CONFIG_N_TX_DESC - 1)) {
+ *temp = 0xC0000000;
+ } else {
+ *temp = 0x80000000;
+ }
+ dsb();
+ p = (struct pbuf *)tx_pbufs_storage[index + bdindex];
+ if (p != NULL) {
+ pbuf_free(p);
+ }
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+ notifyinfo[tx_task_notifier_index + bdindex] = 0;
+#endif
+ 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 emacps_send_handler(void *arg)
+{
+ struct xemac_s *xemac;
+ xemacpsif_s *xemacpsif;
+ XEmacPs_BdRing *txringptr;
+ u32_t regval;
+#if !NO_SYS
+ xInsideISR++;
+#endif
+ xemac = (struct xemac_s *)(arg);
+ xemacpsif = (xemacpsif_s *)(xemac->state);
+ txringptr = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
+ regval = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_TXSR_OFFSET);
+ XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,XEMACPS_TXSR_OFFSET, regval);
+
+ /* If Transmit done interrupt is asserted, process completed BD's */
+ process_sent_bds(xemacpsif, txringptr);
+#if !NO_SYS
+ xInsideISR--;
+#endif
+}
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+XStatus emacps_sgsend(xemacpsif_s *xemacpsif, struct pbuf *p,
+ u32_t block_till_tx_complete, u32_t *to_block_index)
+#else
+XStatus emacps_sgsend(xemacpsif_s *xemacpsif, struct pbuf *p)
+#endif
+{
+ 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 = 0;
+ u32_t index;
+ u32_t max_fr_size;
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+ u32_t tx_task_notifier_index;
+#endif
+
+ txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
+
+ index = get_base_index_txpbufsstorage (xemacpsif);
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+ tx_task_notifier_index = get_base_index_tasknotifyinfo (xemacpsif);
+#endif
+
+ /* 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) {
+ 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[index + bdindex] != 0) {
+ 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. */
+ if (xemacpsif->emacps.Config.IsCacheCoherent == 0) {
+ Xil_DCacheFlushRange((UINTPTR)q->payload, (UINTPTR)q->len);
+ }
+
+ XEmacPs_BdSetAddressTx(txbd, (UINTPTR)q->payload);
+
+#ifdef ZYNQMP_USE_JUMBO
+ max_fr_size = MAX_FRAME_SIZE_JUMBO - 18;
+#else
+ max_fr_size = XEMACPS_MAX_FRAME_SIZE - 18;
+#endif
+ if (q->len > max_fr_size)
+ XEmacPs_BdSetLength(txbd, max_fr_size & 0x3FFF);
+ else
+ XEmacPs_BdSetLength(txbd, q->len & 0x3FFF);
+
+ tx_pbufs_storage[index + bdindex] = (UINTPTR)q;
+
+ pbuf_ref(q);
+ last_txbd = txbd;
+ XEmacPs_BdClearLast(txbd);
+ txbd = XEmacPs_BdRingNext(txring, txbd);
+ }
+#if LWIP_UDP_OPT_BLOCK_TX_TILL_COMPLETE
+ if (block_till_tx_complete == 1) {
+ notifyinfo[tx_task_notifier_index + bdindex] = 1;
+ *to_block_index = tx_task_notifier_index + bdindex;
+ }
+#endif
+ 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);
+ dsb();
+
+ status = XEmacPs_BdRingToHw(txring, n_pbufs, txbdset);
+ if (status != XST_SUCCESS) {
+ 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));
+ return status;
+}
+
+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 *temp;
+ u32_t index;
+
+ index = get_base_index_rxpbufsstorage (xemacpsif);
+
+ freebds = XEmacPs_BdRingGetFreeCnt (rxring);
+ while (freebds > 0) {
+ freebds--;
+#ifdef ZYNQMP_USE_JUMBO
+ p = pbuf_alloc(PBUF_RAW, MAX_FRAME_SIZE_JUMBO, PBUF_POOL);
+#else
+ p = pbuf_alloc(PBUF_RAW, XEMACPS_MAX_FRAME_SIZE, PBUF_POOL);
+#endif
+ 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;
+ }
+#ifdef ZYNQMP_USE_JUMBO
+ if (xemacpsif->emacps.Config.IsCacheCoherent == 0) {
+ Xil_DCacheInvalidateRange((UINTPTR)p->payload, (UINTPTR)MAX_FRAME_SIZE_JUMBO);
+ }
+#else
+ if (xemacpsif->emacps.Config.IsCacheCoherent == 0) {
+ Xil_DCacheInvalidateRange((UINTPTR)p->payload, (UINTPTR)XEMACPS_MAX_FRAME_SIZE);
+ }
+#endif
+ bdindex = XEMACPS_BD_TO_INDEX(rxring, rxbd);
+ temp = (u32 *)rxbd;
+ temp++;
+ /* Status field should be cleared first to avoid drops */
+ *temp = 0;
+ dsb();
+
+ /* Set high address when required */
+#ifdef __aarch64__
+ XEmacPs_BdWrite(rxbd, XEMACPS_BD_ADDR_HI_OFFSET,
+ (((UINTPTR)p->payload) & ULONG64_HI_MASK) >> 32U);
+#endif
+ /* Set address field; add WRAP bit on last descriptor */
+ if (bdindex == (XLWIP_CONFIG_N_RX_DESC - 1)) {
+ XEmacPs_BdWrite(rxbd, XEMACPS_BD_ADDR_OFFSET, ((UINTPTR)p->payload | XEMACPS_RXBUF_WRAP_MASK));
+ } else {
+ XEmacPs_BdWrite(rxbd, XEMACPS_BD_ADDR_OFFSET, (UINTPTR)p->payload);
+ }
+
+ rx_pbufs_storage[index + bdindex] = (UINTPTR)p;
+ }
+}
+
+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;
+ u32_t index;
+ u32_t gigeversion;
+
+ xemac = (struct xemac_s *)(arg);
+ xemacpsif = (xemacpsif_s *)(xemac->state);
+ rxring = &XEmacPs_GetRxRing(&xemacpsif->emacps);
+
+#if !NO_SYS
+ xInsideISR++;
+#endif
+
+ gigeversion = ((Xil_In32(xemacpsif->emacps.Config.BaseAddress + 0xFC)) >> 16) & 0xFFF;
+ index = get_base_index_rxpbufsstorage (xemacpsif);
+ /*
+ * 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);
+ if (gigeversion <= 2) {
+ 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[index + bdindex];
+
+ /*
+ * Adjust the buffer size to the actual number of bytes received.
+ */
+#ifdef ZYNQMP_USE_JUMBO
+ rx_bytes = XEmacPs_GetRxFrameSize(&xemacpsif->emacps, curbdptr);
+#else
+ rx_bytes = XEmacPs_BdGetLength(curbdptr);
+#endif
+ pbuf_realloc(p, rx_bytes);
+
+ /* Invalidate RX frame before queuing to handle
+ * L1 cache prefetch conditions on any architecture.
+ */
+ if (xemacpsif->emacps.Config.IsCacheCoherent == 0) {
+ Xil_DCacheInvalidateRange((UINTPTR)p->payload, 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);
+ }
+ curbdptr = XEmacPs_BdRingNext( rxring, curbdptr);
+ }
+ /* free up the BD's */
+ XEmacPs_BdRingFree(rxring, bd_processed, rxbdset);
+ setup_rx_bds(xemacpsif, rxring);
+ }
+#if !NO_SYS
+ sys_sem_signal(&xemac->sem_rx_data_available);
+ xInsideISR--;
+#endif
+
+ return;
+}
+
+void clean_dma_txdescs(struct xemac_s *xemac)
+{
+ XEmacPs_Bd bdtemplate;
+ XEmacPs_BdRing *txringptr;
+ xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
+
+ txringptr = &XEmacPs_GetTxRing(&xemacpsif->emacps);
+
+ XEmacPs_BdClear(&bdtemplate);
+ XEmacPs_BdSetStatus(&bdtemplate, XEMACPS_TXBUF_USED_MASK);
+
+ /*
+ * Create the TxBD ring
+ */
+ XEmacPs_BdRingCreate(txringptr, (UINTPTR) xemacpsif->tx_bdspace,
+ (UINTPTR) xemacpsif->tx_bdspace, BD_ALIGNMENT,
+ XLWIP_CONFIG_N_TX_DESC);
+ XEmacPs_BdRingClone(txringptr, &bdtemplate, XEMACPS_SEND);
+}
+
+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 UINTPTR tempaddress;
+ u32_t index;
+ u32_t gigeversion;
+ XEmacPs_Bd *bdtxterminate = NULL;
+ XEmacPs_Bd *bdrxterminate = NULL;
+ u32 *temp;
+
+ xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
+ struct xtopology_t *xtopologyp = &xtopology[xemac->topology_index];
+
+ index = get_base_index_rxpbufsstorage (xemacpsif);
+ gigeversion = ((Xil_In32(xemacpsif->emacps.Config.BaseAddress + 0xFC)) >> 16) & 0xFFF;
+ /*
+ * 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) {
+#if defined (ARMR5)
+ Xil_SetTlbAttributes((s32_t)bd_space, STRONG_ORDERD_SHARED | PRIV_RW_USER_RW); // addr, attr
+#else
+#if defined __aarch64__
+ Xil_SetTlbAttributes((u64)bd_space, NORM_NONCACHE | INNER_SHAREABLE);
+#else
+ Xil_SetTlbAttributes((s32_t)bd_space, DEVICE_MEMORY); // addr, attr
+#endif
+#endif
+ 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 = (UINTPTR)&(bd_space[bd_space_index]);
+ xemacpsif->rx_bdspace = (void *)tempaddress;
+ bd_space_index += 0x10000;
+ tempaddress = (UINTPTR)&(bd_space[bd_space_index]);
+ xemacpsif->tx_bdspace = (void *)tempaddress;
+ bd_space_index += 0x10000;
+ if (gigeversion > 2) {
+ tempaddress = (UINTPTR)&(bd_space[bd_space_index]);
+ bdrxterminate = (XEmacPs_Bd *)tempaddress;
+ bd_space_index += 0x10000;
+ tempaddress = (UINTPTR)&(bd_space[bd_space_index]);
+ bdtxterminate = (XEmacPs_Bd *)tempaddress;
+ bd_space_index += 0x10000;
+ }
+
+ LWIP_DEBUGF(NETIF_DEBUG, ("rx_bdspace: %p \r\n", xemacpsif->rx_bdspace));
+ LWIP_DEBUGF(NETIF_DEBUG, ("tx_bdspace: %p \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, (UINTPTR) xemacpsif->rx_bdspace,
+ (UINTPTR) 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, (UINTPTR) xemacpsif->tx_bdspace,
+ (UINTPTR) 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++) {
+#ifdef ZYNQMP_USE_JUMBO
+ p = pbuf_alloc(PBUF_RAW, MAX_FRAME_SIZE_JUMBO, PBUF_POOL);
+#else
+ p = pbuf_alloc(PBUF_RAW, XEMACPS_MAX_FRAME_SIZE, PBUF_POOL);
+#endif
+ 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;
+ }
+
+ bdindex = XEMACPS_BD_TO_INDEX(rxringptr, rxbd);
+ temp = (u32 *)rxbd;
+ *temp = 0;
+ if (bdindex == (XLWIP_CONFIG_N_RX_DESC - 1)) {
+ *temp = 0x00000002;
+ }
+ temp++;
+ *temp = 0;
+ dsb();
+#ifdef ZYNQMP_USE_JUMBO
+ if (xemacpsif->emacps.Config.IsCacheCoherent == 0) {
+ Xil_DCacheInvalidateRange((UINTPTR)p->payload, (UINTPTR)MAX_FRAME_SIZE_JUMBO);
+ }
+#else
+ if (xemacpsif->emacps.Config.IsCacheCoherent == 0) {
+ Xil_DCacheInvalidateRange((UINTPTR)p->payload, (UINTPTR)XEMACPS_MAX_FRAME_SIZE);
+ }
+#endif
+ XEmacPs_BdSetAddressRx(rxbd, (UINTPTR)p->payload);
+
+ rx_pbufs_storage[index + bdindex] = (UINTPTR)p;
+ }
+ XEmacPs_SetQueuePtr(&(xemacpsif->emacps), xemacpsif->emacps.RxBdRing.BaseBdAddr, 0, XEMACPS_RECV);
+ if (gigeversion > 2) {
+ XEmacPs_SetQueuePtr(&(xemacpsif->emacps), xemacpsif->emacps.TxBdRing.BaseBdAddr, 1, XEMACPS_SEND);
+ }else {
+ XEmacPs_SetQueuePtr(&(xemacpsif->emacps), xemacpsif->emacps.TxBdRing.BaseBdAddr, 0, XEMACPS_SEND);
+ }
+ if (gigeversion > 2)
+ {
+ /*
+ * This version of GEM supports priority queuing and the current
+ * driver is using tx priority queue 1 and normal rx queue for
+ * packet transmit and receive. The below code ensure that the
+ * other queue pointers are parked to known state for avoiding
+ * the controller to malfunction by fetching the descriptors
+ * from these queues.
+ */
+ XEmacPs_BdClear(bdrxterminate);
+ XEmacPs_BdSetAddressRx(bdrxterminate, (XEMACPS_RXBUF_NEW_MASK |
+ XEMACPS_RXBUF_WRAP_MASK));
+ XEmacPs_Out32((xemacpsif->emacps.Config.BaseAddress + XEMACPS_RXQ1BASE_OFFSET),
+ (UINTPTR)bdrxterminate);
+ XEmacPs_BdClear(bdtxterminate);
+ XEmacPs_BdSetStatus(bdtxterminate, (XEMACPS_TXBUF_USED_MASK |
+ XEMACPS_TXBUF_WRAP_MASK));
+ XEmacPs_Out32((xemacpsif->emacps.Config.BaseAddress + XEMACPS_TXQBASE_OFFSET),
+ (UINTPTR)bdtxterminate);
+ }
+#if !NO_SYS
+ xPortInstallInterruptHandler(xtopologyp->scugic_emac_intr,
+ ( Xil_InterruptHandler ) XEmacPs_IntrHandler,
+ (void *)&xemacpsif->emacps);
+#else
+ /*
+ * 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);
+#endif
+ /*
+ * 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;
+}
+
+/*
+ * resetrx_on_no_rxdata():
+ *
+ * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata
+ * called by the user.
+ * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.
+ * Under heavy Rx traffic because of the HW bug there are times when the Rx path
+ * becomes unresponsive. The workaround for it is to check for the Rx path for
+ * traffic (by reading the stats registers regularly). If the stats register
+ * does not increment for sometime (proving no Rx traffic), the function resets
+ * the Rx data path.
+ *
+ */
+
+void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)
+{
+ u32_t regctrl;
+ u32_t tempcntr;
+ u32_t gigeversion;
+
+ gigeversion = ((Xil_In32(xemacpsif->emacps.Config.BaseAddress + 0xFC)) >> 16) & 0xFFF;
+ if (gigeversion == 2) {
+ tempcntr = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET);
+ if ((!tempcntr) && (!(xemacpsif->last_rx_frms_cntr))) {
+ regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET);
+ regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);
+ XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET, regctrl);
+ regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);
+ regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);
+ XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);
+ }
+ xemacpsif->last_rx_frms_cntr = tempcntr;
+ }
+}
+
+void free_txrx_pbufs(xemacpsif_s *xemacpsif)
+{
+ s32_t index;
+ s32_t index1;
+ struct pbuf *p;
+
+ index1 = get_base_index_txpbufsstorage (xemacpsif);
+
+ for (index = index1; index < (index1 + XLWIP_CONFIG_N_TX_DESC); index++) {
+ if (tx_pbufs_storage[index] != 0) {
+ p = (struct pbuf *)tx_pbufs_storage[index];
+ pbuf_free(p);
+ tx_pbufs_storage[index] = 0;
+ }
+ }
+
+ index1 = get_base_index_rxpbufsstorage(xemacpsif);
+ for (index = index1; index < (index1 + XLWIP_CONFIG_N_RX_DESC); index++) {
+ p = (struct pbuf *)rx_pbufs_storage[index];
+ pbuf_free(p);
+
+ }
+}
+
+void free_onlytx_pbufs(xemacpsif_s *xemacpsif)
+{
+ s32_t index;
+ s32_t index1;
+ struct pbuf *p;
+
+ index1 = get_base_index_txpbufsstorage (xemacpsif);
+ for (index = index1; index < (index1 + XLWIP_CONFIG_N_TX_DESC); index++) {
+ if (tx_pbufs_storage[index] != 0) {
+ p = (struct pbuf *)tx_pbufs_storage[index];
+ pbuf_free(p);
+ tx_pbufs_storage[index] = 0;
+ }
+ }
+}
+
+/* reset Tx and Rx DMA pointers after XEmacPs_Stop */
+void reset_dma(struct xemac_s *xemac)
+{
+ u8 txqueuenum;
+ u32_t gigeversion;
+ xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
+ XEmacPs_BdRing *txringptr = &XEmacPs_GetTxRing(&xemacpsif->emacps);
+ XEmacPs_BdRing *rxringptr = &XEmacPs_GetRxRing(&xemacpsif->emacps);
+
+ XEmacPs_BdRingPtrReset(txringptr, xemacpsif->tx_bdspace);
+ XEmacPs_BdRingPtrReset(rxringptr, xemacpsif->rx_bdspace);
+
+ gigeversion = ((Xil_In32(xemacpsif->emacps.Config.BaseAddress + 0xFC)) >> 16) & 0xFFF;
+ if (gigeversion > 2) {
+ txqueuenum = 1;
+ } else {
+ txqueuenum = 0;
+ }
+
+ XEmacPs_SetQueuePtr(&(xemacpsif->emacps), xemacpsif->emacps.RxBdRing.BaseBdAddr, 0, XEMACPS_RECV);
+ XEmacPs_SetQueuePtr(&(xemacpsif->emacps), xemacpsif->emacps.TxBdRing.BaseBdAddr, txqueuenum, XEMACPS_SEND);
+}
+
+void emac_disable_intr(void)
+{
+ XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, emac_intr_num);
+}
+
+void emac_enable_intr(void)
+{
+ XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, emac_intr_num);
+}
diff --git a/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif_hw.c b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif_hw.c
new file mode 100644
index 0000000..a1fdeda
--- /dev/null
+++ b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif_hw.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2010 - 2021 Xilinx, 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 "netif/xemacpsif.h"
+#include "lwipopts.h"
+
+#if XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1 || \
+ XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1
+#define PCM_PMA_CORE_PRESENT
+#else
+#undef PCM_PMA_CORE_PRESENT
+#endif
+
+u32_t link_speed = 100;
+extern XEmacPs_Config XEmacPs_ConfigTable[];
+extern u32_t phymapemac0[32];
+extern u32_t phymapemac1[32];
+extern u32_t phyaddrforemac;
+extern enum ethernet_link_status eth_link_status;
+
+#if !NO_SYS
+extern long xInsideISR;
+#endif
+
+XEmacPs_Config *xemacps_lookup_config(unsigned mac_base)
+{
+ XEmacPs_Config *cfgptr = NULL;
+ s32_t i;
+
+ for (i = 0; i < XPAR_XEMACPS_NUM_INSTANCES; i++) {
+ if (XEmacPs_ConfigTable[i].BaseAddress == mac_base) {
+ cfgptr = &XEmacPs_ConfigTable[i];
+ break;
+ }
+ }
+
+ return (cfgptr);
+}
+
+void init_emacps(xemacpsif_s *xemacps, struct netif *netif)
+{
+ XEmacPs *xemacpsp;
+ s32_t status = XST_SUCCESS;
+ u32_t i;
+ u32_t phyfoundforemac0 = FALSE;
+ u32_t phyfoundforemac1 = FALSE;
+
+ xemacpsp = &xemacps->emacps;
+
+#ifdef ZYNQMP_USE_JUMBO
+ XEmacPs_SetOptions(xemacpsp, XEMACPS_JUMBO_ENABLE_OPTION);
+#endif
+
+#ifdef LWIP_IGMP
+ XEmacPs_SetOptions(xemacpsp, XEMACPS_MULTICAST_OPTION);
+#endif
+
+ /* set mac address */
+ status = XEmacPs_SetMacAddress(xemacpsp, (void*)(netif->hwaddr), 1);
+ if (status != XST_SUCCESS) {
+ xil_printf("In %s:Emac Mac Address set failed...\r\n",__func__);
+ }
+
+ XEmacPs_SetMdioDivisor(xemacpsp, MDC_DIV_224);
+
+/* Please refer to file header comments for the file xemacpsif_physpeed.c
+ * to know more about the PHY programming sequence.
+ * For PCS PMA core, phy_setup_emacps is called with the predefined PHY address
+ * exposed through xaparemeters.h
+ * For RGMII case, assuming multiple PHYs can be present on the MDIO bus,
+ * detect_phy is called to get the addresses of the PHY present on
+ * a particular MDIO bus (emac0 or emac1). This address map is populated
+ * in phymapemac0 or phymapemac1.
+ * phy_setup_emacps is then called for each PHY present on the MDIO bus.
+ */
+#ifdef PCM_PMA_CORE_PRESENT
+#ifdef XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT
+ link_speed = phy_setup_emacps(xemacpsp, XPAR_PCSPMA_1000BASEX_PHYADDR);
+#elif XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT
+ link_speed = phy_setup_emacps(xemacpsp, XPAR_PCSPMA_SGMII_PHYADDR);
+#endif
+#else
+ detect_phy(xemacpsp);
+ for (i = 31; i > 0; i--) {
+ if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
+ if (phymapemac0[i] == TRUE) {
+ link_speed = phy_setup_emacps(xemacpsp, i);
+ phyfoundforemac0 = TRUE;
+ phyaddrforemac = i;
+ }
+ } else {
+ if (phymapemac1[i] == TRUE) {
+ link_speed = phy_setup_emacps(xemacpsp, i);
+ phyfoundforemac1 = TRUE;
+ phyaddrforemac = i;
+ }
+ }
+ }
+ /* If no PHY was detected, use broadcast PHY address of 0 */
+ if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
+ if (phyfoundforemac0 == FALSE)
+ link_speed = phy_setup_emacps(xemacpsp, 0);
+ } else {
+ if (phyfoundforemac1 == FALSE)
+ link_speed = phy_setup_emacps(xemacpsp, 0);
+ }
+#endif
+
+ if (link_speed == XST_FAILURE) {
+ eth_link_status = ETH_LINK_DOWN;
+ xil_printf("Phy setup failure %s \n\r",__func__);
+ return;
+ } else {
+ eth_link_status = ETH_LINK_UP;
+ }
+
+ XEmacPs_SetOperatingSpeed(xemacpsp, link_speed);
+ /* Setting the operating speed of the MAC needs a delay. */
+ {
+ volatile s32_t wait;
+ for (wait=0; wait < 20000; wait++);
+ }
+}
+
+void init_emacps_on_error (xemacpsif_s *xemacps, struct netif *netif)
+{
+ XEmacPs *xemacpsp;
+ s32_t status = XST_SUCCESS;
+
+ xemacpsp = &xemacps->emacps;
+
+ /* set mac address */
+ status = XEmacPs_SetMacAddress(xemacpsp, (void*)(netif->hwaddr), 1);
+ if (status != XST_SUCCESS) {
+ xil_printf("In %s:Emac Mac Address set failed...\r\n",__func__);
+ }
+
+ XEmacPs_SetOperatingSpeed(xemacpsp, link_speed);
+
+ /* Setting the operating speed of the MAC needs a delay. */
+ {
+ volatile s32_t wait;
+ for (wait=0; wait < 20000; wait++);
+ }
+}
+
+void setup_isr (struct xemac_s *xemac)
+{
+ xemacpsif_s *xemacpsif;
+
+ xemacpsif = (xemacpsif_s *)(xemac->state);
+ /*
+ * Setup callbacks
+ */
+ XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMASEND,
+ (void *) emacps_send_handler,
+ (void *) xemac);
+
+ XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMARECV,
+ (void *) emacps_recv_handler,
+ (void *) xemac);
+
+ XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_ERROR,
+ (void *) emacps_error_handler,
+ (void *) xemac);
+}
+
+void start_emacps (xemacpsif_s *xemacps)
+{
+ /* start the temac */
+ XEmacPs_Start(&xemacps->emacps);
+}
+
+void restart_emacps_transmitter (xemacpsif_s *xemacps) {
+ u32_t Reg;
+ Reg = XEmacPs_ReadReg(xemacps->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET);
+ Reg = Reg & (~XEMACPS_NWCTRL_TXEN_MASK);
+ XEmacPs_WriteReg(xemacps->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET, Reg);
+
+ Reg = XEmacPs_ReadReg(xemacps->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET);
+ Reg = Reg | (XEMACPS_NWCTRL_TXEN_MASK);
+ XEmacPs_WriteReg(xemacps->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET, Reg);
+}
+
+void emacps_error_handler(void *arg,u8 Direction, u32 ErrorWord)
+{
+ struct xemac_s *xemac;
+ xemacpsif_s *xemacpsif;
+ XEmacPs_BdRing *rxring;
+ XEmacPs_BdRing *txring;
+#if !NO_SYS
+ xInsideISR++;
+#endif
+
+ xemac = (struct xemac_s *)(arg);
+ xemacpsif = (xemacpsif_s *)(xemac->state);
+ rxring = &XEmacPs_GetRxRing(&xemacpsif->emacps);
+ txring = &XEmacPs_GetTxRing(&xemacpsif->emacps);
+
+ if (ErrorWord != 0) {
+ switch (Direction) {
+ case XEMACPS_RECV:
+ if (ErrorWord & XEMACPS_RXSR_HRESPNOK_MASK) {
+ LWIP_DEBUGF(NETIF_DEBUG, ("Receive DMA error\r\n"));
+ HandleEmacPsError(xemac);
+ }
+ if (ErrorWord & XEMACPS_RXSR_RXOVR_MASK) {
+ LWIP_DEBUGF(NETIF_DEBUG, ("Receive over run\r\n"));
+ emacps_recv_handler(arg);
+ setup_rx_bds(xemacpsif, rxring);
+ }
+ if (ErrorWord & XEMACPS_RXSR_BUFFNA_MASK) {
+ LWIP_DEBUGF(NETIF_DEBUG, ("Receive buffer not available\r\n"));
+ emacps_recv_handler(arg);
+ setup_rx_bds(xemacpsif, rxring);
+ }
+ break;
+ case XEMACPS_SEND:
+ if (ErrorWord & XEMACPS_TXSR_HRESPNOK_MASK) {
+ LWIP_DEBUGF(NETIF_DEBUG, ("Transmit DMA error\r\n"));
+ HandleEmacPsError(xemac);
+ }
+ if (ErrorWord & XEMACPS_TXSR_URUN_MASK) {
+ LWIP_DEBUGF(NETIF_DEBUG, ("Transmit under run\r\n"));
+ HandleTxErrors(xemac);
+ }
+ if (ErrorWord & XEMACPS_TXSR_BUFEXH_MASK) {
+ LWIP_DEBUGF(NETIF_DEBUG, ("Transmit buffer exhausted\r\n"));
+ HandleTxErrors(xemac);
+ }
+ if (ErrorWord & XEMACPS_TXSR_RXOVR_MASK) {
+ LWIP_DEBUGF(NETIF_DEBUG, ("Transmit retry excessed limits\r\n"));
+ HandleTxErrors(xemac);
+ }
+ if (ErrorWord & XEMACPS_TXSR_FRAMERX_MASK) {
+ LWIP_DEBUGF(NETIF_DEBUG, ("Transmit collision\r\n"));
+ process_sent_bds(xemacpsif, txring);
+ }
+ break;
+ }
+ }
+#if !NO_SYS
+ xInsideISR--;
+#endif
+}
diff --git a/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif_physpeed.c b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif_physpeed.c
new file mode 100644
index 0000000..069020a
--- /dev/null
+++ b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xemacpsif_physpeed.c
@@ -0,0 +1,1037 @@
+/*
+ * Copyright (C) 2010 - 2019 Xilinx, 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.
+ *
+ */
+
+/*****************************************************************************
+* This file xemacpsif_physpeed.c implements functionalities to:
+* - Detect the available PHYs connected to a MAC
+* - Negotiate speed
+* - Configure speed
+* - Configure the SLCR registers for the negotiated speed
+*
+* In a typical use case, users of the APIs implemented in this file need to
+* do the following.
+* - Call the API detect_phy. It probes for the available PHYs connected to a MAC.
+* The MACs can be Emac0 (XPAR_XEMACPS_0_BASEADDR, 0xE000B000) or Emac1
+* (XPAR_XEMACPS_0_BASEADDR, 0xE000C000). It populates an array to notify
+* about the detected PHYs. The array phymapemac0 is used for Emac0 and
+* phymapemac1 is for Emac1.
+* - The users need to parse the corresponding arrays, phymapemac0 or phymapemac1
+* to know the available PHYs for a MAC. The users then need to call
+* phy_setup_emacps to setup the PHYs for proper speed setting. The API
+* phy_setup_emacps should be called with the PHY address for which the speed
+* needs to be negotiated or configured. In a specific use case, if 2 PHYs are
+* connected to Emac0 with addresses of 7 and 11, then users get these address
+* details from phymapemac0 (after calling detect_phy) and then call
+* phy_setup_emacps twice, with ab address of 7 and 11.
+* - Points to note: The MAC can operate at only one speed. If a MAC is connected
+* to multiple PHYs, then all PHYs must negotiate and configured for the same
+* speed.
+* - This file implements static functions to set proper SLCR clocks. As stated
+* above, all PHYs connected to a PHY must operate at same speed and the SLCR
+* clock will be setup accordingly.
+*
+* This file implements the following PHY types.
+* - The standard RGMII.
+* - It provides support for GMII to RGMII converter Xilinx IP. This Xilinx IP
+* sits on the MDIO bus with a predefined PHY address. This IP exposes register
+* that needs to be programmed with the negotiated speed.
+* For example, in a typical design, the Emac0 or Emac1 exposes GMII interface.
+* The user can then use the Xilinx IP that converts GMII to RGMII.
+* The external PHY (most typically Marvell 88E1116R) negotiates for speed
+* with the remote PHY. The implementation in this file then programs the
+* Xilinx IP with this negotiated speed. The Xilinx IP has a predefined IP
+* address exposed through xparameters.h
+* - The SGMII and 1000 BaseX PHY interfaces.
+* If the PHY interface is SGMII or 1000 BaseX a separate "get_IEEE_phy_speed"
+* is used which is different from standard RGMII "get_IEEE_phy_speed".
+* The 1000 BaseX always operates at 1000 Mbps. The SGMII interface can
+* negotiate speed accordingly.
+* For SGMII or 1000 BaseX interfaces, the detect_phy should not be called.
+* The phy addresses for these interfaces are fixed at the design time.
+*
+* Point to note:
+* A MAC can not be connected to PHYs where there is a mix between
+* SGMII or 1000 Basex or GMII/MII/RGMII.
+* In a typical multiple PHY designs, it is expected that the PHYs connected
+* will be RGMII or GMII.
+*
+* The users can choose not to negotiate speed from lwip settings GUI.
+* If they opt to choose a particular PHY speed, then the PHY will hard code
+* the speed to operate only at the corresponding speed. It will not advertise
+* any other speeds. It is users responsibility to ensure that the remote PHY
+* supports the speed programmed through the lwip gui.
+*
+* The following combination of MDIO/PHY are supported:
+* - Multiple PHYs connected to the MDIO bus of a MAC. If Emac0 MDIO is connected
+* to single/multiple PHYs, it is supported. Similarly Emac1 MDIO connected to
+* single/multiple PHYs is supported.
+* - A design where both the interfaces are present and are connected to their own
+* MDIO bus is supported.
+*
+* The following MDIO/PHY setup is not supported:
+* - A design has both the MACs present. MDIO bus is available only for one MAC
+* (Emac0 or Emac1). This MDIO bus has multiple PHYs available for both the
+* MACs. The negotiated speed for PHYs sitting on the MDIO bus of one MAC will
+* not be see for the other MAC and hence the speed/SLCR settings of the other
+* MAC cannot be programmed. Hence this kind of design will not work for
+* this implementation.
+*
+********************************************************************************/
+
+#include "netif/xemacpsif.h"
+#include "lwipopts.h"
+#include "xparameters_ps.h"
+#include "xparameters.h"
+#include "xemac_ieee_reg.h"
+
+#if defined (__aarch64__)
+#include "bspconfig.h"
+#include "xil_smc.h"
+#endif
+
+#define PHY_DETECT_REG 1
+#define PHY_IDENTIFIER_1_REG 2
+#define PHY_IDENTIFIER_2_REG 3
+#define PHY_DETECT_MASK 0x1808
+#define PHY_MARVELL_IDENTIFIER 0x0141
+#define PHY_TI_IDENTIFIER 0x2000
+#define PHY_REALTEK_IDENTIFIER 0x001c
+#define PHY_XILINX_PCS_PMA_ID1 0x0174
+#define PHY_XILINX_PCS_PMA_ID2 0x0C00
+
+#define XEMACPS_GMII2RGMII_SPEED1000_FD 0x140
+#define XEMACPS_GMII2RGMII_SPEED100_FD 0x2100
+#define XEMACPS_GMII2RGMII_SPEED10_FD 0x100
+#define XEMACPS_GMII2RGMII_REG_NUM 0x10
+
+#define PHY_REGCR 0x0D
+#define PHY_ADDAR 0x0E
+#define PHY_RGMIIDCTL 0x86
+#define PHY_RGMIICTL 0x32
+#define PHY_STS 0x11
+#define PHY_TI_CR 0x10
+#define PHY_TI_CFG4 0x31
+
+#define PHY_REGCR_ADDR 0x001F
+#define PHY_REGCR_DATA 0x401F
+#define PHY_TI_CRVAL 0x5048
+#define PHY_TI_CFG4RESVDBIT7 0x80
+
+/* Frequency setting */
+#define SLCR_LOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x4)
+#define SLCR_UNLOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x8)
+#define SLCR_GEM0_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x140)
+#define SLCR_GEM1_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x144)
+#define SLCR_GEM_SRCSEL_EMIO 0x40
+#define SLCR_LOCK_KEY_VALUE 0x767B
+#define SLCR_UNLOCK_KEY_VALUE 0xDF0D
+#define SLCR_ADDR_GEM_RST_CTRL (XPS_SYS_CTRL_BASEADDR + 0x214)
+#define EMACPS_SLCR_DIV_MASK 0xFC0FC0FF
+
+#if XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1 || \
+ XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1
+#define PCM_PMA_CORE_PRESENT
+#else
+#undef PCM_PMA_CORE_PRESENT
+#endif
+
+#ifdef PCM_PMA_CORE_PRESENT
+#define IEEE_CTRL_RESET 0x9140
+#define IEEE_CTRL_ISOLATE_DISABLE 0xFBFF
+#endif
+
+u32_t phymapemac0[32];
+u32_t phymapemac1[32];
+
+#if defined (PCM_PMA_CORE_PRESENT) || defined (CONFIG_LINKSPEED_AUTODETECT)
+static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr);
+#endif
+static void SetUpSLCRDivisors(UINTPTR mac_baseaddr, s32_t speed);
+#if defined (CONFIG_LINKSPEED1000) || defined (CONFIG_LINKSPEED100) \
+ || defined (CONFIG_LINKSPEED10)
+static u32_t configure_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr, u32_t speed);
+#endif
+
+#ifdef PCM_PMA_CORE_PRESENT
+u32_t phy_setup_emacps (XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ u32_t link_speed;
+ u16_t regval;
+ u16_t phy_id;
+
+ if(phy_addr == 0) {
+ for (phy_addr = 31; phy_addr > 0; phy_addr--) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG,
+ &phy_id);
+
+ if (phy_id == PHY_XILINX_PCS_PMA_ID1) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_2_REG,
+ &phy_id);
+ if (phy_id == PHY_XILINX_PCS_PMA_ID2) {
+ /* Found a valid PHY address */
+ LWIP_DEBUGF(NETIF_DEBUG, ("XEmacPs detect_phy: PHY detected at address %d.\r\n",
+ phy_addr));
+ break;
+ }
+ }
+ }
+ }
+
+ link_speed = get_IEEE_phy_speed(xemacpsp, phy_addr);
+ if (link_speed == 1000)
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
+ else if (link_speed == 100)
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
+ else
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
+
+ xil_printf("link speed for phy address %d: %d\r\n", phy_addr, link_speed);
+ return link_speed;
+}
+
+static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ u16_t temp;
+ u16_t control;
+ u16_t status;
+ u16_t partner_capabilities;
+
+ xil_printf("Start PHY autonegotiation \r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
+ control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
+ control &= IEEE_CTRL_ISOLATE_DISABLE;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
+ sleep(1);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET,
+ &status);
+ }
+ xil_printf("autonegotiation complete \r\n");
+
+#if XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 1);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_1_REG_OFFSET, &temp);
+ if ((temp & 0x0020) == 0x0020) {
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+ return 1000;
+ }
+ else {
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+ xil_printf("Link error, temp = %x\r\n", temp);
+ return 0;
+ }
+#elif XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1
+ xil_printf("Waiting for Link to be up; Polling for SGMII core Reg \r\n");
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_1_REG_OFFSET, &temp);
+ while(!(temp & 0x8000)) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_1_REG_OFFSET, &temp);
+ }
+ if((temp & 0x0C00) == 0x0800) {
+ return 1000;
+ }
+ else if((temp & 0x0C00) == 0x0400) {
+ return 100;
+ }
+ else if((temp & 0x0C00) == 0x0000) {
+ return 10;
+ } else {
+ xil_printf("get_IEEE_phy_speed(): Invalid speed bit value, Defaulting to Speed = 10 Mbps\r\n");
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &temp);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, 0x0100);
+ return 10;
+ }
+#endif
+
+}
+
+#else /*PCM_PMA_CORE_PRESENT not defined, GMII/RGMII case*/
+void detect_phy(XEmacPs *xemacpsp)
+{
+ u16_t phy_reg;
+ u32_t phy_addr;
+ u32_t emacnum;
+
+ if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR)
+ emacnum = 0;
+ else
+ emacnum = 1;
+ for (phy_addr = 31; phy_addr > 0; phy_addr--) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_DETECT_REG,
+ &phy_reg);
+
+ if ((phy_reg != 0xFFFF) &&
+ ((phy_reg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
+ /* Found a valid PHY address */
+ LWIP_DEBUGF(NETIF_DEBUG, ("XEmacPs detect_phy: PHY detected at address %d.\r\n",
+ phy_addr));
+ if (emacnum == 0)
+ phymapemac0[phy_addr] = TRUE;
+ else
+ phymapemac1[phy_addr] = TRUE;
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG,
+ &phy_reg);
+ if ((phy_reg != PHY_MARVELL_IDENTIFIER) &&
+ (phy_reg != PHY_TI_IDENTIFIER) &&
+ (phy_reg != PHY_REALTEK_IDENTIFIER)) {
+ xil_printf("WARNING: Not a Marvell or TI or Realtek Ethernet PHY. Please verify the initialization sequence\r\n");
+ }
+ }
+ }
+}
+
+u32_t phy_setup_emacps (XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ u32_t link_speed;
+ u32_t conv_present = 0;
+ u32_t convspeeddupsetting = 0;
+ u32_t convphyaddr = 0;
+
+#ifdef XPAR_GMII2RGMIICON_0N_ETH0_ADDR
+ convphyaddr = XPAR_GMII2RGMIICON_0N_ETH0_ADDR;
+ conv_present = 1;
+#endif
+#ifdef XPAR_GMII2RGMIICON_0N_ETH1_ADDR
+ convphyaddr = XPAR_GMII2RGMIICON_0N_ETH1_ADDR;
+ conv_present = 1;
+#endif
+
+#ifdef CONFIG_LINKSPEED_AUTODETECT
+ link_speed = get_IEEE_phy_speed(xemacpsp, phy_addr);
+ if (link_speed == 1000) {
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD;
+ } else if (link_speed == 100) {
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD;
+ } else if (link_speed != XST_FAILURE){
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD;
+ } else {
+ xil_printf("Phy setup error \r\n");
+ return XST_FAILURE;
+ }
+#elif defined(CONFIG_LINKSPEED1000)
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
+ link_speed = 1000;
+ configure_IEEE_phy_speed(xemacpsp, phy_addr, link_speed);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD;
+ sleep(1);
+#elif defined(CONFIG_LINKSPEED100)
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
+ link_speed = 100;
+ configure_IEEE_phy_speed(xemacpsp, phy_addr, link_speed);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD;
+ sleep(1);
+#elif defined(CONFIG_LINKSPEED10)
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
+ link_speed = 10;
+ configure_IEEE_phy_speed(xemacpsp, phy_addr, link_speed);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD;
+ sleep(1);
+#endif
+ if (conv_present) {
+ XEmacPs_PhyWrite(xemacpsp, convphyaddr,
+ XEMACPS_GMII2RGMII_REG_NUM, convspeeddupsetting);
+ }
+
+ xil_printf("link speed for phy address %d: %d\r\n", phy_addr, link_speed);
+ return link_speed;
+}
+
+#if defined CONFIG_LINKSPEED_AUTODETECT
+static u32_t get_TI_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ u16_t control;
+ u16_t status;
+ u16_t status_speed;
+ u32_t timeout_counter = 0;
+ u32_t phyregtemp;
+ u32_t RetStatus;
+
+ xil_printf("Start PHY autonegotiation \r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, 0x1F, (u16_t *)&phyregtemp);
+ phyregtemp |= 0x4000;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1F, phyregtemp);
+ RetStatus = XEmacPs_PhyRead(xemacpsp, phy_addr, 0x1F, (u16_t *)&phyregtemp);
+ if (RetStatus != XST_SUCCESS) {
+ xil_printf("Error during sw reset \n\r");
+ return XST_FAILURE;
+ }
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, 0, (u16_t *)&phyregtemp);
+ phyregtemp |= 0x8000;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, 0, phyregtemp);
+
+ /*
+ * Delay
+ */
+ sleep(1);
+
+ RetStatus = XEmacPs_PhyRead(xemacpsp, phy_addr, 0, (u16_t *)&phyregtemp);
+ if (RetStatus != XST_SUCCESS) {
+ xil_printf("Error during reset \n\r");
+ return XST_FAILURE;
+ }
+
+ /* FIFO depth */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_TI_CR, PHY_TI_CRVAL);
+ RetStatus = XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_TI_CR, (u16_t *)&phyregtemp);
+ if (RetStatus != XST_SUCCESS) {
+ xil_printf("Error writing to 0x10 \n\r");
+ return XST_FAILURE;
+ }
+
+ /* TX/RX tuning */
+ /* Write to PHY_RGMIIDCTL */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, PHY_RGMIIDCTL);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
+ RetStatus = XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, 0xA8);
+ if (RetStatus != XST_SUCCESS) {
+ xil_printf("Error in tuning");
+ return XST_FAILURE;
+ }
+
+ /* Read PHY_RGMIIDCTL */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, PHY_RGMIIDCTL);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
+ RetStatus = XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_ADDAR, (u16_t *)&phyregtemp);
+ if (RetStatus != XST_SUCCESS) {
+ xil_printf("Error in tuning");
+ return XST_FAILURE;
+ }
+
+ /* Write PHY_RGMIICTL */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, PHY_RGMIICTL);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
+ RetStatus = XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, 0xD3);
+ if (RetStatus != XST_SUCCESS) {
+ xil_printf("Error in tuning");
+ return XST_FAILURE;
+ }
+
+ /* Read PHY_RGMIICTL */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, PHY_RGMIICTL);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
+ RetStatus = XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_ADDAR, (u16_t *)&phyregtemp);
+ if (RetStatus != XST_SUCCESS) {
+ xil_printf("Error in tuning");
+ return XST_FAILURE;
+ }
+
+ /* SW workaround for unstable link when RX_CTRL is not STRAP MODE 3 or 4 */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, PHY_TI_CFG4);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
+ RetStatus = XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_ADDAR, (u16_t *)&phyregtemp);
+ phyregtemp &= ~(PHY_TI_CFG4RESVDBIT7);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, PHY_TI_CFG4);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
+ RetStatus = XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, phyregtemp);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
+ control |= IEEE_ASYMMETRIC_PAUSE_MASK;
+ control |= IEEE_PAUSE_MASK;
+ control |= ADVERTISE_100;
+ control |= ADVERTISE_10;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ &control);
+ control |= ADVERTISE_1000;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
+ control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+
+ xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
+
+ while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
+ sleep(1);
+ timeout_counter++;
+
+ if (timeout_counter == 30) {
+ xil_printf("Auto negotiation error \r\n");
+ return XST_FAILURE;
+ }
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ }
+ xil_printf("autonegotiation complete \r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_STS, &status_speed);
+ if ((status_speed & 0xC000) == 0x8000) {
+ return 1000;
+ } else if ((status_speed & 0xC000) == 0x4000) {
+ return 100;
+ } else {
+ return 10;
+ }
+
+ return XST_SUCCESS;
+}
+
+static u32_t get_Marvell_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ u16_t temp;
+ u16_t control;
+ u16_t status;
+ u16_t status_speed;
+ u32_t timeout_counter = 0;
+ u32_t temp_speed;
+
+ xil_printf("Start PHY autonegotiation \r\n");
+
+ XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
+ control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
+ control |= IEEE_ASYMMETRIC_PAUSE_MASK;
+ control |= IEEE_PAUSE_MASK;
+ control |= ADVERTISE_100;
+ control |= ADVERTISE_10;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ &control);
+ control |= ADVERTISE_1000;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ control);
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
+ &control);
+ control |= (7 << 12); /* max number of gigabit attempts */
+ control |= (1 << 11); /* enable downshift */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
+ control);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
+ control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_RESET_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ while (1) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ if (control & IEEE_CTRL_RESET_MASK)
+ continue;
+ else
+ break;
+ }
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+
+ xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
+
+ while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
+ sleep(1);
+ XEmacPs_PhyRead(xemacpsp, phy_addr,
+ IEEE_COPPER_SPECIFIC_STATUS_REG_2, &temp);
+ timeout_counter++;
+
+ if (timeout_counter == 30) {
+ xil_printf("Auto negotiation error \r\n");
+ return XST_FAILURE;
+ }
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ }
+ xil_printf("autonegotiation complete \r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr,IEEE_SPECIFIC_STATUS_REG,
+ &status_speed);
+ if (status_speed & 0x400) {
+ temp_speed = status_speed & IEEE_SPEED_MASK;
+
+ if (temp_speed == IEEE_SPEED_1000)
+ return 1000;
+ else if(temp_speed == IEEE_SPEED_100)
+ return 100;
+ else
+ return 10;
+ }
+
+ return XST_SUCCESS;
+}
+
+static u32_t get_Realtek_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ u16_t control;
+ u16_t status;
+ u16_t status_speed;
+ u32_t timeout_counter = 0;
+ u32_t temp_speed;
+
+ xil_printf("Start PHY autonegotiation \r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
+ control |= IEEE_ASYMMETRIC_PAUSE_MASK;
+ control |= IEEE_PAUSE_MASK;
+ control |= ADVERTISE_100;
+ control |= ADVERTISE_10;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ &control);
+ control |= ADVERTISE_1000;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
+ control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_RESET_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ while (1) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ if (control & IEEE_CTRL_RESET_MASK)
+ continue;
+ else
+ break;
+ }
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+
+ xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
+
+ while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
+ sleep(1);
+ timeout_counter++;
+
+ if (timeout_counter == 30) {
+ xil_printf("Auto negotiation error \r\n");
+ return XST_FAILURE;
+ }
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ }
+ xil_printf("autonegotiation complete \r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr,IEEE_SPECIFIC_STATUS_REG,
+ &status_speed);
+ if (status_speed & 0x400) {
+ temp_speed = status_speed & IEEE_SPEED_MASK;
+
+ if (temp_speed == IEEE_SPEED_1000)
+ return 1000;
+ else if(temp_speed == IEEE_SPEED_100)
+ return 100;
+ else
+ return 10;
+ }
+
+ return XST_FAILURE;
+}
+
+static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ u16_t phy_identity;
+ u32_t RetStatus;
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG,
+ &phy_identity);
+ if (phy_identity == PHY_TI_IDENTIFIER) {
+ RetStatus = get_TI_phy_speed(xemacpsp, phy_addr);
+ } else if (phy_identity == PHY_REALTEK_IDENTIFIER) {
+ RetStatus = get_Realtek_phy_speed(xemacpsp, phy_addr);
+ } else {
+ RetStatus = get_Marvell_phy_speed(xemacpsp, phy_addr);
+ }
+
+ return RetStatus;
+}
+#endif
+
+#if defined (CONFIG_LINKSPEED1000) || defined (CONFIG_LINKSPEED100) \
+ || defined (CONFIG_LINKSPEED10)
+static u32_t configure_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr, u32_t speed)
+{
+ u16_t control;
+ u16_t autonereg;
+
+ XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
+ control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
+ autonereg |= IEEE_ASYMMETRIC_PAUSE_MASK;
+ autonereg |= IEEE_PAUSE_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control &= ~IEEE_CTRL_LINKSPEED_1000M;
+ control &= ~IEEE_CTRL_LINKSPEED_100M;
+ control &= ~IEEE_CTRL_LINKSPEED_10M;
+
+ if (speed == 1000) {
+ control |= IEEE_CTRL_LINKSPEED_1000M;
+
+ /* Don't advertise PHY speed of 100 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
+ autonereg &= (~ADVERTISE_100);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
+
+ /* Don't advertise PHY speed of 10 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
+ autonereg &= (~ADVERTISE_10);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
+
+ /* Advertise PHY speed of 1000 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, &autonereg);
+ autonereg |= ADVERTISE_1000;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, autonereg);
+ }
+
+ else if (speed == 100) {
+ control |= IEEE_CTRL_LINKSPEED_100M;
+
+ /* Don't advertise PHY speed of 1000 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, &autonereg);
+ autonereg &= (~ADVERTISE_1000);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, autonereg);
+
+ /* Don't advertise PHY speed of 10 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
+ autonereg &= (~ADVERTISE_10);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
+
+ /* Advertise PHY speed of 100 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
+ autonereg |= ADVERTISE_100;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
+ }
+
+ else if (speed == 10) {
+ control |= IEEE_CTRL_LINKSPEED_10M;
+
+ /* Don't advertise PHY speed of 1000 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, &autonereg);
+ autonereg &= (~ADVERTISE_1000);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, autonereg);
+
+ /* Don't advertise PHY speed of 100 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
+ autonereg &= (~ADVERTISE_100);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
+
+ /* Advertise PHY speed of 10 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
+ autonereg |= ADVERTISE_10;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
+ }
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET,
+ control | IEEE_CTRL_RESET_MASK);
+ {
+ volatile s32_t wait;
+ for (wait=0; wait < 100000; wait++);
+ }
+ return 0;
+}
+#endif
+#endif /*PCM_PMA_CORE_PRESENT*/
+
+static void SetUpSLCRDivisors(UINTPTR mac_baseaddr, s32_t speed)
+{
+ volatile UINTPTR slcrBaseAddress;
+ u32_t SlcrDiv0 = 0;
+ u32_t SlcrDiv1 = 0;
+ u32_t SlcrTxClkCntrl;
+ u32_t gigeversion;
+ volatile UINTPTR CrlApbBaseAddr;
+ u32_t CrlApbDiv0 = 0;
+ u32_t CrlApbDiv1 = 0;
+ u32_t CrlApbGemCtrl;
+#if defined (__aarch64__) && (EL1_NONSECURE == 1)
+ u32_t ClkId;
+#endif
+
+ gigeversion = ((Xil_In32(mac_baseaddr + 0xFC)) >> 16) & 0xFFF;
+ if (gigeversion == 2) {
+
+ Xil_Out32(SLCR_UNLOCK_ADDR, SLCR_UNLOCK_KEY_VALUE);
+
+ if (mac_baseaddr == ZYNQ_EMACPS_0_BASEADDR) {
+ slcrBaseAddress = SLCR_GEM0_CLK_CTRL_ADDR;
+ } else {
+ slcrBaseAddress = SLCR_GEM1_CLK_CTRL_ADDR;
+ }
+
+ if(Xil_In32(slcrBaseAddress) &
+ SLCR_GEM_SRCSEL_EMIO) {
+ return;
+ }
+
+ if (speed == 1000) {
+ if (mac_baseaddr == ZYNQ_EMACPS_0_BASEADDR) {
+#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1;
+#endif
+ } else {
+#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1;
+#endif
+ }
+ } else if (speed == 100) {
+ if (mac_baseaddr == ZYNQ_EMACPS_0_BASEADDR) {
+#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1;
+#endif
+ } else {
+#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV1;
+#endif
+ }
+ } else {
+ if (mac_baseaddr == ZYNQ_EMACPS_0_BASEADDR) {
+#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1;
+#endif
+ } else {
+#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV1;
+#endif
+ }
+ }
+
+ if (SlcrDiv0 != 0 && SlcrDiv1 != 0) {
+ SlcrTxClkCntrl = Xil_In32(slcrBaseAddress);
+ SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
+ SlcrTxClkCntrl |= (SlcrDiv1 << 20);
+ SlcrTxClkCntrl |= (SlcrDiv0 << 8);
+ Xil_Out32(slcrBaseAddress, SlcrTxClkCntrl);
+ Xil_Out32(SLCR_LOCK_ADDR, SLCR_LOCK_KEY_VALUE);
+ } else {
+ xil_printf("Clock Divisors incorrect - Please check\r\n");
+ }
+ } else if (gigeversion == GEM_VERSION_ZYNQMP) {
+ /* Setup divisors in CRL_APB for Zynq Ultrascale+ MPSoC */
+ if (mac_baseaddr == ZYNQMP_EMACPS_0_BASEADDR) {
+ CrlApbBaseAddr = CRL_APB_GEM0_REF_CTRL;
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_1_BASEADDR) {
+ CrlApbBaseAddr = CRL_APB_GEM1_REF_CTRL;
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_2_BASEADDR) {
+ CrlApbBaseAddr = CRL_APB_GEM2_REF_CTRL;
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_3_BASEADDR) {
+ CrlApbBaseAddr = CRL_APB_GEM3_REF_CTRL;
+ }
+
+ if (speed == 1000) {
+ if (mac_baseaddr == ZYNQMP_EMACPS_0_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_1_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_2_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_2_ENET_SLCR_1000MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_2_ENET_SLCR_1000MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_2_ENET_SLCR_1000MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_3_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_3_ENET_SLCR_1000MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_3_ENET_SLCR_1000MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_3_ENET_SLCR_1000MBPS_DIV1;
+#endif
+ }
+ } else if (speed == 100) {
+ if (mac_baseaddr == ZYNQMP_EMACPS_0_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_0_ENET_SLCR_100MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_0_ENET_SLCR_100MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_0_ENET_SLCR_100MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_1_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_1_ENET_SLCR_100MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_1_ENET_SLCR_100MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_1_ENET_SLCR_100MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_2_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_2_ENET_SLCR_100MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_2_ENET_SLCR_100MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_2_ENET_SLCR_100MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_3_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_3_ENET_SLCR_100MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_3_ENET_SLCR_100MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_3_ENET_SLCR_100MBPS_DIV1;
+#endif
+ }
+ } else {
+ if (mac_baseaddr == ZYNQMP_EMACPS_0_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_0_ENET_SLCR_10MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_0_ENET_SLCR_10MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_0_ENET_SLCR_10MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_1_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_1_ENET_SLCR_10MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_1_ENET_SLCR_10MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_1_ENET_SLCR_10MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_2_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_2_ENET_SLCR_10MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_2_ENET_SLCR_10MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_2_ENET_SLCR_10MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_3_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_3_ENET_SLCR_10MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_3_ENET_SLCR_10MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_3_ENET_SLCR_10MBPS_DIV1;
+#endif
+ }
+ }
+
+ if (CrlApbDiv0 != 0 && CrlApbDiv1 != 0) {
+ #if defined (__aarch64__) && (EL1_NONSECURE == 1)
+ XSmc_OutVar RegRead;
+ RegRead = Xil_Smc(MMIO_READ_SMC_FID, (u64)(CrlApbBaseAddr),
+ 0, 0, 0, 0, 0, 0);
+ CrlApbGemCtrl = RegRead.Arg0 >> 32;
+ #else
+ CrlApbGemCtrl = Xil_In32(CrlApbBaseAddr);
+ #endif
+ CrlApbGemCtrl &= ~CRL_APB_GEM_DIV0_MASK;
+ CrlApbGemCtrl |= CrlApbDiv0 << CRL_APB_GEM_DIV0_SHIFT;
+ CrlApbGemCtrl &= ~CRL_APB_GEM_DIV1_MASK;
+ CrlApbGemCtrl |= CrlApbDiv1 << CRL_APB_GEM_DIV1_SHIFT;
+ #if defined (__aarch64__) && (EL1_NONSECURE == 1)
+ Xil_Smc(MMIO_WRITE_SMC_FID, (u64)(CrlApbBaseAddr) | ((u64)(0xFFFFFFFF) << 32),
+ (u64)CrlApbGemCtrl, 0, 0, 0, 0, 0);
+ do {
+ RegRead = Xil_Smc(MMIO_READ_SMC_FID, (u64)(CrlApbBaseAddr),
+ 0, 0, 0, 0, 0, 0);
+ } while((RegRead.Arg0 >> 32) != CrlApbGemCtrl);
+ #else
+ Xil_Out32(CrlApbBaseAddr, CrlApbGemCtrl);
+ #endif
+ } else {
+ xil_printf("Clock Divisors incorrect - Please check\r\n");
+ }
+ } else if (gigeversion == GEM_VERSION_VERSAL) {
+ /* Setup divisors in CRL for Versal */
+ if (mac_baseaddr == VERSAL_EMACPS_0_BASEADDR) {
+ CrlApbBaseAddr = VERSAL_CRL_GEM0_REF_CTRL;
+#if defined (__aarch64__) && (EL1_NONSECURE == 1)
+ ClkId = CLK_GEM0_REF;
+#endif
+ } else if (mac_baseaddr == VERSAL_EMACPS_1_BASEADDR) {
+ CrlApbBaseAddr = VERSAL_CRL_GEM1_REF_CTRL;
+#if defined (__aarch64__) && (EL1_NONSECURE == 1)
+ ClkId = CLK_GEM1_REF;
+#endif
+ }
+
+ if (speed == 1000) {
+ if (mac_baseaddr == VERSAL_EMACPS_0_BASEADDR) {
+#ifdef XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0
+ CrlApbDiv0 = XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0;
+#endif
+ } else if (mac_baseaddr == VERSAL_EMACPS_1_BASEADDR) {
+#ifdef XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0
+ CrlApbDiv0 = XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0;
+#endif
+ }
+ } else if (speed == 100) {
+ if (mac_baseaddr == VERSAL_EMACPS_0_BASEADDR) {
+#ifdef XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_ETHERNET_0_ENET_SLCR_100MBPS_DIV0
+ CrlApbDiv0 = XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_ETHERNET_0_ENET_SLCR_100MBPS_DIV0;
+#endif
+ } else if (mac_baseaddr == VERSAL_EMACPS_1_BASEADDR) {
+#ifdef XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_ETHERNET_1_ENET_SLCR_100MBPS_DIV0
+ CrlApbDiv0 = XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_ETHERNET_1_ENET_SLCR_100MBPS_DIV0;
+#endif
+ }
+ } else {
+ if (mac_baseaddr == VERSAL_EMACPS_0_BASEADDR) {
+#ifdef XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_ETHERNET_0_ENET_SLCR_10MBPS_DIV0
+ CrlApbDiv0 = XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_ETHERNET_0_ENET_SLCR_10MBPS_DIV0;
+#endif
+ } else if (mac_baseaddr == VERSAL_EMACPS_1_BASEADDR) {
+#ifdef XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_ETHERNET_1_ENET_SLCR_10MBPS_DIV0
+ CrlApbDiv0 = XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_ETHERNET_1_ENET_SLCR_10MBPS_DIV0;
+#endif
+ }
+ }
+
+ if (CrlApbDiv0 != 0) {
+#if defined (__aarch64__) && (EL1_NONSECURE == 1)
+ Xil_Smc(PM_SET_DIVIDER_SMC_FID, (((u64)CrlApbDiv0 << 32) | ClkId), 0, 0, 0, 0, 0, 0);
+#else
+ CrlApbGemCtrl = Xil_In32(CrlApbBaseAddr);
+ CrlApbGemCtrl &= ~VERSAL_CRL_GEM_DIV_MASK;
+ CrlApbGemCtrl |= CrlApbDiv0 << VERSAL_CRL_APB_GEM_DIV_SHIFT;
+
+ Xil_Out32(CrlApbBaseAddr, CrlApbGemCtrl);
+#endif
+ } else {
+ xil_printf("Clock Divisors incorrect - Please check\r\n");
+ }
+ }
+
+ return;
+}
diff --git a/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xpqueue.c b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xpqueue.c
new file mode 100644
index 0000000..b5a773e
--- /dev/null
+++ b/embeddedsw/ThirdParty/sw_services/lwip211/src/contrib/ports/xilinx/netif/xpqueue.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2007 - 2019 Xilinx, 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 <stdlib.h>
+
+#include "netif/xpqueue.h"
+#include "xil_printf.h"
+
+#define NUM_QUEUES 2
+
+pq_queue_t pq_queue[NUM_QUEUES];
+
+pq_queue_t *
+pq_create_queue()
+{
+ static int i;
+ pq_queue_t *q = NULL;
+
+ if (i >= NUM_QUEUES) {
+ xil_printf("ERR: Max Queues allocated\n\r");
+ return q;
+ }
+
+ q = &pq_queue[i++];
+
+ if (!q)
+ return q;
+
+ q->head = q->tail = q->len = 0;
+
+ return q;
+}
+
+int
+pq_enqueue(pq_queue_t *q, void *p)
+{
+ if (q->len == PQ_QUEUE_SIZE)
+ return -1;
+
+ q->data[q->head] = p;
+ q->head = (q->head + 1)%PQ_QUEUE_SIZE;
+ q->len++;
+
+ return 0;
+}
+
+void*
+pq_dequeue(pq_queue_t *q)
+{
+ int ptail;
+
+ if (q->len == 0)
+ return NULL;
+
+ ptail = q->tail;
+ q->tail = (q->tail + 1)%PQ_QUEUE_SIZE;
+ q->len--;
+
+ return q->data[ptail];
+}
+
+int
+pq_qlength(pq_queue_t *q)
+{
+ return q->len;
+}