mirror of
https://github.com/apache/nuttx.git
synced 2026-05-20 12:33:27 +08:00
arch/risc-v/src/mpfs/mpfs_ethernet.c: Add RX timeout workaround for broken PHYs
If the interface is UP, and no packets are received in 30s, re-initialize the interface by calling the already implemented mpfs_txtimeout_expiry. This is a workaround for a bug where IF might be UP and working but packets can only be transmitted. Receive side just doesn't work at all. The bug manifests at least in older LAN8742A (rev A and B), for which also a silicon errata exists. The original issue can be re-produced easily by disconnecting and reconnecting the ethernet cable while the IF is up. Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This commit is contained in:
committed by
Xiang Xiao
parent
f3142be127
commit
ea321d86cb
@@ -700,6 +700,14 @@ config MPFS_PHYINIT
|
||||
---help---
|
||||
call mpfs_phy_boardinitialize() on init
|
||||
|
||||
config MPFS_PHY_RX_TIMEOUT_WA
|
||||
int "RX restart timeout workaround"
|
||||
default 0
|
||||
---help---
|
||||
This is a workaround for LAN8742A rev A and B silicon errata.
|
||||
Reset ETH interface in case no RX packets have been received
|
||||
in configured time. Set to 0 to disable.
|
||||
|
||||
config MPFS_ETH0_PHY_KSZ9477
|
||||
bool "Use ksz9477 switch as an SGMII PHY for ETH0"
|
||||
default n
|
||||
|
||||
@@ -171,6 +171,15 @@
|
||||
|
||||
#define MPFS_TXTIMEOUT (60 * CLK_TCK)
|
||||
|
||||
/* RX timeout: Workaround for LAN8742A rev A and B silicon errata
|
||||
* "Cable diagnostics incorrectly returns Open cable connection for
|
||||
* terminated cable"
|
||||
*/
|
||||
|
||||
#if CONFIG_MPFS_PHY_RX_TIMEOUT_WA != 0
|
||||
#define MPFS_RXTIMEOUT (CONFIG_MPFS_PHY_RX_TIMEOUT_WA * CLK_TCK)
|
||||
#endif
|
||||
|
||||
/* PHY reset tim in loop counts */
|
||||
|
||||
#define PHY_RESET_WAIT_COUNT (10)
|
||||
@@ -268,6 +277,9 @@ struct mpfs_ethmac_s
|
||||
uint8_t phyaddr; /* PHY address */
|
||||
#endif
|
||||
struct wdog_s txtimeout; /* TX timeout timer */
|
||||
#ifdef MPFS_RXTIMEOUT
|
||||
struct wdog_s rxtimeout; /* RX timeout timer */
|
||||
#endif
|
||||
struct work_s irqwork; /* For deferring interrupt work to the work queue */
|
||||
struct work_s pollwork; /* For deferring poll work to the work queue */
|
||||
struct work_s timeoutwork; /* For managing timeouts */
|
||||
@@ -390,6 +402,7 @@ static int mpfs_ethconfig(struct mpfs_ethmac_s *priv);
|
||||
static void mpfs_ethreset(struct mpfs_ethmac_s *priv);
|
||||
|
||||
static void mpfs_interrupt_work(void *arg);
|
||||
static void mpfs_txtimeout_expiry(wdparm_t arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
@@ -471,6 +484,16 @@ static int mpfs_interrupt_0(int irq, void *context, void *arg)
|
||||
wd_cancel(&priv->txtimeout);
|
||||
}
|
||||
|
||||
#ifdef MPFS_RXTIMEOUT
|
||||
if ((isr & INT_RX) != 0)
|
||||
{
|
||||
/* If a RX transfer just completed, restart the timeout */
|
||||
|
||||
wd_start(&priv->rxtimeout, MPFS_RXTIMEOUT,
|
||||
mpfs_txtimeout_expiry, (wdparm_t)priv);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Schedule to perform the interrupt processing on the worker thread. */
|
||||
|
||||
work_queue(ETHWORK, &priv->irqwork, mpfs_interrupt_work, priv, 0);
|
||||
@@ -1559,6 +1582,15 @@ static int mpfs_ifup(struct net_driver_s *dev)
|
||||
up_enable_irq(priv->mac_q_int[2]);
|
||||
up_enable_irq(priv->mac_q_int[3]);
|
||||
|
||||
#ifdef MPFS_RXTIMEOUT
|
||||
/* Set up the RX timeout. If we don't receive anything in time, try
|
||||
* to re-initialize
|
||||
*/
|
||||
|
||||
wd_start(&priv->rxtimeout, MPFS_RXTIMEOUT,
|
||||
mpfs_txtimeout_expiry, (wdparm_t)priv);
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -1602,6 +1634,12 @@ static int mpfs_ifdown(struct net_driver_s *dev)
|
||||
|
||||
wd_cancel(&priv->txtimeout);
|
||||
|
||||
#ifdef MPFS_RXTIMEOUT
|
||||
/* Cancel the RX timeout timers */
|
||||
|
||||
wd_cancel(&priv->rxtimeout);
|
||||
#endif
|
||||
|
||||
/* Put the MAC in its reset, non-operational state. This should be
|
||||
* a known configuration that will guarantee the mpfs_ifup() always
|
||||
* successfully brings the interface back up.
|
||||
|
||||
Reference in New Issue
Block a user