Fix triggering false watchdog timeout when controller is in PAUSE

state.  Previously it used to check if controller has sent a
PAUSE frame to the remote peer.

Reported by:	David Imhoff via Brad Smith <brad@OpenBSD.org>
Submitted by:	davidch (initial version)
Reviewed by:	davidch, David Imhoff <dimhoff_devel@xs4all.nl>
This commit is contained in:
Pyun YongHyeon 2013-06-30 05:12:18 +00:00
parent fd57292555
commit d925c58c98
2 changed files with 31 additions and 3 deletions

View File

@ -2077,10 +2077,12 @@ bce_miibus_statchg(device_t dev)
DBPRINT(sc, BCE_INFO_PHY,
"%s(): Enabling RX flow control.\n", __FUNCTION__);
BCE_SETBIT(sc, BCE_EMAC_RX_MODE, BCE_EMAC_RX_MODE_FLOW_EN);
sc->bce_flags |= BCE_USING_RX_FLOW_CONTROL;
} else {
DBPRINT(sc, BCE_INFO_PHY,
"%s(): Disabling RX flow control.\n", __FUNCTION__);
BCE_CLRBIT(sc, BCE_EMAC_RX_MODE, BCE_EMAC_RX_MODE_FLOW_EN);
sc->bce_flags &= ~BCE_USING_RX_FLOW_CONTROL;
}
if ((IFM_OPTIONS(media_active) & IFM_ETH_TXPAUSE) != 0) {
@ -7828,18 +7830,42 @@ bce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
static void
bce_watchdog(struct bce_softc *sc)
{
uint32_t status;
DBENTER(BCE_EXTREME_SEND);
BCE_LOCK_ASSERT(sc);
status = 0;
/* If the watchdog timer hasn't expired then just exit. */
if (sc->watchdog_timer == 0 || --sc->watchdog_timer)
goto bce_watchdog_exit;
status = REG_RD(sc, BCE_EMAC_RX_STATUS);
/* If pause frames are active then don't reset the hardware. */
/* ToDo: Should we reset the timer here? */
if (REG_RD(sc, BCE_EMAC_TX_STATUS) & BCE_EMAC_TX_STATUS_XOFFED)
goto bce_watchdog_exit;
if ((sc->bce_flags & BCE_USING_RX_FLOW_CONTROL) != 0) {
if ((status & BCE_EMAC_RX_STATUS_FFED) != 0) {
/*
* If link partner has us in XOFF state then wait for
* the condition to clear.
*/
sc->watchdog_timer = BCE_TX_TIMEOUT;
goto bce_watchdog_exit;
} else if ((status & BCE_EMAC_RX_STATUS_FF_RECEIVED) != 0 &&
(status & BCE_EMAC_RX_STATUS_N_RECEIVED) != 0) {
/*
* If we're not currently XOFF'ed but have recently
* been XOFF'd/XON'd then assume that's delaying TX
* this time around.
*/
sc->watchdog_timer = BCE_TX_TIMEOUT;
goto bce_watchdog_exit;
}
/*
* Any other condition is unexpected and the controller
* should be reset.
*/
}
BCE_PRINTF("%s(%d): Watchdog timeout occurred, resetting!\n",
__FILE__, __LINE__);
@ -7863,6 +7889,7 @@ bce_watchdog(struct bce_softc *sc)
sc->bce_ifp->if_oerrors++;
bce_watchdog_exit:
REG_WR(sc, BCE_EMAC_RX_STATUS, status);
DBEXIT(BCE_EXTREME_SEND);
}

View File

@ -6465,6 +6465,7 @@ struct bce_softc
#define BCE_USING_MSIX_FLAG 0x00000100
#define BCE_PCIE_FLAG 0x00000200
#define BCE_USING_TX_FLOW_CONTROL 0x00000400
#define BCE_USING_RX_FLOW_CONTROL 0x00000800
/* Controller capability flags. */
u32 bce_cap_flags;