Module Name: src Committed By: riastradh Date: Sun Mar 13 11:29:31 UTC 2022
Modified Files: src/sys/dev/usb: uhci.c Log Message: uhci(4): Fix synchronization between suspend/resume and poll hub. - sc_intr_lock is not relevant to anything here -- stop using it. - Never schedule the callout while suspended. - Don't futz with usepolling; it makes sense only when all other CPUs and threads are quiesced, which is not the case here. To generate a diff of this commit: cvs rdiff -u -r1.312 -r1.313 src/sys/dev/usb/uhci.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/usb/uhci.c diff -u src/sys/dev/usb/uhci.c:1.312 src/sys/dev/usb/uhci.c:1.313 --- src/sys/dev/usb/uhci.c:1.312 Wed Mar 9 22:17:41 2022 +++ src/sys/dev/usb/uhci.c Sun Mar 13 11:29:31 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: uhci.c,v 1.312 2022/03/09 22:17:41 riastradh Exp $ */ +/* $NetBSD: uhci.c,v 1.313 2022/03/13 11:29:31 riastradh Exp $ */ /* * Copyright (c) 1998, 2004, 2011, 2012, 2016, 2020 The NetBSD Foundation, Inc. @@ -42,7 +42,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.312 2022/03/09 22:17:41 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.313 2022/03/13 11:29:31 riastradh Exp $"); #ifdef _KERNEL_OPT #include "opt_usb.h" @@ -638,6 +638,7 @@ uhci_detach(struct uhci_softc *sc, int f if (rv != 0) return rv; + KASSERT(sc->sc_intr_xfer == NULL); callout_halt(&sc->sc_poll_handle, NULL); callout_destroy(&sc->sc_poll_handle); @@ -717,15 +718,12 @@ uhci_resume(device_t dv, const pmf_qual_ uhci_softc_t *sc = device_private(dv); int cmd; - mutex_spin_enter(&sc->sc_intr_lock); - cmd = UREAD2(sc, UHCI_CMD); - sc->sc_bus.ub_usepolling++; UWRITE2(sc, UHCI_INTR, 0); uhci_globalreset(sc); uhci_reset(sc); if (cmd & UHCI_CMD_RS) - uhci_run(sc, 0, 1); + uhci_run(sc, 0, 0); /* restore saved state */ UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); @@ -733,23 +731,23 @@ uhci_resume(device_t dv, const pmf_qual_ UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof); UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force resume */ - usb_delay_ms_locked(&sc->sc_bus, USB_RESUME_DELAY, &sc->sc_intr_lock); + usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */ UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | UHCI_INTR_IOCE | UHCI_INTR_SPIE); UHCICMD(sc, UHCI_CMD_MAXP); - uhci_run(sc, 1, 1); /* and start traffic again */ - usb_delay_ms_locked(&sc->sc_bus, USB_RESUME_RECOVERY, &sc->sc_intr_lock); - sc->sc_bus.ub_usepolling--; - if (sc->sc_intr_xfer != NULL) - callout_schedule(&sc->sc_poll_handle, sc->sc_ival); + uhci_run(sc, 1, 0); /* and start traffic again */ + usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY); #ifdef UHCI_DEBUG if (uhcidebug >= 2) uhci_dumpregs(sc); #endif + mutex_enter(&sc->sc_lock); sc->sc_suspend = PWR_RESUME; - mutex_spin_exit(&sc->sc_intr_lock); + if (sc->sc_intr_xfer != NULL) + callout_schedule(&sc->sc_poll_handle, sc->sc_ival); + mutex_exit(&sc->sc_lock); return true; } @@ -760,7 +758,11 @@ uhci_suspend(device_t dv, const pmf_qual uhci_softc_t *sc = device_private(dv); int cmd; - mutex_spin_enter(&sc->sc_intr_lock); + mutex_enter(&sc->sc_lock); + sc->sc_suspend = PWR_SUSPEND; + if (sc->sc_intr_xfer != NULL) + callout_halt(&sc->sc_poll_handle, &sc->sc_intr_lock); + mutex_exit(&sc->sc_lock); cmd = UREAD2(sc, UHCI_CMD); @@ -768,12 +770,8 @@ uhci_suspend(device_t dv, const pmf_qual if (uhcidebug >= 2) uhci_dumpregs(sc); #endif - sc->sc_suspend = PWR_SUSPEND; - if (sc->sc_intr_xfer != NULL) - callout_halt(&sc->sc_poll_handle, &sc->sc_intr_lock); - sc->sc_bus.ub_usepolling++; - uhci_run(sc, 0, 1); /* stop the controller */ + uhci_run(sc, 0, 0); /* stop the controller */ cmd &= ~UHCI_CMD_RS; /* save some state if BIOS doesn't */ @@ -783,10 +781,7 @@ uhci_suspend(device_t dv, const pmf_qual UWRITE2(sc, UHCI_INTR, 0); /* disable intrs */ UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter suspend */ - usb_delay_ms_locked(&sc->sc_bus, USB_RESUME_WAIT, &sc->sc_intr_lock); - sc->sc_bus.ub_usepolling--; - - mutex_spin_exit(&sc->sc_intr_lock); + usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); return true; } @@ -3855,7 +3850,8 @@ uhci_root_intr_start(struct usbd_xfer *x /* XXX temporary variable needed to avoid gcc3 warning */ ival = xfer->ux_pipe->up_endpoint->ue_edesc->bInterval; sc->sc_ival = mstohz(ival); - callout_schedule(&sc->sc_poll_handle, sc->sc_ival); + if (sc->sc_suspend == PWR_RESUME) + callout_schedule(&sc->sc_poll_handle, sc->sc_ival); sc->sc_intr_xfer = xfer; xfer->ux_status = USBD_IN_PROGRESS;