Skip to content

Commit 9d20e9c

Browse files
committed
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 <[email protected]>
1 parent b526cfd commit 9d20e9c

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

arch/risc-v/src/mpfs/Kconfig

+8
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,14 @@ config MPFS_PHYINIT
833833
---help---
834834
call mpfs_phy_boardinitialize() on init
835835

836+
config MPFS_PHY_RX_TIMEOUT_WA
837+
int "RX restart timeout workaround"
838+
default 0
839+
---help---
840+
This is a workaround for LAN8742A rev A and B silicon errata.
841+
Reset ETH interface in case no RX packets have been received
842+
in configured time. Set to 0 to disable.
843+
836844
config MPFS_ETH0_PHY_KSZ9477
837845
bool "Use ksz9477 switch as an SGMII PHY for ETH0"
838846
default n

arch/risc-v/src/mpfs/mpfs_ethernet.c

+38
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,15 @@
168168

169169
#define MPFS_TXTIMEOUT (60 * CLK_TCK)
170170

171+
/* RX timeout: Workaround for LAN8742A rev A and B silicon errata
172+
* "Cable diagnostics incorrectly returns Open cable connection for
173+
* terminated cable"
174+
*/
175+
176+
#if CONFIG_MPFS_PHY_RX_TIMEOUT_WA != 0
177+
#define MPFS_RXTIMEOUT (CONFIG_MPFS_PHY_RX_TIMEOUT_WA * CLK_TCK)
178+
#endif
179+
171180
/* PHY reset tim in loop counts */
172181

173182
#define PHY_RESET_WAIT_COUNT (10)
@@ -265,6 +274,9 @@ struct mpfs_ethmac_s
265274
uint8_t phyaddr; /* PHY address */
266275
#endif
267276
struct wdog_s txtimeout; /* TX timeout timer */
277+
#ifdef MPFS_RXTIMEOUT
278+
struct wdog_s rxtimeout; /* RX timeout timer */
279+
#endif
268280
struct work_s irqwork; /* For deferring interrupt work to the work queue */
269281
struct work_s pollwork; /* For deferring poll work to the work queue */
270282
struct work_s timeoutwork; /* For managing timeouts */
@@ -387,6 +399,7 @@ static int mpfs_ethconfig(struct mpfs_ethmac_s *priv);
387399
static void mpfs_ethreset(struct mpfs_ethmac_s *priv);
388400

389401
static void mpfs_interrupt_work(void *arg);
402+
static void mpfs_txtimeout_expiry(wdparm_t arg);
390403

391404
/****************************************************************************
392405
* Private Functions
@@ -468,6 +481,16 @@ static int mpfs_interrupt_0(int irq, void *context, void *arg)
468481
wd_cancel(&priv->txtimeout);
469482
}
470483

484+
#ifdef MPFS_RXTIMEOUT
485+
if ((isr & INT_RX) != 0)
486+
{
487+
/* If a RX transfer just completed, restart the timeout */
488+
489+
wd_start(&priv->rxtimeout, MPFS_RXTIMEOUT,
490+
mpfs_txtimeout_expiry, (wdparm_t)priv);
491+
}
492+
#endif
493+
471494
/* Schedule to perform the interrupt processing on the worker thread. */
472495

473496
work_queue(ETHWORK, &priv->irqwork, mpfs_interrupt_work, priv, 0);
@@ -1556,6 +1579,15 @@ static int mpfs_ifup(struct net_driver_s *dev)
15561579
up_enable_irq(priv->mac_q_int[2]);
15571580
up_enable_irq(priv->mac_q_int[3]);
15581581

1582+
#ifdef MPFS_RXTIMEOUT
1583+
/* Set up the RX timeout. If we don't receive anything in time, try
1584+
* to re-initialize
1585+
*/
1586+
1587+
wd_start(&priv->rxtimeout, MPFS_RXTIMEOUT,
1588+
mpfs_txtimeout_expiry, (wdparm_t)priv);
1589+
#endif
1590+
15591591
return OK;
15601592
}
15611593

@@ -1599,6 +1631,12 @@ static int mpfs_ifdown(struct net_driver_s *dev)
15991631

16001632
wd_cancel(&priv->txtimeout);
16011633

1634+
#ifdef MPFS_RXTIMEOUT
1635+
/* Cancel the RX timeout timers */
1636+
1637+
wd_cancel(&priv->rxtimeout);
1638+
#endif
1639+
16021640
/* Put the MAC in its reset, non-operational state. This should be
16031641
* a known configuration that will guarantee the mpfs_ifup() always
16041642
* successfully brings the interface back up.

0 commit comments

Comments
 (0)