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-head
mailing list