svn commit: r266546 - head/sys/dev/iwn

Edward Tomasz Napierala trasz at FreeBSD.org
Thu May 22 15:29:26 UTC 2014


Author: trasz
Date: Thu May 22 15:29:25 2014
New Revision: 266546
URL: http://svnweb.freebsd.org/changeset/base/266546

Log:
  Make iwn(4) able to get itself back into working condition after
  "fatal firmware error" happens.  Previously it was neccessary to reset
  it manually, using "/etc/rc.d/netif restart".
  
  Approved by:	adrian@
  MFC after:	1 month
  Sponsored by:	The FreeBSD Foundation

Modified:
  head/sys/dev/iwn/if_iwn.c
  head/sys/dev/iwn/if_iwnvar.h

Modified: head/sys/dev/iwn/if_iwn.c
==============================================================================
--- head/sys/dev/iwn/if_iwn.c	Thu May 22 15:00:32 2014	(r266545)
+++ head/sys/dev/iwn/if_iwn.c	Thu May 22 15:29:25 2014	(r266546)
@@ -332,6 +332,7 @@ static int	iwn_hw_init(struct iwn_softc 
 static void	iwn_hw_stop(struct iwn_softc *);
 static void	iwn_radio_on(void *, int);
 static void	iwn_radio_off(void *, int);
+static void	iwn_panicked(void *, int);
 static void	iwn_init_locked(struct iwn_softc *);
 static void	iwn_init(void *);
 static void	iwn_stop_locked(struct iwn_softc *);
@@ -671,6 +672,15 @@ iwn_attach(device_t dev)
 	TASK_INIT(&sc->sc_reinit_task, 0, iwn_hw_reset, sc);
 	TASK_INIT(&sc->sc_radioon_task, 0, iwn_radio_on, sc);
 	TASK_INIT(&sc->sc_radiooff_task, 0, iwn_radio_off, sc);
+	TASK_INIT(&sc->sc_panic_task, 0, iwn_panicked, sc);
+
+	sc->sc_tq = taskqueue_create("iwn_taskq", M_WAITOK,
+	    taskqueue_thread_enqueue, &sc->sc_tq);
+	error = taskqueue_start_threads(&sc->sc_tq, 1, 0, "iwn_taskq");
+	if (error != 0) {
+		device_printf(dev, "can't start threads, error %d\n", error);
+		goto fail;
+	}
 
 	iwn_sysctlattach(sc);
 
@@ -1334,6 +1344,10 @@ iwn_detach(device_t dev)
 		ieee80211_draintask(ic, &sc->sc_radiooff_task);
 
 		iwn_stop(sc);
+
+		taskqueue_drain_all(sc->sc_tq);
+		taskqueue_free(sc->sc_tq);
+
 		callout_drain(&sc->watchdog_to);
 		callout_drain(&sc->calib_to);
 		ieee80211_ifdetach(ic);
@@ -3944,8 +3958,8 @@ iwn_intr(void *arg)
 #endif
 		/* Dump firmware error log and stop. */
 		iwn_fatal_intr(sc);
-		ifp->if_flags &= ~IFF_UP;
-		iwn_stop_locked(sc);
+
+		taskqueue_enqueue(sc->sc_tq, &sc->sc_panic_task);
 		goto done;
 	}
 	if ((r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX | IWN_INT_RX_PERIODIC)) ||
@@ -8412,6 +8426,38 @@ iwn_radio_off(void *arg0, int pending)
 }
 
 static void
+iwn_panicked(void *arg0, int pending)
+{
+	struct iwn_softc *sc = arg0;
+	struct ifnet *ifp = sc->sc_ifp;
+	struct ieee80211com *ic = ifp->if_l2com;
+	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
+	int error;
+
+	if (vap == NULL) {
+		printf("%s: null vap\n", __func__);
+		return;
+	}
+
+	device_printf(sc->sc_dev, "%s: controller panicked, iv_state = %d; "
+	    "resetting...\n", __func__, vap->iv_state);
+
+	iwn_stop(sc);
+	iwn_init(sc);
+	iwn_start(sc->sc_ifp);
+	if (vap->iv_state >= IEEE80211_S_AUTH &&
+	    (error = iwn_auth(sc, vap)) != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: could not move to auth state\n", __func__);
+	}
+	if (vap->iv_state >= IEEE80211_S_RUN &&
+	    (error = iwn_run(sc, vap)) != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: could not move to run state\n", __func__);
+	}
+}
+
+static void
 iwn_init_locked(struct iwn_softc *sc)
 {
 	struct ifnet *ifp = sc->sc_ifp;

Modified: head/sys/dev/iwn/if_iwnvar.h
==============================================================================
--- head/sys/dev/iwn/if_iwnvar.h	Thu May 22 15:00:32 2014	(r266545)
+++ head/sys/dev/iwn/if_iwnvar.h	Thu May 22 15:29:25 2014	(r266546)
@@ -308,6 +308,10 @@ struct iwn_softc {
 	struct task		sc_reinit_task;
 	struct task		sc_radioon_task;
 	struct task		sc_radiooff_task;
+	struct task		sc_panic_task;
+
+	/* Taskqueue */
+	struct taskqueue	*sc_tq;
 
 	/* Calibration information */
 	struct callout		calib_to;


More information about the svn-src-all mailing list