c48d16db91f44dcd516d5d893515c30e165583f6
[oweals/openwrt.git] /
1 From fa776ef749c924cd3ff3ffa257d7a63a27224399 Mon Sep 17 00:00:00 2001
2 From: Jonathan Bell <jonathan@raspberrypi.org>
3 Date: Thu, 30 May 2019 10:38:40 +0100
4 Subject: [PATCH] usb: xhci: hack xhci_urb_enqueue to support
5  hid.mousepoll behaviour
6
7 xHCI creates endpoint contexts directly from the device's endpoint
8 data, so submitting URBs with urb->interval different from the hardware
9 interval has no effect.
10
11 Add an explicit reconfiguration of the endpoint context when requested,
12 which will happen only when the interval is different from the cached
13 value. In practice, the reconfiguration only happens on the first URB
14 submitted for the endpoint.
15
16 Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
17 ---
18  drivers/usb/host/xhci.c | 86 +++++++++++++++++++++++++++++++++++++++++
19  1 file changed, 86 insertions(+)
20
21 --- a/drivers/usb/host/xhci.c
22 +++ b/drivers/usb/host/xhci.c
23 @@ -1425,6 +1425,87 @@ command_cleanup:
24  }
25  
26  /*
27 + * RPI: Fixup endpoint intervals when requested
28 + * - Check interval versus the (cached) endpoint context
29 + * - set the endpoint interval to the new value
30 + * - force an endpoint configure command
31 + */
32 +static void xhci_fixup_interval(struct xhci_hcd *xhci, struct urb *urb,
33 +                               unsigned int slot_id, unsigned int ep_index)
34 +{
35 +       struct xhci_ep_ctx *ep_ctx_out, *ep_ctx_in;
36 +       struct xhci_command *command;
37 +       struct xhci_input_control_ctx *ctrl_ctx;
38 +       struct xhci_virt_device *vdev;
39 +       int xhci_interval, ep_interval;
40 +       int ret;
41 +       unsigned long flags;
42 +       u32 ep_info_tmp;
43 +
44 +       spin_lock_irqsave(&xhci->lock, flags);
45 +
46 +       vdev = xhci->devs[slot_id];
47 +       /* Get context-derived endpoint interval */
48 +       ep_ctx_out = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index);
49 +       ep_ctx_in = xhci_get_ep_ctx(xhci, vdev->in_ctx, ep_index);
50 +       xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx_out->ep_info));
51 +       ep_interval = urb->interval * 8;
52 +
53 +       if (ep_interval == xhci_interval) {
54 +               spin_unlock_irqrestore(&xhci->lock, flags);
55 +               return;
56 +       }
57 +
58 +       xhci_dbg(xhci, "Fixup interval ep_interval=%d xhci_interval=%d\n",
59 +                ep_interval, xhci_interval);
60 +       command = xhci_alloc_command_with_ctx(xhci, true, GFP_ATOMIC);
61 +       if (!command) {
62 +               /* Failure here is benign, poll at the original rate */
63 +               spin_unlock_irqrestore(&xhci->lock, flags);
64 +               return;
65 +       }
66 +
67 +       /* xHCI uses exponents for intervals... */
68 +       xhci_interval = fls(ep_interval) - 1;
69 +       xhci_interval = clamp_val(xhci_interval, 3, 10);
70 +       ep_info_tmp = le32_to_cpu(ep_ctx_out->ep_info);
71 +       ep_info_tmp &= ~EP_INTERVAL(255);
72 +       ep_info_tmp |= EP_INTERVAL(xhci_interval);
73 +
74 +       /* Keep the endpoint context up-to-date while issuing the command. */
75 +       xhci_endpoint_copy(xhci, vdev->in_ctx,
76 +                          vdev->out_ctx, ep_index);
77 +       ep_ctx_in->ep_info = cpu_to_le32(ep_info_tmp);
78 +
79 +       /*
80 +        * We need to drop the lock, so take an explicit copy
81 +        * of the ep context.
82 +        */
83 +       xhci_endpoint_copy(xhci, command->in_ctx, vdev->in_ctx, ep_index);
84 +
85 +       ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
86 +       if (!ctrl_ctx) {
87 +               xhci_warn(xhci,
88 +                         "%s: Could not get input context, bad type.\n",
89 +                         __func__);
90 +               spin_unlock_irqrestore(&xhci->lock, flags);
91 +               xhci_free_command(xhci, command);
92 +               return;
93 +       }
94 +       ctrl_ctx->add_flags = xhci_get_endpoint_flag_from_index(ep_index);
95 +       ctrl_ctx->drop_flags = 0;
96 +
97 +       spin_unlock_irqrestore(&xhci->lock, flags);
98 +
99 +       ret = xhci_configure_endpoint(xhci, urb->dev, command,
100 +                                     false, false);
101 +       if (ret)
102 +               xhci_warn(xhci, "%s: Configure endpoint failed: %d\n",
103 +                         __func__, ret);
104 +       xhci_free_command(xhci, command);
105 +}
106 +
107 +/*
108   * non-error returns are a promise to giveback() the urb later
109   * we drop ownership so next owner (or urb unlink) can get it
110   */
111 @@ -1492,6 +1573,11 @@ static int xhci_urb_enqueue(struct usb_h
112                 }
113         }
114  
115 +       if (usb_endpoint_xfer_int(&urb->ep->desc) &&
116 +           (urb->dev->speed == USB_SPEED_FULL ||
117 +            urb->dev->speed == USB_SPEED_LOW))
118 +               xhci_fixup_interval(xhci, urb, slot_id, ep_index);
119 +
120         spin_lock_irqsave(&xhci->lock, flags);
121  
122         if (xhci->xhc_state & XHCI_STATE_DYING) {