234 lines
6.4 KiB
C
234 lines
6.4 KiB
C
|
/*
|
||
|
* 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.
|
||
|
*
|
||
|
*/
|
||
|
/*
|
||
|
* 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.
|
||
|
*
|
||
|
* </pre>
|
||
|
*/
|
||
|
|
||
|
#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 server_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(&server_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
|