From owner-svn-src-stable@FreeBSD.ORG Thu Dec 19 07:14:00 2013 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id C245F6A9; Thu, 19 Dec 2013 07:14:00 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id AC9F61222; Thu, 19 Dec 2013 07:14:00 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id rBJ7E01b095815; Thu, 19 Dec 2013 07:14:00 GMT (envelope-from hselasky@svn.freebsd.org) Received: (from hselasky@localhost) by svn.freebsd.org (8.14.7/8.14.7/Submit) id rBJ7DxDm095803; Thu, 19 Dec 2013 07:13:59 GMT (envelope-from hselasky@svn.freebsd.org) Message-Id: <201312190713.rBJ7DxDm095803@svn.freebsd.org> From: Hans Petter Selasky Date: Thu, 19 Dec 2013 07:13:59 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r259603 - in stable/10/sys/dev/usb: . controller X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 19 Dec 2013 07:14:00 -0000 Author: hselasky Date: Thu Dec 19 07:13:59 2013 New Revision: 259603 URL: http://svnweb.freebsd.org/changeset/base/259603 Log: MFC r259023 and r259095: Improve the XHCI command timeout recovery handling code. Fix some typos while at it. Modified: stable/10/sys/dev/usb/controller/usb_controller.c stable/10/sys/dev/usb/controller/xhci.c stable/10/sys/dev/usb/usb_bus.h stable/10/sys/dev/usb/usb_controller.h Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/dev/usb/controller/usb_controller.c ============================================================================== --- stable/10/sys/dev/usb/controller/usb_controller.c Thu Dec 19 07:12:40 2013 (r259602) +++ stable/10/sys/dev/usb/controller/usb_controller.c Thu Dec 19 07:13:59 2013 (r259603) @@ -296,6 +296,28 @@ usb_resume(device_t dev) } /*------------------------------------------------------------------------* + * usb_bus_reset_async_locked + *------------------------------------------------------------------------*/ +void +usb_bus_reset_async_locked(struct usb_bus *bus) +{ + USB_BUS_LOCK_ASSERT(bus, MA_OWNED); + + DPRINTF("\n"); + + if (bus->reset_msg[0].hdr.pm_qentry.tqe_prev != NULL || + bus->reset_msg[1].hdr.pm_qentry.tqe_prev != NULL) { + DPRINTF("Reset already pending\n"); + return; + } + + device_printf(bus->parent, "Resetting controller\n"); + + usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus), + &bus->reset_msg[0], &bus->reset_msg[1]); +} + +/*------------------------------------------------------------------------* * usb_shutdown *------------------------------------------------------------------------*/ static int @@ -419,7 +441,7 @@ usb_bus_detach(struct usb_proc_msg *pm) /*------------------------------------------------------------------------* * usb_bus_suspend * - * This function is used to suspend the USB contoller. + * This function is used to suspend the USB controller. *------------------------------------------------------------------------*/ static void usb_bus_suspend(struct usb_proc_msg *pm) @@ -429,6 +451,8 @@ usb_bus_suspend(struct usb_proc_msg *pm) usb_error_t err; uint8_t do_unlock; + DPRINTF("\n"); + bus = ((struct usb_bus_msg *)pm)->bus; udev = bus->devices[USB_ROOT_HUB_ADDR]; @@ -474,7 +498,7 @@ usb_bus_suspend(struct usb_proc_msg *pm) /*------------------------------------------------------------------------* * usb_bus_resume * - * This function is used to resume the USB contoller. + * This function is used to resume the USB controller. *------------------------------------------------------------------------*/ static void usb_bus_resume(struct usb_proc_msg *pm) @@ -484,6 +508,8 @@ usb_bus_resume(struct usb_proc_msg *pm) usb_error_t err; uint8_t do_unlock; + DPRINTF("\n"); + bus = ((struct usb_bus_msg *)pm)->bus; udev = bus->devices[USB_ROOT_HUB_ADDR]; @@ -533,9 +559,31 @@ usb_bus_resume(struct usb_proc_msg *pm) } /*------------------------------------------------------------------------* + * usb_bus_reset + * + * This function is used to reset the USB controller. + *------------------------------------------------------------------------*/ +static void +usb_bus_reset(struct usb_proc_msg *pm) +{ + struct usb_bus *bus; + + DPRINTF("\n"); + + bus = ((struct usb_bus_msg *)pm)->bus; + + if (bus->bdev == NULL || bus->no_explore != 0) + return; + + /* a suspend and resume will reset the USB controller */ + usb_bus_suspend(pm); + usb_bus_resume(pm); +} + +/*------------------------------------------------------------------------* * usb_bus_shutdown * - * This function is used to shutdown the USB contoller. + * This function is used to shutdown the USB controller. *------------------------------------------------------------------------*/ static void usb_bus_shutdown(struct usb_proc_msg *pm) @@ -750,6 +798,11 @@ usb_attach_sub(device_t dev, struct usb_ bus->resume_msg[1].hdr.pm_callback = &usb_bus_resume; bus->resume_msg[1].bus = bus; + bus->reset_msg[0].hdr.pm_callback = &usb_bus_reset; + bus->reset_msg[0].bus = bus; + bus->reset_msg[1].hdr.pm_callback = &usb_bus_reset; + bus->reset_msg[1].bus = bus; + bus->shutdown_msg[0].hdr.pm_callback = &usb_bus_shutdown; bus->shutdown_msg[0].bus = bus; bus->shutdown_msg[1].hdr.pm_callback = &usb_bus_shutdown; Modified: stable/10/sys/dev/usb/controller/xhci.c ============================================================================== --- stable/10/sys/dev/usb/controller/xhci.c Thu Dec 19 07:12:40 2013 (r259602) +++ stable/10/sys/dev/usb/controller/xhci.c Thu Dec 19 07:13:59 2013 (r259603) @@ -278,6 +278,69 @@ xhci_ctx_get_le64(struct xhci_softc *sc, } #endif +static int +xhci_reset_command_queue_locked(struct xhci_softc *sc) +{ + struct usb_page_search buf_res; + struct xhci_hw_root *phwr; + uint64_t addr; + uint32_t temp; + + DPRINTF("\n"); + + temp = XREAD4(sc, oper, XHCI_CRCR_LO); + if (temp & XHCI_CRCR_LO_CRR) { + DPRINTF("Command ring running\n"); + temp &= ~(XHCI_CRCR_LO_CS | XHCI_CRCR_LO_CA); + + /* + * Try to abort the last command as per section + * 4.6.1.2 "Aborting a Command" of the XHCI + * specification: + */ + + /* stop and cancel */ + XWRITE4(sc, oper, XHCI_CRCR_LO, temp | XHCI_CRCR_LO_CS); + XWRITE4(sc, oper, XHCI_CRCR_HI, 0); + + XWRITE4(sc, oper, XHCI_CRCR_LO, temp | XHCI_CRCR_LO_CA); + XWRITE4(sc, oper, XHCI_CRCR_HI, 0); + + /* wait 250ms */ + usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 4); + + /* check if command ring is still running */ + temp = XREAD4(sc, oper, XHCI_CRCR_LO); + if (temp & XHCI_CRCR_LO_CRR) { + DPRINTF("Comand ring still running\n"); + return (USB_ERR_IOERROR); + } + } + + /* reset command ring */ + sc->sc_command_ccs = 1; + sc->sc_command_idx = 0; + + usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); + + /* setup command ring control base address */ + addr = buf_res.physaddr; + phwr = buf_res.buffer; + addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[0]; + + DPRINTF("CRCR=0x%016llx\n", (unsigned long long)addr); + + memset(phwr->hwr_commands, 0, sizeof(phwr->hwr_commands)); + phwr->hwr_commands[XHCI_MAX_COMMANDS - 1].qwTrb0 = htole64(addr); + + usb_pc_cpu_flush(&sc->sc_hw.root_pc); + + XWRITE4(sc, oper, XHCI_CRCR_LO, ((uint32_t)addr) | XHCI_CRCR_LO_RCS); + XWRITE4(sc, oper, XHCI_CRCR_HI, (uint32_t)(addr >> 32)); + + return (0); +} + usb_error_t xhci_start_controller(struct xhci_softc *sc) { @@ -1059,6 +1122,7 @@ xhci_do_command(struct xhci_softc *sc, s uint32_t temp; uint8_t i; uint8_t j; + uint8_t timeout = 0; int err; XHCI_CMD_ASSERT_LOCKED(sc); @@ -1072,7 +1136,7 @@ xhci_do_command(struct xhci_softc *sc, s /* Queue command */ USB_BUS_LOCK(&sc->sc_bus); - +retry: i = sc->sc_command_idx; j = sc->sc_command_ccs; @@ -1143,25 +1207,22 @@ xhci_do_command(struct xhci_softc *sc, s err = 0; } if (err != 0) { - DPRINTFN(0, "Command timeout!\n"); - + DPRINTF("Command timeout!\n"); /* - * Try to abort the last command as per section - * 4.6.1.2 "Aborting a Command" of the XHCI - * specification: + * After some weeks of continuous operation, it has + * been observed that the ASMedia Technology, ASM1042 + * SuperSpeed USB Host Controller can suddenly stop + * accepting commands via the command queue. Try to + * first reset the command queue. If that fails do a + * host controller reset. */ - temp = XREAD4(sc, oper, XHCI_CRCR_LO); - XWRITE4(sc, oper, XHCI_CRCR_LO, temp | XHCI_CRCR_LO_CA); - - /* wait for abort event, if any */ - err = cv_timedwait(&sc->sc_cmd_cv, &sc->sc_bus.bus_mtx, hz / 16); - - if (err != 0 && xhci_interrupt_poll(sc) != 0) { - DPRINTF("Command was completed when polling\n"); - err = 0; - } - if (err != 0) { - DPRINTF("Command abort timeout!\n"); + if (timeout == 0 && + xhci_reset_command_queue_locked(sc) == 0) { + timeout = 1; + goto retry; + } else { + DPRINTF("Controller reset!\n"); + usb_bus_reset_async_locked(&sc->sc_bus); } err = USB_ERR_TIMEOUT; trb->dwTrb2 = 0; Modified: stable/10/sys/dev/usb/usb_bus.h ============================================================================== --- stable/10/sys/dev/usb/usb_bus.h Thu Dec 19 07:12:40 2013 (r259602) +++ stable/10/sys/dev/usb/usb_bus.h Thu Dec 19 07:13:59 2013 (r259603) @@ -81,6 +81,7 @@ struct usb_bus { struct usb_bus_msg attach_msg[2]; struct usb_bus_msg suspend_msg[2]; struct usb_bus_msg resume_msg[2]; + struct usb_bus_msg reset_msg[2]; struct usb_bus_msg shutdown_msg[2]; /* * This mutex protects the USB hardware: Modified: stable/10/sys/dev/usb/usb_controller.h ============================================================================== --- stable/10/sys/dev/usb/usb_controller.h Thu Dec 19 07:12:40 2013 (r259602) +++ stable/10/sys/dev/usb/usb_controller.h Thu Dec 19 07:13:59 2013 (r259603) @@ -191,6 +191,7 @@ void usb_bus_mem_flush_all(struct usb_bu uint8_t usb_bus_mem_alloc_all(struct usb_bus *bus, bus_dma_tag_t dmat, usb_bus_mem_cb_t *cb); void usb_bus_mem_free_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb); uint16_t usb_isoc_time_expand(struct usb_bus *bus, uint16_t isoc_time_curr); +void usb_bus_reset_async_locked(struct usb_bus *bus); #if USB_HAVE_TT_SUPPORT uint8_t usbd_fs_isoc_schedule_alloc_slot(struct usb_xfer *isoc_xfer, uint16_t isoc_time); #endif