summaryrefslogtreecommitdiffstats
path: root/sys/dev/mxge
diff options
context:
space:
mode:
authorgallatin <gallatin@FreeBSD.org>2008-07-17 15:46:35 +0000
committergallatin <gallatin@FreeBSD.org>2008-07-17 15:46:35 +0000
commit57b9f1fb864a686e2691533a5e946d0e52380798 (patch)
treebc0473177cbea69c5d364d971073f830b90ba776 /sys/dev/mxge
parent26c7a0cd2bbc8e5f2e7bd917abd64ffdd37cc82d (diff)
downloadFreeBSD-src-57b9f1fb864a686e2691533a5e946d0e52380798.zip
FreeBSD-src-57b9f1fb864a686e2691533a5e946d0e52380798.tar.gz
Clean up mxge's use of callouts as pointed out by jhb,
and handle NIC hardware watchdog resets. - remove buggy code at the top of mxge_tick() which tried to detect a race which is already detected in the kernel's callout code. - move callout_stop() and callout_reset() into mxge_close() mxge_open() rather than doing the callout manipulation all over the place. - use callout_drain(), rather than callout_stop() to prevent a potential race between mxge_tick() and mxge_detach() which could lead to softclock using a destroyed mutex - restructure the mxge_tick() and mxge_watchdog_reset() routines to avoid resetting a callout, and then immediately stopping it if the watchdog reset routine is called, and fails. - enable the driver to handle NIC hardware watchdog resets by restoring the NIC's PCI config space, which is lost when the NIC hardware watchdog triggers. Reviewed by: jhb (previus version)
Diffstat (limited to 'sys/dev/mxge')
-rw-r--r--sys/dev/mxge/if_mxge.c55
1 files changed, 19 insertions, 36 deletions
diff --git a/sys/dev/mxge/if_mxge.c b/sys/dev/mxge/if_mxge.c
index 4f421f1..0777701 100644
--- a/sys/dev/mxge/if_mxge.c
+++ b/sys/dev/mxge/if_mxge.c
@@ -72,6 +72,7 @@ __FBSDID("$FreeBSD$");
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
+#include <dev/pci/pci_private.h> /* XXX for pci_cfg_restore */
#include <vm/vm.h> /* for pmap_mapdev() */
#include <vm/pmap.h>
@@ -1348,11 +1349,8 @@ mxge_change_lro_locked(mxge_softc_t *sc, int lro_cnt)
ifp->if_capenable |= IFCAP_LRO;
sc->lro_cnt = lro_cnt;
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- callout_stop(&sc->co_hdl);
mxge_close(sc);
err = mxge_open(sc);
- if (err == 0)
- callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc);
}
return err;
}
@@ -3319,6 +3317,7 @@ mxge_open(mxge_softc_t *sc)
}
sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc);
return 0;
@@ -3335,6 +3334,7 @@ mxge_close(mxge_softc_t *sc)
mxge_cmd_t cmd;
int err, old_down_cnt;
+ callout_stop(&sc->co_hdl);
sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
old_down_cnt = sc->down_cnt;
mb();
@@ -3399,9 +3399,10 @@ mxge_read_reboot(mxge_softc_t *sc)
return (pci_read_config(dev, vs + 0x14, 4));
}
-static void
+static int
mxge_watchdog_reset(mxge_softc_t *sc)
{
+ struct pci_devinfo *dinfo;
int err;
uint32_t reboot;
uint16_t cmd;
@@ -3428,7 +3429,7 @@ mxge_watchdog_reset(mxge_softc_t *sc)
cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2);
if (cmd == 0xffff) {
device_printf(sc->dev, "NIC disappeared!\n");
- goto abort;
+ return (err);
}
}
if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) {
@@ -3437,9 +3438,8 @@ mxge_watchdog_reset(mxge_softc_t *sc)
device_printf(sc->dev, "NIC rebooted, status = 0x%x\n",
reboot);
/* restore PCI configuration space */
-
- /* XXXX waiting for pci_cfg_restore() to be exported */
- goto abort; /* just abort for now */
+ dinfo = device_get_ivars(sc->dev);
+ pci_cfg_restore(sc->dev, dinfo);
/* and redo any changes we made to our config space */
mxge_setup_cfg_space(sc);
@@ -3457,22 +3457,15 @@ mxge_watchdog_reset(mxge_softc_t *sc)
be32toh(sc->ss->fw_stats->send_done_count));
device_printf(sc->dev, "not resetting\n");
}
-
-abort:
- /*
- * stop the watchdog if the nic is dead, to avoid spamming the
- * console
- */
- if (err != 0) {
- callout_stop(&sc->co_hdl);
- }
+ return (err);
}
-static void
+static int
mxge_watchdog(mxge_softc_t *sc)
{
mxge_tx_ring_t *tx = &sc->ss->tx;
uint32_t rx_pause = be32toh(sc->ss->fw_stats->dropped_pause);
+ int err = 0;
/* see if we have outstanding transmits, which
have been pending for more than mxge_ticks */
@@ -3481,7 +3474,7 @@ mxge_watchdog(mxge_softc_t *sc)
tx->done == tx->watchdog_done) {
/* check for pause blocking before resetting */
if (tx->watchdog_rx_pause == rx_pause)
- mxge_watchdog_reset(sc);
+ err = mxge_watchdog_reset(sc);
else
device_printf(sc->dev, "Flow control blocking "
"xmits, check link partner\n");
@@ -3493,6 +3486,7 @@ mxge_watchdog(mxge_softc_t *sc)
if (sc->need_media_probe)
mxge_media_probe(sc);
+ return (err);
}
static void
@@ -3513,24 +3507,18 @@ static void
mxge_tick(void *arg)
{
mxge_softc_t *sc = arg;
-
-
- /* Synchronize with possible callout reset/stop. */
- if (callout_pending(&sc->co_hdl) ||
- !callout_active(&sc->co_hdl)) {
- mtx_unlock(&sc->driver_mtx);
- return;
- }
+ int err = 0;
/* aggregate stats from different slices */
mxge_update_stats(sc);
-
- callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc);
if (!sc->watchdog_countdown) {
- mxge_watchdog(sc);
+ err = mxge_watchdog(sc);
sc->watchdog_countdown = 4;
}
sc->watchdog_countdown--;
+ if (err == 0)
+ callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc);
+
}
static int
@@ -3554,7 +3542,6 @@ mxge_change_mtu(mxge_softc_t *sc, int mtu)
old_mtu = ifp->if_mtu;
ifp->if_mtu = mtu;
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- callout_stop(&sc->co_hdl);
mxge_close(sc);
err = mxge_open(sc);
if (err != 0) {
@@ -3562,7 +3549,6 @@ mxge_change_mtu(mxge_softc_t *sc, int mtu)
mxge_close(sc);
(void) mxge_open(sc);
}
- callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc);
}
mtx_unlock(&sc->driver_mtx);
return err;
@@ -3605,8 +3591,6 @@ mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
if (ifp->if_flags & IFF_UP) {
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
err = mxge_open(sc);
- callout_reset(&sc->co_hdl, mxge_ticks,
- mxge_tick, sc);
} else {
/* take care of promis can allmulti
flag chages */
@@ -3616,7 +3600,6 @@ mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
}
} else {
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- callout_stop(&sc->co_hdl);
mxge_close(sc);
}
}
@@ -4313,11 +4296,11 @@ mxge_detach(device_t dev)
return EBUSY;
}
mtx_lock(&sc->driver_mtx);
- callout_stop(&sc->co_hdl);
if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING)
mxge_close(sc);
mtx_unlock(&sc->driver_mtx);
ether_ifdetach(sc->ifp);
+ callout_drain(&sc->co_hdl);
ifmedia_removeall(&sc->media);
mxge_dummy_rdma(sc, 0);
mxge_rem_sysctls(sc);
OpenPOWER on IntegriCloud