1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <assert.h>
6 #include <ddk/debug.h>
7 #include <zircon/assert.h>
8 
9 #include <usb/usb-request.h>
10 #include <fbl/auto_lock.h>
11 
12 #include "dwc3.h"
13 #include "dwc3-regs.h"
14 #include "dwc3-types.h"
15 
16 #include <stdio.h>
17 #include <string.h>
18 
19 #define EP_FIFO_SIZE    PAGE_SIZE
20 
dwc3_ep_trb_phys(dwc3_endpoint_t * ep,dwc3_trb_t * trb)21 static zx_paddr_t dwc3_ep_trb_phys(dwc3_endpoint_t* ep, dwc3_trb_t* trb) {
22     return io_buffer_phys(&ep->fifo.buffer) + (trb - ep->fifo.first) * sizeof(*trb);
23 }
24 
dwc3_enable_ep(dwc3_t * dwc,unsigned ep_num,bool enable)25 static void dwc3_enable_ep(dwc3_t* dwc, unsigned ep_num, bool enable) {
26     auto* mmio = dwc3_mmio(dwc);
27 
28     fbl::AutoLock lock(&dwc->lock);
29 
30     if (enable) {
31         DALEPENA::Get().ReadFrom(mmio).EnableEp(ep_num).WriteTo(mmio);
32     } else {
33         DALEPENA::Get().ReadFrom(mmio).DisableEp(ep_num).WriteTo(mmio);
34     }
35 }
36 
dwc3_ep_fifo_init(dwc3_t * dwc,unsigned ep_num)37 zx_status_t dwc3_ep_fifo_init(dwc3_t* dwc, unsigned ep_num) {
38     ZX_DEBUG_ASSERT(ep_num < countof(dwc->eps));
39     dwc3_endpoint_t* ep = &dwc->eps[ep_num];
40     dwc3_fifo_t* fifo = &ep->fifo;
41 
42     static_assert(EP_FIFO_SIZE <= PAGE_SIZE, "");
43     zx_status_t status = io_buffer_init(&fifo->buffer, dwc->bti_handle.get(), EP_FIFO_SIZE,
44                                         IO_BUFFER_RW | IO_BUFFER_CONTIG);
45     if (status != ZX_OK) {
46         return status;
47     }
48 
49     fifo->first = static_cast<dwc3_trb_t*>(io_buffer_virt(&fifo->buffer));
50     fifo->next = fifo->first;
51     fifo->current = nullptr;
52     fifo->last = fifo->first + (EP_FIFO_SIZE / sizeof(dwc3_trb_t)) - 1;
53 
54     // set up link TRB pointing back to the start of the fifo
55     dwc3_trb_t* trb = fifo->last;
56     zx_paddr_t trb_phys = io_buffer_phys(&fifo->buffer);
57     trb->ptr_low = (uint32_t)trb_phys;
58     trb->ptr_high = (uint32_t)(trb_phys >> 32);
59     trb->status = 0;
60     trb->control = TRB_TRBCTL_LINK | TRB_HWO;
61     io_buffer_cache_flush(&ep->fifo.buffer, (trb - ep->fifo.first) * sizeof(*trb), sizeof(*trb));
62 
63     return ZX_OK;
64 }
65 
dwc3_ep_fifo_release(dwc3_t * dwc,unsigned ep_num)66 void dwc3_ep_fifo_release(dwc3_t* dwc, unsigned ep_num) {
67     ZX_DEBUG_ASSERT(ep_num < countof(dwc->eps));
68     dwc3_endpoint_t* ep = &dwc->eps[ep_num];
69 
70     io_buffer_release(&ep->fifo.buffer);
71 }
72 
dwc3_ep_start_transfer(dwc3_t * dwc,unsigned ep_num,unsigned type,zx_paddr_t buffer,size_t length,bool send_zlp)73 void dwc3_ep_start_transfer(dwc3_t* dwc, unsigned ep_num, unsigned type, zx_paddr_t buffer,
74                             size_t length, bool send_zlp) {
75     zxlogf(LTRACE, "dwc3_ep_start_transfer ep %u type %u length %zu\n", ep_num, type, length);
76 
77     // special case: EP0_OUT and EP0_IN use the same fifo
78     dwc3_endpoint_t* ep = (ep_num == EP0_IN ? &dwc->eps[EP0_OUT] : &dwc->eps[ep_num]);
79 
80     dwc3_trb_t* trb = ep->fifo.next++;
81     if (ep->fifo.next == ep->fifo.last) {
82         ep->fifo.next = ep->fifo.first;
83     }
84     if (ep->fifo.current == nullptr) {
85         ep->fifo.current = trb;
86     }
87 
88     trb->ptr_low = (uint32_t)buffer;
89     trb->ptr_high = (uint32_t)(buffer >> 32);
90     trb->status = TRB_BUFSIZ(static_cast<uint32_t>(length));
91     if (send_zlp) {
92         trb->control = type | TRB_HWO;
93     } else {
94         trb->control = type | TRB_LST | TRB_IOC | TRB_HWO;
95     }
96     io_buffer_cache_flush(&ep->fifo.buffer, (trb - ep->fifo.first) * sizeof(*trb), sizeof(*trb));
97 
98     if (send_zlp) {
99         dwc3_trb_t* zlp_trb = ep->fifo.next++;
100         if (ep->fifo.next == ep->fifo.last) {
101             ep->fifo.next = ep->fifo.first;
102         }
103         zlp_trb->ptr_low = 0;
104         zlp_trb->ptr_high = 0;
105         zlp_trb->status = TRB_BUFSIZ(0);
106         zlp_trb->control = type | TRB_LST | TRB_IOC | TRB_HWO;
107         io_buffer_cache_flush(&ep->fifo.buffer, (zlp_trb - ep->fifo.first) * sizeof(*trb),
108                               sizeof(*trb));
109     }
110 
111     dwc3_cmd_ep_start_transfer(dwc, ep_num, dwc3_ep_trb_phys(ep, trb));
112 }
113 
dwc3_ep_queue_next_locked(dwc3_t * dwc,dwc3_endpoint_t * ep)114 static void dwc3_ep_queue_next_locked(dwc3_t* dwc, dwc3_endpoint_t* ep) {
115     dwc_usb_req_internal_t* req_int;
116 
117     if (ep->current_req == nullptr && ep->got_not_ready &&
118         (req_int = list_remove_head_type(&ep->queued_reqs, dwc_usb_req_internal_t, node))
119             != nullptr) {
120         usb_request_t* req = INTERNAL_TO_USB_REQ(req_int);
121         ep->current_req = req;
122         ep->got_not_ready = false;
123         if (EP_IN(ep->ep_num)) {
124             usb_request_cache_flush(req, 0, req->header.length);
125         } else {
126             usb_request_cache_flush_invalidate(req, 0, req->header.length);
127         }
128 
129         // TODO(voydanoff) scatter/gather support
130         phys_iter_t iter;
131         zx_paddr_t phys;
132         usb_request_physmap(req, dwc->bti_handle.get());
133         usb_request_phys_iter_init(&iter, req, PAGE_SIZE);
134         usb_request_phys_iter_next(&iter, &phys);
135         bool send_zlp = req->header.send_zlp && (req->header.length % ep->max_packet_size) == 0;
136         dwc3_ep_start_transfer(dwc, ep->ep_num, TRB_TRBCTL_NORMAL, phys, req->header.length,
137                                send_zlp);
138     }
139 }
140 
dwc3_ep_config(dwc3_t * dwc,const usb_endpoint_descriptor_t * ep_desc,const usb_ss_ep_comp_descriptor_t * ss_comp_desc)141 zx_status_t dwc3_ep_config(dwc3_t* dwc, const usb_endpoint_descriptor_t* ep_desc,
142                            const usb_ss_ep_comp_descriptor_t* ss_comp_desc) {
143     // convert address to index in range 0 - 31
144     // low bit is IN/OUT
145     unsigned ep_num = dwc3_ep_num(ep_desc->bEndpointAddress);
146     if (ep_num < 2) {
147         // index 0 and 1 are for endpoint zero
148         return ZX_ERR_INVALID_ARGS;
149     }
150 
151     uint8_t ep_type = usb_ep_type(ep_desc);
152     if (ep_type == USB_ENDPOINT_ISOCHRONOUS) {
153         zxlogf(ERROR, "dwc3_ep_config: isochronous endpoints are not supported\n");
154         return ZX_ERR_NOT_SUPPORTED;
155     }
156 
157     dwc3_endpoint_t* ep = &dwc->eps[ep_num];
158 
159     fbl::AutoLock lock(&ep->lock);
160 
161     zx_status_t status = dwc3_ep_fifo_init(dwc, ep_num);
162     if (status != ZX_OK) {
163         zxlogf(ERROR, "dwc3_config_ep: dwc3_ep_fifo_init failed %d\n", status);
164         return status;
165     }
166     ep->max_packet_size = usb_ep_max_packet(ep_desc);
167     ep->type = ep_type;
168     ep->interval = ep_desc->bInterval;
169     // TODO(voydanoff) USB3 support
170 
171     ep->enabled = true;
172 
173     if (dwc->configured) {
174         dwc3_ep_queue_next_locked(dwc, ep);
175     }
176 
177     return ZX_OK;
178 }
179 
dwc3_ep_disable(dwc3_t * dwc,uint8_t ep_addr)180 zx_status_t dwc3_ep_disable(dwc3_t* dwc, uint8_t ep_addr) {
181     // convert address to index in range 0 - 31
182     // low bit is IN/OUT
183     unsigned ep_num = dwc3_ep_num(ep_addr);
184     if (ep_num < 2) {
185         // index 0 and 1 are for endpoint zero
186         return ZX_ERR_INVALID_ARGS;
187     }
188 
189     dwc3_endpoint_t* ep = &dwc->eps[ep_num];
190 
191     fbl::AutoLock lock(&ep->lock);
192 
193     dwc3_ep_fifo_release(dwc, ep_num);
194     ep->enabled = false;
195 
196     return ZX_OK;
197 }
198 
dwc3_ep_queue(dwc3_t * dwc,unsigned ep_num,usb_request_t * req)199 void dwc3_ep_queue(dwc3_t* dwc, unsigned ep_num, usb_request_t* req) {
200     dwc3_endpoint_t* ep = &dwc->eps[ep_num];
201     auto* req_int = USB_REQ_TO_INTERNAL(req);
202 
203     // OUT transactions must have length > 0 and multiple of max packet size
204     if (EP_OUT(ep_num)) {
205         if (req->header.length == 0 || req->header.length % ep->max_packet_size != 0) {
206             zxlogf(ERROR, "dwc3_ep_queue: OUT transfers must be multiple of max packet size\n");
207             usb_request_complete(req, ZX_ERR_INVALID_ARGS, 0, &req_int->complete_cb);
208             return;
209         }
210     }
211 
212     fbl::AutoLock lock(&ep->lock);
213 
214     if (!ep->enabled) {
215         usb_request_complete(req, ZX_ERR_BAD_STATE, 0, &req_int->complete_cb);
216         return;
217     }
218 
219     list_add_tail(&ep->queued_reqs, &req_int->node);
220 
221     if (dwc->configured) {
222         dwc3_ep_queue_next_locked(dwc, ep);
223     }
224 }
225 
dwc3_ep_set_config(dwc3_t * dwc,unsigned ep_num,bool enable)226 void dwc3_ep_set_config(dwc3_t* dwc, unsigned ep_num, bool enable) {
227     zxlogf(TRACE, "dwc3_ep_set_config %u\n", ep_num);
228 
229     dwc3_endpoint_t* ep = &dwc->eps[ep_num];
230 
231     if (enable) {
232         dwc3_cmd_ep_set_config(dwc, ep_num, ep->type, ep->max_packet_size, ep->interval, false);
233         dwc3_cmd_ep_transfer_config(dwc, ep_num);
234         dwc3_enable_ep(dwc, ep_num, true);
235     } else {
236         dwc3_enable_ep(dwc, ep_num, false);
237     }
238 }
239 
dwc3_start_eps(dwc3_t * dwc)240 void dwc3_start_eps(dwc3_t* dwc) {
241     zxlogf(TRACE, "dwc3_start_eps\n");
242 
243     dwc3_cmd_ep_set_config(dwc, EP0_IN, USB_ENDPOINT_CONTROL, dwc->eps[EP0_IN].max_packet_size, 0,
244                            true);
245     dwc3_cmd_start_new_config(dwc, EP0_OUT, 2);
246 
247     for (unsigned ep_num = 2; ep_num < countof(dwc->eps); ep_num++) {
248         dwc3_endpoint_t* ep = &dwc->eps[ep_num];
249         if (ep->enabled) {
250             dwc3_ep_set_config(dwc, ep_num, true);
251 
252             fbl::AutoLock lock(&ep->lock);
253             dwc3_ep_queue_next_locked(dwc, ep);
254         }
255     }
256 }
257 
dwc_ep_read_trb(dwc3_endpoint_t * ep,dwc3_trb_t * trb,dwc3_trb_t * out_trb)258 void dwc_ep_read_trb(dwc3_endpoint_t* ep, dwc3_trb_t* trb, dwc3_trb_t* out_trb) {
259     if (trb >= ep->fifo.first && trb < ep->fifo.last) {
260         io_buffer_cache_flush_invalidate(&ep->fifo.buffer, (trb - ep->fifo.first) * sizeof(*trb),
261                                          sizeof(*trb));
262         memcpy((void *)out_trb, (void *)trb, sizeof(*trb));
263     } else {
264         zxlogf(ERROR, "dwc_ep_read_trb: bad trb\n");
265     }
266 }
267 
dwc3_ep_xfer_started(dwc3_t * dwc,unsigned ep_num,unsigned rsrc_id)268 void dwc3_ep_xfer_started(dwc3_t* dwc, unsigned ep_num, unsigned rsrc_id) {
269     dwc3_endpoint_t* ep = &dwc->eps[ep_num];
270     fbl::AutoLock lock(&ep->lock);
271 
272     ep->rsrc_id = rsrc_id;
273 }
274 
dwc3_ep_xfer_not_ready(dwc3_t * dwc,unsigned ep_num,unsigned stage)275 void dwc3_ep_xfer_not_ready(dwc3_t* dwc, unsigned ep_num, unsigned stage) {
276     zxlogf(LTRACE, "dwc3_ep_xfer_not_ready ep %u state %d\n", ep_num, dwc->ep0_state);
277 
278     if (ep_num == EP0_OUT || ep_num == EP0_IN) {
279         dwc3_ep0_xfer_not_ready(dwc, ep_num, stage);
280     } else {
281         dwc3_endpoint_t* ep = &dwc->eps[ep_num];
282 
283         fbl::AutoLock lock(&ep->lock);
284         ep->got_not_ready = true;
285         dwc3_ep_queue_next_locked(dwc, ep);
286     }
287 }
288 
dwc3_ep_xfer_complete(dwc3_t * dwc,unsigned ep_num)289 void dwc3_ep_xfer_complete(dwc3_t* dwc, unsigned ep_num) {
290     zxlogf(LTRACE, "dwc3_ep_xfer_complete ep %u state %d\n", ep_num, dwc->ep0_state);
291 
292     if (ep_num >= countof(dwc->eps)) {
293         zxlogf(ERROR, "dwc3_ep_xfer_complete: bad ep_num %u\n", ep_num);
294         return;
295     }
296 
297     if (ep_num == EP0_OUT || ep_num == EP0_IN) {
298         dwc3_ep0_xfer_complete(dwc, ep_num);
299     } else {
300         dwc3_endpoint_t* ep = &dwc->eps[ep_num];
301 
302         ep->lock.Acquire();
303         usb_request_t* req = ep->current_req;
304         ep->current_req = nullptr;
305 
306         if (req) {
307             dwc3_trb_t  trb;
308             dwc_ep_read_trb(ep, ep->fifo.current, &trb);
309             ep->fifo.current = nullptr;
310             if (trb.control & TRB_HWO) {
311                 zxlogf(ERROR, "TRB_HWO still set in dwc3_ep_xfer_complete\n");
312             }
313 
314             zx_off_t actual = req->header.length - TRB_BUFSIZ(trb.status);
315 //            dwc3_ep_queue_next_locked(dwc, ep);
316 
317             ep->lock.Release();
318 
319             auto* req_int = USB_REQ_TO_INTERNAL(req);
320             usb_request_complete(req, ZX_OK, actual, &req_int->complete_cb);
321         } else {
322             ep->lock.Release();
323             zxlogf(ERROR, "dwc3_ep_xfer_complete: no usb request found to complete!\n");
324         }
325     }
326 }
327 
dwc3_ep_set_stall(dwc3_t * dwc,unsigned ep_num,bool stall)328 zx_status_t dwc3_ep_set_stall(dwc3_t* dwc, unsigned ep_num, bool stall) {
329     if (ep_num >= countof(dwc->eps)) {
330         return ZX_ERR_INVALID_ARGS;
331     }
332 
333     dwc3_endpoint_t* ep = &dwc->eps[ep_num];
334     fbl::AutoLock lock(&ep->lock);
335 
336     if (!ep->enabled) {
337         return ZX_ERR_BAD_STATE;
338     }
339     if (stall && !ep->stalled) {
340         dwc3_cmd_ep_set_stall(dwc, ep_num);
341     } else if (!stall && ep->stalled) {
342         dwc3_cmd_ep_clear_stall(dwc, ep_num);
343     }
344     ep->stalled = stall;
345 
346     return ZX_OK;
347 }
348 
dwc3_ep_end_transfers(dwc3_t * dwc,unsigned ep_num,zx_status_t reason)349 void dwc3_ep_end_transfers(dwc3_t* dwc, unsigned ep_num, zx_status_t reason) {
350     dwc3_endpoint_t* ep = &dwc->eps[ep_num];
351     fbl::AutoLock lock(&ep->lock);
352 
353     if (ep->current_req) {
354         dwc3_cmd_ep_end_transfer(dwc, ep_num);
355         auto* req_int = USB_REQ_TO_INTERNAL(ep->current_req);
356         usb_request_complete(ep->current_req, reason, 0, &req_int->complete_cb);
357         ep->current_req = nullptr;
358     }
359 
360     dwc_usb_req_internal_t* req_int;
361     while ((req_int = list_remove_head_type(&ep->queued_reqs, dwc_usb_req_internal_t, node))
362                 != nullptr) {
363         usb_request_t* req = INTERNAL_TO_USB_REQ(req_int);
364         usb_request_complete(req, reason, 0, &req_int->complete_cb);
365     }
366 }
367