summaryrefslogtreecommitdiffstats
path: root/sys/dev/re
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2011-11-23 02:08:05 +0000
committeryongari <yongari@FreeBSD.org>2011-11-23 02:08:05 +0000
commit428ebfa96cbd3cfcc89cca529bca9c4e21b10b0b (patch)
tree16d899443064290d148678ebe5a68b532ed41ac1 /sys/dev/re
parente322b8dfb2862a7c69ba8b24ff8b8ff0dc50cffe (diff)
downloadFreeBSD-src-428ebfa96cbd3cfcc89cca529bca9c4e21b10b0b.zip
FreeBSD-src-428ebfa96cbd3cfcc89cca529bca9c4e21b10b0b.tar.gz
Disable accepting frames in re_stop() to put RX MAC into idle state.
Because there is no reliable way to know whether RX MAC is in stopped state, rejecting all frames would be the only way to minimize possible races. Otherwise it's possible to receive frames while stop command execution is in progress and controller can DMA the frame to freed RX buffer during that period. This was observed on recent PCIe controllers(i.e. RTL8111F). While this change may not be required on old controllers it wouldn't make negative effects on old controllers. One side effect of this change is disabling receive so driver reprograms RL_RXCFG to receive WOL frames when it is put into suspend or shutdown. This should address occasional 'memory modified free' errors seen on recent RealTek controllers.
Diffstat (limited to 'sys/dev/re')
-rw-r--r--sys/dev/re/if_re.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c
index 85e0772..462518c 100644
--- a/sys/dev/re/if_re.c
+++ b/sys/dev/re/if_re.c
@@ -3456,6 +3456,16 @@ re_stop(struct rl_softc *sc)
callout_stop(&sc->rl_stat_callout);
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ /*
+ * Disable accepting frames to put RX MAC into idle state.
+ * Otherwise it's possible to get frames while stop command
+ * execution is in progress and controller can DMA the frame
+ * to already freed RX buffer during that period.
+ */
+ CSR_WRITE_4(sc, RL_RXCFG, CSR_READ_4(sc, RL_RXCFG) &
+ ~(RL_RXCFG_RX_ALLPHYS | RL_RXCFG_RX_INDIV | RL_RXCFG_RX_MULTI |
+ RL_RXCFG_RX_BROAD));
+
if ((sc->rl_flags & RL_FLAG_CMDSTOP) != 0)
CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_STOPREQ | RL_CMD_TX_ENB |
RL_CMD_RX_ENB);
@@ -3604,9 +3614,11 @@ re_setwol(struct rl_softc *sc)
CSR_WRITE_1(sc, RL_GPIO,
CSR_READ_1(sc, RL_GPIO) & ~0x01);
}
- if ((ifp->if_capenable & IFCAP_WOL) != 0 &&
- (sc->rl_flags & RL_FLAG_WOLRXENB) != 0)
- CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RX_ENB);
+ if ((ifp->if_capenable & IFCAP_WOL) != 0) {
+ re_set_rxmode(sc);
+ if ((sc->rl_flags & RL_FLAG_WOLRXENB) != 0)
+ CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RX_ENB);
+ }
/* Enable config register write. */
CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
OpenPOWER on IntegriCloud