/****************************************************************************** * * Copyright (C) 2010 - 2018 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * ******************************************************************************/ /* * platform_zynq.c * * Zynq platform specific functions. * * 02/29/2012: UART initialization is removed. Timer initializations are * removed. All unnecessary include files and hash defines are removed. * 03/01/2013: Timer initialization is added back. Support for SI #692601 is * added in the timer callback. The SI #692601 refers to the following issue. * * The EmacPs has a HW bug 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. * * */ #ifdef __arm__ #include "platform_config.h" #ifdef PLATFORM_ZYNQ #include "xparameters.h" #include "xparameters_ps.h" /* defines XPAR values */ #include "xil_cache.h" #include "xscugic.h" #include "lwip/tcp.h" #include "xil_printf.h" #include "netif/xadapter.h" #include "xscutimer.h" #include "xtime_l.h" #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 void tcp_fasttmr(void); void tcp_slowtmr(void); 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 = 24; 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) { TcpSlowTmrFlag = 1; #if LWIP_DHCP==1 dhcp_timer++; dhcp_timoutcntr--; 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 init_platform() { platform_setup_timer(); platform_setup_interrupts(); return; } void cleanup_platform() { Xil_ICacheDisable(); Xil_DCacheDisable(); return; } u64_t get_time_ms() { #define COUNTS_PER_MILLI_SECOND (COUNTS_PER_SECOND/1000) XTime tCur = 0; XTime_GetTime(&tCur); return (tCur/COUNTS_PER_MILLI_SECOND); } #endif #endif