diff options
Diffstat (limited to 'target/linux/brcm2708/patches-4.19/950-0551-usb-xhci-hack-xhci_urb_enqueue-to-support-hid.mousep.patch')
-rw-r--r-- | target/linux/brcm2708/patches-4.19/950-0551-usb-xhci-hack-xhci_urb_enqueue-to-support-hid.mousep.patch | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.19/950-0551-usb-xhci-hack-xhci_urb_enqueue-to-support-hid.mousep.patch b/target/linux/brcm2708/patches-4.19/950-0551-usb-xhci-hack-xhci_urb_enqueue-to-support-hid.mousep.patch new file mode 100644 index 0000000000..a8056287a7 --- /dev/null +++ b/target/linux/brcm2708/patches-4.19/950-0551-usb-xhci-hack-xhci_urb_enqueue-to-support-hid.mousep.patch @@ -0,0 +1,122 @@ +From ebd33389465183268879eb8c3eefe9e7e5363cf3 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell <jonathan@raspberrypi.org> +Date: Thu, 30 May 2019 10:38:40 +0100 +Subject: [PATCH 551/725] usb: xhci: hack xhci_urb_enqueue to support + hid.mousepoll behaviour + +xHCI creates endpoint contexts directly from the device's endpoint +data, so submitting URBs with urb->interval different from the hardware +interval has no effect. + +Add an explicit reconfiguration of the endpoint context when requested, +which will happen only when the interval is different from the cached +value. In practice, the reconfiguration only happens on the first URB +submitted for the endpoint. + +Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org> +--- + drivers/usb/host/xhci.c | 86 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 86 insertions(+) + +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -1416,6 +1416,87 @@ command_cleanup: + } + + /* ++ * RPI: Fixup endpoint intervals when requested ++ * - Check interval versus the (cached) endpoint context ++ * - set the endpoint interval to the new value ++ * - force an endpoint configure command ++ */ ++static void xhci_fixup_interval(struct xhci_hcd *xhci, struct urb *urb, ++ unsigned int slot_id, unsigned int ep_index) ++{ ++ struct xhci_ep_ctx *ep_ctx_out, *ep_ctx_in; ++ struct xhci_command *command; ++ struct xhci_input_control_ctx *ctrl_ctx; ++ struct xhci_virt_device *vdev; ++ int xhci_interval, ep_interval; ++ int ret; ++ unsigned long flags; ++ u32 ep_info_tmp; ++ ++ spin_lock_irqsave(&xhci->lock, flags); ++ ++ vdev = xhci->devs[slot_id]; ++ /* Get context-derived endpoint interval */ ++ ep_ctx_out = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index); ++ ep_ctx_in = xhci_get_ep_ctx(xhci, vdev->in_ctx, ep_index); ++ xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx_out->ep_info)); ++ ep_interval = urb->interval * 8; ++ ++ if (ep_interval == xhci_interval) { ++ spin_unlock_irqrestore(&xhci->lock, flags); ++ return; ++ } ++ ++ xhci_dbg(xhci, "Fixup interval ep_interval=%d xhci_interval=%d\n", ++ ep_interval, xhci_interval); ++ command = xhci_alloc_command_with_ctx(xhci, true, GFP_ATOMIC); ++ if (!command) { ++ /* Failure here is benign, poll at the original rate */ ++ spin_unlock_irqrestore(&xhci->lock, flags); ++ return; ++ } ++ ++ /* xHCI uses exponents for intervals... */ ++ xhci_interval = fls(ep_interval) - 1; ++ xhci_interval = clamp_val(xhci_interval, 3, 10); ++ ep_info_tmp = le32_to_cpu(ep_ctx_out->ep_info); ++ ep_info_tmp &= ~EP_INTERVAL(255); ++ ep_info_tmp |= EP_INTERVAL(xhci_interval); ++ ++ /* Keep the endpoint context up-to-date while issuing the command. */ ++ xhci_endpoint_copy(xhci, vdev->in_ctx, ++ vdev->out_ctx, ep_index); ++ ep_ctx_in->ep_info = cpu_to_le32(ep_info_tmp); ++ ++ /* ++ * We need to drop the lock, so take an explicit copy ++ * of the ep context. ++ */ ++ xhci_endpoint_copy(xhci, command->in_ctx, vdev->in_ctx, ep_index); ++ ++ ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx); ++ if (!ctrl_ctx) { ++ xhci_warn(xhci, ++ "%s: Could not get input context, bad type.\n", ++ __func__); ++ spin_unlock_irqrestore(&xhci->lock, flags); ++ xhci_free_command(xhci, command); ++ return; ++ } ++ ctrl_ctx->add_flags = xhci_get_endpoint_flag_from_index(ep_index); ++ ctrl_ctx->drop_flags = 0; ++ ++ spin_unlock_irqrestore(&xhci->lock, flags); ++ ++ ret = xhci_configure_endpoint(xhci, urb->dev, command, ++ false, false); ++ if (ret) ++ xhci_warn(xhci, "%s: Configure endpoint failed: %d\n", ++ __func__, ret); ++ xhci_free_command(xhci, command); ++} ++ ++/* + * non-error returns are a promise to giveback() the urb later + * we drop ownership so next owner (or urb unlink) can get it + */ +@@ -1483,6 +1564,11 @@ static int xhci_urb_enqueue(struct usb_h + } + } + ++ if (usb_endpoint_xfer_int(&urb->ep->desc) && ++ (urb->dev->speed == USB_SPEED_FULL || ++ urb->dev->speed == USB_SPEED_LOW)) ++ xhci_fixup_interval(xhci, urb, slot_id, ep_index); ++ + spin_lock_irqsave(&xhci->lock, flags); + + if (xhci->xhc_state & XHCI_STATE_DYING) { |