Module Name: src Committed By: christos Date: Fri Feb 5 16:06:25 UTC 2021
Modified Files: src/sys/dev/pci: if_wpi.c Log Message: PR/55975: Riccardo Mottola: Don't try to lock a mutex from an interrupt context. To generate a diff of this commit: cvs rdiff -u -r1.89 -r1.90 src/sys/dev/pci/if_wpi.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/if_wpi.c diff -u src/sys/dev/pci/if_wpi.c:1.89 src/sys/dev/pci/if_wpi.c:1.90 --- src/sys/dev/pci/if_wpi.c:1.89 Fri Mar 20 13:19:25 2020 +++ src/sys/dev/pci/if_wpi.c Fri Feb 5 11:06:24 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wpi.c,v 1.89 2020/03/20 17:19:25 sevan Exp $ */ +/* $NetBSD: if_wpi.c,v 1.90 2021/02/05 16:06:24 christos Exp $ */ /*- * Copyright (c) 2006, 2007 @@ -18,7 +18,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_wpi.c,v 1.89 2020/03/20 17:19:25 sevan Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wpi.c,v 1.90 2021/02/05 16:06:24 christos Exp $"); /* * Driver for Intel PRO/Wireless 3945ABG 802.11 network adapters. @@ -158,6 +158,8 @@ static bool wpi_resume(device_t, const p static int wpi_getrfkill(struct wpi_softc *); static void wpi_sysctlattach(struct wpi_softc *); static void wpi_rsw_thread(void *); +static void wpi_rsw_suspend(struct wpi_softc *); +static void wpi_stop_intr(struct ifnet *, int); #ifdef WPI_DEBUG #define DPRINTF(x) do { if (wpi_debug > 0) printf x; } while (0) @@ -1769,7 +1771,7 @@ wpi_notif_intr(struct wpi_softc *sc) "Radio transmitter is off\n"); /* turn the interface down */ ifp->if_flags &= ~IFF_UP; - wpi_stop(ifp, 1); + wpi_stop_intr(ifp, 1); splx(s); return; /* no further processing */ } @@ -1853,7 +1855,7 @@ wpi_softintr(void *arg) /* SYSTEM FAILURE, SYSTEM FAILURE */ aprint_error_dev(sc->sc_dev, "fatal firmware error\n"); ifp->if_flags &= ~IFF_UP; - wpi_stop(ifp, 1); + wpi_stop_intr(ifp, 1); return; } @@ -2203,7 +2205,7 @@ wpi_watchdog(struct ifnet *ifp) if (--sc->sc_tx_timer == 0) { aprint_error_dev(sc->sc_dev, "device timeout\n"); ifp->if_flags &= ~IFF_UP; - wpi_stop(ifp, 1); + wpi_stop_intr(ifp, 1); if_statinc(ifp, if_oerrors); return; } @@ -3200,7 +3202,7 @@ wpi_init(struct ifnet *ifp) uint32_t tmp; int qid, ntries, error; - wpi_stop(ifp,1); + wpi_stop(ifp, 1); (void)wpi_reset(sc); wpi_mem_lock(sc); @@ -3311,7 +3313,7 @@ fail1: wpi_stop(ifp, 1); } static void -wpi_stop(struct ifnet *ifp, int disable) +wpi_stop1(struct ifnet *ifp, int disable, bool fromintr) { struct wpi_softc *sc = ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; @@ -3323,13 +3325,11 @@ wpi_stop(struct ifnet *ifp, int disable) ieee80211_new_state(ic, IEEE80211_S_INIT, -1); - /* suspend rfkill test thread */ - mutex_enter(&sc->sc_rsw_mtx); - sc->sc_rsw_suspend = true; - cv_broadcast(&sc->sc_rsw_cv); - while (!sc->sc_rsw_suspended) - cv_wait(&sc->sc_rsw_cv, &sc->sc_rsw_mtx); - mutex_exit(&sc->sc_rsw_mtx); + if (fromintr) { + sc->sc_rsw_suspend = true; // XXX: without mutex or wait + } else { + wpi_rsw_suspend(sc); + } /* disable interrupts */ WPI_WRITE(sc, WPI_MASK, 0); @@ -3361,6 +3361,18 @@ wpi_stop(struct ifnet *ifp, int disable) WPI_WRITE(sc, WPI_RESET, tmp | WPI_SW_RESET); } +static void +wpi_stop(struct ifnet *ifp, int disable) +{ + wpi_stop1(ifp, disable, false); +} + +static void +wpi_stop_intr(struct ifnet *ifp, int disable) +{ + wpi_stop1(ifp, disable, true); +} + static bool wpi_resume(device_t dv, const pmf_qual_t *qual) { @@ -3463,6 +3475,18 @@ err: } static void +wpi_rsw_suspend(struct wpi_softc *sc) +{ + /* suspend rfkill test thread */ + mutex_enter(&sc->sc_rsw_mtx); + sc->sc_rsw_suspend = true; + cv_broadcast(&sc->sc_rsw_cv); + while (!sc->sc_rsw_suspended) + cv_wait(&sc->sc_rsw_cv, &sc->sc_rsw_mtx); + mutex_exit(&sc->sc_rsw_mtx); +} + +static void wpi_rsw_thread(void *arg) { struct wpi_softc *sc = (struct wpi_softc *)arg;