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