From 29f9822bace17fe6189a0048b7591a5188cdc329 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 1 Jun 2022 09:45:13 +0200 Subject: if_atsam: Recover from receive freezes Under unknown conditions the receive path ended up in a frozen state. In this state, the DMA and driver descriptor head were equal and all receive descriptors had the used bit set. So, the DMA was unable to store received frames. However, the receive daemon was never woken up to refill the receive buffers. It seems that the RXUBR interrupt can be used to recover from this state. Update #4651. --- rtemsbsd/sys/dev/atsam/if_atsam.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/rtemsbsd/sys/dev/atsam/if_atsam.c b/rtemsbsd/sys/dev/atsam/if_atsam.c index fff21c65..21a28fcd 100644 --- a/rtemsbsd/sys/dev/atsam/if_atsam.c +++ b/rtemsbsd/sys/dev/atsam/if_atsam.c @@ -108,6 +108,8 @@ #define MDIO_PHY MII_PHY_ANY #define IGNORE_RX_ERR false +#define RX_INTERRUPTS (GMAC_ISR_RCOMP | GMAC_ISR_RXUBR | GMAC_ISR_ROVR) + #define RX_DESC_LOG2 3 #define RX_DESC_COUNT (1U << RX_DESC_LOG2) #define RX_DESC_WRAP(idx) \ @@ -187,6 +189,7 @@ typedef struct if_atsam_softc { struct if_atsam_stats { /* Software */ uint32_t rx_overrun_errors; + uint32_t rx_used_bit_reads; uint32_t rx_interrupts; uint32_t tx_tur_errors; uint32_t tx_rlex_errors; @@ -400,15 +403,19 @@ static void if_atsam_interrupt_handler(void *arg) } /* Check receive interrupts */ - if (__predict_true((is & (GMAC_IER_ROVR | GMAC_IER_RCOMP)) != 0)) { - if (__predict_false((is & GMAC_IER_ROVR) != 0)) { + if (__predict_true((is & RX_INTERRUPTS) != 0)) { + if (__predict_false((is & GMAC_ISR_RXUBR) != 0)) { + ++sc->stats.rx_used_bit_reads; + } + + if (__predict_false((is & GMAC_ISR_ROVR) != 0)) { ++sc->stats.rx_overrun_errors; } ++sc->stats.rx_interrupts; - /* Erase the interrupts for RX completion and errors */ - pHw->GMAC_IDR = GMAC_IER_RCOMP | GMAC_IER_ROVR; + /* Disable RX interrupts */ + pHw->GMAC_IDR = RX_INTERRUPTS; (void)rtems_event_send(sc->rx_daemon_tid, ATSAMV7_ETH_RX_EVENT_INTERRUPT); @@ -511,7 +518,7 @@ if_atsam_rx_daemon(rtems_task_argument arg) sc->rx_idx_head = idx; /* Enable RX interrupts */ - pHw->GMAC_IER = GMAC_IER_RCOMP | GMAC_IER_ROVR; + pHw->GMAC_IER = RX_INTERRUPTS; (void) rtems_event_receive(ATSAMV7_ETH_RX_EVENT_INTERRUPT, RTEMS_EVENT_ALL | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &out); @@ -1292,6 +1299,9 @@ if_atsam_add_sysctls(device_t dev) SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_overrun_errors", CTLFLAG_RD, &sc->stats.rx_overrun_errors, 0, "RX overrun errors"); + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_used_bit_reads", + CTLFLAG_RD, &sc->stats.rx_used_bit_reads, 0, + "RX used bit reads"); SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_interrupts", CTLFLAG_RD, &sc->stats.rx_interrupts, 0, "Rx interrupts"); -- cgit v1.2.3