Branch data Line data Source code
1 : : /*==========================================================================
2 : : * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_ddma.c $
3 : : * $Revision: #10 $
4 : : * $Date: 2011/10/20 $
5 : : * $Change: 1869464 $
6 : : *
7 : : * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
8 : : * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
9 : : * otherwise expressly agreed to in writing between Synopsys and you.
10 : : *
11 : : * The Software IS NOT an item of Licensed Software or Licensed Product under
12 : : * any End User Software License Agreement or Agreement for Licensed Product
13 : : * with Synopsys or any supplement thereto. You are permitted to use and
14 : : * redistribute this Software in source and binary forms, with or without
15 : : * modification, provided that redistributions of source code must retain this
16 : : * notice. You may not view, use, disclose, copy or distribute this file or
17 : : * any information contained herein except pursuant to this license grant from
18 : : * Synopsys. If you do not agree with this notice, including the disclaimer
19 : : * below, then you are not authorized to use the Software.
20 : : *
21 : : * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
22 : : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : : * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
25 : : * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 : : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 : : * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 : : * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 : : * DAMAGE.
32 : : * ========================================================================== */
33 : : #ifndef DWC_DEVICE_ONLY
34 : :
35 : : /** @file
36 : : * This file contains Descriptor DMA support implementation for host mode.
37 : : */
38 : :
39 : : #include "dwc_otg_hcd.h"
40 : : #include "dwc_otg_regs.h"
41 : :
42 : : extern bool microframe_schedule;
43 : :
44 : : static inline uint8_t frame_list_idx(uint16_t frame)
45 : : {
46 : 0 : return (frame & (MAX_FRLIST_EN_NUM - 1));
47 : : }
48 : :
49 : : static inline uint16_t desclist_idx_inc(uint16_t idx, uint16_t inc, uint8_t speed)
50 : : {
51 : 0 : return (idx + inc) &
52 : : (((speed ==
53 : : DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
54 : : MAX_DMA_DESC_NUM_GENERIC) - 1);
55 : : }
56 : :
57 : : static inline uint16_t desclist_idx_dec(uint16_t idx, uint16_t inc, uint8_t speed)
58 : : {
59 : 0 : return (idx - inc) &
60 : : (((speed ==
61 : : DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
62 : : MAX_DMA_DESC_NUM_GENERIC) - 1);
63 : : }
64 : :
65 : : static inline uint16_t max_desc_num(dwc_otg_qh_t * qh)
66 : : {
67 : 0 : return (((qh->ep_type == UE_ISOCHRONOUS)
68 : 0 : && (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH))
69 : : ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC);
70 : : }
71 : : static inline uint16_t frame_incr_val(dwc_otg_qh_t * qh)
72 : : {
73 : 0 : return ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH)
74 : 0 : ? ((qh->interval + 8 - 1) / 8)
75 : : : qh->interval);
76 : : }
77 : :
78 : 0 : static int desc_list_alloc(struct device *dev, dwc_otg_qh_t * qh)
79 : : {
80 : : int retval = 0;
81 : :
82 : 0 : qh->desc_list = (dwc_otg_host_dma_desc_t *)
83 : 0 : DWC_DMA_ALLOC(dev, sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh),
84 : : &qh->desc_list_dma);
85 : :
86 : 0 : if (!qh->desc_list) {
87 : : retval = -DWC_E_NO_MEMORY;
88 : 0 : DWC_ERROR("%s: DMA descriptor list allocation failed\n", __func__);
89 : :
90 : : }
91 : :
92 : 0 : dwc_memset(qh->desc_list, 0x00,
93 : : sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
94 : :
95 : 0 : qh->n_bytes =
96 : 0 : (uint32_t *) DWC_ALLOC(sizeof(uint32_t) * max_desc_num(qh));
97 : :
98 : 0 : if (!qh->n_bytes) {
99 : : retval = -DWC_E_NO_MEMORY;
100 : 0 : DWC_ERROR
101 : : ("%s: Failed to allocate array for descriptors' size actual values\n",
102 : : __func__);
103 : :
104 : : }
105 : 0 : return retval;
106 : :
107 : : }
108 : :
109 : 0 : static void desc_list_free(struct device *dev, dwc_otg_qh_t * qh)
110 : : {
111 : 0 : if (qh->desc_list) {
112 : 0 : DWC_DMA_FREE(dev, max_desc_num(qh), qh->desc_list,
113 : : qh->desc_list_dma);
114 : 0 : qh->desc_list = NULL;
115 : : }
116 : :
117 : 0 : if (qh->n_bytes) {
118 : 0 : DWC_FREE(qh->n_bytes);
119 : 0 : qh->n_bytes = NULL;
120 : : }
121 : 0 : }
122 : :
123 : 0 : static int frame_list_alloc(dwc_otg_hcd_t * hcd)
124 : : {
125 : : struct device *dev = dwc_otg_hcd_to_dev(hcd);
126 : : int retval = 0;
127 : :
128 : 0 : if (hcd->frame_list)
129 : : return 0;
130 : :
131 : 0 : hcd->frame_list = DWC_DMA_ALLOC(dev, 4 * MAX_FRLIST_EN_NUM,
132 : : &hcd->frame_list_dma);
133 : 0 : if (!hcd->frame_list) {
134 : : retval = -DWC_E_NO_MEMORY;
135 : 0 : DWC_ERROR("%s: Frame List allocation failed\n", __func__);
136 : : }
137 : :
138 : 0 : dwc_memset(hcd->frame_list, 0x00, 4 * MAX_FRLIST_EN_NUM);
139 : :
140 : 0 : return retval;
141 : : }
142 : :
143 : 0 : static void frame_list_free(dwc_otg_hcd_t * hcd)
144 : : {
145 : : struct device *dev = dwc_otg_hcd_to_dev(hcd);
146 : :
147 : 0 : if (!hcd->frame_list)
148 : 0 : return;
149 : :
150 : 0 : DWC_DMA_FREE(dev, 4 * MAX_FRLIST_EN_NUM, hcd->frame_list, hcd->frame_list_dma);
151 : 0 : hcd->frame_list = NULL;
152 : : }
153 : :
154 : 0 : static void per_sched_enable(dwc_otg_hcd_t * hcd, uint16_t fr_list_en)
155 : : {
156 : :
157 : : hcfg_data_t hcfg;
158 : :
159 : 0 : hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
160 : :
161 : 0 : if (hcfg.b.perschedena) {
162 : : /* already enabled */
163 : 0 : return;
164 : : }
165 : :
166 : 0 : DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hflbaddr,
167 : : hcd->frame_list_dma);
168 : :
169 : 0 : switch (fr_list_en) {
170 : : case 64:
171 : 0 : hcfg.b.frlisten = 3;
172 : 0 : break;
173 : : case 32:
174 : 0 : hcfg.b.frlisten = 2;
175 : 0 : break;
176 : : case 16:
177 : 0 : hcfg.b.frlisten = 1;
178 : 0 : break;
179 : : case 8:
180 : 0 : hcfg.b.frlisten = 0;
181 : 0 : break;
182 : : default:
183 : : break;
184 : : }
185 : :
186 : 0 : hcfg.b.perschedena = 1;
187 : :
188 : : DWC_DEBUGPL(DBG_HCD, "Enabling Periodic schedule\n");
189 : 0 : DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
190 : :
191 : : }
192 : :
193 : 0 : static void per_sched_disable(dwc_otg_hcd_t * hcd)
194 : : {
195 : : hcfg_data_t hcfg;
196 : :
197 : 0 : hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
198 : :
199 : 0 : if (!hcfg.b.perschedena) {
200 : : /* already disabled */
201 : 0 : return;
202 : : }
203 : 0 : hcfg.b.perschedena = 0;
204 : :
205 : : DWC_DEBUGPL(DBG_HCD, "Disabling Periodic schedule\n");
206 : 0 : DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
207 : : }
208 : :
209 : : /*
210 : : * Activates/Deactivates FrameList entries for the channel
211 : : * based on endpoint servicing period.
212 : : */
213 : 0 : void update_frame_list(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t enable)
214 : : {
215 : : uint16_t i, j, inc;
216 : : dwc_hc_t *hc = NULL;
217 : :
218 : 0 : if (!qh->channel) {
219 : 0 : DWC_ERROR("qh->channel = %p", qh->channel);
220 : 0 : return;
221 : : }
222 : :
223 : 0 : if (!hcd) {
224 : 0 : DWC_ERROR("------hcd = %p", hcd);
225 : 0 : return;
226 : : }
227 : :
228 : 0 : if (!hcd->frame_list) {
229 : 0 : DWC_ERROR("-------hcd->frame_list = %p", hcd->frame_list);
230 : 0 : return;
231 : : }
232 : :
233 : : hc = qh->channel;
234 : : inc = frame_incr_val(qh);
235 : 0 : if (qh->ep_type == UE_ISOCHRONOUS)
236 : 0 : i = frame_list_idx(qh->sched_frame);
237 : : else
238 : : i = 0;
239 : :
240 : : j = i;
241 : : do {
242 : 0 : if (enable)
243 : 0 : hcd->frame_list[j] |= (1 << hc->hc_num);
244 : : else
245 : 0 : hcd->frame_list[j] &= ~(1 << hc->hc_num);
246 : 0 : j = (j + inc) & (MAX_FRLIST_EN_NUM - 1);
247 : : }
248 : 0 : while (j != i);
249 : 0 : if (!enable)
250 : : return;
251 : 0 : hc->schinfo = 0;
252 : 0 : if (qh->channel->speed == DWC_OTG_EP_SPEED_HIGH) {
253 : : j = 1;
254 : : /* TODO - check this */
255 : 0 : inc = (8 + qh->interval - 1) / qh->interval;
256 : 0 : for (i = 0; i < inc; i++) {
257 : 0 : hc->schinfo |= j;
258 : 0 : j = j << qh->interval;
259 : : }
260 : : } else {
261 : 0 : hc->schinfo = 0xff;
262 : : }
263 : : }
264 : :
265 : : #if 1
266 : 0 : void dump_frame_list(dwc_otg_hcd_t * hcd)
267 : : {
268 : : int i = 0;
269 : 0 : DWC_PRINTF("--FRAME LIST (hex) --\n");
270 : 0 : for (i = 0; i < MAX_FRLIST_EN_NUM; i++) {
271 : 0 : DWC_PRINTF("%x\t", hcd->frame_list[i]);
272 : 0 : if (!(i % 8) && i)
273 : 0 : DWC_PRINTF("\n");
274 : : }
275 : 0 : DWC_PRINTF("\n----\n");
276 : :
277 : 0 : }
278 : : #endif
279 : :
280 : 0 : static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
281 : : {
282 : 0 : dwc_hc_t *hc = qh->channel;
283 : 0 : if (dwc_qh_is_non_per(qh)) {
284 : 0 : if (!microframe_schedule)
285 : 0 : hcd->non_periodic_channels--;
286 : : else
287 : 0 : hcd->available_host_channels++;
288 : : } else
289 : 0 : update_frame_list(hcd, qh, 0);
290 : :
291 : : /*
292 : : * The condition is added to prevent double cleanup try in case of device
293 : : * disconnect. See channel cleanup in dwc_otg_hcd_disconnect_cb().
294 : : */
295 : 0 : if (hc->qh) {
296 : 0 : dwc_otg_hc_cleanup(hcd->core_if, hc);
297 : 0 : DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
298 : 0 : hc->qh = NULL;
299 : : }
300 : :
301 : 0 : qh->channel = NULL;
302 : 0 : qh->ntd = 0;
303 : :
304 : 0 : if (qh->desc_list) {
305 : 0 : dwc_memset(qh->desc_list, 0x00,
306 : : sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
307 : : }
308 : 0 : }
309 : :
310 : : /**
311 : : * Initializes a QH structure's Descriptor DMA related members.
312 : : * Allocates memory for descriptor list.
313 : : * On first periodic QH, allocates memory for FrameList
314 : : * and enables periodic scheduling.
315 : : *
316 : : * @param hcd The HCD state structure for the DWC OTG controller.
317 : : * @param qh The QH to init.
318 : : *
319 : : * @return 0 if successful, negative error code otherwise.
320 : : */
321 : 0 : int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
322 : : {
323 : : struct device *dev = dwc_otg_hcd_to_dev(hcd);
324 : : int retval = 0;
325 : :
326 : 0 : if (qh->do_split) {
327 : 0 : DWC_ERROR("SPLIT Transfers are not supported in Descriptor DMA.\n");
328 : 0 : return -1;
329 : : }
330 : :
331 : 0 : retval = desc_list_alloc(dev, qh);
332 : :
333 : 0 : if ((retval == 0)
334 : 0 : && (qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)) {
335 : 0 : if (!hcd->frame_list) {
336 : 0 : retval = frame_list_alloc(hcd);
337 : : /* Enable periodic schedule on first periodic QH */
338 : 0 : if (retval == 0)
339 : 0 : per_sched_enable(hcd, MAX_FRLIST_EN_NUM);
340 : : }
341 : : }
342 : :
343 : 0 : qh->ntd = 0;
344 : :
345 : 0 : return retval;
346 : : }
347 : :
348 : : /**
349 : : * Frees descriptor list memory associated with the QH.
350 : : * If QH is periodic and the last, frees FrameList memory
351 : : * and disables periodic scheduling.
352 : : *
353 : : * @param hcd The HCD state structure for the DWC OTG controller.
354 : : * @param qh The QH to init.
355 : : */
356 : 0 : void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
357 : : {
358 : : struct device *dev = dwc_otg_hcd_to_dev(hcd);
359 : :
360 : 0 : desc_list_free(dev, qh);
361 : :
362 : : /*
363 : : * Channel still assigned due to some reasons.
364 : : * Seen on Isoc URB dequeue. Channel halted but no subsequent
365 : : * ChHalted interrupt to release the channel. Afterwards
366 : : * when it comes here from endpoint disable routine
367 : : * channel remains assigned.
368 : : */
369 : 0 : if (qh->channel)
370 : 0 : release_channel_ddma(hcd, qh);
371 : :
372 : 0 : if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)
373 : 0 : && (microframe_schedule || !hcd->periodic_channels) && hcd->frame_list) {
374 : :
375 : 0 : per_sched_disable(hcd);
376 : 0 : frame_list_free(hcd);
377 : : }
378 : 0 : }
379 : :
380 : : static uint8_t frame_to_desc_idx(dwc_otg_qh_t * qh, uint16_t frame_idx)
381 : : {
382 : 0 : if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
383 : : /*
384 : : * Descriptor set(8 descriptors) index
385 : : * which is 8-aligned.
386 : : */
387 : 0 : return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
388 : : } else {
389 : 0 : return (frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1));
390 : : }
391 : : }
392 : :
393 : : /*
394 : : * Determine starting frame for Isochronous transfer.
395 : : * Few frames skipped to prevent race condition with HC.
396 : : */
397 : 0 : static uint8_t calc_starting_frame(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
398 : : uint8_t * skip_frames)
399 : : {
400 : : uint16_t frame = 0;
401 : 0 : hcd->frame_number = dwc_otg_hcd_get_frame_number(hcd);
402 : :
403 : : /* sched_frame is always frame number(not uFrame) both in FS and HS !! */
404 : :
405 : : /*
406 : : * skip_frames is used to limit activated descriptors number
407 : : * to avoid the situation when HC services the last activated
408 : : * descriptor firstly.
409 : : * Example for FS:
410 : : * Current frame is 1, scheduled frame is 3. Since HC always fetches the descriptor
411 : : * corresponding to curr_frame+1, the descriptor corresponding to frame 2
412 : : * will be fetched. If the number of descriptors is max=64 (or greather) the
413 : : * list will be fully programmed with Active descriptors and it is possible
414 : : * case(rare) that the latest descriptor(considering rollback) corresponding
415 : : * to frame 2 will be serviced first. HS case is more probable because, in fact,
416 : : * up to 11 uframes(16 in the code) may be skipped.
417 : : */
418 : 0 : if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
419 : : /*
420 : : * Consider uframe counter also, to start xfer asap.
421 : : * If half of the frame elapsed skip 2 frames otherwise
422 : : * just 1 frame.
423 : : * Starting descriptor index must be 8-aligned, so
424 : : * if the current frame is near to complete the next one
425 : : * is skipped as well.
426 : : */
427 : :
428 : 0 : if (dwc_micro_frame_num(hcd->frame_number) >= 5) {
429 : 0 : *skip_frames = 2 * 8;
430 : 0 : frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
431 : : } else {
432 : 0 : *skip_frames = 1 * 8;
433 : 0 : frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
434 : : }
435 : :
436 : : frame = dwc_full_frame_num(frame);
437 : : } else {
438 : : /*
439 : : * Two frames are skipped for FS - the current and the next.
440 : : * But for descriptor programming, 1 frame(descriptor) is enough,
441 : : * see example above.
442 : : */
443 : 0 : *skip_frames = 1;
444 : 0 : frame = dwc_frame_num_inc(hcd->frame_number, 2);
445 : : }
446 : :
447 : 0 : return frame;
448 : : }
449 : :
450 : : /*
451 : : * Calculate initial descriptor index for isochronous transfer
452 : : * based on scheduled frame.
453 : : */
454 : 0 : static uint8_t recalc_initial_desc_idx(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
455 : : {
456 : : uint16_t frame = 0, fr_idx, fr_idx_tmp;
457 : 0 : uint8_t skip_frames = 0;
458 : : /*
459 : : * With current ISOC processing algorithm the channel is being
460 : : * released when no more QTDs in the list(qh->ntd == 0).
461 : : * Thus this function is called only when qh->ntd == 0 and qh->channel == 0.
462 : : *
463 : : * So qh->channel != NULL branch is not used and just not removed from the
464 : : * source file. It is required for another possible approach which is,
465 : : * do not disable and release the channel when ISOC session completed,
466 : : * just move QH to inactive schedule until new QTD arrives.
467 : : * On new QTD, the QH moved back to 'ready' schedule,
468 : : * starting frame and therefore starting desc_index are recalculated.
469 : : * In this case channel is released only on ep_disable.
470 : : */
471 : :
472 : : /* Calculate starting descriptor index. For INTERRUPT endpoint it is always 0. */
473 : 0 : if (qh->channel) {
474 : 0 : frame = calc_starting_frame(hcd, qh, &skip_frames);
475 : : /*
476 : : * Calculate initial descriptor index based on FrameList current bitmap
477 : : * and servicing period.
478 : : */
479 : 0 : fr_idx_tmp = frame_list_idx(frame);
480 : 0 : fr_idx =
481 : 0 : (MAX_FRLIST_EN_NUM + frame_list_idx(qh->sched_frame) -
482 : : fr_idx_tmp)
483 : 0 : % frame_incr_val(qh);
484 : 0 : fr_idx = (fr_idx + fr_idx_tmp) % MAX_FRLIST_EN_NUM;
485 : : } else {
486 : 0 : qh->sched_frame = calc_starting_frame(hcd, qh, &skip_frames);
487 : 0 : fr_idx = frame_list_idx(qh->sched_frame);
488 : : }
489 : :
490 : 0 : qh->td_first = qh->td_last = frame_to_desc_idx(qh, fr_idx);
491 : :
492 : 0 : return skip_frames;
493 : : }
494 : :
495 : : #define ISOC_URB_GIVEBACK_ASAP
496 : :
497 : : #define MAX_ISOC_XFER_SIZE_FS 1023
498 : : #define MAX_ISOC_XFER_SIZE_HS 3072
499 : : #define DESCNUM_THRESHOLD 4
500 : :
501 : 0 : static void init_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
502 : : uint8_t skip_frames)
503 : : {
504 : : struct dwc_otg_hcd_iso_packet_desc *frame_desc;
505 : : dwc_otg_qtd_t *qtd;
506 : : dwc_otg_host_dma_desc_t *dma_desc;
507 : : uint16_t idx, inc, n_desc, ntd_max, max_xfer_size;
508 : :
509 : 0 : idx = qh->td_last;
510 : 0 : inc = qh->interval;
511 : : n_desc = 0;
512 : :
513 : 0 : ntd_max = (max_desc_num(qh) + qh->interval - 1) / qh->interval;
514 : 0 : if (skip_frames && !qh->channel)
515 : 0 : ntd_max = ntd_max - skip_frames / qh->interval;
516 : :
517 : 0 : max_xfer_size =
518 : 0 : (qh->dev_speed ==
519 : : DWC_OTG_EP_SPEED_HIGH) ? MAX_ISOC_XFER_SIZE_HS :
520 : : MAX_ISOC_XFER_SIZE_FS;
521 : :
522 : 0 : DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
523 : 0 : while ((qh->ntd < ntd_max)
524 : 0 : && (qtd->isoc_frame_index_last <
525 : 0 : qtd->urb->packet_count)) {
526 : :
527 : 0 : dma_desc = &qh->desc_list[idx];
528 : 0 : dwc_memset(dma_desc, 0x00, sizeof(dwc_otg_host_dma_desc_t));
529 : :
530 : 0 : frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
531 : :
532 : 0 : if (frame_desc->length > max_xfer_size)
533 : 0 : qh->n_bytes[idx] = max_xfer_size;
534 : : else
535 : 0 : qh->n_bytes[idx] = frame_desc->length;
536 : 0 : dma_desc->status.b_isoc.n_bytes = qh->n_bytes[idx];
537 : 0 : dma_desc->status.b_isoc.a = 1;
538 : 0 : dma_desc->status.b_isoc.sts = 0;
539 : :
540 : 0 : dma_desc->buf = qtd->urb->dma + frame_desc->offset;
541 : :
542 : 0 : qh->ntd++;
543 : :
544 : 0 : qtd->isoc_frame_index_last++;
545 : :
546 : : #ifdef ISOC_URB_GIVEBACK_ASAP
547 : : /*
548 : : * Set IOC for each descriptor corresponding to the
549 : : * last frame of the URB.
550 : : */
551 : 0 : if (qtd->isoc_frame_index_last ==
552 : 0 : qtd->urb->packet_count)
553 : 0 : dma_desc->status.b_isoc.ioc = 1;
554 : :
555 : : #endif
556 : 0 : idx = desclist_idx_inc(idx, inc, qh->dev_speed);
557 : : n_desc++;
558 : :
559 : : }
560 : 0 : qtd->in_process = 1;
561 : : }
562 : :
563 : 0 : qh->td_last = idx;
564 : :
565 : : #ifdef ISOC_URB_GIVEBACK_ASAP
566 : : /* Set IOC for the last descriptor if descriptor list is full */
567 : 0 : if (qh->ntd == ntd_max) {
568 : 0 : idx = desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
569 : 0 : qh->desc_list[idx].status.b_isoc.ioc = 1;
570 : : }
571 : : #else
572 : : /*
573 : : * Set IOC bit only for one descriptor.
574 : : * Always try to be ahead of HW processing,
575 : : * i.e. on IOC generation driver activates next descriptors but
576 : : * core continues to process descriptors followed the one with IOC set.
577 : : */
578 : :
579 : : if (n_desc > DESCNUM_THRESHOLD) {
580 : : /*
581 : : * Move IOC "up". Required even if there is only one QTD
582 : : * in the list, cause QTDs migth continue to be queued,
583 : : * but during the activation it was only one queued.
584 : : * Actually more than one QTD might be in the list if this function called
585 : : * from XferCompletion - QTDs was queued during HW processing of the previous
586 : : * descriptor chunk.
587 : : */
588 : : idx = dwc_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), qh->dev_speed);
589 : : } else {
590 : : /*
591 : : * Set the IOC for the latest descriptor
592 : : * if either number of descriptor is not greather than threshold
593 : : * or no more new descriptors activated.
594 : : */
595 : : idx = dwc_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
596 : : }
597 : :
598 : : qh->desc_list[idx].status.b_isoc.ioc = 1;
599 : : #endif
600 : 0 : }
601 : :
602 : 0 : static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
603 : : {
604 : :
605 : : dwc_hc_t *hc;
606 : : dwc_otg_host_dma_desc_t *dma_desc;
607 : : dwc_otg_qtd_t *qtd;
608 : : int num_packets, len, n_desc = 0;
609 : :
610 : 0 : hc = qh->channel;
611 : :
612 : : /*
613 : : * Start with hc->xfer_buff initialized in
614 : : * assign_and_init_hc(), then if SG transfer consists of multiple URBs,
615 : : * this pointer re-assigned to the buffer of the currently processed QTD.
616 : : * For non-SG request there is always one QTD active.
617 : : */
618 : :
619 : 0 : DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
620 : :
621 : 0 : if (n_desc) {
622 : : /* SG request - more than 1 QTDs */
623 : 0 : hc->xfer_buff = (uint8_t *)qtd->urb->dma + qtd->urb->actual_length;
624 : 0 : hc->xfer_len = qtd->urb->length - qtd->urb->actual_length;
625 : : }
626 : :
627 : 0 : qtd->n_desc = 0;
628 : :
629 : : do {
630 : 0 : dma_desc = &qh->desc_list[n_desc];
631 : 0 : len = hc->xfer_len;
632 : :
633 : 0 : if (len > MAX_DMA_DESC_SIZE)
634 : 0 : len = MAX_DMA_DESC_SIZE - hc->max_packet + 1;
635 : :
636 : 0 : if (hc->ep_is_in) {
637 : 0 : if (len > 0) {
638 : 0 : num_packets = (len + hc->max_packet - 1) / hc->max_packet;
639 : : } else {
640 : : /* Need 1 packet for transfer length of 0. */
641 : : num_packets = 1;
642 : : }
643 : : /* Always program an integral # of max packets for IN transfers. */
644 : 0 : len = num_packets * hc->max_packet;
645 : : }
646 : :
647 : 0 : dma_desc->status.b.n_bytes = len;
648 : :
649 : 0 : qh->n_bytes[n_desc] = len;
650 : :
651 : 0 : if ((qh->ep_type == UE_CONTROL)
652 : 0 : && (qtd->control_phase == DWC_OTG_CONTROL_SETUP))
653 : 0 : dma_desc->status.b.sup = 1; /* Setup Packet */
654 : :
655 : 0 : dma_desc->status.b.a = 1; /* Active descriptor */
656 : 0 : dma_desc->status.b.sts = 0;
657 : :
658 : 0 : dma_desc->buf =
659 : 0 : ((unsigned long)hc->xfer_buff & 0xffffffff);
660 : :
661 : : /*
662 : : * Last descriptor(or single) of IN transfer
663 : : * with actual size less than MaxPacket.
664 : : */
665 : 0 : if (len > hc->xfer_len) {
666 : 0 : hc->xfer_len = 0;
667 : : } else {
668 : 0 : hc->xfer_buff += len;
669 : 0 : hc->xfer_len -= len;
670 : : }
671 : :
672 : 0 : qtd->n_desc++;
673 : 0 : n_desc++;
674 : : }
675 : 0 : while ((hc->xfer_len > 0) && (n_desc != MAX_DMA_DESC_NUM_GENERIC));
676 : :
677 : :
678 : 0 : qtd->in_process = 1;
679 : :
680 : 0 : if (qh->ep_type == UE_CONTROL)
681 : : break;
682 : :
683 : 0 : if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
684 : : break;
685 : : }
686 : :
687 : 0 : if (n_desc) {
688 : : /* Request Transfer Complete interrupt for the last descriptor */
689 : 0 : qh->desc_list[n_desc - 1].status.b.ioc = 1;
690 : : /* End of List indicator */
691 : 0 : qh->desc_list[n_desc - 1].status.b.eol = 1;
692 : :
693 : 0 : hc->ntd = n_desc;
694 : : }
695 : 0 : }
696 : :
697 : : /**
698 : : * For Control and Bulk endpoints initializes descriptor list
699 : : * and starts the transfer.
700 : : *
701 : : * For Interrupt and Isochronous endpoints initializes descriptor list
702 : : * then updates FrameList, marking appropriate entries as active.
703 : : * In case of Isochronous, the starting descriptor index is calculated based
704 : : * on the scheduled frame, but only on the first transfer descriptor within a session.
705 : : * Then starts the transfer via enabling the channel.
706 : : * For Isochronous endpoint the channel is not halted on XferComplete
707 : : * interrupt so remains assigned to the endpoint(QH) until session is done.
708 : : *
709 : : * @param hcd The HCD state structure for the DWC OTG controller.
710 : : * @param qh The QH to init.
711 : : *
712 : : * @return 0 if successful, negative error code otherwise.
713 : : */
714 : 0 : void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
715 : : {
716 : : /* Channel is already assigned */
717 : 0 : dwc_hc_t *hc = qh->channel;
718 : : uint8_t skip_frames = 0;
719 : :
720 : 0 : switch (hc->ep_type) {
721 : : case DWC_OTG_EP_TYPE_CONTROL:
722 : : case DWC_OTG_EP_TYPE_BULK:
723 : 0 : init_non_isoc_dma_desc(hcd, qh);
724 : :
725 : 0 : dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
726 : 0 : break;
727 : : case DWC_OTG_EP_TYPE_INTR:
728 : 0 : init_non_isoc_dma_desc(hcd, qh);
729 : :
730 : 0 : update_frame_list(hcd, qh, 1);
731 : :
732 : 0 : dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
733 : 0 : break;
734 : : case DWC_OTG_EP_TYPE_ISOC:
735 : :
736 : 0 : if (!qh->ntd)
737 : 0 : skip_frames = recalc_initial_desc_idx(hcd, qh);
738 : :
739 : 0 : init_isoc_dma_desc(hcd, qh, skip_frames);
740 : :
741 : 0 : if (!hc->xfer_started) {
742 : :
743 : 0 : update_frame_list(hcd, qh, 1);
744 : :
745 : : /*
746 : : * Always set to max, instead of actual size.
747 : : * Otherwise ntd will be changed with
748 : : * channel being enabled. Not recommended.
749 : : *
750 : : */
751 : 0 : hc->ntd = max_desc_num(qh);
752 : : /* Enable channel only once for ISOC */
753 : 0 : dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
754 : : }
755 : :
756 : : break;
757 : : default:
758 : :
759 : : break;
760 : : }
761 : 0 : }
762 : :
763 : 0 : static void complete_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
764 : : dwc_hc_t * hc,
765 : : dwc_otg_hc_regs_t * hc_regs,
766 : : dwc_otg_halt_status_e halt_status)
767 : : {
768 : : struct dwc_otg_hcd_iso_packet_desc *frame_desc;
769 : : dwc_otg_qtd_t *qtd, *qtd_tmp;
770 : : dwc_otg_qh_t *qh;
771 : : dwc_otg_host_dma_desc_t *dma_desc;
772 : : uint16_t idx, remain;
773 : : uint8_t urb_compl;
774 : :
775 : 0 : qh = hc->qh;
776 : 0 : idx = qh->td_first;
777 : :
778 : 0 : if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
779 : 0 : DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry)
780 : 0 : qtd->in_process = 0;
781 : : return;
782 : 0 : } else if ((halt_status == DWC_OTG_HC_XFER_AHB_ERR) ||
783 : 0 : (halt_status == DWC_OTG_HC_XFER_BABBLE_ERR)) {
784 : : /*
785 : : * Channel is halted in these error cases.
786 : : * Considered as serious issues.
787 : : * Complete all URBs marking all frames as failed,
788 : : * irrespective whether some of the descriptors(frames) succeeded or no.
789 : : * Pass error code to completion routine as well, to
790 : : * update urb->status, some of class drivers might use it to stop
791 : : * queing transfer requests.
792 : : */
793 : : int err = (halt_status == DWC_OTG_HC_XFER_AHB_ERR)
794 : : ? (-DWC_E_IO)
795 : 0 : : (-DWC_E_OVERFLOW);
796 : :
797 : 0 : DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
798 : 0 : for (idx = 0; idx < qtd->urb->packet_count; idx++) {
799 : 0 : frame_desc = &qtd->urb->iso_descs[idx];
800 : 0 : frame_desc->status = err;
801 : : }
802 : 0 : hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, err);
803 : 0 : dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
804 : : }
805 : : return;
806 : : }
807 : :
808 : 0 : DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
809 : :
810 : 0 : if (!qtd->in_process)
811 : : break;
812 : :
813 : : urb_compl = 0;
814 : :
815 : : do {
816 : :
817 : 0 : dma_desc = &qh->desc_list[idx];
818 : :
819 : 0 : frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
820 : 0 : remain = hc->ep_is_in ? dma_desc->status.b_isoc.n_bytes : 0;
821 : :
822 : 0 : if (dma_desc->status.b_isoc.sts == DMA_DESC_STS_PKTERR) {
823 : : /*
824 : : * XactError or, unable to complete all the transactions
825 : : * in the scheduled micro-frame/frame,
826 : : * both indicated by DMA_DESC_STS_PKTERR.
827 : : */
828 : 0 : qtd->urb->error_count++;
829 : 0 : frame_desc->actual_length = qh->n_bytes[idx] - remain;
830 : 0 : frame_desc->status = -DWC_E_PROTOCOL;
831 : : } else {
832 : : /* Success */
833 : :
834 : 0 : frame_desc->actual_length = qh->n_bytes[idx] - remain;
835 : 0 : frame_desc->status = 0;
836 : : }
837 : :
838 : 0 : if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
839 : : /*
840 : : * urb->status is not used for isoc transfers here.
841 : : * The individual frame_desc status are used instead.
842 : : */
843 : :
844 : 0 : hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
845 : 0 : dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
846 : :
847 : : /*
848 : : * This check is necessary because urb_dequeue can be called
849 : : * from urb complete callback(sound driver example).
850 : : * All pending URBs are dequeued there, so no need for
851 : : * further processing.
852 : : */
853 : 0 : if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
854 : : return;
855 : : }
856 : :
857 : : urb_compl = 1;
858 : :
859 : : }
860 : :
861 : 0 : qh->ntd--;
862 : :
863 : : /* Stop if IOC requested descriptor reached */
864 : 0 : if (dma_desc->status.b_isoc.ioc) {
865 : 0 : idx = desclist_idx_inc(idx, qh->interval, hc->speed);
866 : 0 : goto stop_scan;
867 : : }
868 : :
869 : 0 : idx = desclist_idx_inc(idx, qh->interval, hc->speed);
870 : :
871 : 0 : if (urb_compl)
872 : : break;
873 : : }
874 : 0 : while (idx != qh->td_first);
875 : : }
876 : : stop_scan:
877 : 0 : qh->td_first = idx;
878 : : }
879 : :
880 : 0 : uint8_t update_non_isoc_urb_state_ddma(dwc_otg_hcd_t * hcd,
881 : : dwc_hc_t * hc,
882 : : dwc_otg_qtd_t * qtd,
883 : : dwc_otg_host_dma_desc_t * dma_desc,
884 : : dwc_otg_halt_status_e halt_status,
885 : : uint32_t n_bytes, uint8_t * xfer_done)
886 : : {
887 : :
888 : 0 : uint16_t remain = hc->ep_is_in ? dma_desc->status.b.n_bytes : 0;
889 : 0 : dwc_otg_hcd_urb_t *urb = qtd->urb;
890 : :
891 : 0 : if (halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
892 : 0 : urb->status = -DWC_E_IO;
893 : 0 : return 1;
894 : : }
895 : 0 : if (dma_desc->status.b.sts == DMA_DESC_STS_PKTERR) {
896 : 0 : switch (halt_status) {
897 : : case DWC_OTG_HC_XFER_STALL:
898 : 0 : urb->status = -DWC_E_PIPE;
899 : 0 : break;
900 : : case DWC_OTG_HC_XFER_BABBLE_ERR:
901 : 0 : urb->status = -DWC_E_OVERFLOW;
902 : 0 : break;
903 : : case DWC_OTG_HC_XFER_XACT_ERR:
904 : 0 : urb->status = -DWC_E_PROTOCOL;
905 : 0 : break;
906 : : default:
907 : 0 : DWC_ERROR("%s: Unhandled descriptor error status (%d)\n", __func__,
908 : : halt_status);
909 : 0 : break;
910 : : }
911 : : return 1;
912 : : }
913 : :
914 : 0 : if (dma_desc->status.b.a == 1) {
915 : : DWC_DEBUGPL(DBG_HCDV,
916 : : "Active descriptor encountered on channel %d\n",
917 : : hc->hc_num);
918 : : return 0;
919 : : }
920 : :
921 : 0 : if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) {
922 : 0 : if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
923 : 0 : urb->actual_length += n_bytes - remain;
924 : 0 : if (remain || urb->actual_length == urb->length) {
925 : : /*
926 : : * For Control Data stage do not set urb->status=0 to prevent
927 : : * URB callback. Set it when Status phase done. See below.
928 : : */
929 : 0 : *xfer_done = 1;
930 : : }
931 : :
932 : 0 : } else if (qtd->control_phase == DWC_OTG_CONTROL_STATUS) {
933 : 0 : urb->status = 0;
934 : 0 : *xfer_done = 1;
935 : : }
936 : : /* No handling for SETUP stage */
937 : : } else {
938 : : /* BULK and INTR */
939 : 0 : urb->actual_length += n_bytes - remain;
940 : 0 : if (remain || urb->actual_length == urb->length) {
941 : 0 : urb->status = 0;
942 : 0 : *xfer_done = 1;
943 : : }
944 : : }
945 : :
946 : : return 0;
947 : : }
948 : :
949 : 0 : static void complete_non_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
950 : : dwc_hc_t * hc,
951 : : dwc_otg_hc_regs_t * hc_regs,
952 : : dwc_otg_halt_status_e halt_status)
953 : : {
954 : : dwc_otg_hcd_urb_t *urb = NULL;
955 : : dwc_otg_qtd_t *qtd, *qtd_tmp;
956 : : dwc_otg_qh_t *qh;
957 : : dwc_otg_host_dma_desc_t *dma_desc;
958 : : uint32_t n_bytes, n_desc, i;
959 : : uint8_t failed = 0, xfer_done;
960 : :
961 : : n_desc = 0;
962 : :
963 : 0 : qh = hc->qh;
964 : :
965 : 0 : if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
966 : 0 : DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
967 : 0 : qtd->in_process = 0;
968 : : }
969 : 0 : return;
970 : : }
971 : :
972 : 0 : DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
973 : :
974 : 0 : urb = qtd->urb;
975 : :
976 : : n_bytes = 0;
977 : 0 : xfer_done = 0;
978 : :
979 : 0 : for (i = 0; i < qtd->n_desc; i++) {
980 : 0 : dma_desc = &qh->desc_list[n_desc];
981 : :
982 : 0 : n_bytes = qh->n_bytes[n_desc];
983 : :
984 : 0 : failed =
985 : : update_non_isoc_urb_state_ddma(hcd, hc, qtd,
986 : : dma_desc,
987 : : halt_status, n_bytes,
988 : : &xfer_done);
989 : :
990 : 0 : if (failed
991 : 0 : || (xfer_done
992 : 0 : && (urb->status != -DWC_E_IN_PROGRESS))) {
993 : :
994 : 0 : hcd->fops->complete(hcd, urb->priv, urb,
995 : 0 : urb->status);
996 : 0 : dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
997 : :
998 : 0 : if (failed)
999 : : goto stop_scan;
1000 : 0 : } else if (qh->ep_type == UE_CONTROL) {
1001 : 0 : if (qtd->control_phase == DWC_OTG_CONTROL_SETUP) {
1002 : 0 : if (urb->length > 0) {
1003 : 0 : qtd->control_phase = DWC_OTG_CONTROL_DATA;
1004 : : } else {
1005 : 0 : qtd->control_phase = DWC_OTG_CONTROL_STATUS;
1006 : : }
1007 : : DWC_DEBUGPL(DBG_HCDV, " Control setup transaction done\n");
1008 : 0 : } else if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
1009 : 0 : if (xfer_done) {
1010 : 0 : qtd->control_phase = DWC_OTG_CONTROL_STATUS;
1011 : : DWC_DEBUGPL(DBG_HCDV, " Control data transfer done\n");
1012 : 0 : } else if (i + 1 == qtd->n_desc) {
1013 : : /*
1014 : : * Last descriptor for Control data stage which is
1015 : : * not completed yet.
1016 : : */
1017 : 0 : dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
1018 : : }
1019 : : }
1020 : : }
1021 : :
1022 : 0 : n_desc++;
1023 : : }
1024 : :
1025 : : }
1026 : :
1027 : : stop_scan:
1028 : :
1029 : 0 : if (qh->ep_type != UE_CONTROL) {
1030 : : /*
1031 : : * Resetting the data toggle for bulk
1032 : : * and interrupt endpoints in case of stall. See handle_hc_stall_intr()
1033 : : */
1034 : 0 : if (halt_status == DWC_OTG_HC_XFER_STALL)
1035 : 0 : qh->data_toggle = DWC_OTG_HC_PID_DATA0;
1036 : : else
1037 : 0 : dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
1038 : : }
1039 : :
1040 : 0 : if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
1041 : : hcint_data_t hcint;
1042 : 0 : hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
1043 : 0 : if (hcint.b.nyet) {
1044 : : /*
1045 : : * Got a NYET on the last transaction of the transfer. It
1046 : : * means that the endpoint should be in the PING state at the
1047 : : * beginning of the next transfer.
1048 : : */
1049 : 0 : qh->ping_state = 1;
1050 : 0 : clear_hc_int(hc_regs, nyet);
1051 : : }
1052 : :
1053 : : }
1054 : :
1055 : : }
1056 : :
1057 : : /**
1058 : : * This function is called from interrupt handlers.
1059 : : * Scans the descriptor list, updates URB's status and
1060 : : * calls completion routine for the URB if it's done.
1061 : : * Releases the channel to be used by other transfers.
1062 : : * In case of Isochronous endpoint the channel is not halted until
1063 : : * the end of the session, i.e. QTD list is empty.
1064 : : * If periodic channel released the FrameList is updated accordingly.
1065 : : *
1066 : : * Calls transaction selection routines to activate pending transfers.
1067 : : *
1068 : : * @param hcd The HCD state structure for the DWC OTG controller.
1069 : : * @param hc Host channel, the transfer is completed on.
1070 : : * @param hc_regs Host channel registers.
1071 : : * @param halt_status Reason the channel is being halted,
1072 : : * or just XferComplete for isochronous transfer
1073 : : */
1074 : 0 : void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
1075 : : dwc_hc_t * hc,
1076 : : dwc_otg_hc_regs_t * hc_regs,
1077 : : dwc_otg_halt_status_e halt_status)
1078 : : {
1079 : : uint8_t continue_isoc_xfer = 0;
1080 : : dwc_otg_transaction_type_e tr_type;
1081 : 0 : dwc_otg_qh_t *qh = hc->qh;
1082 : :
1083 : 0 : if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
1084 : :
1085 : 0 : complete_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
1086 : :
1087 : : /* Release the channel if halted or session completed */
1088 : 0 : if (halt_status != DWC_OTG_HC_XFER_COMPLETE ||
1089 : 0 : DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
1090 : :
1091 : : /* Halt the channel if session completed */
1092 : 0 : if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
1093 : 0 : dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
1094 : : }
1095 : :
1096 : 0 : release_channel_ddma(hcd, qh);
1097 : 0 : dwc_otg_hcd_qh_remove(hcd, qh);
1098 : : } else {
1099 : : /* Keep in assigned schedule to continue transfer */
1100 : 0 : DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
1101 : : &qh->qh_list_entry);
1102 : : continue_isoc_xfer = 1;
1103 : :
1104 : : }
1105 : : /** @todo Consider the case when period exceeds FrameList size.
1106 : : * Frame Rollover interrupt should be used.
1107 : : */
1108 : : } else {
1109 : : /* Scan descriptor list to complete the URB(s), then release the channel */
1110 : 0 : complete_non_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
1111 : :
1112 : 0 : release_channel_ddma(hcd, qh);
1113 : 0 : dwc_otg_hcd_qh_remove(hcd, qh);
1114 : :
1115 : 0 : if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
1116 : : /* Add back to inactive non-periodic schedule on normal completion */
1117 : 0 : dwc_otg_hcd_qh_add(hcd, qh);
1118 : : }
1119 : :
1120 : : }
1121 : 0 : tr_type = dwc_otg_hcd_select_transactions(hcd);
1122 : 0 : if (tr_type != DWC_OTG_TRANSACTION_NONE || continue_isoc_xfer) {
1123 : 0 : if (continue_isoc_xfer) {
1124 : 0 : if (tr_type == DWC_OTG_TRANSACTION_NONE) {
1125 : : tr_type = DWC_OTG_TRANSACTION_PERIODIC;
1126 : 0 : } else if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC) {
1127 : : tr_type = DWC_OTG_TRANSACTION_ALL;
1128 : : }
1129 : : }
1130 : 0 : dwc_otg_hcd_queue_transactions(hcd, tr_type);
1131 : : }
1132 : 0 : }
1133 : :
1134 : : #endif /* DWC_DEVICE_ONLY */
|