From owner-freebsd-current@FreeBSD.ORG Sun Aug 12 04:43:07 2007 Return-Path: Delivered-To: current@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id E282816A417 for ; Sun, 12 Aug 2007 04:43:07 +0000 (UTC) (envelope-from truckman@FreeBSD.org) Received: from gw.catspoiler.org (adsl-75-1-14-242.dsl.scrm01.sbcglobal.net [75.1.14.242]) by mx1.freebsd.org (Postfix) with ESMTP id A952113C45B for ; Sun, 12 Aug 2007 04:43:07 +0000 (UTC) (envelope-from truckman@FreeBSD.org) Received: from FreeBSD.org (mousie.catspoiler.org [192.168.101.2]) by gw.catspoiler.org (8.13.3/8.13.3) with ESMTP id l7C4gtMP060591; Sat, 11 Aug 2007 21:42:59 -0700 (PDT) (envelope-from truckman@FreeBSD.org) Message-Id: <200708120442.l7C4gtMP060591@gw.catspoiler.org> Date: Sat, 11 Aug 2007 21:42:55 -0700 (PDT) From: Don Lewis To: bruce@cran.org.uk In-Reply-To: <200708120157.l7C1vWcI060342@gw.catspoiler.org> MIME-Version: 1.0 Content-Type: TEXT/plain; charset=us-ascii Cc: current@FreeBSD.org Subject: Re: RE: Reboot on "shutdown -r" hangs after final "uptime ..." string X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 12 Aug 2007 04:43:08 -0000 On 11 Aug, Don Lewis wrote: > On 11 Aug, To: bruce@cran.org.uk wrote: >> On 12 Aug, bruce@cran.org.uk wrote: > >> Something that you might want to also print is the value of >> EOREAD4(sc, EHCI_USBSTS) >> immediately before the >> EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); >> call in ehci_hcreset(). Bit 12 of this register (EHCI_STS_HCH) should >> be a zero before the write to do the reset is performed. > > Correction, this bit should be a one before doing the reset. > >> Maybe >> ehci_hcreset() needs to wait for that to happen (as is done in >> ehci_init()), rather than just waiting a fixed amount of time. > > I misread the code in ehci_init(), which is waiting for a transition in > the opposite direction. I don't know why, because the EHCI spec says > that the 1->0 transition is immediate. A revised version of the patch is below. The only change is the addition of a second wait loop in ehci_hcreset(), which would be necessary according the the EHCI spec if the controller could ever require more than 1ms to stop. This patch might fix the problem on your machine if you are observing a zero for bit 12 (EHCI_STS_HCH) of the EHCI_USBSTS register in ehci_hcreset(). Index: sys/dev/usb/ehci.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/ehci.c,v retrieving revision 1.55 diff -u -r1.55 ehci.c --- sys/dev/usb/ehci.c 20 Jun 2007 05:10:52 -0000 1.55 +++ sys/dev/usb/ehci.c 12 Aug 2007 03:55:54 -0000 @@ -311,6 +311,39 @@ ehci_device_isoc_done, }; +static usbd_status +ehci_hcreset(ehci_softc_t *sc) +{ + u_int32_t hcr; + u_int i; + + EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */ + for (i = 0; i < 100; i++) { + usb_delay_ms(&sc->sc_bus, 1); + hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; + if (hcr) + break; + } + if (!hcr) + /* + * Fall through and try reset anyway even though + * Table 2-9 in the EHCI spec says this will result + * in undefined behavior. + */ + printf("%s: stop timeout\n", + device_get_nameunit(sc->sc_bus.bdev)); + + EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); + for (i = 0; i < 100; i++) { + usb_delay_ms(&sc->sc_bus, 1); + hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET; + if (!hcr) + return (USBD_NORMAL_COMPLETION); + } + printf("%s: reset timeout\n", device_get_nameunit(sc->sc_bus.bdev)); + return (USBD_IOERROR); +} + usbd_status ehci_init(ehci_softc_t *sc) { @@ -365,20 +398,9 @@ /* Reset the controller */ DPRINTF(("%s: resetting\n", device_get_nameunit(sc->sc_bus.bdev))); - EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */ - usb_delay_ms(&sc->sc_bus, 1); - EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); - for (i = 0; i < 100; i++) { - usb_delay_ms(&sc->sc_bus, 1); - hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET; - if (!hcr) - break; - } - if (hcr) { - printf("%s: reset timeout\n", - device_get_nameunit(sc->sc_bus.bdev)); - return (USBD_IOERROR); - } + err = ehci_hcreset(sc); + if (err != USBD_NORMAL_COMPLETION) + return (err); /* frame list size at default, read back what we got and use that */ switch (EHCI_CMD_FLS(EOREAD4(sc, EHCI_USBCMD))) { @@ -927,8 +949,7 @@ sc->sc_dying = 1; EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); - EOWRITE4(sc, EHCI_USBCMD, 0); - EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); + (void) ehci_hcreset(sc); callout_stop(&sc->sc_tmo_intrlist); callout_stop(&sc->sc_tmo_pcd); @@ -1090,8 +1111,7 @@ ehci_softc_t *sc = v; DPRINTF(("ehci_shutdown: stopping the HC\n")); - EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */ - EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); + (void) ehci_hcreset(sc); } usbd_status If this doesn't help, you could test the SMI hypothesis by disabling the SMI on OS Ownership Enable bit before clearing the EHCI_LEGSUP_OSOWNED bit. Something like the following should disable the SMI enable bit, but I don't know what side effects it might have. It could even melt your computer ;-) In any case, it's not a proper fix. static void ehci_pci_givecontroller(device_t self) { ehci_softc_t *sc = device_get_softc(self); u_int32_t cparams, eec, legsup; int eecp; cparams = EREAD4(sc, EHCI_HCCPARAMS); for (eecp = EHCI_HCC_EECP(cparams); eecp != 0; eecp = EHCI_EECP_NEXT(eec)) { eec = pci_read_config(self, eecp, 4); if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP) continue; /* NEW */ legsup = pci_read_config(self,eecp+EHCI_LEGSUP_USBLEGCTLSTS,4); /* NEW */ legsup = legsup & ~0x200; /* NEW */ pci_write_config(self, eecp+EHCI_LEGSUP_USBLEGCTLSTS, legsup,4); legsup = eec; pci_write_config(self, eecp, legsup & ~EHCI_LEGSUP_OSOWNED, 4); } }