Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 22 May 2014 14:56:34 +0000 (UTC)
From:      Edward Tomasz Napierala <trasz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r266544 - head/sys/dev/iwn
Message-ID:  <201405221456.s4MEuYkb095774@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: trasz
Date: Thu May 22 14:56:34 2014
New Revision: 266544
URL: http://svnweb.freebsd.org/changeset/base/266544

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

Modified: head/sys/dev/iwn/if_iwn.c
==============================================================================
--- head/sys/dev/iwn/if_iwn.c	Thu May 22 12:30:56 2014	(r266543)
+++ head/sys/dev/iwn/if_iwn.c	Thu May 22 14:56:34 2014	(r266544)
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/module.h>
 #include <sys/queue.h>
 #include <sys/taskqueue.h>
+#include <sys/kthread.h>
 
 #include <machine/bus.h>
 #include <machine/resource.h>
@@ -342,6 +343,7 @@ static void	iwn_set_channel(struct ieee8
 static void	iwn_scan_curchan(struct ieee80211_scan_state *, unsigned long);
 static void	iwn_scan_mindwell(struct ieee80211_scan_state *);
 static void	iwn_hw_reset(void *, int);
+static void	iwn_reinit_thread(void *);
 #ifdef	IWN_DEBUG
 static char	*iwn_get_csr_string(int);
 static void	iwn_debug_register(struct iwn_softc *);
@@ -1197,6 +1199,8 @@ iwn4965_attach(struct iwn_softc *sc, uin
 	/* Enable normal btcoex */
 	sc->sc_flags |= IWN_FLAG_BTCOEX;
 
+	kthread_add(iwn_reinit_thread, sc, NULL, NULL, 0, 0, "iwn_reinit");
+
 	DPRINTF(sc, IWN_DEBUG_TRACE, "%s: end\n",__func__);
 
 	return 0;
@@ -3884,6 +3888,52 @@ iwn_fatal_intr(struct iwn_softc *sc)
 }
 
 static void
+iwn_reinit_thread(void *arg)
+{
+	struct iwn_softc *sc = arg;
+	int error;
+
+	mtx_lock(&sc->sc_mtx);
+	for (;;) {
+		struct ifnet *ifp;
+		struct ieee80211com *ic;
+		struct ieee80211vap *vap;
+
+		msleep(&sc->fwname, &sc->sc_mtx, PCATCH, "iwn_reinit", 0);
+
+		ifp = sc->sc_ifp;
+		ic = ifp->if_l2com;
+		vap = TAILQ_FIRST(&ic->ic_vaps);
+
+		if (vap == NULL) {
+			printf("%s: null vap\n", __func__);
+			continue;
+		}
+
+		device_printf(sc->sc_dev, "%s: controller panicked; "
+		    "resetting; iv_state = %d...\n", __func__, vap->iv_state);
+		mtx_unlock(&sc->sc_mtx);
+		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__);
+		}
+		mtx_lock(&sc->sc_mtx);
+	}
+	mtx_unlock(&sc->sc_mtx);
+
+	kthread_exit();
+}
+
+static void
 iwn_intr(void *arg)
 {
 	struct iwn_softc *sc = arg;
@@ -3944,8 +3994,10 @@ iwn_intr(void *arg)
 #endif
 		/* Dump firmware error log and stop. */
 		iwn_fatal_intr(sc);
-		ifp->if_flags &= ~IFF_UP;
-		iwn_stop_locked(sc);
+
+		device_printf(sc->sc_dev, "%s: reinit; %p\n",
+		    __func__, &sc->fwname);
+		wakeup(&sc->fwname);
 		goto done;
 	}
 	if ((r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX | IWN_INT_RX_PERIODIC)) ||



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