Author: hselasky
Date: Mon Oct  7 08:25:25 2019
New Revision: 353179
URL: https://svnweb.freebsd.org/changeset/base/353179

Log:
  MFC r352556:
  Add quirk for XHCI(4) controllers to support USB control transfers
  above 1Kbyte.  It might look like some XHCI(4) controllers do not
  support when the USB control transfer is split using a link TRB. The
  next NORMAL TRB after the link TRB is simply failing with XHCI error
  code 4. The quirk ensures we allocate a 64Kbyte buffer so that the
  data stage TRB is not broken with a link TRB.
  
  Found at:     EuroBSDcon 2019
  Sponsored by: Mellanox Technologies

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

Modified: stable/10/sys/dev/usb/controller/xhci.c
==============================================================================
--- stable/10/sys/dev/usb/controller/xhci.c     Mon Oct  7 08:24:46 2019        
(r353178)
+++ stable/10/sys/dev/usb/controller/xhci.c     Mon Oct  7 08:25:25 2019        
(r353179)
@@ -605,6 +605,9 @@ xhci_init(struct xhci_softc *sc, device_t self, uint8_
        device_printf(self, "%d bytes context size, %d-bit DMA\n",
            sc->sc_ctx_is_64_byte ? 64 : 32, (int)sc->sc_bus.dma_bits);
 
+       /* enable 64Kbyte control endpoint quirk */
+       sc->sc_bus.control_ep_quirk = 1;
+
        temp = XREAD4(sc, capa, XHCI_HCSPARAMS1);
 
        /* get number of device slots */

Modified: stable/10/sys/dev/usb/usb_bus.h
==============================================================================
--- stable/10/sys/dev/usb/usb_bus.h     Mon Oct  7 08:24:46 2019        
(r353178)
+++ stable/10/sys/dev/usb/usb_bus.h     Mon Oct  7 08:25:25 2019        
(r353179)
@@ -129,6 +129,7 @@ struct usb_bus {
        uint8_t do_probe;               /* set if USB should be re-probed */
        uint8_t no_explore;             /* don't explore USB ports */
        uint8_t dma_bits;               /* number of DMA address lines */
+       uint8_t control_ep_quirk;       /* need 64kByte buffer for data stage */
 };
 
 #endif                                 /* _USB_BUS_H_ */

Modified: stable/10/sys/dev/usb/usb_transfer.c
==============================================================================
--- stable/10/sys/dev/usb/usb_transfer.c        Mon Oct  7 08:24:46 2019        
(r353178)
+++ stable/10/sys/dev/usb/usb_transfer.c        Mon Oct  7 08:25:25 2019        
(r353179)
@@ -105,6 +105,33 @@ static const struct usb_config usb_control_ep_cfg[USB_
        },
 };
 
+static const struct usb_config usb_control_ep_quirk_cfg[USB_CTRL_XFER_MAX] = {
+
+       /* This transfer is used for generic control endpoint transfers */
+
+       [0] = {
+               .type = UE_CONTROL,
+               .endpoint = 0x00,       /* Control endpoint */
+               .direction = UE_DIR_ANY,
+               .bufsize = 65535,       /* bytes */
+               .callback = &usb_request_callback,
+               .usb_mode = USB_MODE_DUAL,      /* both modes */
+       },
+
+       /* This transfer is used for generic clear stall only */
+
+       [1] = {
+               .type = UE_CONTROL,
+               .endpoint = 0x00,       /* Control pipe */
+               .direction = UE_DIR_ANY,
+               .bufsize = sizeof(struct usb_device_request),
+               .callback = &usb_do_clear_stall_callback,
+               .timeout = 1000,        /* 1 second */
+               .interval = 50, /* 50ms */
+               .usb_mode = USB_MODE_HOST,
+       },
+};
+
 /* function prototypes */
 
 static void    usbd_update_max_frame_size(struct usb_xfer *);
@@ -1020,7 +1047,8 @@ usbd_transfer_setup(struct usb_device *udev,
                         * context, else there is a chance of
                         * deadlock!
                         */
-                       if (setup_start == usb_control_ep_cfg)
+                       if (setup_start == usb_control_ep_cfg ||
+                           setup_start == usb_control_ep_quirk_cfg)
                                info->done_p =
                                    USB_BUS_CONTROL_XFER_PROC(udev->bus);
                        else if (xfer_mtx == &Giant)
@@ -3148,7 +3176,8 @@ repeat:
         */
        iface_index = 0;
        if (usbd_transfer_setup(udev, &iface_index,
-           udev->ctrl_xfer, usb_control_ep_cfg, USB_CTRL_XFER_MAX, NULL,
+           udev->ctrl_xfer, udev->bus->control_ep_quirk ?
+           usb_control_ep_quirk_cfg : usb_control_ep_cfg, USB_CTRL_XFER_MAX, 
NULL,
            &udev->device_mtx)) {
                DPRINTFN(0, "could not setup default "
                    "USB transfer\n");
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to