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_interrupt_endpoint_create              PORTABLE C      */
38 /*                                                           6.1.11       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function will create an interrupt endpoint. The interrupt      */
46 /*    endpoint has an interval of operation from 1 to 255. In EHCI, the   */
47 /*    hardware assisted interrupt is from 1 to 32.                        */
48 /*                                                                        */
49 /*    This routine will match the best interval for the EHCI hardware.    */
50 /*    It will also determine the best node to hook the endpoint based on  */
51 /*    the load that already exists on the horizontal ED chain.            */
52 /*                                                                        */
53 /*    For the ones curious about this coding. The tricky part is to       */
54 /*    understand how the interrupt matrix is constructed. We have used    */
55 /*    eds with the skip bit on to build a frame of anchor eds. Each ED    */
56 /*    creates a node for an appropriate combination of interval frequency */
57 /*    in the list.                                                        */
58 /*                                                                        */
59 /*    After obtaining a pointer to the list with the lowest traffic, we   */
60 /*    traverse the list from the highest interval until we reach the      */
61 /*    interval required. At that node, we anchor our real ED to the node  */
62 /*    and link the ED that was attached to the node to our ED.            */
63 /*                                                                        */
64 /*  INPUT                                                                 */
65 /*                                                                        */
66 /*    hcd_ehci                              Pointer to EHCI controller    */
67 /*    endpoint                              Pointer to endpoint           */
68 /*                                                                        */
69 /*  OUTPUT                                                                */
70 /*                                                                        */
71 /*    Completion Status                                                   */
72 /*                                                                        */
73 /*  CALLS                                                                 */
74 /*                                                                        */
75 /*    _ux_hcd_ehci_ed_obtain                Obtain an ED                  */
76 /*    _ux_hcd_ehci_least_traffic_list_get   Get least traffic list        */
77 /*    _ux_hcd_ehci_poll_rate_entry_get      Get anchor for poll rate      */
78 /*    _ux_utility_physical_address          Get physical address          */
79 /*    _ux_host_mutex_on                     Get mutex                     */
80 /*    _ux_host_mutex_off                    Put mutex                     */
81 /*    _ux_hcd_ehci_periodic_descriptor_link Link/unlink descriptor        */
82 /*                                                                        */
83 /*  CALLED BY                                                             */
84 /*                                                                        */
85 /*    EHCI Controller Driver                                              */
86 /*                                                                        */
87 /*  RELEASE HISTORY                                                       */
88 /*                                                                        */
89 /*    DATE              NAME                      DESCRIPTION             */
90 /*                                                                        */
91 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
92 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
93 /*                                            optimized based on compile  */
94 /*                                            definitions,                */
95 /*                                            resulting in version 6.1    */
96 /*  11-09-2020     Chaoqiong Xiao           Modified comment(s),          */
97 /*                                            fixed compile warnings,     */
98 /*                                            resulting in version 6.1.2  */
99 /*  04-02-2021     Chaoqiong Xiao           Modified comment(s),          */
100 /*                                            fixed compile issues with   */
101 /*                                            some macro options,         */
102 /*                                            filled max transfer length, */
103 /*                                            resulting in version 6.1.6  */
104 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
105 /*                                            fixed standalone compile,   */
106 /*                                            resulting in version 6.1.11 */
107 /*                                                                        */
108 /**************************************************************************/
_ux_hcd_ehci_interrupt_endpoint_create(UX_HCD_EHCI * hcd_ehci,UX_ENDPOINT * endpoint)109 UINT  _ux_hcd_ehci_interrupt_endpoint_create(UX_HCD_EHCI *hcd_ehci, UX_ENDPOINT *endpoint)
110 {
111 
112 UX_DEVICE                       *device;
113 UX_EHCI_ED                      *ed;
114 UX_EHCI_ED                      *ed_list;
115 UX_EHCI_ED                      *ed_anchor;
116 UINT                            interval;
117 UINT                            poll_depth;
118 ULONG                           max_packet_size;
119 ULONG                           num_transaction;
120 ULONG                           microframe_load[8];
121 #if defined(UX_HCD_EHCI_SPLIT_TRANSFER_ENABLE)
122 ULONG                           microframe_ssplit_count[8];
123 UINT                            csplit_count;
124 ULONG                           cmask;
125 #else
126 #define                         microframe_ssplit_count     UX_NULL
127 #endif
128 UX_EHCI_PERIODIC_LINK_POINTER   lp;
129 UINT                            i;
130 
131 
132     /* Get the pointer to the device.  */
133     device =  endpoint -> ux_endpoint_device;
134 
135 #if !defined(UX_HCD_EHCI_SPLIT_TRANSFER_ENABLE)
136 
137     /* Only high speed transfer supported without split transfer.  */
138     if (device -> ux_device_speed != UX_HIGH_SPEED_DEVICE)
139         return(UX_FUNCTION_NOT_SUPPORTED);
140 #endif
141 
142     /* We need to take into account the nature of the HCD to define the max size
143        of any transfer in the transfer request.  */
144     endpoint -> ux_endpoint_transfer_request.ux_transfer_request_maximum_length =  UX_EHCI_MAX_PAYLOAD;
145 
146     /* Obtain a ED for this new endpoint. This ED will live as long as the endpoint is
147        active and will be the container for the tds.  */
148     ed =  _ux_hcd_ehci_ed_obtain(hcd_ehci);
149     if (ed == UX_NULL)
150         return(UX_NO_ED_AVAILABLE);
151 
152     /* Attach the ED to the endpoint container.  */
153     endpoint -> ux_endpoint_ed =  (VOID *) ed;
154 
155     /* Now do the opposite, attach the ED container to the physical ED.  */
156     ed -> REF_AS.INTR.ux_ehci_ed_endpoint =  endpoint;
157 
158     /* Set the default MPS Capability info in the ED.  */
159     max_packet_size = endpoint -> ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_PACKET_SIZE_MASK;
160     ed -> ux_ehci_ed_cap0 =  max_packet_size << UX_EHCI_QH_MPS_LOC;
161 
162     /* Set the device address.  */
163     ed -> ux_ehci_ed_cap0 |=  device -> ux_device_address;
164 
165     /* Add the endpoint address.  */
166     ed -> ux_ehci_ed_cap0 |=  (endpoint -> ux_endpoint_descriptor.bEndpointAddress & ~UX_ENDPOINT_DIRECTION) << UX_EHCI_QH_ED_AD_LOC;
167 
168     /* Set the High Bandwidth Pipe Multiplier to number transactions.  */
169     num_transaction = (endpoint -> ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_NUMBER_OF_TRANSACTIONS_MASK) >> UX_MAX_NUMBER_OF_TRANSACTIONS_SHIFT;
170     if (num_transaction < 3)
171         num_transaction ++;
172     ed -> ux_ehci_ed_cap1 |= (num_transaction << UX_EHCI_QH_HBPM_LOC);
173 
174     /* Set the device speed for full and low speed devices behind a HUB. The HUB address and the
175        port index must be stored in the endpoint. For low/full speed devices, the C-mask field must be set.  */
176     switch (device -> ux_device_speed)
177     {
178 
179     case UX_HIGH_SPEED_DEVICE:
180         ed -> ux_ehci_ed_cap0 |=  UX_EHCI_QH_HIGH_SPEED;
181         break;
182 
183     case UX_LOW_SPEED_DEVICE:
184         ed -> ux_ehci_ed_cap0 |=  UX_EHCI_QH_LOW_SPEED;
185 
186         /* Fall through.  */
187     default:
188 
189 #if UX_MAX_DEVICES > 1
190         /* The device must be on a hub for this code to execute. We still do a sanity check.  */
191         if (device -> ux_device_parent != UX_NULL)
192         {
193 
194             /* Store the parent hub device address.  */
195             ed -> ux_ehci_ed_cap1 |=  device -> ux_device_parent -> ux_device_address << UX_EHCI_QH_HUB_ADDR_LOC;
196 
197             /* And the port index onto which this device is attached.  */
198             ed -> ux_ehci_ed_cap1 |=  device -> ux_device_port_location << UX_EHCI_QH_PORT_NUMBER_LOC;
199         }
200 #endif
201         break;
202     }
203 
204     /* Get the interval for the endpoint and match it to a EHCI list.
205        We match anything that is > 32ms to the 32ms interval layer.
206        The 32ms list is layer 5, 16ms list is 4 ... the 1ms list is depth 0.  */
207     interval = endpoint -> ux_endpoint_descriptor.bInterval;
208 #if defined(UX_HCD_EHCI_SPLIT_TRANSFER_ENABLE)
209     if (device -> ux_device_speed != UX_HIGH_SPEED_DEVICE)
210     {
211 
212         /* Convert from ms to 2^i.  */
213         for (i = 0; i < 16; i ++)
214         {
215             if (interval <= (1u << i))
216                 break;
217         }
218 
219         /* Index 0 for 1ms (interval 4).  */
220         interval = 4 + i;
221     }
222     else
223 #endif
224     {
225         /* High-speed interval is 2^(interval - 1) * 1/2^3.   */
226         if (interval <= 4)
227             i = 0;
228         else
229             i = interval - 4;
230 
231         /* Index 0 for 1ms.  */
232     }
233 
234     /* Match > 32ms to 32ms list.  */
235     /* Poll depth deeper, interval smaller.  */
236     if (i > 5)
237         poll_depth = 0;
238     else
239         poll_depth = 5 - i;
240 
241     /* Keep interval < 1ms for micro-frame calculation.  */
242     /* Make it index steps to move.  */
243     if (interval > 0)
244     {
245         interval --;
246         interval &= 0x3;
247     }
248     interval = (1u << interval); /* 1 (1/8ms), 2, 4, 8 (1ms)  */
249 
250     /* We are now updating the periodic list.  */
251     _ux_host_mutex_on(&hcd_ehci -> ux_hcd_ehci_periodic_mutex);
252 
253     /* Get the list index with the least traffic.  */
254     ed_list =  _ux_hcd_ehci_least_traffic_list_get(hcd_ehci, microframe_load, microframe_ssplit_count);
255 
256     /* Now we need to scan the list of eds from the lowest load entry until we reach the
257        appropriate interval node. The depth index is the interval EHCI value and the
258        1st entry is pointed by the ED list entry.  */
259     ed_anchor = _ux_hcd_ehci_poll_rate_entry_get(hcd_ehci, ed_list, poll_depth);
260 
261     /* Save anchor pointer for interrupt ED.  */
262     ed -> REF_AS.INTR.ux_ehci_ed_anchor = ed_anchor;
263 
264     /* Calculate packet size with num transactions.  */
265     max_packet_size *= num_transaction;
266 
267     /* Go through the transaction loads for start
268        index of micro-frame.  */
269     for (i = 0; i < interval; i ++)
270     {
271 
272         /* Skip if load too much.  */
273         if (microframe_load[i] + max_packet_size > UX_MAX_BYTES_PER_MICROFRAME_HS)
274             continue;
275 
276 #if defined(UX_HCD_EHCI_SPLIT_TRANSFER_ENABLE)
277         if (device -> ux_device_speed != UX_HIGH_SPEED_DEVICE)
278         {
279 
280             /* Skip Y6 since host must not use it.  */
281             if (i == 6)
282                 continue;
283 
284             /* Skip if start split count over 16 split.  */
285             if (microframe_ssplit_count[i] >= 16)
286                 continue;
287         }
288 #endif
289 
290         /* Use the load.  */
291         break;
292     }
293 
294     /* Sanity check, bandwidth checked before endpoint creation so there should
295        not be error but we check it any way.  */
296     if (i >= interval)
297     {
298         _ux_host_mutex_off(&hcd_ehci -> ux_hcd_ehci_periodic_mutex);
299         ed -> ux_ehci_ed_status = UX_UNUSED;
300         return(UX_NO_BANDWIDTH_AVAILABLE);
301     }
302 
303     /* Now start microframe index is calculated, build masks.  */
304 
305     /* It's interval is larger than 1ms, use any of micro-frame.  */
306     if (interval >= 8)
307     {
308 
309         /* Interrupt schedule.  */
310         ed -> ux_ehci_ed_cap1 |= (UX_EHCI_SMASK_0 << i);
311 
312 #if defined(UX_HCD_EHCI_SPLIT_TRANSFER_ENABLE)
313         /* For split transfer, complete split should be scheduled.  */
314         if (device -> ux_device_speed != UX_HIGH_SPEED_DEVICE)
315         {
316 
317             /* Interrupt IN/OUT:
318                must schedule a complete-split transaction in each of the two
319                microframes following the first microframe in which the
320                full/low speed transaction is budgeted. An additional
321                complete-split must also be scheduled in the third following
322                microframe unless the full/low speed transaction was budgeted
323                to start in Y6. */
324 
325             if (i == 5)
326             {
327 
328                 /* Budgeted in Y6, Follow two (C7, C0).  */
329                 cmask = UX_EHCI_CMASK_INT_Y5;
330                 csplit_count = 2;
331             }
332             else
333             {
334 
335                 /* Follow three.  */
336                 cmask = UX_EHCI_CMASK_INT_Y0 << i;
337                 if (i > 3)
338                 {
339                     cmask |= cmask >> 8;
340                     cmask &= UX_EHCI_CMASK_MASK;
341                 }
342                 csplit_count = 3;
343             }
344 
345             /* Reserve count for SSplit (Max 16).  */
346             ed_anchor ->REF_AS.ANCHOR.ux_ehci_ed_microframe_ssplit_count[i] ++;
347 
348             /* Reserve packet bytes for microframe load.  */
349             if (endpoint -> ux_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION)
350             {
351 
352                 /* Reserve load for CSplit.  */
353                 ed_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[(i + 2)&7] = (USHORT)(ed_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[(i + 2)&7] + max_packet_size);
354                 ed_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[(i + 3)&7] = (USHORT)(ed_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[(i + 3)&7] + max_packet_size);
355 
356                 /* Need additional CSplit.  */
357                 if (csplit_count > 2)
358                     ed_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[(i + 4)&7] = (USHORT)(ed_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[(i + 4)&7] + max_packet_size);
359             }
360             else
361             {
362 
363                 /* Reserve load for SSplit.  */
364                 ed_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[i] = (USHORT)(ed_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[i] + max_packet_size);
365             }
366 
367             /* Update schedule masks.  */
368             ed -> ux_ehci_ed_cap1 |= cmask;
369         }
370         else
371 #endif
372         {
373             /* Update anchor micro-frame load.  */
374             ed_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[i] = (USHORT)(ed_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[i] + max_packet_size);
375         }
376     }
377     else
378     {
379 
380         /* It must be high speed high bandwidth one.  */
381         switch(interval)
382         {
383         case 1:
384             ed -> ux_ehci_ed_cap1 |= UX_EHCI_SMASK_INTERVAL_1;
385             break;
386         case 2:
387             ed -> ux_ehci_ed_cap1 |= UX_EHCI_SMASK_INTERVAL_2 << i;
388             break;
389         default: /* 4, interval 3, 1/2ms */
390             ed -> ux_ehci_ed_cap1 |= UX_EHCI_SMASK_INTERVAL_3 << i;
391             break;
392         }
393 
394         /* Update anchor micro-frame loads.  */
395         for (; i < 8; i += interval)
396             ed_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[i] = (USHORT)(ed_anchor -> REF_AS.ANCHOR.ux_ehci_ed_microframe_load[i] + max_packet_size);
397     }
398 
399     /* We found the node entry of the ED pointer that will be the anchor for this interrupt
400        endpoint. Now we attach this endpoint to the anchor and rebuild the chain.  */
401 
402     /* Physical LP, with Typ QH, clear T.  */
403     lp.void_ptr = _ux_utility_physical_address(ed);
404     lp.value |= UX_EHCI_TYP_QH;
405 
406     /* Save previous LP: to anchor.  */
407     ed -> ux_ehci_ed_previous_ed = ed_anchor;
408 
409     /* Link the QH at next to anchor.  */
410     _ux_hcd_ehci_periodic_descriptor_link(ed_anchor, lp.void_ptr, ed, ed_anchor -> ux_ehci_ed_queue_head);
411 
412     /* Insert ED to interrupt scan list for fast done queue scan.  */
413     ed -> ux_ehci_ed_next_ed = hcd_ehci -> ux_hcd_ehci_interrupt_ed_list;
414     hcd_ehci -> ux_hcd_ehci_interrupt_ed_list = ed;
415 
416     /* Release the periodic list.  */
417     _ux_host_mutex_off(&hcd_ehci -> ux_hcd_ehci_periodic_mutex);
418 
419     /* Return successful completion.  */
420     return(UX_SUCCESS);
421 }
422