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.  don't check the return
value of pmf_device_register*().

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.
This commit is contained in:
mrg 2024-03-24 03:29:02 +00:00
parent c3c0699382
commit 6e3a54761d
1 changed files with 30 additions and 27 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ehci_pci.c,v 1.76 2023/01/24 08:40:46 mlelstv Exp $ */
/* $NetBSD: ehci_pci.c,v 1.77 2024/03/24 03:29:02 mrg Exp $ */
/*
* Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.76 2023/01/24 08:40:46 mlelstv Exp $");
__KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.77 2024/03/24 03:29:02 mrg Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -85,10 +85,12 @@ struct ehci_pci_softc {
void *sc_ih; /* interrupt vectoring */
enum {
EHCI_INIT_NONE,
EHCI_INIT_OWNER,
EHCI_INIT_INITED
} 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,
@ -200,9 +202,6 @@ ehci_pci_attach(device_t parent, device_t self, void *aux)
sc->sc_ih = pci_intr_establish_xname(pc, sc->sc_pihp[0], IPL_USB,
ehci_intr, sc, device_xname(self));
if (sc->sc_ih == NULL) {
pci_intr_release(sc->sc_pc, sc->sc_pihp, 1);
sc->sc_pihp = NULL;
aprint_error_dev(self, "couldn't establish interrupt");
if (intrstr != NULL)
aprint_error(" at %s", intrstr);
@ -258,6 +257,7 @@ ehci_pci_attach(device_t parent, device_t self, void *aux)
sc->sc.sc_ncomp = ncomp;
ehci_get_ownership(&sc->sc, pc, tag);
sc->sc_init_state = EHCI_INIT_OWNER;
int err = ehci_init(&sc->sc);
if (err) {
@ -266,9 +266,8 @@ ehci_pci_attach(device_t parent, device_t self, void *aux)
}
sc->sc_init_state = EHCI_INIT_INITED;
if (!pmf_device_register1(self, ehci_pci_suspend, ehci_pci_resume,
ehci_shutdown))
aprint_error_dev(self, "couldn't establish power handler\n");
pmf_device_register1(self, ehci_pci_suspend, ehci_pci_resume,
ehci_shutdown);
/* Attach usb device. */
sc->sc.sc_child = config_found(self, &sc->sc.sc_bus, usbctlprint,
@ -276,15 +275,31 @@ ehci_pci_attach(device_t parent, device_t self, void *aux)
return;
fail:
ehci_pci_release_resources(sc);
pmf_device_register(self, NULL, NULL);
}
static void
ehci_pci_release_resources(struct ehci_pci_softc *sc)
{
if (sc->sc_init_state >= EHCI_INIT_OWNER)
ehci_release_ownership(&sc->sc, sc->sc_pc, sc->sc_tag);
if (sc->sc_ih) {
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.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;
}
sc->sc_init_state = EHCI_INIT_NONE;
}
static int
@ -302,26 +317,14 @@ 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_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_pihp != NULL) {
pci_intr_release(sc->sc_pc, sc->sc_pihp, 1);
sc->sc_pihp = 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;
}
ehci_pci_release_resources(sc);
#if 1
/* XXX created in ehci.c */