Author: hselasky
Date: Thu Dec 19 07:12:40 2013
New Revision: 259602
URL: http://svnweb.freebsd.org/changeset/base/259602

Log:
  MFC r259023 and r259095:
  Improve the XHCI command timeout recovery handling code.
  Fix some typos while at it.

Modified:
  stable/9/sys/dev/usb/controller/usb_controller.c
  stable/9/sys/dev/usb/controller/xhci.c
  stable/9/sys/dev/usb/usb_bus.h
  stable/9/sys/dev/usb/usb_controller.h
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/dev/   (props changed)

Modified: stable/9/sys/dev/usb/controller/usb_controller.c
==============================================================================
--- stable/9/sys/dev/usb/controller/usb_controller.c    Thu Dec 19 07:12:34 
2013        (r259601)
+++ stable/9/sys/dev/usb/controller/usb_controller.c    Thu Dec 19 07:12:40 
2013        (r259602)
@@ -278,6 +278,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(&bus->explore_proc,
+           &bus->reset_msg[0], &bus->reset_msg[1]);
+}
+
+/*------------------------------------------------------------------------*
  *     usb_shutdown
  *------------------------------------------------------------------------*/
 static int
@@ -399,7 +421,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)
@@ -409,6 +431,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];
 
@@ -454,7 +478,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)
@@ -464,6 +488,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];
 
@@ -513,9 +539,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)
@@ -728,6 +776,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/9/sys/dev/usb/controller/xhci.c
==============================================================================
--- stable/9/sys/dev/usb/controller/xhci.c      Thu Dec 19 07:12:34 2013        
(r259601)
+++ stable/9/sys/dev/usb/controller/xhci.c      Thu Dec 19 07:12:40 2013        
(r259602)
@@ -253,6 +253,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)
 {
@@ -1025,6 +1088,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);
@@ -1038,7 +1102,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;
 
@@ -1109,25 +1173,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/9/sys/dev/usb/usb_bus.h
==============================================================================
--- stable/9/sys/dev/usb/usb_bus.h      Thu Dec 19 07:12:34 2013        
(r259601)
+++ stable/9/sys/dev/usb/usb_bus.h      Thu Dec 19 07:12:40 2013        
(r259602)
@@ -71,6 +71,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/9/sys/dev/usb/usb_controller.h
==============================================================================
--- stable/9/sys/dev/usb/usb_controller.h       Thu Dec 19 07:12:34 2013        
(r259601)
+++ stable/9/sys/dev/usb/usb_controller.h       Thu Dec 19 07:12:40 2013        
(r259602)
@@ -186,6 +186,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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to