cec6a906823450bfa846c0275358202ca1c1a987
[oweals/openwrt.git] /
1 From 6a313b6072925ab757688328b9f91b16d5a39bb3 Mon Sep 17 00:00:00 2001
2 From: Peter Chen <peter.chen@nxp.com>
3 Date: Fri, 9 Feb 2018 10:11:32 +0800
4 Subject: [PATCH] MLK-17380-4 usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE
5  Test for USB2
6
7 This function is similar with EHCI's, but implemented using XHCI.
8 The USB2 host needs to send SETUP packet first, then wait 15
9 seconds before DATA (IN) + STATUS stage.
10
11 It is needed at USB Certification test for Embedded Host 2.0, and
12 the detail is at CH6.4.1.1 of On-The-Go and Embedded Host Supplement
13 to the USB Revision 2.0 Specification
14
15 Acked-by: Jun Li <jun.li@nxp.com>
16 Signed-off-by: Peter Chen <peter.chen@nxp.com>
17 (cherry picked from commit 8d46e3bca527a5d899446d3858274fb5cbab1a1e)
18 ---
19  drivers/usb/host/xhci-hub.c  |   9 ++++
20  drivers/usb/host/xhci-ring.c | 123 +++++++++++++++++++++++++++++++++++++++++++
21  drivers/usb/host/xhci.c      |   1 +
22  drivers/usb/host/xhci.h      |  10 ++++
23  4 files changed, 143 insertions(+)
24
25 --- a/drivers/usb/host/xhci-hub.c
26 +++ b/drivers/usb/host/xhci-hub.c
27 @@ -1378,6 +1378,15 @@ int xhci_hub_control(struct usb_hcd *hcd
28                         /* 4.19.6 Port Test Modes (USB2 Test Mode) */
29                         if (hcd->speed != HCD_USB2)
30                                 goto error;
31 +#ifdef CONFIG_USB_HCD_TEST_MODE
32 +                       if (test_mode == EHSET_TEST_SINGLE_STEP_SET_FEATURE) {
33 +                               spin_unlock_irqrestore(&xhci->lock, flags);
34 +                               retval = ehset_single_step_set_feature(hcd,
35 +                                                               wIndex + 1);
36 +                               spin_lock_irqsave(&xhci->lock, flags);
37 +                               break;
38 +                       }
39 +#endif
40                         if (test_mode > TEST_FORCE_EN || test_mode < TEST_J)
41                                 goto error;
42                         retval = xhci_enter_test_mode(xhci, test_mode, wIndex,
43 --- a/drivers/usb/host/xhci-ring.c
44 +++ b/drivers/usb/host/xhci-ring.c
45 @@ -3545,6 +3545,129 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
46         return 0;
47  }
48  
49 +#ifdef CONFIG_USB_HCD_TEST_MODE
50 +/*
51 + * This function prepare TRBs and submits them for the
52 + * SINGLE_STEP_SET_FEATURE Test.
53 + * This is done in two parts: first SETUP req for GetDesc is sent then
54 + * 15 seconds later, the IN stage for GetDesc starts to req data from dev
55 + *
56 + * is_setup : argument decides which of the two stage needs to be
57 + * performed; TRUE - SETUP and FALSE - IN+STATUS
58 + * Returns 0 if success
59 + */
60 +int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
61 +       struct urb *urb, int is_setup)
62 +{
63 +       int slot_id;
64 +       unsigned int ep_index;
65 +       struct xhci_ring *ep_ring;
66 +       int ret;
67 +       struct usb_ctrlrequest *setup;
68 +       struct xhci_generic_trb *start_trb;
69 +       int start_cycle;
70 +       u32 field, length_field, remainder;
71 +       struct urb_priv *urb_priv;
72 +       struct xhci_td *td;
73 +       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
74 +
75 +       /* urb_priv will be free after transcation has completed */
76 +       urb_priv = kzalloc(sizeof(struct urb_priv) +
77 +                       sizeof(struct xhci_td), GFP_KERNEL);
78 +       if (!urb_priv)
79 +               return -ENOMEM;
80 +
81 +       td = &urb_priv->td[0];
82 +       urb_priv->num_tds = 1;
83 +       urb_priv->num_tds_done = 0;
84 +       urb->hcpriv = urb_priv;
85 +
86 +       ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
87 +       if (!ep_ring) {
88 +               ret = -EINVAL;
89 +               goto free_priv;
90 +       }
91 +
92 +       slot_id = urb->dev->slot_id;
93 +       ep_index = xhci_get_endpoint_index(&urb->ep->desc);
94 +
95 +       setup = (struct usb_ctrlrequest *) urb->setup_packet;
96 +       if (is_setup) {
97 +               ret = prepare_transfer(xhci, xhci->devs[slot_id],
98 +                               ep_index, urb->stream_id,
99 +                               1, urb, 0, GFP_KERNEL);
100 +               if (ret < 0)
101 +                       goto free_priv;
102 +
103 +               start_trb = &ep_ring->enqueue->generic;
104 +               start_cycle = ep_ring->cycle_state;
105 +               /* Save the DMA address of the last TRB in the TD */
106 +               td->last_trb = ep_ring->enqueue;
107 +               field = TRB_IOC | TRB_IDT | TRB_TYPE(TRB_SETUP) | start_cycle;
108 +               /* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */
109 +               if ((xhci->hci_version >= 0x100) ||
110 +                               (xhci->quirks & XHCI_MTK_HOST))
111 +                       field |= TRB_TX_TYPE(TRB_DATA_IN);
112 +
113 +               queue_trb(xhci, ep_ring, false,
114 +                         setup->bRequestType | setup->bRequest << 8 |
115 +                         le16_to_cpu(setup->wValue) << 16,
116 +                         le16_to_cpu(setup->wIndex) |
117 +                         le16_to_cpu(setup->wLength) << 16,
118 +                         TRB_LEN(8) | TRB_INTR_TARGET(0),
119 +                         /* Immediate data in pointer */
120 +                         field);
121 +               giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
122 +                               start_cycle, start_trb);
123 +               return 0;
124 +       }
125 +
126 +       ret = prepare_transfer(xhci, xhci->devs[slot_id],
127 +                       ep_index, urb->stream_id,
128 +                       2, urb, 0, GFP_KERNEL);
129 +       if (ret < 0)
130 +               goto free_priv;
131 +
132 +       start_trb = &ep_ring->enqueue->generic;
133 +       start_cycle = ep_ring->cycle_state;
134 +       field = TRB_ISP | TRB_TYPE(TRB_DATA);
135 +
136 +       remainder = xhci_td_remainder(xhci, 0,
137 +                                  urb->transfer_buffer_length,
138 +                                  urb->transfer_buffer_length,
139 +                                  urb, 1);
140 +
141 +       length_field = TRB_LEN(urb->transfer_buffer_length) |
142 +               TRB_TD_SIZE(remainder) |
143 +               TRB_INTR_TARGET(0);
144 +
145 +       if (urb->transfer_buffer_length > 0) {
146 +               field |= TRB_DIR_IN;
147 +               queue_trb(xhci, ep_ring, true,
148 +                               lower_32_bits(urb->transfer_dma),
149 +                               upper_32_bits(urb->transfer_dma),
150 +                               length_field,
151 +                               field | ep_ring->cycle_state);
152 +       }
153 +
154 +       td->last_trb = ep_ring->enqueue;
155 +       field = TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state;
156 +       queue_trb(xhci, ep_ring, false,
157 +                       0,
158 +                       0,
159 +                       TRB_INTR_TARGET(0),
160 +                       field);
161 +
162 +       giveback_first_trb(xhci, slot_id, ep_index, 0,
163 +                       start_cycle, start_trb);
164 +
165 +       return 0;
166 +free_priv:
167 +       xhci_urb_free_priv(urb_priv);
168 +       return ret;
169 +}
170 +#endif /* CONFIG_USB_HCD_TEST_MODE */
171 +
172  /*
173   * The transfer burst count field of the isochronous TRB defines the number of
174   * bursts that are required to move all packets in this TD.  Only SuperSpeed
175 --- a/drivers/usb/host/xhci.c
176 +++ b/drivers/usb/host/xhci.c
177 @@ -5352,6 +5352,7 @@ static const struct hc_driver xhci_hc_dr
178         .disable_usb3_lpm_timeout =     xhci_disable_usb3_lpm_timeout,
179         .find_raw_port_number = xhci_find_raw_port_number,
180         .clear_tt_buffer_complete = xhci_clear_tt_buffer_complete,
181 +       .submit_single_step_set_feature = xhci_submit_single_step_set_feature,
182  };
183  
184  void xhci_init_driver(struct hc_driver *drv,
185 --- a/drivers/usb/host/xhci.h
186 +++ b/drivers/usb/host/xhci.h
187 @@ -2141,6 +2141,16 @@ int xhci_find_raw_port_number(struct usb
188  struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd);
189  
190  void xhci_hc_died(struct xhci_hcd *xhci);
191 +#ifdef CONFIG_USB_HCD_TEST_MODE
192 +int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
193 +       struct urb *urb, int is_setup);
194 +#else
195 +static inline int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
196 +       struct urb *urb, int is_setup)
197 +{
198 +       return 0;
199 +}
200 +#endif
201  
202  #ifdef CONFIG_PM
203  int xhci_bus_suspend(struct usb_hcd *hcd);