summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2013-12-03 22:37:25 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2013-12-03 22:37:25 +0000
commit3736c9c00c21361fa36336b0aecc922eae1c4b4f (patch)
treea13cf04dd1934871ec822a99f857f7b6db7586f4
parentae2b2f43b5009803f6c11bdff263534c39beadd7 (diff)
Seems we simply have to live with fatal firmware errors. Even Linux, with its
driver written by Intel engineers occasionally gets them. So when we get one, simply reset the chip, reload the firware and bring the interface up again. Tested by naddy@, who unfortunately is experiencing the quantum zeno effect making his iwi(4) not crap out. ok stsp@
-rw-r--r--sys/dev/pci/if_iwi.c29
-rw-r--r--sys/dev/pci/if_iwivar.h6
2 files changed, 21 insertions, 14 deletions
diff --git a/sys/dev/pci/if_iwi.c b/sys/dev/pci/if_iwi.c
index b0beb0f7770..58c81056d5e 100644
--- a/sys/dev/pci/if_iwi.c
+++ b/sys/dev/pci/if_iwi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwi.c,v 1.114 2013/11/14 12:39:14 dlg Exp $ */
+/* $OpenBSD: if_iwi.c,v 1.115 2013/12/03 22:37:24 kettenis Exp $ */
/*-
* Copyright (c) 2004-2008
@@ -74,7 +74,8 @@ const struct pci_matchid iwi_devices[] = {
int iwi_match(struct device *, void *, void *);
void iwi_attach(struct device *, struct device *, void *);
int iwi_activate(struct device *, int);
-void iwi_resume(void *, void *);
+void iwi_resume(struct iwi_softc *);
+void iwi_init_task(void *, void *);
int iwi_alloc_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *);
void iwi_reset_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *);
void iwi_free_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *);
@@ -174,8 +175,6 @@ iwi_attach(struct device *parent, struct device *self, void *aux)
sc->sc_pct = pa->pa_pc;
sc->sc_pcitag = pa->pa_tag;
- task_set(&sc->sc_resume_t, iwi_resume, sc, NULL);
-
/* clear device specific PCI configuration register 0x41 */
data = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
data &= ~0x0000ff00;
@@ -326,6 +325,7 @@ iwi_attach(struct device *parent, struct device *self, void *aux)
sc->sc_txtap.wt_ihdr.it_present = htole32(IWI_TX_RADIOTAP_PRESENT);
#endif
+ task_set(&sc->init_task, iwi_init_task, sc, NULL);
return;
fail: while (--ac >= 0)
@@ -345,7 +345,7 @@ iwi_activate(struct device *self, int act)
iwi_stop(ifp, 0);
break;
case DVACT_RESUME:
- task_add(systq, &sc->sc_resume_t);
+ iwi_resume(sc);
break;
}
@@ -353,24 +353,31 @@ iwi_activate(struct device *self, int act)
}
void
-iwi_resume(void *arg1, void *arg2)
+iwi_resume(struct iwi_softc *sc)
{
- struct iwi_softc *sc = arg1;
- struct ifnet *ifp = &sc->sc_ic.ic_if;
pcireg_t data;
- int s;
/* clear device specific PCI configuration register 0x41 */
data = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
data &= ~0x0000ff00;
pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, data);
+ task_add(systq, &sc->init_task);
+}
+
+void
+iwi_init_task(void *arg1, void *arg2)
+{
+ struct iwi_softc *sc = arg1;
+ struct ifnet *ifp = &sc->sc_ic.ic_if;
+ int s;
+
s = splnet();
while (sc->sc_flags & IWI_FLAG_BUSY)
tsleep(&sc->sc_flags, 0, "iwipwr", 0);
sc->sc_flags |= IWI_FLAG_BUSY;
- if (ifp->if_flags & IFF_UP)
+ if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP)
iwi_init(ifp);
sc->sc_flags &= ~IWI_FLAG_BUSY;
@@ -1159,8 +1166,8 @@ iwi_intr(void *arg)
if (r & IWI_INTR_FATAL_ERROR) {
printf("%s: fatal firmware error\n", sc->sc_dev.dv_xname);
- ifp->if_flags &= ~IFF_UP;
iwi_stop(ifp, 1);
+ task_add(systq, &sc->init_task);
return 1;
}
diff --git a/sys/dev/pci/if_iwivar.h b/sys/dev/pci/if_iwivar.h
index a9b2e189dcb..1ca82c0c444 100644
--- a/sys/dev/pci/if_iwivar.h
+++ b/sys/dev/pci/if_iwivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwivar.h,v 1.24 2013/11/14 12:39:14 dlg Exp $ */
+/* $OpenBSD: if_iwivar.h,v 1.25 2013/12/03 22:37:24 kettenis Exp $ */
/*-
* Copyright (c) 2004-2006
@@ -112,9 +112,9 @@ struct iwi_softc {
pcitag_t sc_pcitag;
bus_size_t sc_sz;
- int sc_tx_timer;
+ struct task init_task;
- struct task sc_resume_t;
+ int sc_tx_timer;
#if NBPFILTER > 0
caddr_t sc_drvbpf;