#include "xparameters.h" #include "xparameters_ps.h" #include "netif/xadapter.h" #include "xil_cache.h" #include "xscugic.h" #include "lwip/tcp.h" #include "lwip/init.h" #include "xil_printf.h" #include "platform.h" #include "xscutimer.h" #if LWIP_DHCP==1 #include "lwip/dhcp.h" #endif #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID #define TIMER_DEVICE_ID XPAR_SCUTIMER_DEVICE_ID #define INTC_BASE_ADDR XPAR_SCUGIC_0_CPU_BASEADDR #define INTC_DIST_BASE_ADDR XPAR_SCUGIC_0_DIST_BASEADDR #define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR #define RESET_RX_CNTR_LIMIT 400 static XScuTimer TimerInstance; #ifndef USE_SOFTETH_ON_ZYNQ static int ResetRxCntr = 0; extern struct netif *echo_netif; #endif volatile int TcpFastTmrFlag = 0; volatile int TcpSlowTmrFlag = 0; #if LWIP_DHCP==1 volatile int dhcp_timoutcntr = 200; void dhcp_fine_tmr(); void dhcp_coarse_tmr(); #endif void timer_callback(XScuTimer * TimerInstance) { /* we need to call tcp_fasttmr & tcp_slowtmr at intervals specified * by lwIP. It is not important that the timing is absoluetly accurate. */ static int odd = 1; #if LWIP_DHCP==1 static int dhcp_timer = 0; #endif TcpFastTmrFlag = 1; odd = !odd; #ifndef USE_SOFTETH_ON_ZYNQ ResetRxCntr++; #endif if (odd) { #if LWIP_DHCP==1 dhcp_timer++; dhcp_timoutcntr--; #endif TcpSlowTmrFlag = 1; #if LWIP_DHCP==1 dhcp_fine_tmr(); if (dhcp_timer >= 120) { dhcp_coarse_tmr(); dhcp_timer = 0; } #endif } /* For providing an SW alternative for the SI #692601. Under heavy * Rx traffic if at some point the Rx path becomes unresponsive, the * following API call will ensures a SW reset of the Rx path. The * API xemacpsif_resetrx_on_no_rxdata is called every 100 milliseconds. * This ensures that if the above HW bug is hit, in the worst case, * the Rx path cannot become unresponsive for more than 100 * milliseconds. */ #ifndef USE_SOFTETH_ON_ZYNQ if (ResetRxCntr >= RESET_RX_CNTR_LIMIT) { xemacpsif_resetrx_on_no_rxdata(echo_netif); ResetRxCntr = 0; } #endif XScuTimer_ClearInterruptStatus(TimerInstance); } void platform_setup_timer(void) { int Status = XST_SUCCESS; XScuTimer_Config *ConfigPtr; int TimerLoadValue = 0; ConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID); Status = XScuTimer_CfgInitialize(&TimerInstance, ConfigPtr, ConfigPtr->BaseAddr); if (Status != XST_SUCCESS) { xil_printf("In %s: Scutimer Cfg initialization failed...\r\n", __func__); return; } Status = XScuTimer_SelfTest(&TimerInstance); if (Status != XST_SUCCESS) { xil_printf("In %s: Scutimer Self test failed...\r\n", __func__); return; } XScuTimer_EnableAutoReload(&TimerInstance); /* * Set for 250 milli seconds timeout. */ TimerLoadValue = XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 8; XScuTimer_LoadTimer(&TimerInstance, TimerLoadValue); return; } void platform_setup_interrupts(void) { Xil_ExceptionInit(); XScuGic_DeviceInitialize(INTC_DEVICE_ID); /* * Connect the interrupt controller interrupt handler to the hardware * interrupt handling logic in the processor. */ Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT, (Xil_ExceptionHandler)XScuGic_DeviceInterruptHandler, (void *)INTC_DEVICE_ID); /* * 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, TIMER_IRPT_INTR, (Xil_ExceptionHandler)timer_callback, (void *)&TimerInstance); /* * Enable the interrupt for scu timer. */ XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, TIMER_IRPT_INTR); return; } void platform_enable_interrupts() { /* * Enable non-critical exceptions. */ Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ); XScuTimer_EnableInterrupt(&TimerInstance); XScuTimer_Start(&TimerInstance); return; } void cleanup_platform() { Xil_ICacheDisable(); Xil_DCacheDisable(); return; } //******************************************************************************** static struct netif server_netif; struct netif *echo_netif; #if LWIP_DHCP==1 extern volatile int dhcp_timoutcntr; err_t dhcp_start(struct netif *netif); #endif void lwip_init(); void print_ip(char *msg, ip_addr_t *ip) { print(msg); xil_printf("%d.%d.%d.%d\r\n", ip4_addr1(ip), ip4_addr2(ip), ip4_addr3(ip), ip4_addr4(ip)); } void print_ip_settings(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw) { print_ip("Board IP: ", ip); print_ip("Netmask : ", mask); print_ip("Gateway : ", gw); } int init_platform(unsigned char *mac_ethernet_address, ip_addr_t *ipaddr, ip_addr_t *netmask) { ip_addr_t gw; IP4_ADDR(&gw, 192, 168, 0, 1); echo_netif = &server_netif; #if LWIP_DHCP==1 ip_addr_t ipaddr_dhcp; ip_addr_t netmask_dhcp; ipaddr = &ipaddr_dhcp; netmask = &netmask_dhcp; ipaddr->addr = 0; gw.addr = 0; netmask->addr = 0; #else if(ipaddr == NULL || netmask == NULL) { xil_printf("When DHCP is disabled you must provide an IP address and netmask.\r\n"); return -1; } #endif platform_setup_timer(); platform_setup_interrupts(); lwip_init(); /* Add network interface to the netif_list, and set it as default */ if (!xemac_add(echo_netif, ipaddr, netmask, &gw, mac_ethernet_address, PLATFORM_EMAC_BASEADDR)) { xil_printf("Error adding N/W interface\r\n"); return -1; } netif_set_default(echo_netif); /* now enable interrupts */ platform_enable_interrupts(); /* specify that the network if is up */ netif_set_up(echo_netif); #if (LWIP_DHCP==1) /* Create a new DHCP client for this interface. * Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at * the predefined regular intervals after starting the client. */ dhcp_start(echo_netif); dhcp_timoutcntr = 200; while(((echo_netif->ip_addr.addr) == 0) && (dhcp_timoutcntr > 0)) xemacif_input(echo_netif); if (dhcp_timoutcntr <= 0) { if ((echo_netif->ip_addr.addr) == 0) { xil_printf("DHCP Timeout\r\n"); return -1; } } ipaddr->addr = echo_netif->ip_addr.addr; gw.addr = echo_netif->gw.addr; netmask->addr = echo_netif->netmask.addr; #endif print_ip_settings(ipaddr, netmask, &gw); return 0; } void handle_ethernet() { /* receive and process packets */ xemacif_input(echo_netif); }