]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
Fix CrytoPkg issue in GCC X64 tip.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / XhciSched.c
... / ...
CommitLineData
1/** @file\r
2\r
3 XHCI transfer scheduling routines.\r
4\r
5Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "Xhci.h"\r
17\r
18/**\r
19 Create a command transfer TRB to support XHCI command interfaces.\r
20\r
21 @param Xhc The XHCI Instance.\r
22 @param CmdTrb The cmd TRB to be executed.\r
23\r
24 @return Created URB or NULL.\r
25\r
26**/\r
27URB*\r
28XhcCreateCmdTrb (\r
29 IN USB_XHCI_INSTANCE *Xhc,\r
30 IN TRB_TEMPLATE *CmdTrb\r
31 )\r
32{\r
33 URB *Urb;\r
34\r
35 Urb = AllocateZeroPool (sizeof (URB));\r
36 if (Urb == NULL) {\r
37 return NULL;\r
38 }\r
39\r
40 Urb->Signature = XHC_URB_SIG;\r
41\r
42 Urb->Ring = &Xhc->CmdRing;\r
43 XhcSyncTrsRing (Xhc, Urb->Ring);\r
44 Urb->TrbNum = 1;\r
45 Urb->TrbStart = Urb->Ring->RingEnqueue;\r
46 CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));\r
47 Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;\r
48 Urb->TrbEnd = Urb->TrbStart;\r
49\r
50 Urb->EvtRing = &Xhc->CmdEventRing;\r
51 XhcSyncEventRing (Xhc, Urb->EvtRing);\r
52 Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;\r
53\r
54 return Urb;\r
55}\r
56\r
57/**\r
58 Execute a XHCI cmd TRB pointed by CmdTrb.\r
59\r
60 @param Xhc The XHCI Instance.\r
61 @param CmdTrb The cmd TRB to be executed.\r
62 @param Timeout Indicates the maximum time, in millisecond, which the\r
63 transfer is allowed to complete.\r
64 @param EvtTrb The event TRB corresponding to the cmd TRB.\r
65\r
66 @retval EFI_SUCCESS The transfer was completed successfully.\r
67 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
68 @retval EFI_TIMEOUT The transfer failed due to timeout.\r
69 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
70\r
71**/\r
72EFI_STATUS\r
73EFIAPI\r
74XhcCmdTransfer (\r
75 IN USB_XHCI_INSTANCE *Xhc,\r
76 IN TRB_TEMPLATE *CmdTrb,\r
77 IN UINTN Timeout,\r
78 OUT TRB_TEMPLATE **EvtTrb\r
79 )\r
80{\r
81 EFI_STATUS Status;\r
82 URB *Urb;\r
83\r
84 //\r
85 // Validate the parameters\r
86 //\r
87 if ((Xhc == NULL) || (CmdTrb == NULL)) {\r
88 return EFI_INVALID_PARAMETER;\r
89 }\r
90\r
91 Status = EFI_DEVICE_ERROR;\r
92\r
93 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
94 DEBUG ((EFI_D_ERROR, "XhcCmdTransfer: HC is halted\n"));\r
95 goto ON_EXIT;\r
96 }\r
97\r
98 //\r
99 // Create a new URB, then poll the execution status.\r
100 //\r
101 Urb = XhcCreateCmdTrb (Xhc, CmdTrb);\r
102\r
103 if (Urb == NULL) {\r
104 DEBUG ((EFI_D_ERROR, "XhcCmdTransfer: failed to create URB\n"));\r
105 Status = EFI_OUT_OF_RESOURCES;\r
106 goto ON_EXIT;\r
107 }\r
108\r
109 ASSERT (Urb->EvtRing == &Xhc->CmdEventRing);\r
110\r
111 Status = XhcExecTransfer (Xhc, TRUE, Urb, Timeout);\r
112 *EvtTrb = Urb->EvtTrbStart;\r
113\r
114 if (Urb->Result == EFI_USB_NOERROR) {\r
115 Status = EFI_SUCCESS;\r
116 }\r
117\r
118 FreePool (Urb);\r
119\r
120ON_EXIT:\r
121 return Status;\r
122}\r
123\r
124/**\r
125 Create a new URB for a new transaction.\r
126\r
127 @param Xhc The XHCI Instance\r
128 @param DevAddr The device address\r
129 @param EpAddr Endpoint addrress\r
130 @param DevSpeed The device speed\r
131 @param MaxPacket The max packet length of the endpoint\r
132 @param Type The transaction type\r
133 @param Request The standard USB request for control transfer\r
134 @param Data The user data to transfer\r
135 @param DataLen The length of data buffer\r
136 @param Callback The function to call when data is transferred\r
137 @param Context The context to the callback\r
138\r
139 @return Created URB or NULL\r
140\r
141**/\r
142URB*\r
143XhcCreateUrb (\r
144 IN USB_XHCI_INSTANCE *Xhc,\r
145 IN UINT8 DevAddr,\r
146 IN UINT8 EpAddr,\r
147 IN UINT8 DevSpeed,\r
148 IN UINTN MaxPacket,\r
149 IN UINTN Type,\r
150 IN EFI_USB_DEVICE_REQUEST *Request,\r
151 IN VOID *Data,\r
152 IN UINTN DataLen,\r
153 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
154 IN VOID *Context\r
155 )\r
156{\r
157 USB_ENDPOINT *Ep;\r
158 EFI_STATUS Status;\r
159 URB *Urb;\r
160\r
161 Urb = AllocateZeroPool (sizeof (URB));\r
162 if (Urb == NULL) {\r
163 return NULL;\r
164 }\r
165\r
166 Urb->Signature = XHC_URB_SIG;\r
167 InitializeListHead (&Urb->UrbList);\r
168\r
169 Ep = &Urb->Ep;\r
170 Ep->DevAddr = DevAddr;\r
171 Ep->EpAddr = (UINT8)(EpAddr & 0x0F);\r
172 Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
173 Ep->DevSpeed = DevSpeed;\r
174 Ep->MaxPacket = MaxPacket;\r
175 Ep->Type = Type;\r
176\r
177 Urb->Request = Request;\r
178 Urb->Data = Data;\r
179 Urb->DataLen = DataLen;\r
180 Urb->Callback = Callback;\r
181 Urb->Context = Context;\r
182\r
183 Status = XhcCreateTransferTrb (Xhc, Urb);\r
184 ASSERT_EFI_ERROR (Status);\r
185\r
186 return Urb;\r
187}\r
188\r
189/**\r
190 Create a transfer TRB.\r
191\r
192 @param Xhc The XHCI Instance\r
193 @param Urb The urb used to construct the transfer TRB.\r
194\r
195 @return Created TRB or NULL\r
196\r
197**/\r
198EFI_STATUS\r
199XhcCreateTransferTrb (\r
200 IN USB_XHCI_INSTANCE *Xhc,\r
201 IN URB *Urb\r
202 )\r
203{\r
204 DEVICE_CONTEXT *OutputContext;\r
205 TRANSFER_RING *EPRing;\r
206 UINT8 EPType;\r
207 UINT8 SlotId;\r
208 UINT8 Dci;\r
209 TRB *TrbStart;\r
210 UINTN TotalLen;\r
211 UINTN Len;\r
212 UINTN TrbNum;\r
213\r
214 SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);\r
215 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
216 ASSERT (Dci < 32);\r
217 EPRing = (TRANSFER_RING *)(UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];\r
218 Urb->Ring = EPRing;\r
219 OutputContext = (DEVICE_CONTEXT *)(UINTN) Xhc->DCBAA[SlotId];\r
220 EPType = (UINT8) OutputContext->EP[Dci-1].EPType;\r
221\r
222 //\r
223 // Construct the TRB\r
224 //\r
225 XhcSyncTrsRing (Xhc, EPRing);\r
226 Urb->TrbStart = EPRing->RingEnqueue;\r
227 switch (EPType) {\r
228 case ED_CONTROL_BIDIR:\r
229 Urb->EvtRing = &Xhc->CtrlTrEventRing;\r
230 XhcSyncEventRing (Xhc, Urb->EvtRing);\r
231 Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;\r
232 //\r
233 // For control transfer, create SETUP_STAGE_TRB first.\r
234 //\r
235 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
236 TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;\r
237 TrbStart->TrbCtrSetup.bRequest = Urb->Request->Request;\r
238 TrbStart->TrbCtrSetup.wValue = Urb->Request->Value;\r
239 TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index;\r
240 TrbStart->TrbCtrSetup.wLength = Urb->Request->Length;\r
241 TrbStart->TrbCtrSetup.Lenth = 8;\r
242 TrbStart->TrbCtrSetup.IntTarget = Urb->EvtRing->EventInterrupter;\r
243 TrbStart->TrbCtrSetup.IOC = 1;\r
244 TrbStart->TrbCtrSetup.IDT = 1;\r
245 TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE;\r
246 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
247 TrbStart->TrbCtrSetup.TRT = 3;\r
248 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
249 TrbStart->TrbCtrSetup.TRT = 2;\r
250 } else {\r
251 TrbStart->TrbCtrSetup.TRT = 0;\r
252 }\r
253 //\r
254 // Update the cycle bit\r
255 //\r
256 TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;\r
257 Urb->TrbNum++;\r
258\r
259 //\r
260 // For control transfer, create DATA_STAGE_TRB.\r
261 //\r
262 if (Urb->DataLen > 0) {\r
263 XhcSyncTrsRing (Xhc, EPRing);\r
264 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
265 TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT(Urb->Data);\r
266 TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT(Urb->Data);\r
267 TrbStart->TrbCtrData.Lenth = (UINT32) Urb->DataLen;\r
268 TrbStart->TrbCtrData.TDSize = 0;\r
269 TrbStart->TrbCtrData.IntTarget = Urb->EvtRing->EventInterrupter;\r
270 TrbStart->TrbCtrData.ISP = 1;\r
271 TrbStart->TrbCtrData.IOC = 1;\r
272 TrbStart->TrbCtrData.IDT = 0;\r
273 TrbStart->TrbCtrData.CH = 0;\r
274 TrbStart->TrbCtrData.Type = TRB_TYPE_DATA_STAGE;\r
275 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
276 TrbStart->TrbCtrData.DIR = 1;\r
277 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
278 TrbStart->TrbCtrData.DIR = 0;\r
279 } else {\r
280 TrbStart->TrbCtrData.DIR = 0;\r
281 }\r
282 //\r
283 // Update the cycle bit\r
284 //\r
285 TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;\r
286 Urb->TrbNum++;\r
287 }\r
288 //\r
289 // For control transfer, create STATUS_STAGE_TRB.\r
290 // Get the pointer to next TRB for status stage use\r
291 //\r
292 XhcSyncTrsRing (Xhc, EPRing);\r
293 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
294 TrbStart->TrbCtrStatus.IntTarget = Urb->EvtRing->EventInterrupter;\r
295 TrbStart->TrbCtrStatus.IOC = 1;\r
296 TrbStart->TrbCtrStatus.CH = 0;\r
297 TrbStart->TrbCtrStatus.Type = TRB_TYPE_STATUS_STAGE;\r
298 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
299 TrbStart->TrbCtrStatus.DIR = 0;\r
300 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
301 TrbStart->TrbCtrStatus.DIR = 1;\r
302 } else {\r
303 TrbStart->TrbCtrStatus.DIR = 0;\r
304 }\r
305 //\r
306 // Update the cycle bit\r
307 //\r
308 TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;\r
309 //\r
310 // Update the enqueue pointer\r
311 //\r
312 XhcSyncTrsRing (Xhc, EPRing);\r
313 Urb->TrbNum++;\r
314 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
315\r
316 break;\r
317\r
318 case ED_BULK_OUT:\r
319 case ED_BULK_IN:\r
320 Urb->EvtRing = &Xhc->BulkTrEventRing;\r
321 XhcSyncEventRing (Xhc, Urb->EvtRing);\r
322 Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;\r
323\r
324 TotalLen = 0;\r
325 Len = 0;\r
326 TrbNum = 0;\r
327 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
328 while (TotalLen < Urb->DataLen) {\r
329 if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
330 Len = Urb->DataLen - TotalLen;\r
331 } else {\r
332 Len = 0x10000;\r
333 }\r
334 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
335 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->Data + TotalLen);\r
336 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen);\r
337 TrbStart->TrbNormal.Lenth = (UINT32) Len;\r
338 TrbStart->TrbNormal.TDSize = 0;\r
339 TrbStart->TrbNormal.IntTarget = Urb->EvtRing->EventInterrupter;\r
340 TrbStart->TrbNormal.ISP = 1;\r
341 TrbStart->TrbNormal.IOC = 1;\r
342 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;\r
343 //\r
344 // Update the cycle bit\r
345 //\r
346 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
347\r
348 XhcSyncTrsRing (Xhc, EPRing);\r
349 TrbNum++;\r
350 TotalLen += Len;\r
351 }\r
352\r
353 Urb->TrbNum = TrbNum;\r
354 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
355 break;\r
356\r
357 case ED_INTERRUPT_OUT:\r
358 case ED_INTERRUPT_IN:\r
359 if (Urb->Ep.Type == XHC_INT_TRANSFER_ASYNC) {\r
360 Urb->EvtRing = &Xhc->AsynIntTrEventRing;\r
361 } else if(Urb->Ep.Type == XHC_INT_TRANSFER_SYNC){\r
362 Urb->EvtRing = &Xhc->IntTrEventRing;\r
363 } else {\r
364 DEBUG ((EFI_D_ERROR, "EP Interrupt type error!\n"));\r
365 ASSERT(FALSE);\r
366 }\r
367 XhcSyncEventRing (Xhc, Urb->EvtRing);\r
368 Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;\r
369\r
370 TotalLen = 0;\r
371 Len = 0;\r
372 TrbNum = 0;\r
373 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
374 while (TotalLen < Urb->DataLen) {\r
375 if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
376 Len = Urb->DataLen - TotalLen;\r
377 } else {\r
378 Len = 0x10000;\r
379 }\r
380 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
381 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->Data + TotalLen);\r
382 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen);\r
383 TrbStart->TrbNormal.Lenth = (UINT32) Len;\r
384 TrbStart->TrbNormal.TDSize = 0;\r
385 TrbStart->TrbNormal.IntTarget = Urb->EvtRing->EventInterrupter;\r
386 TrbStart->TrbNormal.ISP = 1;\r
387 TrbStart->TrbNormal.IOC = 1;\r
388 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;\r
389 //\r
390 // Update the cycle bit\r
391 //\r
392 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
393\r
394 XhcSyncTrsRing (Xhc, EPRing);\r
395 TrbNum++;\r
396 TotalLen += Len;\r
397 }\r
398\r
399 Urb->TrbNum = TrbNum;\r
400 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
401 break;\r
402\r
403 default:\r
404 DEBUG ((EFI_D_INFO, "Not supported EPType 0x%x!\n",EPType));\r
405 ASSERT (FALSE);\r
406 break;\r
407 }\r
408\r
409 return EFI_SUCCESS;\r
410}\r
411\r
412\r
413/**\r
414 Initialize the XHCI host controller for schedule.\r
415\r
416 @param Xhc The XHCI Instance to be initialized.\r
417\r
418**/\r
419VOID\r
420XhcInitSched (\r
421 IN USB_XHCI_INSTANCE *Xhc\r
422 )\r
423{\r
424 VOID *Dcbaa;\r
425 UINT64 CmdRing;\r
426 UINTN Entries;\r
427 UINT32 MaxScratchpadBufs;\r
428 UINT64 *ScratchBuf;\r
429 UINT64 *ScratchEntryBuf;\r
430 UINT32 Index;\r
431\r
432 //\r
433 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)\r
434 // to enable the device slots that system software is going to use.\r
435 //\r
436 Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;\r
437 ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);\r
438 XhcWriteOpReg (Xhc, XHC_CONFIG_OFFSET, Xhc->MaxSlotsEn);\r
439\r
440 //\r
441 // The Device Context Base Address Array entry associated with each allocated Device Slot\r
442 // shall contain a 64-bit pointer to the base of the associated Device Context.\r
443 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.\r
444 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.\r
445 //\r
446 Entries = (Xhc->MaxSlotsEn + 1) * sizeof(UINT64);\r
447 Dcbaa = AllocatePages (EFI_SIZE_TO_PAGES (Entries));\r
448 ASSERT (Dcbaa != NULL);\r
449 ZeroMem (Dcbaa, Entries);\r
450\r
451 //\r
452 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.\r
453 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run\r
454 // mode (Run/Stop(R/S) ='1').\r
455 //\r
456 MaxScratchpadBufs = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);\r
457 Xhc->MaxScratchpadBufs = MaxScratchpadBufs;\r
458 ASSERT (MaxScratchpadBufs <= 1023);\r
459 if (MaxScratchpadBufs != 0) {\r
460 ScratchBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)), Xhc->PageSize);\r
461 ASSERT (ScratchBuf != NULL);\r
462 ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));\r
463 Xhc->ScratchBuf = ScratchBuf;\r
464\r
465 for (Index = 0; Index < MaxScratchpadBufs; Index++) {\r
466 ScratchEntryBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (Xhc->PageSize), Xhc->PageSize);\r
467 ASSERT (ScratchEntryBuf != NULL);\r
468 ZeroMem (ScratchEntryBuf, Xhc->PageSize);\r
469 *ScratchBuf++ = (UINT64)(UINTN)ScratchEntryBuf;\r
470 }\r
471\r
472 //\r
473 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the\r
474 // Device Context Base Address Array points to the Scratchpad Buffer Array.\r
475 //\r
476 *(UINT64 *)Dcbaa = (UINT64)(UINTN)Xhc->ScratchBuf;\r
477 }\r
478\r
479 //\r
480 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with\r
481 // a 64-bit address pointing to where the Device Context Base Address Array is located.\r
482 //\r
483 Xhc->DCBAA = (UINT64 *)(UINTN)Dcbaa;\r
484 XhcWriteOpReg64 (Xhc, XHC_DCBAAP_OFFSET, (UINT64)(UINTN)Xhc->DCBAA);\r
485 DEBUG ((EFI_D_INFO, "XhcInitSched:DCBAA=0x%x\n", (UINT64)(UINTN)Xhc->DCBAA));\r
486\r
487 //\r
488 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register\r
489 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.\r
490 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall\r
491 // always be '0'.\r
492 //\r
493 CreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);\r
494 //\r
495 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a\r
496 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.\r
497 // So we set RCS as inverted PCS init value to let Command Ring empty\r
498 //\r
499 CmdRing = (UINT64)(UINTN)Xhc->CmdRing.RingSeg0;\r
500 ASSERT ((CmdRing & 0x3F) == 0);\r
501 CmdRing |= XHC_CRCR_RCS;\r
502 XhcWriteOpReg64 (Xhc, XHC_CRCR_OFFSET, CmdRing);\r
503\r
504 DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));\r
505\r
506 //\r
507 // Disable the 'interrupter enable' bit in USB_CMD\r
508 // and clear IE & IP bit in all Interrupter X Management Registers.\r
509 //\r
510 XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);\r
511 for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {\r
512 XhcClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);\r
513 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);\r
514 }\r
515\r
516 //\r
517 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer\r
518 //\r
519 CreateEventRing (Xhc, CMD_INTER, &Xhc->CmdEventRing);\r
520 CreateEventRing (Xhc, CTRL_INTER, &Xhc->CtrlTrEventRing);\r
521 CreateEventRing (Xhc, BULK_INTER, &Xhc->BulkTrEventRing);\r
522 CreateEventRing (Xhc, INT_INTER, &Xhc->IntTrEventRing);\r
523 CreateEventRing (Xhc, INT_INTER_ASYNC, &Xhc->AsynIntTrEventRing);\r
524}\r
525\r
526/**\r
527 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted\r
528 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint\r
529 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is\r
530 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the\r
531 Stopped to the Running state.\r
532\r
533 @param Xhc The XHCI Instance.\r
534 @param Urb The urb which makes the endpoint halted.\r
535\r
536 @retval EFI_SUCCESS The recovery is successful.\r
537 @retval Others Failed to recovery halted endpoint.\r
538\r
539**/\r
540EFI_STATUS\r
541EFIAPI\r
542XhcRecoverHaltedEndpoint (\r
543 IN USB_XHCI_INSTANCE *Xhc,\r
544 IN URB *Urb\r
545 )\r
546{\r
547 EFI_STATUS Status;\r
548 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
549 CMD_TRB_RESET_ENDPOINT CmdTrbResetED;\r
550 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;\r
551 UINT8 Dci;\r
552 UINT8 SlotId;\r
553\r
554 Status = EFI_SUCCESS;\r
555 SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);\r
556 Dci = XhcEndpointToDci(Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
557\r
558 DEBUG ((EFI_D_INFO, "Recovery Halted Slot = %x,Dci = %x\n", SlotId, Dci));\r
559\r
560 //\r
561 // 1) Send Reset endpoint command to transit from halt to stop state\r
562 //\r
563 ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
564 CmdTrbResetED.CycleBit = 1;\r
565 CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;\r
566 CmdTrbResetED.EDID = Dci;\r
567 CmdTrbResetED.SlotId = SlotId;\r
568 Status = XhcCmdTransfer (\r
569 Xhc,\r
570 (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,\r
571 XHC_GENERIC_TIMEOUT,\r
572 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
573 );\r
574 ASSERT (!EFI_ERROR(Status));\r
575\r
576 //\r
577 // 2)Set dequeue pointer\r
578 //\r
579 ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
580 CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (Urb->Ring->RingEnqueue) | Urb->Ring->RingPCS;\r
581 CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (Urb->Ring->RingEnqueue);\r
582 CmdSetTRDeq.CycleBit = 1;\r
583 CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;\r
584 CmdSetTRDeq.Endpoint = Dci;\r
585 CmdSetTRDeq.SlotId = SlotId;\r
586 Status = XhcCmdTransfer (\r
587 Xhc,\r
588 (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,\r
589 XHC_GENERIC_TIMEOUT,\r
590 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
591 );\r
592 ASSERT (!EFI_ERROR(Status));\r
593\r
594 //\r
595 // 3)Ring the doorbell to transit from stop to active\r
596 //\r
597 XhcRingDoorBell (Xhc, SlotId, Dci);\r
598\r
599 return Status;\r
600}\r
601\r
602/**\r
603 Create XHCI event ring.\r
604\r
605 @param Xhc The XHCI Instance.\r
606 @param EventInterrupter The interrupter of event.\r
607 @param EventRing The created event ring.\r
608\r
609**/\r
610VOID\r
611CreateEventRing (\r
612 IN USB_XHCI_INSTANCE *Xhc,\r
613 IN UINT8 EventInterrupter,\r
614 OUT EVENT_RING *EventRing\r
615 )\r
616{\r
617 VOID *Buf;\r
618 EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;\r
619\r
620 ASSERT (EventRing != NULL);\r
621\r
622 Buf = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER));\r
623 ASSERT (Buf != NULL);\r
624 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
625 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
626\r
627 EventRing->EventRingSeg0 = Buf;\r
628 EventRing->EventInterrupter = EventInterrupter;\r
629 EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;\r
630 EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
631 EventRing->EventRingEnqueue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
632 //\r
633 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'\r
634 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.\r
635 //\r
636 EventRing->EventRingCCS = 1;\r
637\r
638 Buf = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER));\r
639 ASSERT (Buf != NULL);\r
640 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
641 ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
642\r
643 ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;\r
644 EventRing->ERSTBase = ERSTBase;\r
645 ERSTBase->PtrLo = XHC_LOW_32BIT (EventRing->EventRingSeg0);\r
646 ERSTBase->PtrHi = XHC_HIGH_32BIT (EventRing->EventRingSeg0);\r
647 ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;\r
648\r
649 //\r
650 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)\r
651 //\r
652 XhcWriteRuntimeReg (\r
653 Xhc,\r
654 XHC_ERSTSZ_OFFSET + (32 * EventRing->EventInterrupter),\r
655 ERST_NUMBER\r
656 );\r
657 //\r
658 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)\r
659 //\r
660 XhcWriteRuntimeReg64 (\r
661 Xhc,\r
662 XHC_ERDP_OFFSET + (32 * EventRing->EventInterrupter),\r
663 (UINT64)(UINTN)EventRing->EventRingDequeue\r
664 );\r
665 //\r
666 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)\r
667 //\r
668 XhcWriteRuntimeReg64 (\r
669 Xhc,\r
670 XHC_ERSTBA_OFFSET + (32 * EventRing->EventInterrupter),\r
671 (UINT64)(UINTN)ERSTBase\r
672 );\r
673 //\r
674 // Need set IMAN IE bit to enble the ring interrupt\r
675 //\r
676 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (32 * EventRing->EventInterrupter), XHC_IMAN_IE);\r
677}\r
678\r
679/**\r
680 Create XHCI transfer ring.\r
681\r
682 @param Xhc The XHCI Instance.\r
683 @param TrbNum The number of TRB in the ring.\r
684 @param TransferRing The created transfer ring.\r
685\r
686**/\r
687VOID\r
688CreateTransferRing (\r
689 IN USB_XHCI_INSTANCE *Xhc,\r
690 IN UINTN TrbNum,\r
691 OUT TRANSFER_RING *TransferRing\r
692 )\r
693{\r
694 VOID *Buf;\r
695 LINK_TRB *EndTrb;\r
696\r
697 Buf = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TrbNum));\r
698 ASSERT (Buf != NULL);\r
699 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
700 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
701\r
702 TransferRing->RingSeg0 = Buf;\r
703 TransferRing->TrbNumber = TrbNum;\r
704 TransferRing->RingEnqueue = (TRB_TEMPLATE *) TransferRing->RingSeg0;\r
705 TransferRing->RingDequeue = (TRB_TEMPLATE *) TransferRing->RingSeg0;\r
706 TransferRing->RingPCS = 1;\r
707 //\r
708 // 4.9.2 Transfer Ring Management\r
709 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to\r
710 // point to the first TRB in the ring.\r
711 //\r
712 EndTrb = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));\r
713 EndTrb->Type = TRB_TYPE_LINK;\r
714 EndTrb->PtrLo = XHC_LOW_32BIT (Buf);\r
715 EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);\r
716 //\r
717 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.\r
718 //\r
719 EndTrb->TC = 1;\r
720 //\r
721 // Set Cycle bit as other TRB PCS init value\r
722 //\r
723 EndTrb->CycleBit = 0;\r
724}\r
725\r
726/**\r
727 Free XHCI event ring.\r
728\r
729 @param Xhc The XHCI Instance.\r
730 @param EventRing The event ring to be freed.\r
731\r
732**/\r
733EFI_STATUS\r
734EFIAPI\r
735XhcFreeEventRing (\r
736 IN USB_XHCI_INSTANCE *Xhc,\r
737 IN EVENT_RING *EventRing\r
738)\r
739{\r
740 UINT8 Index;\r
741 EVENT_RING_SEG_TABLE_ENTRY *TablePtr;\r
742 VOID *RingBuf;\r
743 EVENT_RING_SEG_TABLE_ENTRY *EventRingPtr;\r
744\r
745 if(EventRing->EventRingSeg0 == NULL) {\r
746 return EFI_SUCCESS;\r
747 }\r
748\r
749 //\r
750 // Get the Event Ring Segment Table base address\r
751 //\r
752 TablePtr = (EVENT_RING_SEG_TABLE_ENTRY *)(EventRing->ERSTBase);\r
753\r
754 //\r
755 // Get all the TRBs Ring and release\r
756 //\r
757 for (Index = 0; Index < ERST_NUMBER; Index++) {\r
758 EventRingPtr = TablePtr + Index;\r
759 RingBuf = (VOID *)(UINTN)(EventRingPtr->PtrLo | ((UINT64)EventRingPtr->PtrHi << 32));\r
760\r
761 if(RingBuf != NULL) {\r
762 FreePages (RingBuf, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER));\r
763 ZeroMem (EventRingPtr, sizeof (EVENT_RING_SEG_TABLE_ENTRY));\r
764 }\r
765 }\r
766\r
767 FreePages (TablePtr, EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER));\r
768 return EFI_SUCCESS;\r
769}\r
770\r
771/**\r
772 Free the resouce allocated at initializing schedule.\r
773\r
774 @param Xhc The XHCI Instance.\r
775\r
776**/\r
777VOID\r
778XhcFreeSched (\r
779 IN USB_XHCI_INSTANCE *Xhc\r
780 )\r
781{\r
782 UINT32 Index;\r
783 UINT64 *ScratchBuf;\r
784\r
785 if (Xhc->ScratchBuf != NULL) {\r
786 ScratchBuf = Xhc->ScratchBuf;\r
787 for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {\r
788 FreeAlignedPages ((VOID*)(UINTN)*ScratchBuf++, EFI_SIZE_TO_PAGES (Xhc->PageSize));\r
789 }\r
790 FreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)));\r
791 }\r
792\r
793 if (Xhc->DCBAA != NULL) {\r
794 FreePages (Xhc->DCBAA, EFI_SIZE_TO_PAGES((Xhc->MaxSlotsEn + 1) * sizeof(UINT64)));\r
795 Xhc->DCBAA = NULL;\r
796 }\r
797\r
798 if (Xhc->CmdRing.RingSeg0 != NULL){\r
799 FreePages (Xhc->CmdRing.RingSeg0, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER));\r
800 Xhc->CmdRing.RingSeg0 = NULL;\r
801 }\r
802\r
803 XhcFreeEventRing (Xhc,&Xhc->CmdEventRing);\r
804 XhcFreeEventRing (Xhc,&Xhc->CtrlTrEventRing);\r
805 XhcFreeEventRing (Xhc,&Xhc->BulkTrEventRing);\r
806 XhcFreeEventRing (Xhc,&Xhc->AsynIntTrEventRing);\r
807 XhcFreeEventRing (Xhc,&Xhc->IntTrEventRing);\r
808}\r
809\r
810/**\r
811 Check if it is ring TRB.\r
812\r
813 @param Ring The transfer ring\r
814 @param Trb The TRB to check if it's in the transfer ring\r
815\r
816 @retval TRUE It is in the ring\r
817 @retval FALSE It is not in the ring\r
818\r
819**/\r
820BOOLEAN\r
821IsTransferRingTrb (\r
822 IN TRANSFER_RING *Ring,\r
823 IN TRB_TEMPLATE *Trb\r
824 )\r
825{\r
826 BOOLEAN Flag;\r
827 TRB_TEMPLATE *Trb1;\r
828 UINTN Index;\r
829\r
830 Trb1 = Ring->RingSeg0;\r
831 Flag = FALSE;\r
832\r
833 ASSERT (Ring->TrbNumber == CMD_RING_TRB_NUMBER || Ring->TrbNumber == TR_RING_TRB_NUMBER);\r
834\r
835 for (Index = 0; Index < Ring->TrbNumber; Index++) {\r
836 if (Trb == Trb1) {\r
837 Flag = TRUE;\r
838 break;\r
839 }\r
840 Trb1++;\r
841 }\r
842\r
843 return Flag;\r
844}\r
845\r
846/**\r
847 Check the URB's execution result and update the URB's\r
848 result accordingly.\r
849\r
850 @param Xhc The XHCI Instance.\r
851 @param Urb The URB to check result.\r
852\r
853 @return Whether the result of URB transfer is finialized.\r
854\r
855**/\r
856EFI_STATUS\r
857XhcCheckUrbResult (\r
858 IN USB_XHCI_INSTANCE *Xhc,\r
859 IN URB *Urb\r
860 )\r
861{\r
862 BOOLEAN StartDone;\r
863 BOOLEAN EndDone;\r
864 EVT_TRB_TRANSFER *EvtTrb;\r
865 TRB_TEMPLATE *TRBPtr;\r
866 UINTN Index;\r
867 UINT8 TRBType;\r
868 EFI_STATUS Status;\r
869\r
870 ASSERT ((Xhc != NULL) && (Urb != NULL));\r
871\r
872 Urb->Completed = 0;\r
873 Urb->Result = EFI_USB_NOERROR;\r
874 Status = EFI_SUCCESS;\r
875 EvtTrb = NULL;\r
876\r
877 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
878 Urb->Result |= EFI_USB_ERR_SYSTEM;\r
879 Status = EFI_DEVICE_ERROR;\r
880 goto EXIT;\r
881 }\r
882\r
883 //\r
884 // Restore the EventRingDequeue and poll the transfer event ring from beginning\r
885 //\r
886 StartDone = FALSE;\r
887 EndDone = FALSE;\r
888 Urb->EvtRing->EventRingDequeue = Urb->EvtTrbStart;\r
889 for (Index = 0; Index < Urb->EvtRing->TrbNumber; Index++) {\r
890 XhcSyncEventRing (Xhc, Urb->EvtRing);\r
891 Status = XhcCheckNewEvent (Xhc, Urb->EvtRing, ((TRB_TEMPLATE **)&EvtTrb));\r
892 if (Status == EFI_NOT_READY) {\r
893 Urb->Result |= EFI_USB_ERR_TIMEOUT;\r
894 goto EXIT;\r
895 }\r
896\r
897 TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | (UINT64) EvtTrb->TRBPtrHi << 32);\r
898\r
899 switch (EvtTrb->Completecode) {\r
900 case TRB_COMPLETION_STALL_ERROR:\r
901 Urb->Result |= EFI_USB_ERR_STALL;\r
902 Status = EFI_DEVICE_ERROR;\r
903 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
904 goto EXIT;\r
905 break;\r
906\r
907 case TRB_COMPLETION_BABBLE_ERROR:\r
908 Urb->Result |= EFI_USB_ERR_BABBLE;\r
909 Status = EFI_DEVICE_ERROR;\r
910 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
911 goto EXIT;\r
912 break;\r
913\r
914 case TRB_COMPLETION_DATA_BUFFER_ERROR:\r
915 Urb->Result |= EFI_USB_ERR_BUFFER;\r
916 Status = EFI_DEVICE_ERROR;\r
917 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));\r
918 goto EXIT;\r
919 break;\r
920\r
921 case TRB_COMPLETION_USB_TRANSACTION_ERROR:\r
922 Urb->Result |= EFI_USB_ERR_TIMEOUT;\r
923 Status = EFI_DEVICE_ERROR;\r
924 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
925 goto EXIT;\r
926 break;\r
927\r
928 case TRB_COMPLETION_SHORT_PACKET:\r
929 case TRB_COMPLETION_SUCCESS:\r
930 if (IsTransferRingTrb (Urb->Ring, TRBPtr)) {\r
931 if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {\r
932 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: short packet happens!\n"));\r
933 }\r
934 TRBType = (UINT8) (TRBPtr->Type);\r
935 if ((TRBType == TRB_TYPE_DATA_STAGE) ||\r
936 (TRBType == TRB_TYPE_NORMAL) ||\r
937 (TRBType == TRB_TYPE_ISOCH)) {\r
938 Urb->Completed += (Urb->DataLen - EvtTrb->Lenth);\r
939 }\r
940 }\r
941 Status = EFI_SUCCESS;\r
942 break;\r
943\r
944 default:\r
945 DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));\r
946 Urb->Result |= EFI_USB_ERR_TIMEOUT;\r
947 Status = EFI_DEVICE_ERROR;\r
948 goto EXIT;\r
949 break;\r
950 }\r
951\r
952 //\r
953 // Only check first and end Trb event address\r
954 //\r
955 if (TRBPtr == Urb->TrbStart) {\r
956 StartDone = TRUE;\r
957 }\r
958\r
959 if (TRBPtr == Urb->TrbEnd) {\r
960 EndDone = TRUE;\r
961 }\r
962\r
963 if (StartDone && EndDone) {\r
964 break;\r
965 }\r
966 }\r
967\r
968EXIT:\r
969 return Status;\r
970}\r
971\r
972\r
973/**\r
974 Execute the transfer by polling the URB. This is a synchronous operation.\r
975\r
976 @param Xhc The XHCI Instance.\r
977 @param CmdTransfer The executed URB is for cmd transfer or not.\r
978 @param Urb The URB to execute.\r
979 @param Timeout The time to wait before abort, in millisecond.\r
980\r
981 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
982 @return EFI_TIMEOUT The transfer failed due to time out.\r
983 @return EFI_SUCCESS The transfer finished OK.\r
984\r
985**/\r
986EFI_STATUS\r
987XhcExecTransfer (\r
988 IN USB_XHCI_INSTANCE *Xhc,\r
989 IN BOOLEAN CmdTransfer,\r
990 IN URB *Urb,\r
991 IN UINTN Timeout\r
992 )\r
993{\r
994 EFI_STATUS Status;\r
995 UINTN Index;\r
996 UINTN Loop;\r
997 UINT8 SlotId;\r
998 UINT8 Dci;\r
999\r
1000 if (CmdTransfer) {\r
1001 SlotId = 0;\r
1002 Dci = 0;\r
1003 } else {\r
1004 SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);\r
1005 Dci = XhcEndpointToDci(Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
1006 }\r
1007\r
1008 Status = EFI_SUCCESS;\r
1009 Loop = (Timeout * XHC_1_MILLISECOND / XHC_POLL_DELAY) + 1;\r
1010 if (Timeout == 0) {\r
1011 Loop = 0xFFFFFFFF;\r
1012 }\r
1013\r
1014 XhcRingDoorBell (Xhc, SlotId, Dci);\r
1015\r
1016 for (Index = 0; Index < Loop; Index++) {\r
1017 Status = XhcCheckUrbResult (Xhc, Urb);\r
1018 if ((Status != EFI_NOT_READY)) {\r
1019 break;\r
1020 }\r
1021 gBS->Stall (XHC_POLL_DELAY);\r
1022 }\r
1023\r
1024 return Status;\r
1025}\r
1026\r
1027/**\r
1028 Delete a single asynchronous interrupt transfer for\r
1029 the device and endpoint.\r
1030\r
1031 @param Xhc The XHCI Instance.\r
1032 @param DevAddr The address of the target device.\r
1033 @param EpNum The endpoint of the target.\r
1034\r
1035 @retval EFI_SUCCESS An asynchronous transfer is removed.\r
1036 @retval EFI_NOT_FOUND No transfer for the device is found.\r
1037\r
1038**/\r
1039EFI_STATUS\r
1040XhciDelAsyncIntTransfer (\r
1041 IN USB_XHCI_INSTANCE *Xhc,\r
1042 IN UINT8 DevAddr,\r
1043 IN UINT8 EpNum\r
1044 )\r
1045{\r
1046 LIST_ENTRY *Entry;\r
1047 LIST_ENTRY *Next;\r
1048 URB *Urb;\r
1049 EFI_USB_DATA_DIRECTION Direction;\r
1050\r
1051 Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
1052 EpNum &= 0x0F;\r
1053\r
1054 Urb = NULL;\r
1055\r
1056 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1057 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1058 if ((Urb->Ep.DevAddr == DevAddr) &&\r
1059 (Urb->Ep.EpAddr == EpNum) &&\r
1060 (Urb->Ep.Direction == Direction)) {\r
1061 RemoveEntryList (&Urb->UrbList);\r
1062 FreePool (Urb->Data);\r
1063 FreePool (Urb);\r
1064 return EFI_SUCCESS;\r
1065 }\r
1066 }\r
1067\r
1068 return EFI_NOT_FOUND;\r
1069}\r
1070\r
1071/**\r
1072 Remove all the asynchronous interrutp transfers.\r
1073\r
1074 @param Xhc The XHCI Instance.\r
1075\r
1076**/\r
1077VOID\r
1078XhciDelAllAsyncIntTransfers (\r
1079 IN USB_XHCI_INSTANCE *Xhc\r
1080 )\r
1081{\r
1082 LIST_ENTRY *Entry;\r
1083 LIST_ENTRY *Next;\r
1084 URB *Urb;\r
1085\r
1086 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1087 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1088 RemoveEntryList (&Urb->UrbList);\r
1089 FreePool (Urb->Data);\r
1090 FreePool (Urb);\r
1091 }\r
1092}\r
1093\r
1094/**\r
1095 Update the queue head for next round of asynchronous transfer\r
1096\r
1097 @param Xhc The XHCI Instance.\r
1098 @param Urb The URB to update\r
1099\r
1100**/\r
1101VOID\r
1102XhcUpdateAsyncRequest (\r
1103 IN USB_XHCI_INSTANCE *Xhc,\r
1104 IN URB *Urb\r
1105 )\r
1106{\r
1107 EFI_STATUS Status;\r
1108\r
1109 if (Urb->Result == EFI_USB_NOERROR) {\r
1110 Status = XhcCreateTransferTrb (Xhc, Urb);\r
1111 ASSERT_EFI_ERROR (Status);\r
1112 Status = RingIntTransferDoorBell (Xhc, Urb);\r
1113 ASSERT_EFI_ERROR (Status);\r
1114 }\r
1115}\r
1116\r
1117\r
1118/**\r
1119 Interrupt transfer periodic check handler.\r
1120\r
1121 @param Event Interrupt event.\r
1122 @param Context Pointer to USB_XHCI_INSTANCE.\r
1123\r
1124**/\r
1125VOID\r
1126EFIAPI\r
1127XhcMonitorAsyncRequests (\r
1128 IN EFI_EVENT Event,\r
1129 IN VOID *Context\r
1130 )\r
1131{\r
1132 USB_XHCI_INSTANCE *Xhc;\r
1133 LIST_ENTRY *Entry;\r
1134 LIST_ENTRY *Next;\r
1135 UINT8 *ProcBuf;\r
1136 URB *Urb;\r
1137 UINT8 SlotId;\r
1138 EFI_STATUS Status;\r
1139 EFI_TPL OldTpl;\r
1140\r
1141 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1142\r
1143 Xhc = (USB_XHCI_INSTANCE*) Context;\r
1144\r
1145 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1146 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1147\r
1148 //\r
1149 // Make sure that the device is available before every check.\r
1150 //\r
1151 SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);\r
1152 if (SlotId == 0) {\r
1153 continue;\r
1154 }\r
1155\r
1156 //\r
1157 // Check the result of URB execution. If it is still\r
1158 // active, check the next one.\r
1159 //\r
1160 Status = XhcCheckUrbResult (Xhc, Urb);\r
1161\r
1162 if (Status == EFI_NOT_READY) {\r
1163 continue;\r
1164 }\r
1165\r
1166 //\r
1167 // Allocate a buffer then copy the transferred data for user.\r
1168 // If failed to allocate the buffer, update the URB for next\r
1169 // round of transfer. Ignore the data of this round.\r
1170 //\r
1171 ProcBuf = NULL;\r
1172 if (Urb->Result == EFI_USB_NOERROR) {\r
1173 ASSERT (Urb->Completed <= Urb->DataLen);\r
1174\r
1175 ProcBuf = AllocateZeroPool (Urb->Completed);\r
1176\r
1177 if (ProcBuf == NULL) {\r
1178 XhcUpdateAsyncRequest (Xhc, Urb);\r
1179 continue;\r
1180 }\r
1181\r
1182 CopyMem (ProcBuf, Urb->Data, Urb->Completed);\r
1183 }\r
1184\r
1185 XhcUpdateAsyncRequest (Xhc, Urb);\r
1186\r
1187 //\r
1188 // Leave error recovery to its related device driver. A\r
1189 // common case of the error recovery is to re-submit the\r
1190 // interrupt transfer which is linked to the head of the\r
1191 // list. This function scans from head to tail. So the\r
1192 // re-submitted interrupt transfer's callback function\r
1193 // will not be called again in this round. Don't touch this\r
1194 // URB after the callback, it may have been removed by the\r
1195 // callback.\r
1196 //\r
1197 if (Urb->Callback != NULL) {\r
1198 //\r
1199 // Restore the old TPL, USB bus maybe connect device in\r
1200 // his callback. Some drivers may has a lower TPL restriction.\r
1201 //\r
1202 gBS->RestoreTPL (OldTpl);\r
1203 (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);\r
1204 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1205 }\r
1206\r
1207 if (ProcBuf != NULL) {\r
1208 gBS->FreePool (ProcBuf);\r
1209 }\r
1210 }\r
1211 gBS->RestoreTPL (OldTpl);\r
1212}\r
1213\r
1214/**\r
1215 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.\r
1216\r
1217 @param Xhc The XHCI Instance.\r
1218 @param ParentRouteChart The route string pointed to the parent device if it exists.\r
1219 @param Port The port to be polled.\r
1220 @param PortState The port state.\r
1221\r
1222 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.\r
1223 @retval Others Should not appear.\r
1224\r
1225**/\r
1226EFI_STATUS\r
1227EFIAPI\r
1228XhcPollPortStatusChange (\r
1229 IN USB_XHCI_INSTANCE *Xhc,\r
1230 IN USB_DEV_ROUTE ParentRouteChart,\r
1231 IN UINT8 Port,\r
1232 IN EFI_USB_PORT_STATUS *PortState\r
1233 )\r
1234{\r
1235 EFI_STATUS Status;\r
1236 UINT8 Speed;\r
1237 UINT8 SlotId;\r
1238 USB_DEV_ROUTE RouteChart;\r
1239\r
1240 Status = EFI_SUCCESS;\r
1241\r
1242 if (ParentRouteChart.Dword == 0) {\r
1243 RouteChart.Route.RouteString = 0;\r
1244 RouteChart.Route.RootPortNum = Port + 1;\r
1245 RouteChart.Route.TierNum = 1;\r
1246 } else {\r
1247 if(Port < 14) {\r
1248 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
1249 } else {\r
1250 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
1251 }\r
1252 RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;\r
1253 RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;\r
1254 }\r
1255\r
1256 if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&\r
1257 ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {\r
1258 //\r
1259 // Has a device attached, Identify device speed after port is enabled.\r
1260 //\r
1261 Speed = EFI_USB_SPEED_FULL;\r
1262 if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
1263 Speed = EFI_USB_SPEED_LOW;\r
1264 } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {\r
1265 Speed = EFI_USB_SPEED_HIGH;\r
1266 } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {\r
1267 Speed = EFI_USB_SPEED_SUPER;\r
1268 }\r
1269 //\r
1270 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.\r
1271 //\r
1272 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
1273 if (SlotId == 0) {\r
1274 Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
1275 ASSERT_EFI_ERROR (Status);\r
1276 }\r
1277 } else if ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) == 0) {\r
1278 //\r
1279 // Device is detached. Disable the allocated device slot and release resource.\r
1280 //\r
1281 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
1282 if (SlotId != 0) {\r
1283 Status = XhcDisableSlotCmd (Xhc, SlotId);\r
1284 ASSERT_EFI_ERROR (Status);\r
1285 }\r
1286 }\r
1287 return Status;\r
1288}\r
1289\r
1290\r
1291/**\r
1292 Calculate the device context index by endpoint address and direction.\r
1293\r
1294 @param EpAddr The target endpoint number.\r
1295 @param Direction The direction of the target endpoint.\r
1296\r
1297 @return The device context index of endpoint.\r
1298\r
1299**/\r
1300UINT8\r
1301XhcEndpointToDci (\r
1302 IN UINT8 EpAddr,\r
1303 IN UINT8 Direction\r
1304 )\r
1305{\r
1306 UINT8 Index;\r
1307\r
1308 if (EpAddr == 0) {\r
1309 return 1;\r
1310 } else {\r
1311 Index = (UINT8) (2 * EpAddr);\r
1312 if (Direction == EfiUsbDataIn) {\r
1313 Index += 1;\r
1314 }\r
1315 return Index;\r
1316 }\r
1317}\r
1318\r
1319/**\r
1320 Find out the slot id according to device address assigned by XHCI's Address_Device cmd.\r
1321\r
1322 @param Xhc The XHCI Instance.\r
1323 @param DevAddr The device address of the target device.\r
1324\r
1325 @return The slot id used by the device.\r
1326\r
1327**/\r
1328UINT8\r
1329XhcDevAddrToSlotId (\r
1330 IN USB_XHCI_INSTANCE *Xhc,\r
1331 IN UINT8 DevAddr\r
1332 )\r
1333{\r
1334 UINT8 Index;\r
1335\r
1336 for (Index = 0; Index < 255; Index++) {\r
1337 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1338 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1339 (Xhc->UsbDevContext[Index + 1].XhciDevAddr == DevAddr)) {\r
1340 break;\r
1341 }\r
1342 }\r
1343\r
1344 if (Index == 255) {\r
1345 return 0;\r
1346 }\r
1347\r
1348 return Xhc->UsbDevContext[Index + 1].SlotId;\r
1349}\r
1350\r
1351/**\r
1352 Find out the actual device address according to the requested device address from UsbBus.\r
1353\r
1354 @param Xhc The XHCI Instance.\r
1355 @param BusDevAddr The requested device address by UsbBus upper driver.\r
1356\r
1357 @return The actual device address assigned to the device.\r
1358\r
1359**/\r
1360UINT8\r
1361EFIAPI\r
1362XhcBusDevAddrToSlotId (\r
1363 IN USB_XHCI_INSTANCE *Xhc,\r
1364 IN UINT8 BusDevAddr\r
1365 )\r
1366{\r
1367 UINT8 Index;\r
1368\r
1369 for (Index = 0; Index < 255; Index++) {\r
1370 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1371 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1372 (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {\r
1373 break;\r
1374 }\r
1375 }\r
1376\r
1377 if (Index == 255) {\r
1378 return 0;\r
1379 }\r
1380\r
1381 return Xhc->UsbDevContext[Index + 1].SlotId;\r
1382}\r
1383\r
1384/**\r
1385 Find out the slot id according to the device's route string.\r
1386\r
1387 @param Xhc The XHCI Instance.\r
1388 @param RouteString The route string described the device location.\r
1389\r
1390 @return The slot id used by the device.\r
1391\r
1392**/\r
1393UINT8\r
1394EFIAPI\r
1395XhcRouteStringToSlotId (\r
1396 IN USB_XHCI_INSTANCE *Xhc,\r
1397 IN USB_DEV_ROUTE RouteString\r
1398 )\r
1399{\r
1400 UINT8 Index;\r
1401\r
1402 for (Index = 0; Index < 255; Index++) {\r
1403 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1404 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1405 (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {\r
1406 break;\r
1407 }\r
1408 }\r
1409\r
1410 if (Index == 255) {\r
1411 return 0;\r
1412 }\r
1413\r
1414 return Xhc->UsbDevContext[Index + 1].SlotId;\r
1415}\r
1416\r
1417/**\r
1418 Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
1419\r
1420 @param Xhc The XHCI Instance.\r
1421 @param EvtRing The event ring to sync.\r
1422\r
1423 @retval EFI_SUCCESS The event ring is synchronized successfully.\r
1424\r
1425**/\r
1426EFI_STATUS\r
1427EFIAPI\r
1428XhcSyncEventRing (\r
1429 IN USB_XHCI_INSTANCE *Xhc,\r
1430 IN EVENT_RING *EvtRing\r
1431 )\r
1432{\r
1433 UINTN Index;\r
1434 TRB_TEMPLATE *EvtTrb1;\r
1435 TRB_TEMPLATE *EvtTrb2;\r
1436 TRB_TEMPLATE *XhcDequeue;\r
1437\r
1438 ASSERT (EvtRing != NULL);\r
1439\r
1440 //\r
1441 // Calculate the EventRingEnqueue and EventRingCCS.\r
1442 // Note: only support single Segment\r
1443 //\r
1444 EvtTrb1 = EvtRing->EventRingSeg0;\r
1445 EvtTrb2 = EvtRing->EventRingSeg0;\r
1446\r
1447 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {\r
1448 if (EvtTrb1->CycleBit != EvtTrb2->CycleBit) {\r
1449 break;\r
1450 }\r
1451 EvtTrb1++;\r
1452 }\r
1453\r
1454 if (Index < EvtRing->TrbNumber) {\r
1455 EvtRing->EventRingEnqueue = EvtTrb1;\r
1456 EvtRing->EventRingCCS = (EvtTrb2->CycleBit) ? 1 : 0;\r
1457 } else {\r
1458 EvtRing->EventRingEnqueue = EvtTrb2;\r
1459 EvtRing->EventRingCCS = (EvtTrb2->CycleBit) ? 0 : 1;\r
1460 }\r
1461\r
1462 //\r
1463 // Apply the EventRingDequeue to Xhc\r
1464 //\r
1465 XhcDequeue = (TRB_TEMPLATE *)(UINTN) XhcReadRuntimeReg64 (\r
1466 Xhc,\r
1467 XHC_ERDP_OFFSET + (32 * EvtRing->EventInterrupter)\r
1468 );\r
1469\r
1470 if (((UINT64)(UINTN)XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)EvtRing->EventRingDequeue & (~0x0F))) {\r
1471 XhcWriteRuntimeReg64 (\r
1472 Xhc,\r
1473 XHC_ERDP_OFFSET + (32 * EvtRing->EventInterrupter),\r
1474 (UINT64)(UINTN)EvtRing->EventRingDequeue | BIT3\r
1475 );\r
1476 }\r
1477\r
1478 return EFI_SUCCESS;\r
1479}\r
1480\r
1481/**\r
1482 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
1483\r
1484 @param Xhc The XHCI Instance.\r
1485 @param TrsRing The transfer ring to sync.\r
1486\r
1487 @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
1488\r
1489**/\r
1490EFI_STATUS\r
1491EFIAPI\r
1492XhcSyncTrsRing (\r
1493 IN USB_XHCI_INSTANCE *Xhc,\r
1494 IN TRANSFER_RING *TrsRing\r
1495 )\r
1496{\r
1497 UINTN Index;\r
1498 TRB_TEMPLATE *TrsTrb;\r
1499\r
1500 ASSERT (TrsRing != NULL);\r
1501 //\r
1502 // Calculate the latest RingEnqueue and RingPCS\r
1503 //\r
1504 TrsTrb = TrsRing->RingEnqueue;\r
1505 ASSERT (TrsTrb != NULL);\r
1506\r
1507 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {\r
1508 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {\r
1509 break;\r
1510 }\r
1511 TrsTrb++;\r
1512 if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {\r
1513 ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);\r
1514 //\r
1515 // set cycle bit in Link TRB as normal\r
1516 //\r
1517 ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;\r
1518 //\r
1519 // Toggle PCS maintained by software\r
1520 //\r
1521 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;\r
1522 TrsTrb = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | ((UINT64)TrsTrb->Parameter2 << 32)) & ~0x0F);\r
1523 }\r
1524 }\r
1525\r
1526 ASSERT (Index != TrsRing->TrbNumber);\r
1527\r
1528 if (TrsTrb != TrsRing->RingEnqueue) {\r
1529 TrsRing->RingEnqueue = TrsTrb;\r
1530 }\r
1531\r
1532 //\r
1533 // Clear the Trb context for enqueue, but reserve the PCS bit\r
1534 //\r
1535 TrsTrb->Parameter1 = 0;\r
1536 TrsTrb->Parameter2 = 0;\r
1537 TrsTrb->Status = 0;\r
1538 TrsTrb->RsvdZ1 = 0;\r
1539 TrsTrb->Type = 0;\r
1540 TrsTrb->Control = 0;\r
1541\r
1542 return EFI_SUCCESS;\r
1543}\r
1544\r
1545/**\r
1546 Check if there is a new generated event.\r
1547\r
1548 @param Xhc The XHCI Instance.\r
1549 @param EvtRing The event ring to check.\r
1550 @param NewEvtTrb The new event TRB found.\r
1551\r
1552 @retval EFI_SUCCESS Found a new event TRB at the event ring.\r
1553 @retval EFI_NOT_READY The event ring has no new event.\r
1554\r
1555**/\r
1556EFI_STATUS\r
1557EFIAPI\r
1558XhcCheckNewEvent (\r
1559 IN USB_XHCI_INSTANCE *Xhc,\r
1560 IN EVENT_RING *EvtRing,\r
1561 OUT TRB_TEMPLATE **NewEvtTrb\r
1562 )\r
1563{\r
1564 EFI_STATUS Status;\r
1565 TRB_TEMPLATE*EvtTrb;\r
1566\r
1567 ASSERT (EvtRing != NULL);\r
1568\r
1569 EvtTrb = EvtRing->EventRingDequeue;\r
1570 *NewEvtTrb = EvtRing->EventRingDequeue;\r
1571\r
1572 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {\r
1573 return EFI_NOT_READY;\r
1574 }\r
1575\r
1576 Status = EFI_SUCCESS;\r
1577\r
1578 if (((EvtTrb->Status >> 24) & 0xFF) != TRB_COMPLETION_SUCCESS) {\r
1579 Status = EFI_DEVICE_ERROR;\r
1580 }\r
1581\r
1582 EvtRing->EventRingDequeue++;\r
1583 //\r
1584 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.\r
1585 //\r
1586 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
1587 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;\r
1588 }\r
1589\r
1590 return Status;\r
1591}\r
1592\r
1593/**\r
1594 Ring the door bell to notify XHCI there is a transaction to be executed.\r
1595\r
1596 @param Xhc The XHCI Instance.\r
1597 @param SlotId The slot id of the target device.\r
1598 @param Dci The device context index of the target slot or endpoint.\r
1599\r
1600 @retval EFI_SUCCESS Successfully ring the door bell.\r
1601\r
1602**/\r
1603EFI_STATUS\r
1604EFIAPI\r
1605XhcRingDoorBell (\r
1606 IN USB_XHCI_INSTANCE *Xhc,\r
1607 IN UINT8 SlotId,\r
1608 IN UINT8 Dci\r
1609 )\r
1610{\r
1611 if (SlotId == 0) {\r
1612 XhcWriteDoorBellReg (Xhc, 0, 0);\r
1613 } else {\r
1614 XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);\r
1615 }\r
1616\r
1617 return EFI_SUCCESS;\r
1618}\r
1619\r
1620/**\r
1621 Ring the door bell to notify XHCI there is a transaction to be executed through URB.\r
1622\r
1623 @param Xhc The XHCI Instance.\r
1624 @param Urb The URB to be rung.\r
1625\r
1626 @retval EFI_SUCCESS Successfully ring the door bell.\r
1627\r
1628**/\r
1629EFI_STATUS\r
1630RingIntTransferDoorBell (\r
1631 IN USB_XHCI_INSTANCE *Xhc,\r
1632 IN URB *Urb\r
1633 )\r
1634{\r
1635 UINT8 SlotId;\r
1636 UINT8 Dci;\r
1637\r
1638 SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);\r
1639 Dci = XhcEndpointToDci(Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
1640 XhcRingDoorBell (Xhc, SlotId, Dci);\r
1641 return EFI_SUCCESS;\r
1642}\r
1643\r
1644/**\r
1645 Assign and initialize the device slot for a new device.\r
1646\r
1647 @param Xhc The XHCI Instance.\r
1648 @param ParentRouteChart The route string pointed to the parent device.\r
1649 @param ParentPort The port at which the device is located.\r
1650 @param RouteChart The route string pointed to the device.\r
1651 @param DeviceSpeed The device speed.\r
1652\r
1653 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
1654\r
1655**/\r
1656EFI_STATUS\r
1657EFIAPI\r
1658XhcInitializeDeviceSlot (\r
1659 IN USB_XHCI_INSTANCE *Xhc,\r
1660 IN USB_DEV_ROUTE ParentRouteChart,\r
1661 IN UINT16 ParentPort,\r
1662 IN USB_DEV_ROUTE RouteChart,\r
1663 IN UINT8 DeviceSpeed\r
1664 )\r
1665{\r
1666 EFI_STATUS Status;\r
1667 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
1668 INPUT_CONTEXT *InputContext;\r
1669 DEVICE_CONTEXT *OutputContext;\r
1670 TRANSFER_RING *EndpointTransferRing;\r
1671 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
1672 UINT8 DeviceAddress;\r
1673 CMD_TRB_ENABLE_SLOT CmdTrb;\r
1674 UINT8 SlotId;\r
1675 UINT8 ParentSlotId;\r
1676 DEVICE_CONTEXT *ParentDeviceContext;\r
1677\r
1678 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
1679 CmdTrb.CycleBit = 1;\r
1680 CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
1681\r
1682 Status = XhcCmdTransfer (\r
1683 Xhc,\r
1684 (TRB_TEMPLATE *) (UINTN) &CmdTrb,\r
1685 XHC_GENERIC_TIMEOUT,\r
1686 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
1687 );\r
1688 ASSERT_EFI_ERROR (Status);\r
1689 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
1690 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
1691 SlotId = (UINT8)EvtTrb->SlotId;\r
1692 ASSERT (SlotId != 0);\r
1693\r
1694 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
1695 Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
1696 Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
1697 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
1698 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
1699\r
1700 //\r
1701 // 4.3.3 Device Slot Initialization\r
1702 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
1703 //\r
1704 InputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT)));\r
1705 ASSERT (InputContext != NULL);\r
1706 ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
1707 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
1708\r
1709 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
1710\r
1711 //\r
1712 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
1713 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
1714 // Context are affected by the command.\r
1715 //\r
1716 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
1717\r
1718 //\r
1719 // 3) Initialize the Input Slot Context data structure\r
1720 //\r
1721 InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
1722 InputContext->Slot.Speed = DeviceSpeed + 1;\r
1723 InputContext->Slot.ContextEntries = 1;\r
1724 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
1725\r
1726 if (RouteChart.Route.RouteString) {\r
1727 //\r
1728 // The device is behind of hub device.\r
1729 //\r
1730 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);\r
1731 ASSERT (ParentSlotId != 0);\r
1732 //\r
1733 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
1734 //\r
1735 ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
1736 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
1737 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
1738 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
1739 //\r
1740 // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
1741 // environment from Full/Low speed signaling environment for a device\r
1742 //\r
1743 InputContext->Slot.TTPortNum = ParentPort;\r
1744 InputContext->Slot.TTHubSlotId = ParentSlotId;\r
1745 }\r
1746 } else {\r
1747 //\r
1748 // Inherit the TT parameters from parent device.\r
1749 //\r
1750 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
1751 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
1752 //\r
1753 // If the device is a High speed device then down the speed to be the same as its parent Hub\r
1754 //\r
1755 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
1756 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
1757 }\r
1758 }\r
1759 }\r
1760\r
1761 //\r
1762 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
1763 //\r
1764 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
1765 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
1766 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
1767 //\r
1768 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
1769 //\r
1770 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
1771\r
1772 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
1773 InputContext->EP[0].MaxPacketSize = 512;\r
1774 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
1775 InputContext->EP[0].MaxPacketSize = 64;\r
1776 } else {\r
1777 InputContext->EP[0].MaxPacketSize = 8;\r
1778 }\r
1779 //\r
1780 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
1781 // 1KB, and Bulk and Isoch endpoints 3KB.\r
1782 //\r
1783 InputContext->EP[0].AverageTRBLength = 8;\r
1784 InputContext->EP[0].MaxBurstSize = 0;\r
1785 InputContext->EP[0].Interval = 0;\r
1786 InputContext->EP[0].MaxPStreams = 0;\r
1787 InputContext->EP[0].Mult = 0;\r
1788 InputContext->EP[0].CErr = 3;\r
1789\r
1790 //\r
1791 // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
1792 //\r
1793 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0) | BIT0;\r
1794 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0);\r
1795\r
1796 //\r
1797 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
1798 //\r
1799 OutputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT)));\r
1800 ASSERT (OutputContext != NULL);\r
1801 ASSERT (((UINTN) OutputContext & 0x3F) == 0);\r
1802 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));\r
1803\r
1804 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
1805 //\r
1806 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
1807 // a pointer to the Output Device Context data structure (6.2.1).\r
1808 //\r
1809 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) OutputContext;\r
1810\r
1811 //\r
1812 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
1813 // Context data structure described above.\r
1814 //\r
1815 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
1816 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (Xhc->UsbDevContext[SlotId].InputContext);\r
1817 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (Xhc->UsbDevContext[SlotId].InputContext);\r
1818 CmdTrbAddr.CycleBit = 1;\r
1819 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
1820 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
1821 Status = XhcCmdTransfer (\r
1822 Xhc,\r
1823 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,\r
1824 XHC_GENERIC_TIMEOUT,\r
1825 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
1826 );\r
1827 ASSERT (!EFI_ERROR(Status));\r
1828\r
1829 DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;\r
1830 DEBUG ((EFI_D_INFO, " Address %d assigned succeefully\n", DeviceAddress));\r
1831\r
1832 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
1833\r
1834 return Status;\r
1835}\r
1836\r
1837/**\r
1838 Disable the specified device slot.\r
1839\r
1840 @param Xhc The XHCI Instance.\r
1841 @param SlotId The slot id to be disabled.\r
1842\r
1843 @retval EFI_SUCCESS Successfully disable the device slot.\r
1844\r
1845**/\r
1846EFI_STATUS\r
1847EFIAPI\r
1848XhcDisableSlotCmd (\r
1849 IN USB_XHCI_INSTANCE *Xhc,\r
1850 IN UINT8 SlotId\r
1851 )\r
1852{\r
1853 EFI_STATUS Status;\r
1854 TRB_TEMPLATE *EvtTrb;\r
1855 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
1856 UINT8 Index;\r
1857 VOID *RingSeg;\r
1858\r
1859 //\r
1860 // Disable the device slots occupied by these devices on its downstream ports.\r
1861 // Entry 0 is reserved.\r
1862 //\r
1863 for (Index = 0; Index < 255; Index++) {\r
1864 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
1865 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
1866 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {\r
1867 continue;\r
1868 }\r
1869\r
1870 Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
1871\r
1872 if (EFI_ERROR (Status)) {\r
1873 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));\r
1874 Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
1875 }\r
1876 }\r
1877\r
1878 //\r
1879 // Construct the disable slot command\r
1880 //\r
1881 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));\r
1882\r
1883 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
1884 CmdTrbDisSlot.CycleBit = 1;\r
1885 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
1886 CmdTrbDisSlot.SlotId = SlotId;\r
1887 Status = XhcCmdTransfer (\r
1888 Xhc,\r
1889 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,\r
1890 XHC_GENERIC_TIMEOUT,\r
1891 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
1892 );\r
1893 ASSERT_EFI_ERROR(Status);\r
1894 //\r
1895 // Free the slot's device context entry\r
1896 //\r
1897 Xhc->DCBAA[SlotId] = 0;\r
1898\r
1899 //\r
1900 // Free the slot related data structure\r
1901 //\r
1902 for (Index = 0; Index < 31; Index++) {\r
1903 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
1904 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
1905 if (RingSeg != NULL) {\r
1906 FreePages (RingSeg, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER));\r
1907 }\r
1908 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
1909 }\r
1910 }\r
1911\r
1912 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
1913 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
1914 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
1915 }\r
1916 }\r
1917\r
1918 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
1919 FreePages (Xhc->UsbDevContext[SlotId].InputContext, EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT)));\r
1920 }\r
1921\r
1922 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
1923 FreePages (Xhc->UsbDevContext[SlotId].OutputContext, EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT)));\r
1924 }\r
1925 //\r
1926 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
1927 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
1928 // remove urb from XHCI's asynchronous transfer list.\r
1929 //\r
1930 Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
1931\r
1932 return Status;\r
1933}\r
1934\r
1935/**\r
1936 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
1937\r
1938 @param Xhc The XHCI Instance.\r
1939 @param SlotId The slot id to be configured.\r
1940 @param DeviceSpeed The device's speed.\r
1941 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
1942\r
1943 @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
1944\r
1945**/\r
1946EFI_STATUS\r
1947EFIAPI\r
1948XhcSetConfigCmd (\r
1949 IN USB_XHCI_INSTANCE *Xhc,\r
1950 IN UINT8 SlotId,\r
1951 IN UINT8 DeviceSpeed,\r
1952 IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
1953 )\r
1954{\r
1955 EFI_STATUS Status;\r
1956\r
1957 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
1958 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
1959 UINT8 Index;\r
1960 UINTN NumEp;\r
1961 UINTN EpIndex;\r
1962 UINT8 EpAddr;\r
1963 UINT8 Direction;\r
1964 UINT8 Dci;\r
1965 UINT8 MaxDci;\r
1966 UINT32 PhyAddr;\r
1967 UINT8 Interval;\r
1968\r
1969 TRANSFER_RING *EndpointTransferRing;\r
1970 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
1971 INPUT_CONTEXT *InputContext;\r
1972 DEVICE_CONTEXT *OutputContext;\r
1973 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
1974 //\r
1975 // 4.6.6 Configure Endpoint\r
1976 //\r
1977 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
1978 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
1979 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
1980 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));\r
1981\r
1982 ASSERT (ConfigDesc != NULL);\r
1983\r
1984 MaxDci = 0;\r
1985\r
1986 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
1987 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
1988 while (IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) {\r
1989 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
1990 }\r
1991\r
1992 NumEp = IfDesc->NumEndpoints;\r
1993\r
1994 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
1995 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
1996 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
1997 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
1998 }\r
1999\r
2000 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
2001 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
2002\r
2003 Dci = XhcEndpointToDci (EpAddr, Direction);\r
2004 ASSERT (Dci < 32);\r
2005 if (Dci > MaxDci) {\r
2006 MaxDci = Dci;\r
2007 }\r
2008\r
2009 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
2010 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
2011\r
2012 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2013 //\r
2014 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
2015 //\r
2016 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2017 } else {\r
2018 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2019 }\r
2020\r
2021 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
2022 case USB_ENDPOINT_BULK:\r
2023 if (Direction == EfiUsbDataIn) {\r
2024 InputContext->EP[Dci-1].CErr = 3;\r
2025 InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
2026 } else {\r
2027 InputContext->EP[Dci-1].CErr = 3;\r
2028 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
2029 }\r
2030\r
2031 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2032 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2033 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2034 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2035 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
2036 }\r
2037\r
2038 break;\r
2039 case USB_ENDPOINT_ISO:\r
2040 if (Direction == EfiUsbDataIn) {\r
2041 InputContext->EP[Dci-1].CErr = 0;\r
2042 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
2043 } else {\r
2044 InputContext->EP[Dci-1].CErr = 0;\r
2045 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
2046 }\r
2047 break;\r
2048 case USB_ENDPOINT_INTERRUPT:\r
2049 if (Direction == EfiUsbDataIn) {\r
2050 InputContext->EP[Dci-1].CErr = 3;\r
2051 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
2052 } else {\r
2053 InputContext->EP[Dci-1].CErr = 3;\r
2054 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
2055 }\r
2056 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2057 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
2058 //\r
2059 // Get the bInterval from descriptor and init the the interval field of endpoint context\r
2060 //\r
2061 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
2062 Interval = EpDesc->Interval;\r
2063 //\r
2064 // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.\r
2065 //\r
2066 InputContext->EP[Dci-1].Interval = 6;\r
2067 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2068 Interval = EpDesc->Interval;\r
2069 ASSERT (Interval >= 1 && Interval <= 16);\r
2070 //\r
2071 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
2072 //\r
2073 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2074 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2075 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;\r
2076 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2077 InputContext->EP[Dci-1].CErr = 3;\r
2078 }\r
2079\r
2080 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2081 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2082 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2083 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
2084 }\r
2085 break;\r
2086\r
2087 case USB_ENDPOINT_CONTROL:\r
2088 default:\r
2089 ASSERT (0);\r
2090 break;\r
2091 }\r
2092\r
2093 PhyAddr = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);\r
2094 PhyAddr &= ~(0x0F);\r
2095 PhyAddr |= ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
2096 InputContext->EP[Dci-1].PtrLo = PhyAddr;\r
2097 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);\r
2098\r
2099 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2100 }\r
2101 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
2102 }\r
2103\r
2104 InputContext->InputControlContext.Dword2 |= BIT0;\r
2105 InputContext->Slot.ContextEntries = MaxDci;\r
2106 //\r
2107 // configure endpoint\r
2108 //\r
2109 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
2110 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext);\r
2111 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext);\r
2112 CmdTrbCfgEP.CycleBit = 1;\r
2113 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
2114 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
2115 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));\r
2116 Status = XhcCmdTransfer (\r
2117 Xhc,\r
2118 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
2119 XHC_GENERIC_TIMEOUT,\r
2120 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2121 );\r
2122 ASSERT_EFI_ERROR(Status);\r
2123\r
2124 return Status;\r
2125}\r
2126\r
2127/**\r
2128 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
2129\r
2130 @param Xhc The XHCI Instance.\r
2131 @param SlotId The slot id to be evaluated.\r
2132 @param MaxPacketSize The max packet size supported by the device control transfer.\r
2133\r
2134 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
2135\r
2136**/\r
2137EFI_STATUS\r
2138EFIAPI\r
2139XhcEvaluateContext (\r
2140 IN USB_XHCI_INSTANCE *Xhc,\r
2141 IN UINT8 SlotId,\r
2142 IN UINT32 MaxPacketSize\r
2143 )\r
2144{\r
2145 EFI_STATUS Status;\r
2146 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
2147 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2148 INPUT_CONTEXT *InputContext;\r
2149\r
2150 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
2151\r
2152 //\r
2153 // 4.6.7 Evaluate Context\r
2154 //\r
2155 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
2156 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
2157\r
2158 InputContext->InputControlContext.Dword2 |= BIT1;\r
2159 InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
2160\r
2161 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
2162 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (InputContext);\r
2163 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (InputContext);\r
2164 CmdTrbEvalu.CycleBit = 1;\r
2165 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
2166 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
2167 DEBUG ((EFI_D_INFO, "Evaluate context\n"));\r
2168 Status = XhcCmdTransfer (\r
2169 Xhc,\r
2170 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,\r
2171 XHC_GENERIC_TIMEOUT,\r
2172 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2173 );\r
2174 ASSERT (!EFI_ERROR(Status));\r
2175\r
2176 return Status;\r
2177}\r
2178\r
2179/**\r
2180 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
2181\r
2182 @param Xhc The XHCI Instance.\r
2183 @param SlotId The slot id to be configured.\r
2184 @param PortNum The total number of downstream port supported by the hub.\r
2185 @param TTT The TT think time of the hub device.\r
2186 @param MTT The multi-TT of the hub device.\r
2187\r
2188 @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
2189\r
2190**/\r
2191EFI_STATUS\r
2192XhcConfigHubContext (\r
2193 IN USB_XHCI_INSTANCE *Xhc,\r
2194 IN UINT8 SlotId,\r
2195 IN UINT8 PortNum,\r
2196 IN UINT8 TTT,\r
2197 IN UINT8 MTT\r
2198 )\r
2199{\r
2200 EFI_STATUS Status;\r
2201\r
2202 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2203 INPUT_CONTEXT *InputContext;\r
2204 DEVICE_CONTEXT *OutputContext;\r
2205 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
2206\r
2207 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
2208 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
2209 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
2210\r
2211 //\r
2212 // 4.6.7 Evaluate Context\r
2213 //\r
2214 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
2215\r
2216 InputContext->InputControlContext.Dword2 |= BIT0;\r
2217\r
2218 //\r
2219 // Copy the slot context from OutputContext to Input context\r
2220 //\r
2221 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));\r
2222 InputContext->Slot.Hub = 1;\r
2223 InputContext->Slot.PortNum = PortNum;\r
2224 InputContext->Slot.TTT = TTT;\r
2225 InputContext->Slot.MTT = MTT;\r
2226\r
2227 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
2228 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext);\r
2229 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext);\r
2230 CmdTrbCfgEP.CycleBit = 1;\r
2231 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
2232 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
2233 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));\r
2234 Status = XhcCmdTransfer (\r
2235 Xhc,\r
2236 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
2237 XHC_GENERIC_TIMEOUT,\r
2238 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2239 );\r
2240 ASSERT (!EFI_ERROR(Status));\r
2241\r
2242 return Status;\r
2243}\r
2244\r