Commit c227a105 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

wrsw_hal: RX calibration retry in case of link not getting up after RX…

wrsw_hal: RX calibration retry in case of link not getting up after RX calibration complete, handle MCR.PDOWN bit explicitly in HAL
parent 7a2fdea3
......@@ -82,6 +82,7 @@ typedef struct {
timeout_t link_timeout;
timeout_t align_timeout;
timeout_t earlyup_timeout;
timeout_t align_to_link_timeout;
int attempts;
}halPortLpdcRx_t;
......@@ -160,6 +161,7 @@ struct hal_port_state {
int evt_reset; /* Set if a reset is requested */
int evt_lock; /* Set if the ptracker must be activated*/
int evt_linkUp; /* Set if link is up ( driver call )*/
int evt_powerDown; /* Set if port is in power down state (MII MCR.PDOWN ==1 ) */
/* Low phase drift calibration data */
halPortLPDC_t *lpdc; /* Use a pointer to avoid to export this structure to PPSi */
......
......@@ -29,6 +29,8 @@
#include "hal_port_fsm_pll.h"
#include "hal_timing.h"
#define __EXPORTED_HEADERS__ /* prevent a #warning notice from linux/types.h */
#include <linux/mii.h>
/**
* State machine
......@@ -61,7 +63,7 @@ static int port_fsm_state_link_up(fsm_t *pfg, int eventMsk, int isNewState);
static void init_port(struct hal_port_state * ps);
static void reset_port(struct hal_port_state * ps);
static void unlock_port( struct hal_port_state * ps);
static void shutdown_port( struct hal_port_state * ps);
static int get_port_link_state(struct hal_port_state * ps,int *linkUp);
static fsm_state_table_entry_t port_fsm_states[] =
......@@ -150,11 +152,15 @@ static int port_fsm_state_init(fsm_t *pfg, int eventMsk, int isNewState) {
static int port_fsm_state_disabled(fsm_t *pfg, int eventMsk, int isNewState) {
struct hal_port_state * ps = (struct hal_port_state*) pfg->priv;
if ( isNewState ) {
if ( isNewState )
{
reset_port(ps);
}
if ( _isHalEventSfpInserted(eventMsk) )
if ( _isHalEventSfpInserted(eventMsk) && !_isHalEventPortPowerDown( eventMsk ) )
{
fsm_fire_state(pfg,HAL_PORT_STATE_LINK_DOWN);
}
return 0;
}
......@@ -194,7 +200,7 @@ static int port_fsm_state_link_down(fsm_t *pfg, int eventMsk, int isNewState) {
/* if final state reached for tx setup state machine then
* we can go LINK_UP state
*/
if (hal_port_rx_setup_fsm_run(ps)==1 ) {
if ( hal_port_rx_setup_fsm_run(ps)==1 ) {
/* measure bitslide regardless of LPDC support,
(if not supported, the value of the register will be zero) */
......@@ -235,13 +241,22 @@ static int port_fsm_state_link_up(fsm_t *pfg, int eventMsk, int isNewState) {
struct hal_port_state * ps = (struct hal_port_state*) pfg->priv;
if ( _isHalEventSfpRemoved(eventMsk) ) {
unlock_port(ps);
shutdown_port(ps);
fsm_fire_state(pfg,HAL_PORT_STATE_DISABLED);
return 0;
}
if( _isHalEventPortPowerDown( eventMsk ))
{
pr_info("Port %d PDOWN detected\n" ,ps->hw_index + 1 );
// MII power down
shutdown_port(ps);
fsm_fire_state(pfg,HAL_PORT_STATE_DISABLED);
return 0;
}
if ( _isHalEventReset(eventMsk) || _isHalEventLinkDown(eventMsk)) {
unlock_port(ps);
if ( _isHalEventReset(eventMsk) || _isHalEventLinkDown(eventMsk) ) {
shutdown_port(ps);
fsm_fire_state(pfg,HAL_PORT_STATE_LINK_DOWN);
return 0;
}
......@@ -292,16 +307,21 @@ static int port_fsm_build_events(fsm_t *pfg) {
int portEventMask=HAL_PORT_EVENT_TIMER;
if ( ps->evt_linkUp != -1 ) {
if ( ps->evt_linkUp >= 0 ) {
portEventMask |= ps->evt_linkUp ?
HAL_PORT_EVENT_LINK_UP : HAL_PORT_EVENT_LINK_DOWN;
}
if ( ps->evt_reset ) {
portEventMask |= HAL_PORT_EVENT_RESET;
ps->evt_reset=0;
}
portEventMask |= ps->sfpPresent ?
HAL_PORT_EVENT_SFP_INSERTED : HAL_PORT_EVENT_SFP_REMOVED;
portEventMask |= ps->evt_powerDown ? HAL_PORT_EVENT_POWER_DOWN : 0;
return portEventMask;
}
......@@ -327,6 +347,7 @@ void hal_port_state_fsm_init_all( struct hal_port_state * ports, halGlobalLPDC_t
hal_port_tx_setup_init_all(ports, globalLpdc);
}
/* Call FSM for on all ports */
void hal_port_state_fsm_run_all( struct hal_port_state * ports) {
int portIndex;
......@@ -337,9 +358,13 @@ void hal_port_state_fsm_run_all( struct hal_port_state * ports) {
for (portIndex = 0; portIndex < HAL_MAX_PORTS; portIndex++) {
struct hal_port_state* ps = &ports[portIndex];
if ( ps->in_use) {
if ( ps->in_use ) {
uint32_t bmcr;
pcs_readl( ps, MII_BMCR, &bmcr );
if ( get_port_link_state(ps, &ps->evt_linkUp)==-1 ) {
ps->evt_powerDown = (bmcr & BMCR_PDOWN);
if ( get_port_link_state(ps, &ps->evt_linkUp) < 0 ) {
// IOTCL error : We put -1 in the link state. It will be considered as invalid
ps->evt_linkUp=-1;
}
......@@ -347,8 +372,6 @@ void hal_port_state_fsm_run_all( struct hal_port_state * ports) {
fsm_generic_run(&ps->fsm);
}
}
}
/* Reset port
......@@ -398,13 +421,21 @@ static void init_port(struct hal_port_state * ps)
}
/* Action done when leaving states locking/up */
static void unlock_port( struct hal_port_state * ps)
static void shutdown_port( struct hal_port_state * ps)
{
if ( hal_tmg_get_mode()==HAL_TIMING_MODE_BC ) {
if ( hal_tmg_get_mode()==HAL_TIMING_MODE_BC )
{
hal_tmg_set_mode(HAL_TIMING_MODE_FREE_MASTER);
}
// make sure the PHY calibration circuitry is put in a KNOWN state
if( ps->lpdc->isSupported )
{
hal_port_tx_setup_fsm_reset( ps );
hal_port_rx_setup_fsm_reset( ps );
}
// Disable tracker
rts_enable_ptracker(ps->hw_index, 0);
ps->locked=0;
......@@ -422,6 +453,8 @@ static int get_port_link_state(struct hal_port_state * ps,int *linkUp)
return -1;
}
//printf("port-get-link-state %s %x\n", ps->name,ifr.ifr_flags & IFF_UP && ifr.ifr_flags & IFF_RUNNING);
*linkUp=(ifr.ifr_flags & IFF_UP && ifr.ifr_flags & IFF_RUNNING);
return 0;
}
......
......@@ -19,31 +19,36 @@ HAL_PORT_EVENT_SFP_INSERTED=(1<<1),
HAL_PORT_EVENT_SFP_REMOVED=(1<<3),
HAL_PORT_EVENT_LINK_UP=(1<<4),
HAL_PORT_EVENT_LINK_DOWN=(1<<5),
HAL_PORT_EVENT_RESET=(1<<6)
HAL_PORT_EVENT_RESET=(1<<6),
HAL_PORT_EVENT_POWER_DOWN=(1<<7)
}halPortEventMask_t ;
static __inline__ int _isHalEventInitialized(halPortEventMask_t eventMsk) {
static inline int _isHalEventInitialized(halPortEventMask_t eventMsk) {
return eventMsk & HAL_PORT_EVENT_TIMER;
}
static __inline__ int _isHalEventSfpInserted(halPortEventMask_t eventMsk) {
static inline int _isHalEventSfpInserted(halPortEventMask_t eventMsk) {
return eventMsk & HAL_PORT_EVENT_SFP_INSERTED;
}
static __inline__ int _isHalEventSfpRemoved(halPortEventMask_t eventMsk) {
static inline int _isHalEventSfpRemoved(halPortEventMask_t eventMsk) {
return eventMsk & HAL_PORT_EVENT_SFP_REMOVED;
}
static __inline__ int _isHalEventLinkUp(halPortEventMask_t eventMsk) {
static inline int _isHalEventLinkUp(halPortEventMask_t eventMsk) {
return eventMsk & HAL_PORT_EVENT_LINK_UP;
}
static __inline__ int _isHalEventLinkDown(halPortEventMask_t eventMsk) {
static inline int _isHalEventLinkDown(halPortEventMask_t eventMsk) {
return eventMsk & HAL_PORT_EVENT_LINK_DOWN;
}
static __inline__ int _isHalEventReset(halPortEventMask_t eventMsk) {
static inline int _isHalEventReset(halPortEventMask_t eventMsk) {
return eventMsk & HAL_PORT_EVENT_RESET;
}
static inline int _isHalEventPortPowerDown(halPortEventMask_t eventMsk) {
return eventMsk & HAL_PORT_EVENT_POWER_DOWN;
}
#endif
......@@ -255,7 +255,8 @@ static int _hal_port_rx_setup_state_validate(fsm_t *pfg, int eventMsk, int isNew
"ps (after %d attempts).\n", ps->hw_index + 1,
phase, rxSetup->attempts);
rts_enable_ptracker(ps->hw_index, 0);
sleep(1); // fixme: really needed?
libwr_tmo_init( &rxSetup->align_to_link_timeout, 5000, 0 );
fsm_fire_state(pfg, HAL_PORT_RX_SETUP_STATE_DONE);
}
......@@ -273,6 +274,11 @@ static int _hal_port_rx_setup_state_validate(fsm_t *pfg, int eventMsk, int isNew
static int _hal_port_rx_setup_state_done(fsm_t *pfg, int eventMsk, int isNewState) {
struct hal_port_state * ps = (struct hal_port_state*) pfg->priv;
int early_up = _isHalRxSetupEventEarlyLinkUp(eventMsk);
int link_aligned = _isHalRxSetupEventRxAligned(eventMsk);
int link_up = _isHalRxSetupEventLinkUp(eventMsk);
/* earlyLinkUp detection only if LPDC support */
if ( ps->lpdc->isSupported ) {
......@@ -282,12 +288,27 @@ static int _hal_port_rx_setup_state_done(fsm_t *pfg, int eventMsk, int isNewStat
ps->hw_index + 1);
fsm_fire_state(pfg, HAL_PORT_RX_SETUP_STATE_START);
return 0;
}
}
if ( _isHalRxSetupEventLinkUp(eventMsk) ) {
return 1; /* Final state reached */;
}
if( libwr_tmo_expired( &ps->lpdc->rxSetup->align_to_link_timeout ) && !link_up && early_up && link_aligned)
{
pr_warning("rxcal: link is fucked up, early+align on, but no PCS link up. Retrying calibration on port %d\n",ps->hw_index + 1);
pcs_writel(ps, MDIO_LPC_CTRL_DMTD_SOURCE_TXOUTCLK,
MDIO_LPC_CTRL);
// force the other side of the link to reset its FSMs too!
usleep(100000);
fsm_fire_state(pfg, HAL_PORT_RX_SETUP_STATE_START);
return 0;
}
}
return 0;
return link_up ? 1 : 0;
}
/* Build FSM events */
......@@ -297,7 +318,9 @@ static int port_rx_setup_fsm_build_events (fsm_t *pfg) {
int portEventMask=HAL_PORT_RX_SETUP_EVENT_TIMER;
if ( ps->evt_linkUp != -1 ) {
//printf("rxBuildEvents port %d lup %d\n", ps->hw_index, ps->evt_linkUp );
if ( ps->evt_linkUp >= 0 ) {
portEventMask |= ps->evt_linkUp ?
HAL_PORT_RX_SETUP_EVENT_LINK_UP : HAL_PORT_RX_SETUP_EVENT_LINK_DOWN;
}
......@@ -371,3 +394,8 @@ int hal_port_rx_setup_fsm_run( struct hal_port_state * ps ) {
return fsm_generic_run( &ps->lpdc->rxSetupFSM );
}
void hal_port_rx_setup_fsm_reset(struct hal_port_state * ps )
{
fsm_set_state( &ps->lpdc->rxSetupFSM, -1 ); // reset state
fsm_fire_state( &ps->lpdc->rxSetupFSM, HAL_PORT_RX_SETUP_STATE_START );
}
......@@ -13,6 +13,7 @@
/* prototypes */
void hal_port_rx_setup_fsm_init(struct hal_port_state * ps );
int hal_port_rx_setup_fsm_run( struct hal_port_state * ps );
void hal_port_rx_setup_fsm_reset(struct hal_port_state * ps );
#endif
......@@ -193,7 +193,9 @@ static int port_tx_setup_fsm_state_wait_lock(fsm_t *pfg, int eventMsk, int isNew
if ( pcs_readl(ps, MDIO_LPC_STAT,&value)>=0 ) {
if ( (value & MDIO_LPC_STAT_RESET_TX_DONE)!=0 ) {
ps->lpdc->txSetup->attempts++;
rts_enable_ptracker(ps->hw_index, 1);
_pll_state.channels[ps->hw_index].flags = 0;
libwr_tmo_init(&txSetup->calib_timeout,
TX_CAL_PHASE_MEAS_TIMEOUT, 1);
......@@ -545,3 +547,12 @@ static int _within_range(int x, int minval, int maxval, int wrap)
}
void hal_port_tx_setup_fsm_reset(struct hal_port_state * ps )
{
fsm_set_state( &ps->lpdc->txSetupFSM, -1 ); // reset state
fsm_fire_state( &ps->lpdc->txSetupFSM, HAL_PORT_TX_SETUP_STATE_START );
pcs_writel(ps, MDIO_LPC_CTRL_RESET_RX |
MDIO_LPC_CTRL_DMTD_SOURCE_TXOUTCLK,
MDIO_LPC_CTRL);
}
......@@ -13,5 +13,6 @@
void hal_port_tx_setup_init_all(struct hal_port_state * ports, halGlobalLPDC_t *globalLpdc);
void hal_port_tx_setup_fsm_init(struct hal_port_state * ps );
int hal_port_tx_setup_fsm_run( struct hal_port_state * ps );
void hal_port_tx_setup_fsm_reset(struct hal_port_state * ps );
#endif
......@@ -39,6 +39,8 @@
extern struct hal_shmem_header *hal_shmem;
extern struct wrs_shm_head *hal_shmem_hdr;
static timeout_t debug_tmo;
hal_ports_t halPorts;
/**
......@@ -262,6 +264,8 @@ int hal_port_shmem_init(char *logfilename)
hal_port_state_fsm_init_all(halPorts.ports, &halPorts.globalLpdc); // Init main port FSM for all ports
libwr_tmo_init( &debug_tmo, 1000, 1 );
led_init_all_ports(halPorts.ports); // Reset all leds
halPorts.numberOfPorts = index;
......@@ -644,6 +648,35 @@ void hal_port_update_all()
/* unlock shmem */
wrs_shm_write(hal_shmem_hdr, WRS_SHM_WRITE_END);
if( libwr_tmo_expired( &debug_tmo ))
{
int i;
printf("PortDBG: \n");
for(i = 0; i < HAL_MAX_PORTS; i++)
{
struct hal_port_state *ps = &halPorts.ports[i];
char txEventsStr[1024];
char rxEventsStr[1024];
if ( !ps->in_use || !ps->lpdc->isSupported )
continue;
strncpy( txEventsStr, fsm_get_event_mask_as_string( &ps->lpdc->txSetupFSM ), sizeof(txEventsStr) );
strncpy( rxEventsStr, fsm_get_event_mask_as_string( &ps->lpdc->rxSetupFSM ), sizeof(rxEventsStr) );
printf(" - wri%d: TX %-20s RX %-20s PORT %-20s TXEvents %-40s RXEvents %-40s\n",
ps->hw_index + 1,
fsm_get_state_name( &ps->lpdc->txSetupFSM ),
fsm_get_state_name( &ps->lpdc->rxSetupFSM ),
fsm_get_state_name( &ps->fsm ),
txEventsStr,
rxEventsStr
);
}
}
}
int hal_port_enable_tracking(const char *port_name)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment