Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 Mar 2014 06:37:08 +0000 (UTC)
From:      Kevin Lo <kevlo@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r263153 - head/sys/dev/usb/wlan
Message-ID:  <201403140637.s2E6b8lq024776@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kevlo
Date: Fri Mar 14 06:37:08 2014
New Revision: 263153
URL: http://svnweb.freebsd.org/changeset/base/263153

Log:
  Similar to r246614, fix panic on removing urtwn(4).  It happens because
  nodes are freed after the adapter is gone.

Modified:
  head/sys/dev/usb/wlan/if_urtwn.c
  head/sys/dev/usb/wlan/if_urtwnreg.h

Modified: head/sys/dev/usb/wlan/if_urtwn.c
==============================================================================
--- head/sys/dev/usb/wlan/if_urtwn.c	Fri Mar 14 06:29:43 2014	(r263152)
+++ head/sys/dev/usb/wlan/if_urtwn.c	Fri Mar 14 06:37:08 2014	(r263153)
@@ -247,8 +247,8 @@ static void		urtwn_iq_calib(struct urtwn
 static void		urtwn_lc_calib(struct urtwn_softc *);
 static void		urtwn_init(void *);
 static void		urtwn_init_locked(void *);
-static void		urtwn_stop(struct ifnet *, int);
-static void		urtwn_stop_locked(struct ifnet *, int);
+static void		urtwn_stop(struct ifnet *);
+static void		urtwn_stop_locked(struct ifnet *);
 static void		urtwn_abort_xfers(struct urtwn_softc *);
 static int		urtwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
 			    const struct ieee80211_bpf_params *);
@@ -459,20 +459,40 @@ urtwn_detach(device_t self)
 	struct urtwn_softc *sc = device_get_softc(self);
 	struct ifnet *ifp = sc->sc_ifp;
 	struct ieee80211com *ic = ifp->if_l2com;
+	unsigned int x;
 	
-	if (!device_is_attached(self))
-		return (0);
+	/* Prevent further ioctls. */
+	URTWN_LOCK(sc);
+	sc->sc_flags |= URTWN_DETACHED;
+	URTWN_UNLOCK(sc);
 
-	urtwn_stop(ifp, 1);
+	urtwn_stop(ifp);
 
 	callout_drain(&sc->sc_watchdog_ch);
 
-	/* stop all USB transfers */
-	usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER);
-	ieee80211_ifdetach(ic);
+	/* Prevent further allocations from RX/TX data lists. */
+	URTWN_LOCK(sc);
+	STAILQ_INIT(&sc->sc_tx_active);
+	STAILQ_INIT(&sc->sc_tx_inactive);
+	STAILQ_INIT(&sc->sc_tx_pending);
+
+	STAILQ_INIT(&sc->sc_rx_active);
+	STAILQ_INIT(&sc->sc_rx_inactive);
+	URTWN_UNLOCK(sc);
 
+	/* drain USB transfers */
+	for (x = 0; x != URTWN_N_TRANSFER; x++)
+		usbd_transfer_drain(sc->sc_xfer[x]);
+
+	/* Free data buffers. */
+	URTWN_LOCK(sc);
 	urtwn_free_tx_list(sc);
 	urtwn_free_rx_list(sc);
+	URTWN_UNLOCK(sc);
+
+	/* stop all USB transfers */
+	usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER);
+	ieee80211_ifdetach(ic);
 
 	if_free(ifp);
 	mtx_destroy(&sc->sc_mtx);
@@ -1758,10 +1778,17 @@ urtwn_start_locked(struct ifnet *ifp, st
 static int
 urtwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
+	struct urtwn_softc *sc = ifp->if_softc;
 	struct ieee80211com *ic = ifp->if_l2com;
 	struct ifreq *ifr = (struct ifreq *) data;
 	int error = 0, startall = 0;
 
+	URTWN_LOCK(sc);
+	error = (sc->sc_flags & URTWN_DETACHED) ? ENXIO : 0;
+	URTWN_UNLOCK(sc);
+	if (error != 0)
+		return (error);
+
 	switch (cmd) {
 	case SIOCSIFFLAGS:
 		if (ifp->if_flags & IFF_UP) {
@@ -1771,7 +1798,7 @@ urtwn_ioctl(struct ifnet *ifp, u_long cm
 			}
 		} else {
 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
-				urtwn_stop(ifp, 1);
+				urtwn_stop(ifp);
 		}
 		if (startall)
 			ieee80211_start_all(ic);
@@ -2785,7 +2812,7 @@ urtwn_init_locked(void *arg)
 	int error;
 
 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
-		urtwn_stop_locked(ifp, 0);
+		urtwn_stop_locked(ifp);
 
 	/* Init firmware commands ring. */
 	sc->fwcur = 0;
@@ -2943,11 +2970,10 @@ urtwn_init(void *arg)
 }
 
 static void
-urtwn_stop_locked(struct ifnet *ifp, int disable)
+urtwn_stop_locked(struct ifnet *ifp)
 {
 	struct urtwn_softc *sc = ifp->if_softc;
 
-	(void)disable;
 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
 
 	callout_stop(&sc->sc_watchdog_ch);
@@ -2955,12 +2981,12 @@ urtwn_stop_locked(struct ifnet *ifp, int
 }
 
 static void
-urtwn_stop(struct ifnet *ifp, int disable)
+urtwn_stop(struct ifnet *ifp)
 {
 	struct urtwn_softc *sc = ifp->if_softc;
 
 	URTWN_LOCK(sc);
-	urtwn_stop_locked(ifp, disable);
+	urtwn_stop_locked(ifp);
 	URTWN_UNLOCK(sc);
 }
 

Modified: head/sys/dev/usb/wlan/if_urtwnreg.h
==============================================================================
--- head/sys/dev/usb/wlan/if_urtwnreg.h	Fri Mar 14 06:29:43 2014	(r263152)
+++ head/sys/dev/usb/wlan/if_urtwnreg.h	Fri Mar 14 06:37:08 2014	(r263153)
@@ -1119,6 +1119,7 @@ struct urtwn_softc {
 	int				ac2idx[WME_NUM_AC];
 	u_int				sc_flags;
 #define URTWN_FLAG_CCK_HIPWR	0x01
+#define URTWN_DETACHED		0x02
 
 	u_int				chip;
 #define URTWN_CHIP_92C		0x01



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