Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 Oct 2019 08:24:07 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r353177 - in stable/12/sys/dev/usb: . controller
Message-ID:  <201910070824.x978O7YX047554@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Mon Oct  7 08:24:07 2019
New Revision: 353177
URL: https://svnweb.freebsd.org/changeset/base/353177

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/12/sys/dev/usb/controller/xhci.c
  stable/12/sys/dev/usb/usb_bus.h
  stable/12/sys/dev/usb/usb_transfer.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/dev/usb/controller/xhci.c
==============================================================================
--- stable/12/sys/dev/usb/controller/xhci.c	Mon Oct  7 08:14:45 2019	(r353176)
+++ stable/12/sys/dev/usb/controller/xhci.c	Mon Oct  7 08:24:07 2019	(r353177)
@@ -601,6 +601,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/12/sys/dev/usb/usb_bus.h
==============================================================================
--- stable/12/sys/dev/usb/usb_bus.h	Mon Oct  7 08:14:45 2019	(r353176)
+++ stable/12/sys/dev/usb/usb_bus.h	Mon Oct  7 08:24:07 2019	(r353177)
@@ -131,6 +131,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/12/sys/dev/usb/usb_transfer.c
==============================================================================
--- stable/12/sys/dev/usb/usb_transfer.c	Mon Oct  7 08:14:45 2019	(r353176)
+++ stable/12/sys/dev/usb/usb_transfer.c	Mon Oct  7 08:24:07 2019	(r353177)
@@ -106,6 +106,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 *);
@@ -1021,7 +1048,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)
@@ -3149,7 +3177,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");



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201910070824.x978O7YX047554>