Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 3 Jun 2013 19:39:37 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r251342 - head/sys/dev/ath
Message-ID:  <201306031939.r53JdbHE039630@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Mon Jun  3 19:39:37 2013
New Revision: 251342
URL: http://svnweb.freebsd.org/changeset/base/251342

Log:
  Fix the order of TX shutdown and reset.
  
  * Grab the reset lock first, so any subsequent interrupt, TX, RX work
    will fail
  
  * Then shut down interrupts
  
  * Then wait for TX/RX to finish running
  
  At this point no further work will be running, so it's safe to do the
  reset path code.
  
  PR:		kern/179232

Modified:
  head/sys/dev/ath/if_ath.c

Modified: head/sys/dev/ath/if_ath.c
==============================================================================
--- head/sys/dev/ath/if_ath.c	Mon Jun  3 19:29:03 2013	(r251341)
+++ head/sys/dev/ath/if_ath.c	Mon Jun  3 19:39:37 2013	(r251342)
@@ -2328,12 +2328,27 @@ ath_reset(struct ifnet *ifp, ATH_RESET_T
 	taskqueue_block(sc->sc_tq);
 
 	ATH_PCU_LOCK(sc);
-	ath_hal_intrset(ah, 0);		/* disable interrupts */
-	ath_txrx_stop_locked(sc);	/* Ensure TX/RX is stopped */
+
+	/*
+	 * Grab the reset lock before TX/RX is stopped.
+	 *
+	 * This is needed to ensure that when the TX/RX actually does finish,
+	 * no further TX/RX/reset runs in parallel with this.
+	 */
 	if (ath_reset_grablock(sc, 1) == 0) {
 		device_printf(sc->sc_dev, "%s: concurrent reset! Danger!\n",
 		    __func__);
 	}
+
+	/* disable interrupts */
+	ath_hal_intrset(ah, 0);
+
+	/*
+	 * Now, ensure that any in progress TX/RX completes before we
+	 * continue.
+	 */
+	ath_txrx_stop_locked(sc);
+
 	ATH_PCU_UNLOCK(sc);
 
 	/*
@@ -4871,12 +4886,18 @@ ath_chan_set(struct ath_softc *sc, struc
 	taskqueue_block(sc->sc_tq);
 
 	ATH_PCU_LOCK(sc);
-	ath_hal_intrset(ah, 0);		/* Stop new RX/TX completion */
-	ath_txrx_stop_locked(sc);	/* Stop pending RX/TX completion */
+
+	/* Stop new RX/TX/interrupt completion */
 	if (ath_reset_grablock(sc, 1) == 0) {
 		device_printf(sc->sc_dev, "%s: concurrent reset! Danger!\n",
 		    __func__);
 	}
+
+	ath_hal_intrset(ah, 0);
+
+	/* Stop pending RX/TX completion */
+	ath_txrx_stop_locked(sc);
+
 	ATH_PCU_UNLOCK(sc);
 
 	DPRINTF(sc, ATH_DEBUG_RESET, "%s: %u (%u MHz, flags 0x%x)\n",



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201306031939.r53JdbHE039630>