From e5be24d7f40ff21e6e4bdaccef8e1e1c25bb581c Mon Sep 17 00:00:00 2001 From: hselasky Date: Mon, 7 Oct 2019 08:25:25 +0000 Subject: [PATCH] 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 git-svn-id: svn://svn.freebsd.org/base/stable/10@353179 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/dev/usb/controller/xhci.c | 3 +++ sys/dev/usb/usb_bus.h | 1 + sys/dev/usb/usb_transfer.c | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c index 3f25ec6a3..af1861282 100644 --- a/sys/dev/usb/controller/xhci.c +++ b/sys/dev/usb/controller/xhci.c @@ -605,6 +605,9 @@ xhci_init(struct xhci_softc *sc, device_t self, uint8_t dma32) 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 */ diff --git a/sys/dev/usb/usb_bus.h b/sys/dev/usb/usb_bus.h index e9d4048e6..10191eb54 100644 --- a/sys/dev/usb/usb_bus.h +++ b/sys/dev/usb/usb_bus.h @@ -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_ */ diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c index 0624ed83d..4ddbc98a9 100644 --- a/sys/dev/usb/usb_transfer.c +++ b/sys/dev/usb/usb_transfer.c @@ -105,6 +105,33 @@ static const struct usb_config usb_control_ep_cfg[USB_CTRL_XFER_MAX] = { }, }; +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"); -- 2.42.0