In iwm_send_cmd(), look at the generation counter instead of the STOPPED flag
to determine whether the interface was reset while we were sleeping. The flag
will be set if the interface is still down when the task wakes up, but the
interface could already be up again in which case the flag will be cleared.
A stale task which sends an outdated command could confuse the firmware.
Index: if_iwm.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
retrieving revision 1.180
diff -u -p -r1.180 if_iwm.c
--- if_iwm.c 8 May 2017 12:41:23 -0000 1.180
+++ if_iwm.c 8 May 2017 13:04:05 -0000
@@ -3630,6 +3630,7 @@ iwm_send_cmd(struct iwm_softc *sc, struc
int group_id;
size_t hdrlen, datasz;
uint8_t *data;
+ int generation = sc->sc_generation;
code = hcmd->id;
async = hcmd->flags & IWM_CMD_ASYNC;
@@ -3651,7 +3652,7 @@ iwm_send_cmd(struct iwm_softc *sc, struc
* Is the hardware still available? (after e.g. above wait).
*/
s = splnet();
- if (sc->sc_flags & IWM_FLAG_STOPPED) {
+ if (generation != sc->sc_generation) {
err = ENXIO;
goto out;
}
@@ -3764,7 +3765,6 @@ iwm_send_cmd(struct iwm_softc *sc, struc
IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
if (!async) {
- int generation = sc->sc_generation;
err = tsleep(desc, PCATCH, "iwmcmd", hz);
if (err == 0) {
/* if hardware is no longer up, return error */