1 /*
2  * Copyright (C) 2007 - 2019 Xilinx, Inc.
3  * Copyright (C) 2021 WangHuachen.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without modification,
7  * are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions and the following disclaimer in the documentation
13  *    and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
20  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
26  * OF SUCH DAMAGE.
27  *
28  * This file is part of the lwIP TCP/IP stack.
29  *
30  */
31 
32 #include "lwipopts.h"
33 #include "xlwipconfig.h"
34 #include "xemac_ieee_reg.h"
35 
36 #if !NO_SYS
37 #ifdef OS_IS_XILKERNEL
38 #include "xmk.h"
39 #include "sys/process.h"
40 #endif
41 #endif
42 
43 #include "lwip/mem.h"
44 #include "lwip/stats.h"
45 #include "lwip/sys.h"
46 #include "lwip/ip.h"
47 #include "lwip/tcp.h"
48 #include "lwip/udp.h"
49 #include "lwip/priv/tcp_priv.h"
50 
51 #include "netif/etharp.h"
52 #include "netif/xadapter.h"
53 
54 #ifdef XLWIP_CONFIG_INCLUDE_EMACLITE
55 #include "netif/xemacliteif.h"
56 #endif
57 
58 #ifdef XLWIP_CONFIG_INCLUDE_AXI_ETHERNET
59 #include "netif/xaxiemacif.h"
60 #endif
61 
62 #ifdef XLWIP_CONFIG_INCLUDE_GEM
63 #include "netif/xemacpsif.h"
64 #endif
65 
66 #if !NO_SYS
67 #include "lwip/tcpip.h"
68 #endif
69 
70 #ifdef OS_IS_FREERTOS
71 #define THREAD_STACKSIZE 256
72 #define LINK_DETECT_THREAD_INTERVAL 1000 /* one second */
73 
74 void link_detect_thread(void *p);
75 #endif
76 
77 /* global lwip debug variable used for debugging */
78 int lwip_runtime_debug = 0;
79 
80 enum ethernet_link_status eth_link_status = ETH_LINK_UNDEFINED;
81 u32_t phyaddrforemac;
82 
83 void
lwip_raw_init()84 lwip_raw_init()
85 {
86     ip_init();    /* Doesn't do much, it should be called to handle future changes. */
87 #if LWIP_UDP
88     udp_init();    /* Clears the UDP PCB list. */
89 #endif
90 #if LWIP_TCP
91     tcp_init();    /* Clears the TCP PCB list and clears some internal TCP timers. */
92             /* Note: you must call tcp_fasttmr() and tcp_slowtmr() at the */
93             /* predefined regular intervals after this initialization. */
94 #endif
95 }
96 
97 static enum xemac_types
find_mac_type(unsigned base)98 find_mac_type(unsigned base)
99 {
100     int i;
101 
102     for (i = 0; i < xtopology_n_emacs; i++) {
103         if (xtopology[i].emac_baseaddr == base)
104             return xtopology[i].emac_type;
105     }
106 
107     return xemac_type_unknown;
108 }
109 
110 int
xtopology_find_index(unsigned base)111 xtopology_find_index(unsigned base)
112 {
113     int i;
114 
115     for (i = 0; i < xtopology_n_emacs; i++) {
116         if (xtopology[i].emac_baseaddr == base)
117             return i;
118     }
119 
120     return -1;
121 }
122 
123 /*
124  * xemac_add: this is a wrapper around lwIP's netif_add function.
125  * The objective is to provide portability between the different Xilinx MAC's
126  * This function can be used to add both xps_ethernetlite and xps_ll_temac
127  * based interfaces
128  */
129 struct netif *
xemac_add(struct netif * netif,ip_addr_t * ipaddr,ip_addr_t * netmask,ip_addr_t * gw,unsigned char * mac_ethernet_address,unsigned mac_baseaddr)130 xemac_add(struct netif *netif,
131     ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw,
132     unsigned char *mac_ethernet_address,
133     unsigned mac_baseaddr)
134 {
135     int i;
136 
137 #ifdef OS_IS_FREERTOS
138     /* Start thread to detect link periodically for Hot Plug autodetect */
139     sys_thread_new("link_detect_thread", link_detect_thread, netif,
140             THREAD_STACKSIZE, tskIDLE_PRIORITY);
141 #endif
142 
143     /* set mac address */
144     netif->hwaddr_len = 6;
145     for (i = 0; i < 6; i++)
146         netif->hwaddr[i] = mac_ethernet_address[i];
147 
148     /* initialize based on MAC type */
149         switch (find_mac_type(mac_baseaddr)) {
150             case xemac_type_xps_emaclite:
151 #ifdef XLWIP_CONFIG_INCLUDE_EMACLITE
152                 return netif_add(netif, ipaddr, netmask, gw,
153                     (void*)(UINTPTR)mac_baseaddr,
154                     xemacliteif_init,
155 #if NO_SYS
156                     ethernet_input
157 #else
158                     tcpip_input
159 #endif
160                     );
161 #else
162                 return NULL;
163 #endif
164             case xemac_type_axi_ethernet:
165 #ifdef XLWIP_CONFIG_INCLUDE_AXI_ETHERNET
166                 return netif_add(netif, ipaddr, netmask, gw,
167                     (void*)(UINTPTR)mac_baseaddr,
168                     xaxiemacif_init,
169 #if NO_SYS
170                     ethernet_input
171 #else
172                     tcpip_input
173 #endif
174                     );
175 #else
176                 return NULL;
177 #endif
178 #if defined (__arm__) || defined (__aarch64__)
179             case xemac_type_emacps:
180 #ifdef XLWIP_CONFIG_INCLUDE_GEM
181                 return netif_add(netif, ipaddr, netmask, gw,
182                         (void*)(UINTPTR)mac_baseaddr,
183                         xemacpsif_init,
184 #if NO_SYS
185                         ethernet_input
186 #else
187                         tcpip_input
188 #endif
189 
190                         );
191 #endif
192 #endif
193             default:
194                 xil_printf("unable to determine type of EMAC with baseaddress 0x%08x\r\n",
195                         mac_baseaddr);
196                 return NULL;
197     }
198 }
199 
200 int
xemacif_input(struct netif * netif)201 xemacif_input(struct netif *netif)
202 {
203     struct xemac_s *emac = (struct xemac_s *)netif->state;
204 
205     int n_packets = 0;
206 
207     switch (emac->type) {
208         case xemac_type_xps_emaclite:
209 #ifdef XLWIP_CONFIG_INCLUDE_EMACLITE
210             n_packets = xemacliteif_input(netif);
211             break;
212 #else
213             // print("incorrect configuration: xps_ethernetlite drivers not present?");
214             while(1);
215             return 0;
216 #endif
217         case xemac_type_axi_ethernet:
218 #ifdef XLWIP_CONFIG_INCLUDE_AXI_ETHERNET
219             n_packets = xaxiemacif_input(netif);
220             break;
221 #else
222             // print("incorrect configuration: axi_ethernet drivers not present?");
223             while(1);
224             return 0;
225 #endif
226 #if defined (__arm__) || defined (__aarch64__)
227         case xemac_type_emacps:
228 #ifdef XLWIP_CONFIG_INCLUDE_GEM
229             n_packets = xemacpsif_input(netif);
230             break;
231 #else
232             xil_printf("incorrect configuration: ps7_ethernet drivers not present?\r\n");
233             while(1);
234             return 0;
235 #endif
236 #endif
237         default:
238             // print("incorrect configuration: unknown temac type");
239             while(1);
240             return 0;
241     }
242 
243     return n_packets;
244 }
245 
246 #if defined(XLWIP_CONFIG_INCLUDE_GEM)
phy_link_detect(XEmacPs * xemacp,u32_t phy_addr)247 u32_t phy_link_detect(XEmacPs *xemacp, u32_t phy_addr)
248 {
249     u16_t status;
250 
251     /* Read Phy Status register twice to get the confirmation of the current
252      * link status.
253      */
254     XEmacPs_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
255     XEmacPs_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
256 
257     if (status & IEEE_STAT_LINK_STATUS)
258         return 1;
259     return 0;
260 }
261 #elif defined(XLWIP_CONFIG_INCLUDE_AXI_ETHERNET)
phy_link_detect(XAxiEthernet * xemacp,u32_t phy_addr)262 static u32_t phy_link_detect(XAxiEthernet *xemacp, u32_t phy_addr)
263 {
264     u16_t status;
265 
266     /* Read Phy Status register twice to get the confirmation of the current
267      * link status.
268      */
269     XAxiEthernet_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
270     XAxiEthernet_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
271 
272     if (status & IEEE_STAT_LINK_STATUS)
273         return 1;
274     return 0;
275 }
276 #elif defined(XLWIP_CONFIG_INCLUDE_EMACLITE)
phy_link_detect(XEmacLite * xemacp,u32_t phy_addr)277 static u32_t phy_link_detect(XEmacLite *xemacp, u32_t phy_addr)
278 {
279     u16_t status;
280 
281     /* Read Phy Status register twice to get the confirmation of the current
282      * link status.
283      */
284     XEmacLite_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
285     XEmacLite_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
286 
287     if (status & IEEE_STAT_LINK_STATUS)
288         return 1;
289     return 0;
290 }
291 #endif
292 
293 #if defined(XLWIP_CONFIG_INCLUDE_GEM)
phy_autoneg_status(XEmacPs * xemacp,u32_t phy_addr)294 u32_t phy_autoneg_status(XEmacPs *xemacp, u32_t phy_addr)
295 {
296     u16_t status;
297 
298     /* Read Phy Status register twice to get the confirmation of the current
299      * link status.
300      */
301     XEmacPs_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
302     XEmacPs_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
303 
304     if (status & IEEE_STAT_AUTONEGOTIATE_COMPLETE)
305         return 1;
306     return 0;
307 }
308 #elif defined(XLWIP_CONFIG_INCLUDE_AXI_ETHERNET)
phy_autoneg_status(XAxiEthernet * xemacp,u32_t phy_addr)309 static u32_t phy_autoneg_status(XAxiEthernet *xemacp, u32_t phy_addr)
310 {
311     u16_t status;
312 
313     /* Read Phy Status register twice to get the confirmation of the current
314      * link status.
315      */
316     XAxiEthernet_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
317     XAxiEthernet_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
318 
319     if (status & IEEE_STAT_AUTONEGOTIATE_COMPLETE)
320         return 1;
321     return 0;
322 }
323 #elif defined(XLWIP_CONFIG_INCLUDE_EMACLITE)
phy_autoneg_status(XEmacLite * xemacp,u32_t phy_addr)324 static u32_t phy_autoneg_status(XEmacLite *xemacp, u32_t phy_addr)
325 {
326     u16_t status;
327 
328     /* Read Phy Status register twice to get the confirmation of the current
329      * link status.
330      */
331     XEmacLite_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
332     XEmacLite_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
333 
334     if (status & IEEE_STAT_AUTONEGOTIATE_COMPLETE)
335         return 1;
336     return 0;
337 }
338 #endif
339 
eth_link_detect(struct netif * netif)340 void eth_link_detect(struct netif *netif)
341 {
342     u32_t link_speed, phy_link_status;
343     struct xemac_s *xemac = (struct xemac_s *)(netif->state);
344 
345 #if defined(XLWIP_CONFIG_INCLUDE_GEM)
346     xemacpsif_s *xemacs = (xemacpsif_s *)(xemac->state);
347     XEmacPs *xemacp = &xemacs->emacps;
348 #elif defined(XLWIP_CONFIG_INCLUDE_AXI_ETHERNET)
349     xaxiemacif_s *xemacs = (xaxiemacif_s *)(xemac->state);
350     XAxiEthernet *xemacp = &xemacs->axi_ethernet;
351 #elif defined(XLWIP_CONFIG_INCLUDE_EMACLITE)
352     xemacliteif_s *xemacs = (xemacliteif_s *)(xemac->state);
353     XEmacLite *xemacp = xemacs->instance;
354 #endif
355 
356     if ((xemacp->IsReady != (u32)XIL_COMPONENT_IS_READY) ||
357             (eth_link_status == ETH_LINK_UNDEFINED))
358         return;
359 
360     phy_link_status = phy_link_detect(xemacp, phyaddrforemac);
361 
362     if ((eth_link_status == ETH_LINK_UP) && (!phy_link_status))
363         eth_link_status = ETH_LINK_DOWN;
364 
365     switch (eth_link_status) {
366         case ETH_LINK_UNDEFINED:
367         case ETH_LINK_UP:
368             return;
369         case ETH_LINK_DOWN:
370             netif_set_link_down(netif);
371             eth_link_status = ETH_LINK_NEGOTIATING;
372             xil_printf("Ethernet Link down\r\n");
373             break;
374         case ETH_LINK_NEGOTIATING:
375             if (phy_link_status &&
376                 phy_autoneg_status(xemacp, phyaddrforemac)) {
377 
378                 /* Initiate Phy setup to get link speed */
379 #if defined(XLWIP_CONFIG_INCLUDE_GEM)
380                 link_speed = phy_setup_emacps(xemacp,
381                                 phyaddrforemac);
382                 XEmacPs_SetOperatingSpeed(xemacp, link_speed);
383 #elif defined(XLWIP_CONFIG_INCLUDE_AXI_ETHERNET)
384                 link_speed = phy_setup_axiemac(xemacp);
385                 XAxiEthernet_SetOperatingSpeed(xemacp,
386                                    link_speed);
387 #endif
388                 netif_set_link_up(netif);
389                 eth_link_status = ETH_LINK_UP;
390                 xil_printf("Ethernet Link up\r\n");
391             }
392             break;
393     }
394 }
395 
396 #ifdef OS_IS_FREERTOS
link_detect_thread(void * p)397 void link_detect_thread(void *p)
398 {
399     struct netif *netif = (struct netif *) p;
400 
401     while (1) {
402         /* Call eth_link_detect() every second to detect Ethernet link
403          * change.
404          */
405         eth_link_detect(netif);
406         vTaskDelay(LINK_DETECT_THREAD_INTERVAL / portTICK_RATE_MS);
407     }
408 }
409 #endif
410