RE: xhci data toggle out of sync

From: Mahesh Vardhamanaiah <maheshmv_at_juniper.net>
Date: Tue, 19 Apr 2022 12:18:25 UTC
Hi HPS,
I think there is some confusion the error I am printing is in HEX value so the decimal error code is 

USB_ERR_IOERROR,		/* 18 */


Sorry about the confusion.

Thanks,
Mahesh




Juniper Business Use Only

-----Original Message-----
From: Hans Petter Selasky <hps@selasky.org> 
Sent: Tuesday, April 19, 2022 5:15 PM
To: Mahesh Vardhamanaiah <maheshmv@juniper.net>; Kamal Prasad <krprasad@juniper.net>; freebsd-usb@freebsd.org
Cc: Steve Kiernan <stevek@juniper.net>; Justin Hibbits <jhibbits@juniper.net>; Kumara N Babu <bkumara@juniper.net>; Kristof Provost <kp@FreeBSD.org>; Bjoern A. Zeeb <bz@FreeBSD.org>
Subject: Re: xhci data toggle out of sync

[External Email. Be cautious of content]


On 4/19/22 13:36, Mahesh Vardhamanaiah wrote:
> Hi HPS,
>
> Please find the diff below for the error prints.
>
>
> [maheshmv@svl-bsdx-02 /b/maheshmv/usb_issue/src]$ git diff 
> sys/dev/usb/controller/xhci.c diff --git 
> a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c index 
> 70a73dcc94c..fa7c1062ada 100644
> --- a/sys/dev/usb/controller/xhci.c
> +++ b/sys/dev/usb/controller/xhci.c
> @@ -3895,6 +3895,7 @@ xhci_configure_reset_endpoint(struct usb_xfer *xfer)
>           * Get the endpoint into the stopped state according to the
>           * endpoint context state diagram in the XHCI specification:
>           */
> +#if 0
>          switch (xhci_get_endpoint_state(udev, epno)) {
>          case XHCI_EPCTX_0_EPSTATE_DISABLED:
>                   break;
> @@ -3909,8 +3910,25 @@ xhci_configure_reset_endpoint(struct usb_xfer *xfer)
>                  err = xhci_cmd_stop_ep(sc, 0, epno, index);
>                  if (err != 0)
>                          DPRINTF("Could not stop endpoint %u\n", 
> epno);
> +               /*
> +                * Need to reset the data toggle, because stop
> +                * endpoint doesn't do that:
> +                */
> +               err = xhci_cmd_reset_ep(sc, 0, epno, index);
> +               if (err != 0)
> +                       DPRINTF("Mahesh Could not reset endpoint 
> + %u\n", epno);
>                  break;
>          }
> +#endif
> +
> +       device_printf(sc->sc_bus.parent, "MMV endpoint %u state %x\n", epno, xhci_get_endpoint_state(udev, epno));
> +       err = xhci_cmd_stop_ep(sc, 0, epno, index);
> +       if (err !=0)
> +               device_printf(sc->sc_bus.parent, "MMV Could not stop 
> + endpoint %u err %x\n", epno, err);
> +
> +       err = xhci_cmd_reset_ep(sc, 0, epno, index);
> +       if (err !=0)
> +               device_printf(sc->sc_bus.parent, "MMV Could not reset 
> + endpoint %u err %x\n", epno, err);
>
>          err = xhci_cmd_set_tr_dequeue_ptr(sc,
>              (pepext->physaddr + (stream_id * sizeof(struct xhci_trb) 
> *
>
>

Hi,

Can you check on your side where the USB_ERR_NO_PIPE comes from? I cannot find it?

xhci_cmd_reset_ep() looks like this:

> static usb_error_t
> xhci_cmd_reset_ep(struct xhci_softc *sc, uint8_t preserve,
>     uint8_t ep_id, uint8_t slot_id)
> {
>       struct xhci_trb trb;
>       uint32_t temp;
>
>       DPRINTF("\n");
>
>       trb.qwTrb0 = 0;
>       trb.dwTrb2 = 0;
>       temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_EP) |
>           XHCI_TRB_3_SLOT_SET(slot_id) |
>           XHCI_TRB_3_EP_SET(ep_id);
>
>       if (preserve)
>               temp |= XHCI_TRB_3_PRSV_BIT;
>
>       trb.dwTrb3 = htole32(temp);
>
>       return (xhci_do_command(sc, &trb, 100 /* ms */)); }

> static usb_error_t
> xhci_do_command(struct xhci_softc *sc, struct xhci_trb *trb,
>     uint16_t timeout_ms)
> {
>       struct usb_page_search buf_res;
>       struct xhci_hw_root *phwr;
>       uint64_t addr;
>       uint32_t temp;
>       uint8_t i;
>       uint8_t j;
>       uint8_t timeout = 0;
>       int err;
>
>       XHCI_CMD_ASSERT_LOCKED(sc);
>
>       /* get hardware root structure */
>
>       usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res);
>
>       phwr = buf_res.buffer;
>
>       /* Queue command */
>
>       USB_BUS_LOCK(&sc->sc_bus);
> retry:
>       i = sc->sc_command_idx;
>       j = sc->sc_command_ccs;
>
>       DPRINTFN(10, "command[%u] = %u (0x%016llx, 0x%08lx, 0x%08lx)\n",
>           i, XHCI_TRB_3_TYPE_GET(le32toh(trb->dwTrb3)),
>           (long long)le64toh(trb->qwTrb0),
>           (long)le32toh(trb->dwTrb2),
>           (long)le32toh(trb->dwTrb3));
>
>       phwr->hwr_commands[i].qwTrb0 = trb->qwTrb0;
>       phwr->hwr_commands[i].dwTrb2 = trb->dwTrb2;
>
>       usb_pc_cpu_flush(&sc->sc_hw.root_pc);
>
>       temp = trb->dwTrb3;
>
>       if (j)
>               temp |= htole32(XHCI_TRB_3_CYCLE_BIT);
>       else
>               temp &= ~htole32(XHCI_TRB_3_CYCLE_BIT);
>
>       temp &= ~htole32(XHCI_TRB_3_TC_BIT);
>
>       phwr->hwr_commands[i].dwTrb3 = temp;
>
>       usb_pc_cpu_flush(&sc->sc_hw.root_pc);
>
>       addr = buf_res.physaddr;
>       addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[i];
>
>       sc->sc_cmd_addr = htole64(addr);
>
>       i++;
>
>       if (i == (XHCI_MAX_COMMANDS - 1)) {
>
>               if (j) {
>                       temp = htole32(XHCI_TRB_3_TC_BIT |
>                           XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) |
>                           XHCI_TRB_3_CYCLE_BIT);
>               } else {
>                       temp = htole32(XHCI_TRB_3_TC_BIT |
>                           XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK));
>               }
>
>               phwr->hwr_commands[i].dwTrb3 = temp;
>
>               usb_pc_cpu_flush(&sc->sc_hw.root_pc);
>
>               i = 0;
>               j ^= 1;
>       }
>
>       sc->sc_command_idx = i;
>       sc->sc_command_ccs = j;
>
>       XWRITE4(sc, door, XHCI_DOORBELL(0), 0);
>
>       err = cv_timedwait(&sc->sc_cmd_cv, &sc->sc_bus.bus_mtx,
>           USB_MS_TO_TICKS(timeout_ms));
>
>       /*
>        * In some error cases event interrupts are not generated.
>        * Poll one time to see if the command has completed.
>        */
>       if (err != 0 && xhci_interrupt_poll(sc) != 0) {
>               DPRINTF("Command was completed when polling\n");
>               err = 0;
>       }
>       if (err != 0) {
>               DPRINTF("Command timeout!\n");
>               /*
>                * 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.
>                */
>               if (timeout == 0 &&
>                   xhci_reset_command_queue_locked(sc) == 0) {
>                       temp = le32toh(trb->dwTrb3);
>
>                       /*
>                        * Avoid infinite XHCI reset loops if the set
>                        * address command fails to respond due to a
>                        * non-enumerating device:
>                        */
>                       if (XHCI_TRB_3_TYPE_GET(temp) == XHCI_TRB_TYPE_ADDRESS_DEVICE &&
>                           (temp & XHCI_TRB_3_BSR_BIT) == 0) {
>                               DPRINTF("Set address timeout\n");
>                       } else {
>                               timeout = 1;
>                               goto retry;
>                       }
>               } else {
>                       DPRINTF("Controller reset!\n");
>                       usb_bus_reset_async_locked(&sc->sc_bus);
>               }
>               err = USB_ERR_TIMEOUT;
>               trb->dwTrb2 = 0;
>               trb->dwTrb3 = 0;
>       } else {
>               temp = le32toh(sc->sc_cmd_result[0]);
>               if (XHCI_TRB_2_ERROR_GET(temp) != XHCI_TRB_ERROR_SUCCESS)
>                       err = USB_ERR_IOERROR;
>
>               trb->dwTrb2 = sc->sc_cmd_result[0];
>               trb->dwTrb3 = sc->sc_cmd_result[1];
>       }
>
>       USB_BUS_UNLOCK(&sc->sc_bus);
>
>       return (err);
> }

--HPS