ehci(4): properly handle failed attach thinkpad a475 fails to attach an ehci instance: ehci0: pre-2.0 USB rev, device ignored which ends up stopping suspend/resume working as the device has no pmf handlers installed. put most of the teardown code into a new common function that is called from failed attach and detach. if attach fails, register NULL pmf handlers. re-order several parts of detach to match the reverse attach order. tested on rockpro64, thinkpad a475, and xps 1645, the a475 can now suspend/resume almost fully successfully. Index: dev/pci/ehci_pci.c =================================================================== RCS file: /cvsroot/src/sys/dev/pci/ehci_pci.c,v retrieving revision 1.76 diff -p -u -r1.76 ehci_pci.c --- dev/pci/ehci_pci.c 24 Jan 2023 08:40:46 -0000 1.76 +++ dev/pci/ehci_pci.c 10 Mar 2024 09:48:49 -0000 @@ -89,6 +89,7 @@ struct ehci_pci_softc { } sc_init_state; }; +static void ehci_pci_release_resources(struct ehci_pci_softc *); static int ehci_sb700_match(const struct pci_attach_args *); static int ehci_apply_amd_quirks(struct ehci_pci_softc *); static enum ehci_pci_quirk_flags ehci_pci_lookup_quirkdata(pci_vendor_id_t, @@ -262,6 +263,7 @@ ehci_pci_attach(device_t parent, device_ int err = ehci_init(&sc->sc); if (err) { aprint_error_dev(self, "init failed, error=%d\n", err); + ehci_release_ownership(&sc->sc, sc->sc_pc, sc->sc_tag); goto fail; } sc->sc_init_state = EHCI_INIT_INITED; @@ -276,12 +278,25 @@ ehci_pci_attach(device_t parent, device_ return; fail: + ehci_pci_release_resources(sc); + + if (!pmf_device_register(self, NULL, NULL)) + aprint_error_dev(self, "couldn't establish power handler\n"); + + sc->sc_init_state = EHCI_INIT_NONE; +} + +static void +ehci_pci_release_resources(struct ehci_pci_softc *sc) +{ + if (sc->sc_ih) { pci_intr_disestablish(sc->sc_pc, sc->sc_ih); + pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); sc->sc_ih = NULL; } + if (sc->sc.sc_size) { - ehci_release_ownership(&sc->sc, sc->sc_pc, sc->sc_tag); bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); sc->sc.sc_size = 0; } @@ -302,27 +317,17 @@ ehci_pci_detach(device_t self, int flags pmf_device_deregister(self); ehci_shutdown(self, flags); - /* disable interrupts */ - EOWRITE4(&sc->sc, EHCI_USBINTR, 0); - /* XXX grotty hack to flush the write */ - (void)EOREAD4(&sc->sc, EHCI_USBINTR); - - if (sc->sc_ih != NULL) { - pci_intr_disestablish(sc->sc_pc, sc->sc_ih); - sc->sc_ih = NULL; - } - - if (sc->sc_pihp != NULL) { - pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); - sc->sc_pihp = NULL; - } + if (sc->sc_init_state >= EHCI_INIT_INITED) { + /* disable interrupts */ + EOWRITE4(&sc->sc, EHCI_USBINTR, 0); + /* XXX grotty hack to flush the write */ + (void)EOREAD4(&sc->sc, EHCI_USBINTR); - if (sc->sc.sc_size) { ehci_release_ownership(&sc->sc, sc->sc_pc, sc->sc_tag); - bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); - sc->sc.sc_size = 0; } + ehci_pci_release_resources(sc); + #if 1 /* XXX created in ehci.c */ if (sc->sc_init_state >= EHCI_INIT_INITED) {