1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
10 /**************************************************************************/
11 
12 
13 /**************************************************************************/
14 /**************************************************************************/
15 /**                                                                       */
16 /** USBX Component                                                        */
17 /**                                                                       */
18 /**   EHCI Controller Driver                                              */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 
24 /* Include necessary system files.  */
25 
26 #define UX_SOURCE_CODE
27 
28 #include "ux_api.h"
29 #include "ux_hcd_ehci.h"
30 #include "ux_host_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_hcd_ehci_hsisochronous_tds_process              PORTABLE C      */
38 /*                                                           6.1.12       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function processes the iTDs of an isochronous endpoint.        */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    hcd_ehci                              Pointer to HCD EHCI           */
50 /*    itd                                   Pointer to HSISO TD           */
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    UX_EHCI_HSISO_TD                      Pointer to HSISO TD           */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    (ux_transfer_request_completion_function)                           */
59 /*                                          Transfer Completion function  */
60 /*    _ux_hcd_ehci_register_read            Read EHCI register            */
61 /*    _ux_host_semaphore_put                Put semaphore                 */
62 /*    _ux_utility_physical_address          Get physical address          */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    EHCI Controller Driver                                              */
67 /*                                                                        */
68 /*  RELEASE HISTORY                                                       */
69 /*                                                                        */
70 /*    DATE              NAME                      DESCRIPTION             */
71 /*                                                                        */
72 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
73 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
74 /*                                            resulting in version 6.1    */
75 /*  11-09-2020     Chaoqiong Xiao           Modified comment(s),          */
76 /*                                            fixed compile warnings,     */
77 /*                                            resulting in version 6.1.2  */
78 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
79 /*                                            refined macros names,       */
80 /*                                            resulting in version 6.1.10 */
81 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
82 /*                                            improved uframe handling,   */
83 /*                                            resulting in version 6.1.12 */
84 /*                                                                        */
85 /**************************************************************************/
_ux_hcd_ehci_hsisochronous_tds_process(UX_HCD_EHCI * hcd_ehci,UX_EHCI_HSISO_TD * itd)86 UX_EHCI_HSISO_TD* _ux_hcd_ehci_hsisochronous_tds_process(
87     UX_HCD_EHCI *hcd_ehci,
88     UX_EHCI_HSISO_TD* itd)
89 {
90 
91 UX_EHCI_HSISO_ED                *ed;
92 UX_EHCI_HSISO_TD                *next_scan_td;
93 ULONG                           n_fr;
94 ULONG                           frindex;
95 ULONG                           frindex1;
96 UX_EHCI_HSISO_TD                *fr_td;
97 UX_EHCI_HSISO_TD                *fr_td1;
98 ULONG                           control;
99 ULONG                           control1;
100 ULONG                           trans_bytes;
101 UX_TRANSFER                     *transfer;
102 UX_EHCI_POINTER                 bp;
103 ULONG                           pg;
104 ULONG                           pg_addr;
105 ULONG                           pg_offset;
106 ULONG                           frindex_now;
107 ULONG                           frindex_start;
108 USHORT                          fr_hc;
109 USHORT                          fr_sw;
110 UINT                            i;
111 
112 
113     /* Get ED.  */
114     ed = itd -> ux_ehci_hsiso_td_ed;
115 
116     /* Get next scan TD.  */
117     next_scan_td = itd -> ux_ehci_hsiso_td_next_scan_td;
118 
119     /* Check if iTD is skipped.  */
120     if (ed -> ux_ehci_hsiso_ed_frstart == 0xFF)
121         return(next_scan_td);
122 
123     /*
124     ** 1. There is requests loaded
125     **    (0) Micro-frame is active (request loaded)
126     **    (1) Active is cleared (HC processed)
127     **    (2) Handle it
128     ** 2. There is micro-frame free
129     **    (0) Micro-frame is free
130     **    (1) Micro-frame not overlap current FRINDEX
131     **    (2) Link request
132     **    (3) Build controls to active micro-frame
133     */
134 
135     /* Get number of frames (8,4,2 or 1).  */
136     n_fr = 8u >> ed -> ux_ehci_hsiso_ed_frinterval_shift;
137 
138     /* Process if there is requests loaded.  */
139     if (ed -> ux_ehci_hsiso_ed_frload > 0)
140     {
141 
142         /* Process count to target micro frames.  */
143         fr_hc = (USHORT)(ed -> ux_ehci_hsiso_ed_fr_hc << ed -> ux_ehci_hsiso_ed_frinterval_shift);
144         fr_hc = (USHORT)(fr_hc + ed -> ux_ehci_hsiso_ed_frstart);
145         fr_hc &= 0x7u;
146 
147         /* Process done iTDs.  */
148         for (i = 0;
149             i < n_fr; /* 8, 4, 2 or 1.  */
150             i += ed -> ux_ehci_hsiso_ed_frinterval)
151         {
152 
153             /* Get frindex.  */
154             frindex = fr_hc + i;
155             frindex &= 7u;
156 
157             if ((ed -> ux_ehci_hsiso_ed_frload & (1u << frindex)) == 0)
158             {
159                 break;
160             }
161 
162             /* Get iTD for the micro-frame.  */
163             fr_td = ed -> ux_ehci_hsiso_ed_fr_td[frindex >> 1];
164 
165             /* Get control.  */
166             control = fr_td -> ux_ehci_hsiso_td_control[frindex];
167 
168             /* Check next frame state, if multiple micro-frames loaded.  */
169             if (n_fr > 1)
170             {
171 
172                 /* Micro-frame is active, check next.  */
173                 if (control & UX_EHCI_HSISO_STATUS_ACTIVE)
174                 {
175 
176                     /* Get next frindex.  */
177                     frindex1 = frindex + ed -> ux_ehci_hsiso_ed_frinterval;
178                     frindex1 &= 7u;
179 
180                     /* Get next iTD for the micro-frame.  */
181                     fr_td1 = ed -> ux_ehci_hsiso_ed_fr_td[frindex1 >> 1];
182 
183                     /* Get control.  */
184                     control1 = fr_td1 -> ux_ehci_hsiso_td_control[frindex1];
185 
186                     /* Next micro-frame is also active, break.  */
187                     if (control1 & UX_EHCI_HSISO_STATUS_ACTIVE)
188                     {
189                         break;
190                     }
191                     else
192                     {
193 
194                         /* Next micro-frame is not loaded, break.  */
195                         if ((ed -> ux_ehci_hsiso_ed_frload & (1u << frindex1)) == 0)
196                         {
197                             break;
198                         }
199 
200                         /* We are here when micro-frame 1 handled before micro-frame 0,
201                         ** which means we missed one request.
202                         */
203 
204                         /* Disable control, discard buffer and handle request.  */
205                         control &= ~(UX_EHCI_HSISO_STATUS_ACTIVE |
206                                                 UX_EHCI_HSISO_XACT_LENGTH_MASK);
207                         fr_td -> ux_ehci_hsiso_td_control[frindex] = control;
208                     }
209 
210                 } /* if (control & UX_EHCI_HSISO_STATUS_ACTIVE) */
211             }
212             else
213             {
214 
215                 /* If iTD is active, break.  */
216                 if (control & UX_EHCI_HSISO_STATUS_ACTIVE)
217                 {
218                     break;
219                 }
220             }
221 
222             /* Clear load map anyway.  */
223             fr_td -> ux_ehci_hsiso_td_frload = (UCHAR)(fr_td -> ux_ehci_hsiso_td_frload & ~(1u << frindex));
224             ed -> ux_ehci_hsiso_ed_frload = (USHORT)(ed -> ux_ehci_hsiso_ed_frload & ~(1u << frindex));
225 
226             /* HC processed.  */
227             ed -> ux_ehci_hsiso_ed_fr_hc ++;
228 
229             /* Unlink it from iTD.  */
230             fr_td -> ux_ehci_hsiso_td_fr_transfer[frindex & 1u] = UX_NULL;
231 
232             /* Handle the request.  */
233             transfer = ed -> ux_ehci_hsiso_ed_transfer_head;
234 
235             /* If there is no transfer linked to, just ignore it.  */
236             if (transfer == UX_NULL)
237                 break;
238 
239             /* Convert error code to completion code.  */
240             if (control & UX_EHCI_HSISO_STATUS_DATA_BUFFER_ERR)
241                 transfer -> ux_transfer_request_completion_code = UX_TRANSFER_BUFFER_OVERFLOW;
242             else
243             {
244                 if (control & UX_EHCI_HSISO_STATUS_MASK)
245                     transfer -> ux_transfer_request_completion_code = UX_TRANSFER_ERROR;
246                 else
247                     transfer -> ux_transfer_request_completion_code = UX_SUCCESS;
248             }
249 
250             /* Get transfer bytes.  */
251             trans_bytes = control & UX_EHCI_HSISO_XACT_LENGTH_MASK;
252             trans_bytes >>= UX_EHCI_HSISO_XACT_LENGTH_SHIFT;
253 
254             /* Save to actual length.  */
255             transfer -> ux_transfer_request_actual_length = trans_bytes;
256 
257             /* Unlink it from request list head.  */
258             ed -> ux_ehci_hsiso_ed_transfer_head =
259                     transfer -> ux_transfer_request_next_transfer_request;
260 
261             /* If no more requests, also set tail to NULL.  */
262             if (ed -> ux_ehci_hsiso_ed_transfer_head == UX_NULL)
263                 ed -> ux_ehci_hsiso_ed_transfer_tail = UX_NULL;
264 
265             /* Invoke callback.  */
266             if (transfer -> ux_transfer_request_completion_function)
267                 transfer -> ux_transfer_request_completion_function(transfer);
268 
269             /* Put semaphore.  */
270             _ux_host_semaphore_put(&transfer -> ux_transfer_request_semaphore);
271 
272         } /* for (;i < n_fr;)  */
273     }
274 
275     /* Build request when there is new unloaded requests.  */
276     if (ed -> ux_ehci_hsiso_ed_transfer_first_new)
277     {
278 
279         /* Get current FRINDEX for SW process.  */
280         frindex_now = _ux_hcd_ehci_register_read(hcd_ehci, EHCI_HCOR_FRAME_INDEX);
281         frindex_now &= 0x7u;
282 
283         /* If transfer starts.  */
284         if (ed -> ux_ehci_hsiso_ed_frstart == 0xFE)
285         {
286 
287             /* 1 micro-frame in iTD.  */
288             if (ed -> ux_ehci_hsiso_ed_frinterval_shift >= 3)
289             {
290 
291                 /* Uses this only micro-frame index.  */
292                 ed -> ux_ehci_hsiso_ed_frstart = ed -> ux_ehci_hsiso_ed_frindex;
293             }
294 
295             /* 8,4,2 micro-frames in each iTD.  */
296             else
297             {
298 
299                 /* Get start index for sw to link requests.  */
300                 if (ed -> ux_ehci_hsiso_ed_frinterval_shift == 0)
301 
302                     /* Interval 1, just add two.  */
303                     frindex_start = frindex_now + 2;
304                 else
305                 {
306 
307                     /* Interval 2, 4.  */
308                     /* Scan indexes, to find an index that has 2 in front or more.  */
309                     for (frindex_start = ed -> ux_ehci_hsiso_ed_frindex;
310                         frindex_start < 9;
311                         frindex_start += ed -> ux_ehci_hsiso_ed_frinterval)
312                     {
313                         if (frindex_start - frindex_now >= 2)
314                             break;
315                     }
316                 }
317 
318                 /* Target to start index calculated and wrap around in one frame.  */
319                 ed -> ux_ehci_hsiso_ed_frstart = frindex_start & 7u;
320             }
321         } /* if (ed -> ux_ehci_hsiso_ed_fr_sw == 0xFE) */
322 
323         /* Process count to target micro frames.  */
324         fr_sw = (USHORT)(ed -> ux_ehci_hsiso_ed_fr_sw << ed -> ux_ehci_hsiso_ed_frinterval_shift);
325         fr_sw = (USHORT)(fr_sw + ed -> ux_ehci_hsiso_ed_frstart);
326         fr_sw &= 0x7u;
327 
328         /* Build requests.  */
329         for (i = 0;
330             i < n_fr;
331             i += ed -> ux_ehci_hsiso_ed_frinterval)
332         {
333 
334             /* Get micro-frame index.  */
335             frindex = i + fr_sw;
336             frindex &= 7u;
337 
338             /* Get iTD.  */
339             fr_td = ed -> ux_ehci_hsiso_ed_fr_td[frindex >> 1];
340 
341             /* Check load status.  */
342             if (fr_td -> ux_ehci_hsiso_td_frload & (1u << frindex))
343             {
344                 break;
345             }
346 
347             /* Get a transfer request.  */
348             transfer = ed -> ux_ehci_hsiso_ed_transfer_first_new;
349             if (transfer == UX_NULL)
350             {
351                 break;
352             }
353 
354             /* Get control status.  */
355             control = fr_td -> ux_ehci_hsiso_td_control[frindex];
356 
357             /* If there are multiple micro-frames, check
358             ** (1) If target micro-frame is already loaded
359             ** (2) If the micro-frame overlapped current one
360             */
361             if (n_fr)
362             {
363 
364                 /* If already loaded(active), break.  */
365                 if (control & UX_EHCI_HSISO_STATUS_ACTIVE)
366                 {
367                     break;
368                 }
369 
370                 /* If index overlap, break.  */
371 
372                 /* Check if frindex exceeds same FRINDEX in next frame.  */
373                 if ((frindex == frindex_now) || (i + fr_sw >= frindex_now + 8))
374                 {
375                     break;
376                 }
377             }
378 
379             /* Now new request is linking.  */
380 
381             /* Process count inc.  */
382             ed -> ux_ehci_hsiso_ed_fr_sw ++;
383 
384             /* Sanity check, iTD is not linked.  */
385             while(fr_td -> ux_ehci_hsiso_td_fr_transfer[frindex & 1u] != UX_NULL);
386 
387             /* Link it to iTD.  */
388             fr_td -> ux_ehci_hsiso_td_fr_transfer[frindex & 1u] = transfer;
389 
390             /* Remove it from new free list.  */
391             ed -> ux_ehci_hsiso_ed_transfer_first_new =
392                         transfer -> ux_transfer_request_next_transfer_request;
393 
394             /* Update load map.  */
395             fr_td -> ux_ehci_hsiso_td_frload = (UCHAR)(fr_td -> ux_ehci_hsiso_td_frload | (1u << frindex));
396             ed -> ux_ehci_hsiso_ed_frload = (UCHAR)(ed -> ux_ehci_hsiso_ed_frload | (1u << frindex));
397 
398             /* Get transfer size.  */
399             trans_bytes = transfer -> ux_transfer_request_requested_length;
400 
401             /* Limit max transfer size.  */
402             if (trans_bytes > fr_td -> ux_ehci_hsiso_td_max_trans_size)
403                 trans_bytes = fr_td -> ux_ehci_hsiso_td_max_trans_size;
404 
405             /* Build the control.  */
406 
407             /* Keep IOC and PG.  */
408             control &= UX_EHCI_HSISO_IOC | UX_EHCI_HSISO_PG_MASK;
409 
410             /* New transfer size.  */
411             control |= (trans_bytes << UX_EHCI_HSISO_XACT_LENGTH_SHIFT);
412 
413             /* Active.  */
414             control |= (UX_EHCI_HSISO_STATUS_ACTIVE);
415 
416             /* Build offset & BPs (5,6/3,4).  */
417 
418             /* Get physical buffer address.  */
419             bp.void_ptr = _ux_utility_physical_address(transfer -> ux_transfer_request_data_pointer);
420 
421             /* Get page offset.  */
422             pg_addr = bp.value & UX_EHCI_PAGE_ALIGN;
423             pg_offset = bp.value & UX_EHCI_HSISO_XACT_OFFSET_MASK;
424 
425             /* Offset in control.  */
426             control |= pg_offset;
427 
428             /* Save BPs.  */
429             pg = (frindex & 1u) ? 5 : 3;
430 
431             /* PG in control.  */
432             control |= pg << UX_EHCI_HSISO_PG_SHIFT;
433 
434             /* Save BPs.  */
435 
436             /* First BP.  */
437             bp.value = pg_addr;
438             fr_td -> ux_ehci_hsiso_td_bp[pg] = bp.void_ptr;
439 
440             /* Next page information.  */
441             pg ++;
442             pg_addr += UX_EHCI_PAGE_SIZE;
443 
444             /* Next BP.  */
445             bp.value = pg_addr;
446             fr_td -> ux_ehci_hsiso_td_bp[pg] = bp.void_ptr;
447 
448             /* Save control.  */
449             UX_DATA_MEMORY_BARRIER
450             fr_td -> ux_ehci_hsiso_td_control[frindex] = control;
451 
452         } /* for(i = 0; i < n_fr; )  */
453 
454     } /* if (ed -> ux_ehci_hsiso_ed_transfer_first_new) */
455 
456     /* If there is no transfer, need start again any way.  */
457     if (ed -> ux_ehci_hsiso_ed_frload == 0)
458     {
459         ed -> ux_ehci_hsiso_ed_frstart = 0xFF;
460         ed -> ux_ehci_hsiso_ed_fr_sw = 0;
461         ed -> ux_ehci_hsiso_ed_fr_hc = 0;
462     }
463 
464    /* Return next iTD in scan list.  */
465    return(next_scan_td);
466 }
467