]>
Commit | Line | Data |
---|---|---|
f0266983 GKH |
1 | From babd183915e91a64e976b9e8ab682bb56624df76 Mon Sep 17 00:00:00 2001 |
2 | From: Douglas Anderson <dianders@chromium.org> | |
3 | Date: Fri, 31 May 2019 13:04:12 -0700 | |
4 | Subject: usb: dwc2: host: Fix wMaxPacketSize handling (fix webcam regression) | |
5 | ||
6 | From: Douglas Anderson <dianders@chromium.org> | |
7 | ||
8 | commit babd183915e91a64e976b9e8ab682bb56624df76 upstream. | |
9 | ||
10 | In commit abb621844f6a ("usb: ch9: make usb_endpoint_maxp() return | |
11 | only packet size") the API to usb_endpoint_maxp() changed. It used to | |
12 | just return wMaxPacketSize but after that commit it returned | |
13 | wMaxPacketSize with the high bits (the multiplier) masked off. If you | |
14 | wanted to get the multiplier it was now up to your code to call the | |
15 | new usb_endpoint_maxp_mult() which was introduced in | |
16 | commit 541b6fe63023 ("usb: add helper to extract bits 12:11 of | |
17 | wMaxPacketSize"). | |
18 | ||
19 | Prior to the API change most host drivers were updated, but no update | |
20 | was made to dwc2. Presumably it was assumed that dwc2 was too | |
21 | simplistic to use the multiplier and thus just didn't support a | |
22 | certain class of USB devices. However, it turns out that dwc2 did use | |
23 | the multiplier and many devices using it were working quite nicely. | |
24 | That means that many USB devices have been broken since the API | |
25 | change. One such device is a Logitech HD Pro Webcam C920. | |
26 | ||
27 | Specifically, though dwc2 didn't directly call usb_endpoint_maxp(), it | |
28 | did call usb_maxpacket() which in turn called usb_endpoint_maxp(). | |
29 | ||
30 | Let's update dwc2 to work properly with the new API. | |
31 | ||
32 | Fixes: abb621844f6a ("usb: ch9: make usb_endpoint_maxp() return only packet size") | |
33 | Cc: stable@vger.kernel.org | |
34 | Acked-by: Minas Harutyunyan <hminas@synopsys.com> | |
35 | Reviewed-by: Matthias Kaehlcke <mka@chromium.org> | |
36 | Signed-off-by: Douglas Anderson <dianders@chromium.org> | |
37 | Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com> | |
38 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
39 | ||
40 | --- | |
41 | drivers/usb/dwc2/hcd.c | 29 +++++++++++++++++------------ | |
42 | drivers/usb/dwc2/hcd.h | 20 +++++++++++--------- | |
43 | drivers/usb/dwc2/hcd_intr.c | 5 +++-- | |
44 | drivers/usb/dwc2/hcd_queue.c | 10 ++++++---- | |
45 | 4 files changed, 37 insertions(+), 27 deletions(-) | |
46 | ||
47 | --- a/drivers/usb/dwc2/hcd.c | |
48 | +++ b/drivers/usb/dwc2/hcd.c | |
49 | @@ -2796,7 +2796,7 @@ static int dwc2_assign_and_init_hc(struc | |
50 | chan->dev_addr = dwc2_hcd_get_dev_addr(&urb->pipe_info); | |
51 | chan->ep_num = dwc2_hcd_get_ep_num(&urb->pipe_info); | |
52 | chan->speed = qh->dev_speed; | |
53 | - chan->max_packet = dwc2_max_packet(qh->maxp); | |
54 | + chan->max_packet = qh->maxp; | |
55 | ||
56 | chan->xfer_started = 0; | |
57 | chan->halt_status = DWC2_HC_XFER_NO_HALT_STATUS; | |
58 | @@ -2874,7 +2874,7 @@ static int dwc2_assign_and_init_hc(struc | |
59 | * This value may be modified when the transfer is started | |
60 | * to reflect the actual transfer length | |
61 | */ | |
62 | - chan->multi_count = dwc2_hb_mult(qh->maxp); | |
63 | + chan->multi_count = qh->maxp_mult; | |
64 | ||
65 | if (hsotg->params.dma_desc_enable) { | |
66 | chan->desc_list_addr = qh->desc_list_dma; | |
67 | @@ -3994,19 +3994,21 @@ static struct dwc2_hcd_urb *dwc2_hcd_urb | |
68 | ||
69 | static void dwc2_hcd_urb_set_pipeinfo(struct dwc2_hsotg *hsotg, | |
70 | struct dwc2_hcd_urb *urb, u8 dev_addr, | |
71 | - u8 ep_num, u8 ep_type, u8 ep_dir, u16 mps) | |
72 | + u8 ep_num, u8 ep_type, u8 ep_dir, | |
73 | + u16 maxp, u16 maxp_mult) | |
74 | { | |
75 | if (dbg_perio() || | |
76 | ep_type == USB_ENDPOINT_XFER_BULK || | |
77 | ep_type == USB_ENDPOINT_XFER_CONTROL) | |
78 | dev_vdbg(hsotg->dev, | |
79 | - "addr=%d, ep_num=%d, ep_dir=%1x, ep_type=%1x, mps=%d\n", | |
80 | - dev_addr, ep_num, ep_dir, ep_type, mps); | |
81 | + "addr=%d, ep_num=%d, ep_dir=%1x, ep_type=%1x, maxp=%d (%d mult)\n", | |
82 | + dev_addr, ep_num, ep_dir, ep_type, maxp, maxp_mult); | |
83 | urb->pipe_info.dev_addr = dev_addr; | |
84 | urb->pipe_info.ep_num = ep_num; | |
85 | urb->pipe_info.pipe_type = ep_type; | |
86 | urb->pipe_info.pipe_dir = ep_dir; | |
87 | - urb->pipe_info.mps = mps; | |
88 | + urb->pipe_info.maxp = maxp; | |
89 | + urb->pipe_info.maxp_mult = maxp_mult; | |
90 | } | |
91 | ||
92 | /* | |
93 | @@ -4097,8 +4099,9 @@ void dwc2_hcd_dump_state(struct dwc2_hso | |
94 | dwc2_hcd_is_pipe_in(&urb->pipe_info) ? | |
95 | "IN" : "OUT"); | |
96 | dev_dbg(hsotg->dev, | |
97 | - " Max packet size: %d\n", | |
98 | - dwc2_hcd_get_mps(&urb->pipe_info)); | |
99 | + " Max packet size: %d (%d mult)\n", | |
100 | + dwc2_hcd_get_maxp(&urb->pipe_info), | |
101 | + dwc2_hcd_get_maxp_mult(&urb->pipe_info)); | |
102 | dev_dbg(hsotg->dev, | |
103 | " transfer_buffer: %p\n", | |
104 | urb->buf); | |
105 | @@ -4665,8 +4668,10 @@ static void dwc2_dump_urb_info(struct us | |
106 | } | |
107 | ||
108 | dev_vdbg(hsotg->dev, " Speed: %s\n", speed); | |
109 | - dev_vdbg(hsotg->dev, " Max packet size: %d\n", | |
110 | - usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); | |
111 | + dev_vdbg(hsotg->dev, " Max packet size: %d (%d mult)\n", | |
112 | + usb_endpoint_maxp(&urb->ep->desc), | |
113 | + usb_endpoint_maxp_mult(&urb->ep->desc)); | |
114 | + | |
115 | dev_vdbg(hsotg->dev, " Data buffer length: %d\n", | |
116 | urb->transfer_buffer_length); | |
117 | dev_vdbg(hsotg->dev, " Transfer buffer: %p, Transfer DMA: %08lx\n", | |
118 | @@ -4749,8 +4754,8 @@ static int _dwc2_hcd_urb_enqueue(struct | |
119 | dwc2_hcd_urb_set_pipeinfo(hsotg, dwc2_urb, usb_pipedevice(urb->pipe), | |
120 | usb_pipeendpoint(urb->pipe), ep_type, | |
121 | usb_pipein(urb->pipe), | |
122 | - usb_maxpacket(urb->dev, urb->pipe, | |
123 | - !(usb_pipein(urb->pipe)))); | |
124 | + usb_endpoint_maxp(&ep->desc), | |
125 | + usb_endpoint_maxp_mult(&ep->desc)); | |
126 | ||
127 | buf = urb->transfer_buffer; | |
128 | ||
129 | --- a/drivers/usb/dwc2/hcd.h | |
130 | +++ b/drivers/usb/dwc2/hcd.h | |
131 | @@ -171,7 +171,8 @@ struct dwc2_hcd_pipe_info { | |
132 | u8 ep_num; | |
133 | u8 pipe_type; | |
134 | u8 pipe_dir; | |
135 | - u16 mps; | |
136 | + u16 maxp; | |
137 | + u16 maxp_mult; | |
138 | }; | |
139 | ||
140 | struct dwc2_hcd_iso_packet_desc { | |
141 | @@ -264,6 +265,7 @@ struct dwc2_hs_transfer_time { | |
142 | * - USB_ENDPOINT_XFER_ISOC | |
143 | * @ep_is_in: Endpoint direction | |
144 | * @maxp: Value from wMaxPacketSize field of Endpoint Descriptor | |
145 | + * @maxp_mult: Multiplier for maxp | |
146 | * @dev_speed: Device speed. One of the following values: | |
147 | * - USB_SPEED_LOW | |
148 | * - USB_SPEED_FULL | |
149 | @@ -340,6 +342,7 @@ struct dwc2_qh { | |
150 | u8 ep_type; | |
151 | u8 ep_is_in; | |
152 | u16 maxp; | |
153 | + u16 maxp_mult; | |
154 | u8 dev_speed; | |
155 | u8 data_toggle; | |
156 | u8 ping_state; | |
157 | @@ -503,9 +506,14 @@ static inline u8 dwc2_hcd_get_pipe_type( | |
158 | return pipe->pipe_type; | |
159 | } | |
160 | ||
161 | -static inline u16 dwc2_hcd_get_mps(struct dwc2_hcd_pipe_info *pipe) | |
162 | +static inline u16 dwc2_hcd_get_maxp(struct dwc2_hcd_pipe_info *pipe) | |
163 | +{ | |
164 | + return pipe->maxp; | |
165 | +} | |
166 | + | |
167 | +static inline u16 dwc2_hcd_get_maxp_mult(struct dwc2_hcd_pipe_info *pipe) | |
168 | { | |
169 | - return pipe->mps; | |
170 | + return pipe->maxp_mult; | |
171 | } | |
172 | ||
173 | static inline u8 dwc2_hcd_get_dev_addr(struct dwc2_hcd_pipe_info *pipe) | |
174 | @@ -620,12 +628,6 @@ static inline bool dbg_urb(struct urb *u | |
175 | static inline bool dbg_perio(void) { return false; } | |
176 | #endif | |
177 | ||
178 | -/* High bandwidth multiplier as encoded in highspeed endpoint descriptors */ | |
179 | -#define dwc2_hb_mult(wmaxpacketsize) (1 + (((wmaxpacketsize) >> 11) & 0x03)) | |
180 | - | |
181 | -/* Packet size for any kind of endpoint descriptor */ | |
182 | -#define dwc2_max_packet(wmaxpacketsize) ((wmaxpacketsize) & 0x07ff) | |
183 | - | |
184 | /* | |
185 | * Returns true if frame1 index is greater than frame2 index. The comparison | |
186 | * is done modulo FRLISTEN_64_SIZE. This accounts for the rollover of the | |
187 | --- a/drivers/usb/dwc2/hcd_intr.c | |
188 | +++ b/drivers/usb/dwc2/hcd_intr.c | |
189 | @@ -1617,8 +1617,9 @@ static void dwc2_hc_ahberr_intr(struct d | |
190 | ||
191 | dev_err(hsotg->dev, " Speed: %s\n", speed); | |
192 | ||
193 | - dev_err(hsotg->dev, " Max packet size: %d\n", | |
194 | - dwc2_hcd_get_mps(&urb->pipe_info)); | |
195 | + dev_err(hsotg->dev, " Max packet size: %d (mult %d)\n", | |
196 | + dwc2_hcd_get_maxp(&urb->pipe_info), | |
197 | + dwc2_hcd_get_maxp_mult(&urb->pipe_info)); | |
198 | dev_err(hsotg->dev, " Data buffer length: %d\n", urb->length); | |
199 | dev_err(hsotg->dev, " Transfer buffer: %p, Transfer DMA: %08lx\n", | |
200 | urb->buf, (unsigned long)urb->dma); | |
201 | --- a/drivers/usb/dwc2/hcd_queue.c | |
202 | +++ b/drivers/usb/dwc2/hcd_queue.c | |
203 | @@ -708,7 +708,7 @@ static void dwc2_hs_pmap_unschedule(stru | |
204 | static int dwc2_uframe_schedule_split(struct dwc2_hsotg *hsotg, | |
205 | struct dwc2_qh *qh) | |
206 | { | |
207 | - int bytecount = dwc2_hb_mult(qh->maxp) * dwc2_max_packet(qh->maxp); | |
208 | + int bytecount = qh->maxp_mult * qh->maxp; | |
209 | int ls_search_slice; | |
210 | int err = 0; | |
211 | int host_interval_in_sched; | |
212 | @@ -1332,7 +1332,7 @@ static int dwc2_check_max_xfer_size(stru | |
213 | u32 max_channel_xfer_size; | |
214 | int status = 0; | |
215 | ||
216 | - max_xfer_size = dwc2_max_packet(qh->maxp) * dwc2_hb_mult(qh->maxp); | |
217 | + max_xfer_size = qh->maxp * qh->maxp_mult; | |
218 | max_channel_xfer_size = hsotg->params.max_transfer_size; | |
219 | ||
220 | if (max_xfer_size > max_channel_xfer_size) { | |
221 | @@ -1517,8 +1517,9 @@ static void dwc2_qh_init(struct dwc2_hso | |
222 | u32 prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT; | |
223 | bool do_split = (prtspd == HPRT0_SPD_HIGH_SPEED && | |
224 | dev_speed != USB_SPEED_HIGH); | |
225 | - int maxp = dwc2_hcd_get_mps(&urb->pipe_info); | |
226 | - int bytecount = dwc2_hb_mult(maxp) * dwc2_max_packet(maxp); | |
227 | + int maxp = dwc2_hcd_get_maxp(&urb->pipe_info); | |
228 | + int maxp_mult = dwc2_hcd_get_maxp_mult(&urb->pipe_info); | |
229 | + int bytecount = maxp_mult * maxp; | |
230 | char *speed, *type; | |
231 | ||
232 | /* Initialize QH */ | |
233 | @@ -1531,6 +1532,7 @@ static void dwc2_qh_init(struct dwc2_hso | |
234 | ||
235 | qh->data_toggle = DWC2_HC_PID_DATA0; | |
236 | qh->maxp = maxp; | |
237 | + qh->maxp_mult = maxp_mult; | |
238 | INIT_LIST_HEAD(&qh->qtd_list); | |
239 | INIT_LIST_HEAD(&qh->qh_list_entry); | |
240 |