I've got an AMD 64 X2 machine that uses the recent NVIDIA GeForce 7050 / nForce 630a chipset that hangs on shutdown. It hangs with both UP and SMP kernels, and with both FreeBSD 6.2-STABLE and 7.0-CURRENT. The problem appears to be that a delay is needed between the the call EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); in ehci_shutdown(), and the call cparams = EREAD4(sc, EHCI_HCCPARAMS); in ehci_pci_givecontroller(). There are three instances of a code sequence that does a controller reset in ehci.c, one of which, in ehci_init(), inserts some delays and periodically polls the controller to look for the completion of the reset. It seems to make sense to encapsulate the latter version of the sequence in a separate function, and then call that function from ehci_reset(), ehci_detach(), and ehci_shutdown(). I implemented this in the attached patch, and it fixes shutdown problem for me on both 7.0-CURRENT and 6.2-STABLE (with some minor tweaks for the latter). I've tested this patch on this system with both i386 and amd64 kernels, and I also tested it on my Pentium-M laptop. The shutdown problems are gone and everything else looks normal, but I don't have any USB 2.0 peripherals to do further testing. I'd appreciate any testing that can be done in the next serveral days before I ask re_at_ for approval to commit this to -CURRENT. 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 4 Aug 2007 21:05:46 -0000 _at__at_ -311,6 +311,25 _at__at_ 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 */ + 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) + 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) { _at__at_ -365,20 +384,9 _at__at_ /* 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))) { _at__at_ -927,8 +935,7 _at__at_ 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); _at__at_ -1090,8 +1097,7 _at__at_ 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_statusReceived on Sat Aug 04 2007 - 22:06:35 UTC
This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:39:15 UTC