]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
MdeModulePkg: Change use of EFI_D_* to DEBUG_*
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / XhciSched.c
CommitLineData
92870c98 1/** @file\r
2\r
3 XHCI transfer scheduling routines.\r
4\r
a3212009 5Copyright (c) 2011 - 2020, Intel Corporation. All rights reserved.<BR>\r
dc528558 6Copyright (c) Microsoft Corporation.<BR>\r
9d510e61 7SPDX-License-Identifier: BSD-2-Clause-Patent\r
92870c98 8\r
9**/\r
10\r
11#include "Xhci.h"\r
12\r
92870c98 13/**\r
14 Create a command transfer TRB to support XHCI command interfaces.\r
15\r
a9292c13 16 @param Xhc The XHCI Instance.\r
92870c98 17 @param CmdTrb The cmd TRB to be executed.\r
18\r
19 @return Created URB or NULL.\r
20\r
21**/\r
22URB*\r
23XhcCreateCmdTrb (\r
a9292c13 24 IN USB_XHCI_INSTANCE *Xhc,\r
25 IN TRB_TEMPLATE *CmdTrb\r
92870c98 26 )\r
27{\r
28 URB *Urb;\r
29\r
30 Urb = AllocateZeroPool (sizeof (URB));\r
31 if (Urb == NULL) {\r
32 return NULL;\r
33 }\r
34\r
35 Urb->Signature = XHC_URB_SIG;\r
36\r
37 Urb->Ring = &Xhc->CmdRing;\r
38 XhcSyncTrsRing (Xhc, Urb->Ring);\r
39 Urb->TrbNum = 1;\r
40 Urb->TrbStart = Urb->Ring->RingEnqueue;\r
a9292c13 41 CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));\r
92870c98 42 Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;\r
43 Urb->TrbEnd = Urb->TrbStart;\r
44\r
92870c98 45 return Urb;\r
46}\r
47\r
48/**\r
49 Execute a XHCI cmd TRB pointed by CmdTrb.\r
50\r
a9292c13 51 @param Xhc The XHCI Instance.\r
92870c98 52 @param CmdTrb The cmd TRB to be executed.\r
a9292c13 53 @param Timeout Indicates the maximum time, in millisecond, which the\r
92870c98 54 transfer is allowed to complete.\r
55 @param EvtTrb The event TRB corresponding to the cmd TRB.\r
56\r
57 @retval EFI_SUCCESS The transfer was completed successfully.\r
58 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
59 @retval EFI_TIMEOUT The transfer failed due to timeout.\r
60 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
61\r
62**/\r
63EFI_STATUS\r
64EFIAPI\r
65XhcCmdTransfer (\r
a9292c13 66 IN USB_XHCI_INSTANCE *Xhc,\r
67 IN TRB_TEMPLATE *CmdTrb,\r
68 IN UINTN Timeout,\r
69 OUT TRB_TEMPLATE **EvtTrb\r
92870c98 70 )\r
71{\r
72 EFI_STATUS Status;\r
73 URB *Urb;\r
74\r
75 //\r
76 // Validate the parameters\r
77 //\r
78 if ((Xhc == NULL) || (CmdTrb == NULL)) {\r
79 return EFI_INVALID_PARAMETER;\r
80 }\r
81\r
82 Status = EFI_DEVICE_ERROR;\r
83\r
84 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
87000d77 85 DEBUG ((DEBUG_ERROR, "XhcCmdTransfer: HC is halted\n"));\r
92870c98 86 goto ON_EXIT;\r
87 }\r
88\r
89 //\r
90 // Create a new URB, then poll the execution status.\r
91 //\r
92 Urb = XhcCreateCmdTrb (Xhc, CmdTrb);\r
93\r
94 if (Urb == NULL) {\r
87000d77 95 DEBUG ((DEBUG_ERROR, "XhcCmdTransfer: failed to create URB\n"));\r
92870c98 96 Status = EFI_OUT_OF_RESOURCES;\r
97 goto ON_EXIT;\r
98 }\r
99\r
a9292c13 100 Status = XhcExecTransfer (Xhc, TRUE, Urb, Timeout);\r
a50f7c4c 101 *EvtTrb = Urb->EvtTrb;\r
92870c98 102\r
103 if (Urb->Result == EFI_USB_NOERROR) {\r
104 Status = EFI_SUCCESS;\r
105 }\r
106\r
1847ed0b 107 XhcFreeUrb (Xhc, Urb);\r
92870c98 108\r
109ON_EXIT:\r
110 return Status;\r
111}\r
112\r
113/**\r
114 Create a new URB for a new transaction.\r
115\r
d98fc9ad
SZ
116 @param Xhc The XHCI Instance\r
117 @param BusAddr The logical device address assigned by UsbBus driver\r
118 @param EpAddr Endpoint addrress\r
119 @param DevSpeed The device speed\r
120 @param MaxPacket The max packet length of the endpoint\r
121 @param Type The transaction type\r
122 @param Request The standard USB request for control transfer\r
123 @param Data The user data to transfer\r
124 @param DataLen The length of data buffer\r
125 @param Callback The function to call when data is transferred\r
126 @param Context The context to the callback\r
92870c98 127\r
128 @return Created URB or NULL\r
129\r
130**/\r
131URB*\r
132XhcCreateUrb (\r
a9292c13 133 IN USB_XHCI_INSTANCE *Xhc,\r
6b4483cd 134 IN UINT8 BusAddr,\r
92870c98 135 IN UINT8 EpAddr,\r
136 IN UINT8 DevSpeed,\r
137 IN UINTN MaxPacket,\r
138 IN UINTN Type,\r
139 IN EFI_USB_DEVICE_REQUEST *Request,\r
140 IN VOID *Data,\r
141 IN UINTN DataLen,\r
142 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
143 IN VOID *Context\r
144 )\r
145{\r
146 USB_ENDPOINT *Ep;\r
147 EFI_STATUS Status;\r
148 URB *Urb;\r
149\r
150 Urb = AllocateZeroPool (sizeof (URB));\r
151 if (Urb == NULL) {\r
152 return NULL;\r
153 }\r
154\r
155 Urb->Signature = XHC_URB_SIG;\r
156 InitializeListHead (&Urb->UrbList);\r
157\r
158 Ep = &Urb->Ep;\r
6b4483cd 159 Ep->BusAddr = BusAddr;\r
ce9b5900 160 Ep->EpAddr = (UINT8)(EpAddr & 0x0F);\r
92870c98 161 Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
162 Ep->DevSpeed = DevSpeed;\r
163 Ep->MaxPacket = MaxPacket;\r
164 Ep->Type = Type;\r
165\r
166 Urb->Request = Request;\r
167 Urb->Data = Data;\r
168 Urb->DataLen = DataLen;\r
169 Urb->Callback = Callback;\r
170 Urb->Context = Context;\r
171\r
172 Status = XhcCreateTransferTrb (Xhc, Urb);\r
7538d536 173 ASSERT_EFI_ERROR (Status);\r
260fbf53 174 if (EFI_ERROR (Status)) {\r
87000d77 175 DEBUG ((DEBUG_ERROR, "XhcCreateUrb: XhcCreateTransferTrb Failed, Status = %r\n", Status));\r
d98fc9ad 176 FreePool (Urb);\r
260fbf53
EL
177 Urb = NULL;\r
178 }\r
92870c98 179\r
180 return Urb;\r
181}\r
182\r
1847ed0b
EL
183/**\r
184 Free an allocated URB.\r
185\r
186 @param Xhc The XHCI device.\r
187 @param Urb The URB to free.\r
188\r
189**/\r
190VOID\r
191XhcFreeUrb (\r
192 IN USB_XHCI_INSTANCE *Xhc,\r
193 IN URB *Urb\r
194 )\r
195{\r
196 if ((Xhc == NULL) || (Urb == NULL)) {\r
197 return;\r
198 }\r
d1102dba 199\r
1847ed0b
EL
200 if (Urb->DataMap != NULL) {\r
201 Xhc->PciIo->Unmap (Xhc->PciIo, Urb->DataMap);\r
202 }\r
203\r
204 FreePool (Urb);\r
205}\r
206\r
92870c98 207/**\r
208 Create a transfer TRB.\r
209\r
a9292c13 210 @param Xhc The XHCI Instance\r
92870c98 211 @param Urb The urb used to construct the transfer TRB.\r
212\r
213 @return Created TRB or NULL\r
214\r
215**/\r
216EFI_STATUS\r
92870c98 217XhcCreateTransferTrb (\r
a9292c13 218 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 219 IN URB *Urb\r
220 )\r
221{\r
6b4483cd 222 VOID *OutputContext;\r
92870c98 223 TRANSFER_RING *EPRing;\r
224 UINT8 EPType;\r
225 UINT8 SlotId;\r
226 UINT8 Dci;\r
227 TRB *TrbStart;\r
228 UINTN TotalLen;\r
229 UINTN Len;\r
230 UINTN TrbNum;\r
1847ed0b
EL
231 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
232 EFI_PHYSICAL_ADDRESS PhyAddr;\r
233 VOID *Map;\r
234 EFI_STATUS Status;\r
92870c98 235\r
6b4483cd 236 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
237 if (SlotId == 0) {\r
238 return EFI_DEVICE_ERROR;\r
239 }\r
240\r
a50f7c4c 241 Urb->Finished = FALSE;\r
242 Urb->StartDone = FALSE;\r
243 Urb->EndDone = FALSE;\r
244 Urb->Completed = 0;\r
245 Urb->Result = EFI_USB_NOERROR;\r
246\r
ce9b5900 247 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
a9292c13 248 ASSERT (Dci < 32);\r
249 EPRing = (TRANSFER_RING *)(UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];\r
92870c98 250 Urb->Ring = EPRing;\r
1847ed0b 251 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
6b4483cd 252 if (Xhc->HcCParams.Data.Csz == 0) {\r
253 EPType = (UINT8) ((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType;\r
254 } else {\r
255 EPType = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;\r
256 }\r
0b9c0c65
SZ
257\r
258 //\r
259 // No need to remap.\r
260 //\r
261 if ((Urb->Data != NULL) && (Urb->DataMap == NULL)) {\r
d98fc9ad
SZ
262 if (((UINT8) (Urb->Ep.Direction)) == EfiUsbDataIn) {\r
263 MapOp = EfiPciIoOperationBusMasterWrite;\r
1847ed0b 264 } else {\r
d98fc9ad 265 MapOp = EfiPciIoOperationBusMasterRead;\r
1847ed0b 266 }\r
d1102dba 267\r
1847ed0b
EL
268 Len = Urb->DataLen;\r
269 Status = Xhc->PciIo->Map (Xhc->PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);\r
d1102dba 270\r
1847ed0b 271 if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {\r
87000d77 272 DEBUG ((DEBUG_ERROR, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));\r
1847ed0b
EL
273 return EFI_OUT_OF_RESOURCES;\r
274 }\r
d1102dba 275\r
1847ed0b
EL
276 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);\r
277 Urb->DataMap = Map;\r
278 }\r
92870c98 279\r
280 //\r
281 // Construct the TRB\r
282 //\r
283 XhcSyncTrsRing (Xhc, EPRing);\r
284 Urb->TrbStart = EPRing->RingEnqueue;\r
285 switch (EPType) {\r
286 case ED_CONTROL_BIDIR:\r
92870c98 287 //\r
288 // For control transfer, create SETUP_STAGE_TRB first.\r
289 //\r
a9292c13 290 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
291 TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;\r
292 TrbStart->TrbCtrSetup.bRequest = Urb->Request->Request;\r
293 TrbStart->TrbCtrSetup.wValue = Urb->Request->Value;\r
294 TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index;\r
295 TrbStart->TrbCtrSetup.wLength = Urb->Request->Length;\r
39e97c39 296 TrbStart->TrbCtrSetup.Length = 8;\r
6b4483cd 297 TrbStart->TrbCtrSetup.IntTarget = 0;\r
a9292c13 298 TrbStart->TrbCtrSetup.IOC = 1;\r
299 TrbStart->TrbCtrSetup.IDT = 1;\r
300 TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE;\r
b5379899
WX
301 if (Urb->DataLen > 0) {\r
302 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
303 TrbStart->TrbCtrSetup.TRT = 3;\r
304 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
305 TrbStart->TrbCtrSetup.TRT = 2;\r
306 } else {\r
307 DEBUG ((DEBUG_ERROR, "XhcCreateTransferTrb: Direction sholud be IN or OUT when Data exists!\n"));\r
308 ASSERT (FALSE);\r
309 }\r
92870c98 310 } else {\r
a9292c13 311 TrbStart->TrbCtrSetup.TRT = 0;\r
92870c98 312 }\r
313 //\r
314 // Update the cycle bit\r
315 //\r
a9292c13 316 TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;\r
92870c98 317 Urb->TrbNum++;\r
318\r
319 //\r
320 // For control transfer, create DATA_STAGE_TRB.\r
321 //\r
322 if (Urb->DataLen > 0) {\r
323 XhcSyncTrsRing (Xhc, EPRing);\r
a9292c13 324 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
1847ed0b
EL
325 TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT(Urb->DataPhy);\r
326 TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT(Urb->DataPhy);\r
39e97c39 327 TrbStart->TrbCtrData.Length = (UINT32) Urb->DataLen;\r
a9292c13 328 TrbStart->TrbCtrData.TDSize = 0;\r
6b4483cd 329 TrbStart->TrbCtrData.IntTarget = 0;\r
a9292c13 330 TrbStart->TrbCtrData.ISP = 1;\r
331 TrbStart->TrbCtrData.IOC = 1;\r
332 TrbStart->TrbCtrData.IDT = 0;\r
333 TrbStart->TrbCtrData.CH = 0;\r
334 TrbStart->TrbCtrData.Type = TRB_TYPE_DATA_STAGE;\r
92870c98 335 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
a9292c13 336 TrbStart->TrbCtrData.DIR = 1;\r
92870c98 337 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
a9292c13 338 TrbStart->TrbCtrData.DIR = 0;\r
92870c98 339 } else {\r
a9292c13 340 TrbStart->TrbCtrData.DIR = 0;\r
92870c98 341 }\r
342 //\r
343 // Update the cycle bit\r
344 //\r
a9292c13 345 TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;\r
92870c98 346 Urb->TrbNum++;\r
347 }\r
348 //\r
349 // For control transfer, create STATUS_STAGE_TRB.\r
350 // Get the pointer to next TRB for status stage use\r
351 //\r
352 XhcSyncTrsRing (Xhc, EPRing);\r
a9292c13 353 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
6b4483cd 354 TrbStart->TrbCtrStatus.IntTarget = 0;\r
a9292c13 355 TrbStart->TrbCtrStatus.IOC = 1;\r
356 TrbStart->TrbCtrStatus.CH = 0;\r
357 TrbStart->TrbCtrStatus.Type = TRB_TYPE_STATUS_STAGE;\r
92870c98 358 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
a9292c13 359 TrbStart->TrbCtrStatus.DIR = 0;\r
92870c98 360 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
a9292c13 361 TrbStart->TrbCtrStatus.DIR = 1;\r
92870c98 362 } else {\r
a9292c13 363 TrbStart->TrbCtrStatus.DIR = 0;\r
92870c98 364 }\r
365 //\r
366 // Update the cycle bit\r
367 //\r
a9292c13 368 TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;\r
92870c98 369 //\r
370 // Update the enqueue pointer\r
371 //\r
372 XhcSyncTrsRing (Xhc, EPRing);\r
373 Urb->TrbNum++;\r
a9292c13 374 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
92870c98 375\r
376 break;\r
377\r
378 case ED_BULK_OUT:\r
379 case ED_BULK_IN:\r
92870c98 380 TotalLen = 0;\r
381 Len = 0;\r
382 TrbNum = 0;\r
a9292c13 383 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
92870c98 384 while (TotalLen < Urb->DataLen) {\r
385 if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
386 Len = Urb->DataLen - TotalLen;\r
387 } else {\r
388 Len = 0x10000;\r
389 }\r
a9292c13 390 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
1847ed0b
EL
391 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
392 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
39e97c39 393 TrbStart->TrbNormal.Length = (UINT32) Len;\r
a9292c13 394 TrbStart->TrbNormal.TDSize = 0;\r
6b4483cd 395 TrbStart->TrbNormal.IntTarget = 0;\r
a9292c13 396 TrbStart->TrbNormal.ISP = 1;\r
397 TrbStart->TrbNormal.IOC = 1;\r
398 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;\r
92870c98 399 //\r
400 // Update the cycle bit\r
401 //\r
a9292c13 402 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
92870c98 403\r
404 XhcSyncTrsRing (Xhc, EPRing);\r
405 TrbNum++;\r
406 TotalLen += Len;\r
407 }\r
408\r
409 Urb->TrbNum = TrbNum;\r
a9292c13 410 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
92870c98 411 break;\r
412\r
413 case ED_INTERRUPT_OUT:\r
414 case ED_INTERRUPT_IN:\r
92870c98 415 TotalLen = 0;\r
416 Len = 0;\r
417 TrbNum = 0;\r
a9292c13 418 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
92870c98 419 while (TotalLen < Urb->DataLen) {\r
420 if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
421 Len = Urb->DataLen - TotalLen;\r
422 } else {\r
423 Len = 0x10000;\r
424 }\r
a9292c13 425 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
1847ed0b
EL
426 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
427 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
39e97c39 428 TrbStart->TrbNormal.Length = (UINT32) Len;\r
a9292c13 429 TrbStart->TrbNormal.TDSize = 0;\r
6b4483cd 430 TrbStart->TrbNormal.IntTarget = 0;\r
a9292c13 431 TrbStart->TrbNormal.ISP = 1;\r
432 TrbStart->TrbNormal.IOC = 1;\r
433 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;\r
92870c98 434 //\r
435 // Update the cycle bit\r
436 //\r
a9292c13 437 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
92870c98 438\r
439 XhcSyncTrsRing (Xhc, EPRing);\r
440 TrbNum++;\r
441 TotalLen += Len;\r
442 }\r
443\r
444 Urb->TrbNum = TrbNum;\r
a9292c13 445 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
92870c98 446 break;\r
447\r
448 default:\r
87000d77 449 DEBUG ((DEBUG_INFO, "Not supported EPType 0x%x!\n",EPType));\r
92870c98 450 ASSERT (FALSE);\r
451 break;\r
452 }\r
453\r
454 return EFI_SUCCESS;\r
455}\r
456\r
457\r
458/**\r
459 Initialize the XHCI host controller for schedule.\r
460\r
a9292c13 461 @param Xhc The XHCI Instance to be initialized.\r
92870c98 462\r
463**/\r
464VOID\r
465XhcInitSched (\r
a9292c13 466 IN USB_XHCI_INSTANCE *Xhc\r
92870c98 467 )\r
468{\r
469 VOID *Dcbaa;\r
1847ed0b 470 EFI_PHYSICAL_ADDRESS DcbaaPhy;\r
92870c98 471 UINT64 CmdRing;\r
d1102dba 472 EFI_PHYSICAL_ADDRESS CmdRingPhy;\r
92870c98 473 UINTN Entries;\r
474 UINT32 MaxScratchpadBufs;\r
475 UINT64 *ScratchBuf;\r
1847ed0b
EL
476 EFI_PHYSICAL_ADDRESS ScratchPhy;\r
477 UINT64 *ScratchEntry;\r
478 EFI_PHYSICAL_ADDRESS ScratchEntryPhy;\r
92870c98 479 UINT32 Index;\r
1847ed0b
EL
480 UINTN *ScratchEntryMap;\r
481 EFI_STATUS Status;\r
482\r
483 //\r
484 // Initialize memory management.\r
485 //\r
486 Xhc->MemPool = UsbHcInitMemPool (Xhc->PciIo);\r
487 ASSERT (Xhc->MemPool != NULL);\r
92870c98 488\r
489 //\r
490 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)\r
491 // to enable the device slots that system software is going to use.\r
492 //\r
493 Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;\r
494 ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);\r
495 XhcWriteOpReg (Xhc, XHC_CONFIG_OFFSET, Xhc->MaxSlotsEn);\r
496\r
497 //\r
498 // The Device Context Base Address Array entry associated with each allocated Device Slot\r
499 // shall contain a 64-bit pointer to the base of the associated Device Context.\r
500 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.\r
501 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.\r
502 //\r
503 Entries = (Xhc->MaxSlotsEn + 1) * sizeof(UINT64);\r
1847ed0b 504 Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Entries);\r
92870c98 505 ASSERT (Dcbaa != NULL);\r
a9292c13 506 ZeroMem (Dcbaa, Entries);\r
92870c98 507\r
508 //\r
509 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.\r
510 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run\r
511 // mode (Run/Stop(R/S) ='1').\r
512 //\r
513 MaxScratchpadBufs = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);\r
514 Xhc->MaxScratchpadBufs = MaxScratchpadBufs;\r
ce9b5900 515 ASSERT (MaxScratchpadBufs <= 1023);\r
92870c98 516 if (MaxScratchpadBufs != 0) {\r
1847ed0b
EL
517 //\r
518 // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them\r
519 //\r
520 ScratchEntryMap = AllocateZeroPool (sizeof (UINTN) * MaxScratchpadBufs);\r
521 ASSERT (ScratchEntryMap != NULL);\r
522 Xhc->ScratchEntryMap = ScratchEntryMap;\r
d1102dba 523\r
1847ed0b
EL
524 //\r
525 // Allocate the buffer to record the host address for each entry\r
526 //\r
527 ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);\r
528 ASSERT (ScratchEntry != NULL);\r
529 Xhc->ScratchEntry = ScratchEntry;\r
530\r
414f5bd1 531 ScratchPhy = 0;\r
1847ed0b
EL
532 Status = UsbHcAllocateAlignedPages (\r
533 Xhc->PciIo,\r
534 EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),\r
535 Xhc->PageSize,\r
d1102dba 536 (VOID **) &ScratchBuf,\r
1847ed0b
EL
537 &ScratchPhy,\r
538 &Xhc->ScratchMap\r
539 );\r
540 ASSERT_EFI_ERROR (Status);\r
541\r
a9292c13 542 ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));\r
92870c98 543 Xhc->ScratchBuf = ScratchBuf;\r
544\r
1847ed0b
EL
545 //\r
546 // Allocate each scratch buffer\r
547 //\r
92870c98 548 for (Index = 0; Index < MaxScratchpadBufs; Index++) {\r
414f5bd1 549 ScratchEntryPhy = 0;\r
1847ed0b
EL
550 Status = UsbHcAllocateAlignedPages (\r
551 Xhc->PciIo,\r
552 EFI_SIZE_TO_PAGES (Xhc->PageSize),\r
553 Xhc->PageSize,\r
554 (VOID **) &ScratchEntry[Index],\r
555 &ScratchEntryPhy,\r
556 (VOID **) &ScratchEntryMap[Index]\r
557 );\r
558 ASSERT_EFI_ERROR (Status);\r
559 ZeroMem ((VOID *)(UINTN)ScratchEntry[Index], Xhc->PageSize);\r
560 //\r
561 // Fill with the PCI device address\r
562 //\r
563 *ScratchBuf++ = ScratchEntryPhy;\r
92870c98 564 }\r
92870c98 565 //\r
566 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the\r
567 // Device Context Base Address Array points to the Scratchpad Buffer Array.\r
568 //\r
1847ed0b 569 *(UINT64 *)Dcbaa = (UINT64)(UINTN) ScratchPhy;\r
92870c98 570 }\r
571\r
572 //\r
573 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with\r
574 // a 64-bit address pointing to where the Device Context Base Address Array is located.\r
575 //\r
a9292c13 576 Xhc->DCBAA = (UINT64 *)(UINTN)Dcbaa;\r
6b4483cd 577 //\r
578 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
579 // So divide it to two 32-bytes width register access.\r
580 //\r
1847ed0b
EL
581 DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Entries);\r
582 XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT(DcbaaPhy));\r
583 XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));\r
584\r
87000d77 585 DEBUG ((DEBUG_INFO, "XhcInitSched:DCBAA=0x%x\n", (UINT64)(UINTN)Xhc->DCBAA));\r
92870c98 586\r
587 //\r
588 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register\r
589 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.\r
590 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall\r
591 // always be '0'.\r
592 //\r
593 CreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);\r
594 //\r
595 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a\r
596 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.\r
597 // So we set RCS as inverted PCS init value to let Command Ring empty\r
598 //\r
599 CmdRing = (UINT64)(UINTN)Xhc->CmdRing.RingSeg0;\r
1847ed0b
EL
600 CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, (VOID *)(UINTN) CmdRing, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
601 ASSERT ((CmdRingPhy & 0x3F) == 0);\r
602 CmdRingPhy |= XHC_CRCR_RCS;\r
6b4483cd 603 //\r
604 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
605 // So divide it to two 32-bytes width register access.\r
606 //\r
1847ed0b
EL
607 XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT(CmdRingPhy));\r
608 XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));\r
92870c98 609\r
92870c98 610 //\r
611 // Disable the 'interrupter enable' bit in USB_CMD\r
612 // and clear IE & IP bit in all Interrupter X Management Registers.\r
613 //\r
614 XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);\r
615 for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {\r
616 XhcClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);\r
617 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);\r
618 }\r
619\r
620 //\r
621 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer\r
622 //\r
6b4483cd 623 CreateEventRing (Xhc, &Xhc->EventRing);\r
396ae94d
RN
624 DEBUG ((DEBUG_INFO, "XhcInitSched: Created CMD ring [%p~%p) EVENT ring [%p~%p)\n",\r
625 Xhc->CmdRing.RingSeg0, (UINTN)Xhc->CmdRing.RingSeg0 + sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER,\r
626 Xhc->EventRing.EventRingSeg0, (UINTN)Xhc->EventRing.EventRingSeg0 + sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER\r
627 ));\r
92870c98 628}\r
629\r
630/**\r
631 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted\r
632 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint\r
633 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is\r
634 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the\r
635 Stopped to the Running state.\r
636\r
a9292c13 637 @param Xhc The XHCI Instance.\r
92870c98 638 @param Urb The urb which makes the endpoint halted.\r
639\r
640 @retval EFI_SUCCESS The recovery is successful.\r
641 @retval Others Failed to recovery halted endpoint.\r
642\r
643**/\r
644EFI_STATUS\r
645EFIAPI\r
646XhcRecoverHaltedEndpoint (\r
a9292c13 647 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 648 IN URB *Urb\r
649 )\r
650{\r
a9292c13 651 EFI_STATUS Status;\r
a9292c13 652 UINT8 Dci;\r
653 UINT8 SlotId;\r
92870c98 654\r
6b4483cd 655 Status = EFI_SUCCESS;\r
656 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
657 if (SlotId == 0) {\r
658 return EFI_DEVICE_ERROR;\r
659 }\r
660 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
661 ASSERT (Dci < 32);\r
d1102dba 662\r
87000d77 663 DEBUG ((DEBUG_INFO, "Recovery Halted Slot = %x,Dci = %x\n", SlotId, Dci));\r
92870c98 664\r
665 //\r
666 // 1) Send Reset endpoint command to transit from halt to stop state\r
667 //\r
12e6c738 668 Status = XhcResetEndpoint(Xhc, SlotId, Dci);\r
260fbf53 669 if (EFI_ERROR(Status)) {\r
87000d77 670 DEBUG ((DEBUG_ERROR, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
260fbf53
EL
671 goto Done;\r
672 }\r
92870c98 673\r
674 //\r
675 // 2)Set dequeue pointer\r
676 //\r
12e6c738
FT
677 Status = XhcSetTrDequeuePointer(Xhc, SlotId, Dci, Urb);\r
678 if (EFI_ERROR(Status)) {\r
87000d77 679 DEBUG ((DEBUG_ERROR, "XhcRecoverHaltedEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status));\r
12e6c738
FT
680 goto Done;\r
681 }\r
682\r
683 //\r
684 // 3)Ring the doorbell to transit from stop to active\r
685 //\r
686 XhcRingDoorBell (Xhc, SlotId, Dci);\r
687\r
688Done:\r
689 return Status;\r
690}\r
691\r
692/**\r
693 System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer\r
694 Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to\r
695 the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running\r
696 state.\r
697\r
698 @param Xhc The XHCI Instance.\r
699 @param Urb The urb which doesn't get completed in a specified timeout range.\r
700\r
701 @retval EFI_SUCCESS The dequeuing of the TDs is successful.\r
49be9c3c 702 @retval EFI_ALREADY_STARTED The Urb is finished so no deque is needed.\r
12e6c738
FT
703 @retval Others Failed to stop the endpoint and dequeue the TDs.\r
704\r
705**/\r
706EFI_STATUS\r
707EFIAPI\r
708XhcDequeueTrbFromEndpoint (\r
709 IN USB_XHCI_INSTANCE *Xhc,\r
710 IN URB *Urb\r
711 )\r
712{\r
713 EFI_STATUS Status;\r
714 UINT8 Dci;\r
715 UINT8 SlotId;\r
716\r
717 Status = EFI_SUCCESS;\r
718 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
719 if (SlotId == 0) {\r
720 return EFI_DEVICE_ERROR;\r
721 }\r
722 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
723 ASSERT (Dci < 32);\r
d1102dba 724\r
87000d77 725 DEBUG ((DEBUG_INFO, "Stop Slot = %x,Dci = %x\n", SlotId, Dci));\r
12e6c738
FT
726\r
727 //\r
728 // 1) Send Stop endpoint command to stop xHC from executing of the TDs on the endpoint\r
729 //\r
49be9c3c 730 Status = XhcStopEndpoint(Xhc, SlotId, Dci, Urb);\r
12e6c738 731 if (EFI_ERROR(Status)) {\r
87000d77 732 DEBUG ((DEBUG_ERROR, "XhcDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status));\r
12e6c738
FT
733 goto Done;\r
734 }\r
735\r
736 //\r
737 // 2)Set dequeue pointer\r
738 //\r
49be9c3c
RN
739 if (Urb->Finished && Urb->Result == EFI_USB_NOERROR) {\r
740 //\r
741 // Return Already Started to indicate the pending URB is finished.\r
742 // This fixes BULK data loss when transfer is detected as timeout\r
743 // but finished just before stopping endpoint.\r
744 //\r
745 Status = EFI_ALREADY_STARTED;\r
746 DEBUG ((DEBUG_INFO, "XhcDequeueTrbFromEndpoint: Pending URB is finished: Length Actual/Expect = %d/%d!\n", Urb->Completed, Urb->DataLen));\r
747 } else {\r
748 Status = XhcSetTrDequeuePointer(Xhc, SlotId, Dci, Urb);\r
749 if (EFI_ERROR (Status)) {\r
750 DEBUG ((DEBUG_ERROR, "XhcDequeueTrbFromEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status));\r
751 goto Done;\r
752 }\r
260fbf53 753 }\r
92870c98 754\r
755 //\r
756 // 3)Ring the doorbell to transit from stop to active\r
757 //\r
758 XhcRingDoorBell (Xhc, SlotId, Dci);\r
759\r
260fbf53 760Done:\r
92870c98 761 return Status;\r
762}\r
763\r
764/**\r
765 Create XHCI event ring.\r
766\r
a9292c13 767 @param Xhc The XHCI Instance.\r
92870c98 768 @param EventRing The created event ring.\r
769\r
770**/\r
771VOID\r
92870c98 772CreateEventRing (\r
a9292c13 773 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 774 OUT EVENT_RING *EventRing\r
775 )\r
776{\r
777 VOID *Buf;\r
778 EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;\r
1847ed0b
EL
779 UINTN Size;\r
780 EFI_PHYSICAL_ADDRESS ERSTPhy;\r
781 EFI_PHYSICAL_ADDRESS DequeuePhy;\r
92870c98 782\r
783 ASSERT (EventRing != NULL);\r
784\r
1847ed0b
EL
785 Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;\r
786 Buf = UsbHcAllocateMem (Xhc->MemPool, Size);\r
92870c98 787 ASSERT (Buf != NULL);\r
788 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
1847ed0b 789 ZeroMem (Buf, Size);\r
92870c98 790\r
791 EventRing->EventRingSeg0 = Buf;\r
92870c98 792 EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;\r
a9292c13 793 EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
794 EventRing->EventRingEnqueue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
d1102dba 795\r
1847ed0b 796 DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);\r
d1102dba 797\r
92870c98 798 //\r
799 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'\r
800 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.\r
801 //\r
802 EventRing->EventRingCCS = 1;\r
803\r
e1f2dfec 804 Size = sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER;\r
1847ed0b 805 Buf = UsbHcAllocateMem (Xhc->MemPool, Size);\r
92870c98 806 ASSERT (Buf != NULL);\r
807 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
1847ed0b 808 ZeroMem (Buf, Size);\r
92870c98 809\r
810 ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;\r
811 EventRing->ERSTBase = ERSTBase;\r
1847ed0b
EL
812 ERSTBase->PtrLo = XHC_LOW_32BIT (DequeuePhy);\r
813 ERSTBase->PtrHi = XHC_HIGH_32BIT (DequeuePhy);\r
92870c98 814 ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;\r
815\r
1847ed0b
EL
816 ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, ERSTBase, Size);\r
817\r
92870c98 818 //\r
819 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)\r
820 //\r
821 XhcWriteRuntimeReg (\r
822 Xhc,\r
6b4483cd 823 XHC_ERSTSZ_OFFSET,\r
92870c98 824 ERST_NUMBER\r
825 );\r
826 //\r
827 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)\r
828 //\r
6b4483cd 829 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
830 // So divide it to two 32-bytes width register access.\r
831 //\r
832 XhcWriteRuntimeReg (\r
833 Xhc,\r
834 XHC_ERDP_OFFSET,\r
1847ed0b 835 XHC_LOW_32BIT((UINT64)(UINTN)DequeuePhy)\r
6b4483cd 836 );\r
837 XhcWriteRuntimeReg (\r
92870c98 838 Xhc,\r
6b4483cd 839 XHC_ERDP_OFFSET + 4,\r
1847ed0b 840 XHC_HIGH_32BIT((UINT64)(UINTN)DequeuePhy)\r
92870c98 841 );\r
842 //\r
843 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)\r
844 //\r
6b4483cd 845 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
846 // So divide it to two 32-bytes width register access.\r
847 //\r
848 XhcWriteRuntimeReg (\r
849 Xhc,\r
850 XHC_ERSTBA_OFFSET,\r
1847ed0b 851 XHC_LOW_32BIT((UINT64)(UINTN)ERSTPhy)\r
6b4483cd 852 );\r
853 XhcWriteRuntimeReg (\r
92870c98 854 Xhc,\r
6b4483cd 855 XHC_ERSTBA_OFFSET + 4,\r
1847ed0b 856 XHC_HIGH_32BIT((UINT64)(UINTN)ERSTPhy)\r
92870c98 857 );\r
858 //\r
859 // Need set IMAN IE bit to enble the ring interrupt\r
860 //\r
6b4483cd 861 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);\r
92870c98 862}\r
863\r
864/**\r
865 Create XHCI transfer ring.\r
866\r
a9292c13 867 @param Xhc The XHCI Instance.\r
92870c98 868 @param TrbNum The number of TRB in the ring.\r
869 @param TransferRing The created transfer ring.\r
870\r
871**/\r
872VOID\r
92870c98 873CreateTransferRing (\r
a9292c13 874 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 875 IN UINTN TrbNum,\r
876 OUT TRANSFER_RING *TransferRing\r
877 )\r
878{\r
879 VOID *Buf;\r
a9292c13 880 LINK_TRB *EndTrb;\r
1847ed0b 881 EFI_PHYSICAL_ADDRESS PhyAddr;\r
92870c98 882\r
1847ed0b 883 Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);\r
92870c98 884 ASSERT (Buf != NULL);\r
885 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
a9292c13 886 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
92870c98 887\r
888 TransferRing->RingSeg0 = Buf;\r
889 TransferRing->TrbNumber = TrbNum;\r
a9292c13 890 TransferRing->RingEnqueue = (TRB_TEMPLATE *) TransferRing->RingSeg0;\r
891 TransferRing->RingDequeue = (TRB_TEMPLATE *) TransferRing->RingSeg0;\r
92870c98 892 TransferRing->RingPCS = 1;\r
893 //\r
894 // 4.9.2 Transfer Ring Management\r
895 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to\r
896 // point to the first TRB in the ring.\r
897 //\r
a9292c13 898 EndTrb = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));\r
92870c98 899 EndTrb->Type = TRB_TYPE_LINK;\r
1847ed0b
EL
900 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
901 EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);\r
902 EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 903 //\r
904 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.\r
905 //\r
906 EndTrb->TC = 1;\r
907 //\r
908 // Set Cycle bit as other TRB PCS init value\r
909 //\r
910 EndTrb->CycleBit = 0;\r
911}\r
912\r
913/**\r
914 Free XHCI event ring.\r
915\r
a9292c13 916 @param Xhc The XHCI Instance.\r
92870c98 917 @param EventRing The event ring to be freed.\r
918\r
919**/\r
920EFI_STATUS\r
921EFIAPI\r
922XhcFreeEventRing (\r
a9292c13 923 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 924 IN EVENT_RING *EventRing\r
925)\r
926{\r
92870c98 927 if(EventRing->EventRingSeg0 == NULL) {\r
928 return EFI_SUCCESS;\r
929 }\r
930\r
92870c98 931 //\r
1847ed0b 932 // Free EventRing Segment 0\r
92870c98 933 //\r
1847ed0b 934 UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
92870c98 935\r
936 //\r
1847ed0b 937 // Free ESRT table\r
92870c98 938 //\r
1847ed0b 939 UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
92870c98 940 return EFI_SUCCESS;\r
941}\r
942\r
943/**\r
944 Free the resouce allocated at initializing schedule.\r
945\r
a9292c13 946 @param Xhc The XHCI Instance.\r
92870c98 947\r
948**/\r
949VOID\r
950XhcFreeSched (\r
a9292c13 951 IN USB_XHCI_INSTANCE *Xhc\r
92870c98 952 )\r
953{\r
1847ed0b
EL
954 UINT32 Index;\r
955 UINT64 *ScratchEntry;\r
d1102dba 956\r
92870c98 957 if (Xhc->ScratchBuf != NULL) {\r
1847ed0b 958 ScratchEntry = Xhc->ScratchEntry;\r
92870c98 959 for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {\r
1847ed0b
EL
960 //\r
961 // Free Scratchpad Buffers\r
962 //\r
963 UsbHcFreeAlignedPages (Xhc->PciIo, (VOID*)(UINTN)ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize), (VOID *) Xhc->ScratchEntryMap[Index]);\r
92870c98 964 }\r
1847ed0b
EL
965 //\r
966 // Free Scratchpad Buffer Array\r
967 //\r
968 UsbHcFreeAlignedPages (Xhc->PciIo, Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)), Xhc->ScratchMap);\r
969 FreePool (Xhc->ScratchEntryMap);\r
970 FreePool (Xhc->ScratchEntry);\r
971 }\r
972\r
973 if (Xhc->CmdRing.RingSeg0 != NULL) {\r
974 UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
975 Xhc->CmdRing.RingSeg0 = NULL;\r
92870c98 976 }\r
d1102dba 977\r
1847ed0b 978 XhcFreeEventRing (Xhc,&Xhc->EventRing);\r
92870c98 979\r
980 if (Xhc->DCBAA != NULL) {\r
1847ed0b 981 UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof(UINT64));\r
92870c98 982 Xhc->DCBAA = NULL;\r
983 }\r
d1102dba 984\r
1847ed0b
EL
985 //\r
986 // Free memory pool at last\r
987 //\r
988 if (Xhc->MemPool != NULL) {\r
989 UsbHcFreeMemPool (Xhc->MemPool);\r
990 Xhc->MemPool = NULL;\r
92870c98 991 }\r
92870c98 992}\r
993\r
994/**\r
5a4b3388 995 Check if the Trb is a transaction of the URB.\r
a50f7c4c 996\r
9750503a 997 @param Xhc The XHCI Instance.\r
5a4b3388
RN
998 @param Trb The TRB to be checked\r
999 @param Urb The URB to be checked.\r
a50f7c4c 1000\r
5a4b3388
RN
1001 @retval TRUE It is a transaction of the URB.\r
1002 @retval FALSE It is not any transaction of the URB.\r
a50f7c4c 1003\r
1004**/\r
1005BOOLEAN\r
5a4b3388 1006IsTransferRingTrb (\r
a50f7c4c 1007 IN USB_XHCI_INSTANCE *Xhc,\r
1008 IN TRB_TEMPLATE *Trb,\r
5a4b3388 1009 IN URB *Urb\r
a50f7c4c 1010 )\r
1011{\r
5a4b3388
RN
1012 LINK_TRB *LinkTrb;\r
1013 TRB_TEMPLATE *CheckedTrb;\r
1014 UINTN Index;\r
1015 EFI_PHYSICAL_ADDRESS PhyAddr;\r
a50f7c4c 1016\r
5a4b3388
RN
1017 CheckedTrb = Urb->TrbStart;\r
1018 for (Index = 0; Index < Urb->TrbNum; Index++) {\r
1019 if (Trb == CheckedTrb) {\r
1020 return TRUE;\r
1021 }\r
1022 CheckedTrb++;\r
1023 //\r
1024 // If the checked TRB is the link TRB at the end of the transfer ring,\r
1025 // recircle it to the head of the ring.\r
1026 //\r
1027 if (CheckedTrb->Type == TRB_TYPE_LINK) {\r
1028 LinkTrb = (LINK_TRB *) CheckedTrb;\r
1029 PhyAddr = (EFI_PHYSICAL_ADDRESS)(LinkTrb->PtrLo | LShiftU64 ((UINT64) LinkTrb->PtrHi, 32));\r
1030 CheckedTrb = (TRB_TEMPLATE *)(UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN) PhyAddr, sizeof (TRB_TEMPLATE));\r
1031 ASSERT (CheckedTrb == Urb->Ring->RingSeg0);\r
a50f7c4c 1032 }\r
1033 }\r
1034\r
1035 return FALSE;\r
1036}\r
1037\r
1038/**\r
5a4b3388 1039 Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.\r
92870c98 1040\r
5a4b3388
RN
1041 @param Xhc The XHCI Instance.\r
1042 @param Trb The TRB to be checked.\r
1043 @param Urb The pointer to the matched Urb.\r
92870c98 1044\r
5a4b3388
RN
1045 @retval TRUE The Trb is matched with a transaction of the URBs in the async list.\r
1046 @retval FALSE The Trb is not matched with any URBs in the async list.\r
92870c98 1047\r
1048**/\r
1049BOOLEAN\r
5a4b3388
RN
1050IsAsyncIntTrb (\r
1051 IN USB_XHCI_INSTANCE *Xhc,\r
a50f7c4c 1052 IN TRB_TEMPLATE *Trb,\r
5a4b3388 1053 OUT URB **Urb\r
92870c98 1054 )\r
1055{\r
5a4b3388
RN
1056 LIST_ENTRY *Entry;\r
1057 LIST_ENTRY *Next;\r
1058 URB *CheckedUrb;\r
92870c98 1059\r
dc528558 1060 BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
5a4b3388
RN
1061 CheckedUrb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1062 if (IsTransferRingTrb (Xhc, Trb, CheckedUrb)) {\r
1063 *Urb = CheckedUrb;\r
a50f7c4c 1064 return TRUE;\r
92870c98 1065 }\r
92870c98 1066 }\r
1067\r
a50f7c4c 1068 return FALSE;\r
92870c98 1069}\r
1070\r
5a4b3388 1071\r
92870c98 1072/**\r
1073 Check the URB's execution result and update the URB's\r
1074 result accordingly.\r
1075\r
a9292c13 1076 @param Xhc The XHCI Instance.\r
92870c98 1077 @param Urb The URB to check result.\r
1078\r
1079 @return Whether the result of URB transfer is finialized.\r
1080\r
1081**/\r
a40a5c08 1082BOOLEAN\r
92870c98 1083XhcCheckUrbResult (\r
a9292c13 1084 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1085 IN URB *Urb\r
1086 )\r
1087{\r
92870c98 1088 EVT_TRB_TRANSFER *EvtTrb;\r
a9292c13 1089 TRB_TEMPLATE *TRBPtr;\r
92870c98 1090 UINTN Index;\r
1091 UINT8 TRBType;\r
1092 EFI_STATUS Status;\r
a50f7c4c 1093 URB *AsyncUrb;\r
1094 URB *CheckedUrb;\r
1095 UINT64 XhcDequeue;\r
1096 UINT32 High;\r
1097 UINT32 Low;\r
1847ed0b 1098 EFI_PHYSICAL_ADDRESS PhyAddr;\r
92870c98 1099\r
1100 ASSERT ((Xhc != NULL) && (Urb != NULL));\r
1101\r
09e4dbeb 1102 Status = EFI_SUCCESS;\r
1103 AsyncUrb = NULL;\r
a50f7c4c 1104\r
1105 if (Urb->Finished) {\r
1106 goto EXIT;\r
1107 }\r
1108\r
1109 EvtTrb = NULL;\r
92870c98 1110\r
1111 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
1112 Urb->Result |= EFI_USB_ERR_SYSTEM;\r
92870c98 1113 goto EXIT;\r
1114 }\r
1115\r
1116 //\r
a50f7c4c 1117 // Traverse the event ring to find out all new events from the previous check.\r
92870c98 1118 //\r
a50f7c4c 1119 XhcSyncEventRing (Xhc, &Xhc->EventRing);\r
1120 for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {\r
1121 Status = XhcCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **)&EvtTrb));\r
92870c98 1122 if (Status == EFI_NOT_READY) {\r
a50f7c4c 1123 //\r
1124 // All new events are handled, return directly.\r
1125 //\r
92870c98 1126 goto EXIT;\r
1127 }\r
1128\r
6b4483cd 1129 //\r
1130 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.\r
1131 //\r
1132 if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {\r
1133 continue;\r
1134 }\r
d1102dba 1135\r
1847ed0b
EL
1136 //\r
1137 // Need convert pci device address to host address\r
1138 //\r
1139 PhyAddr = (EFI_PHYSICAL_ADDRESS)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));\r
1140 TRBPtr = (TRB_TEMPLATE *)(UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN) PhyAddr, sizeof (TRB_TEMPLATE));\r
92870c98 1141\r
a50f7c4c 1142 //\r
49be9c3c
RN
1143 // Update the status of URB including the pending URB, the URB that is currently checked,\r
1144 // and URBs in the XHCI's async interrupt transfer list.\r
a50f7c4c 1145 // This way is used to avoid that those completed async transfer events don't get\r
1146 // handled in time and are flushed by newer coming events.\r
1147 //\r
49be9c3c
RN
1148 if (Xhc->PendingUrb != NULL && IsTransferRingTrb (Xhc, TRBPtr, Xhc->PendingUrb)) {\r
1149 CheckedUrb = Xhc->PendingUrb;\r
1150 } else if (IsTransferRingTrb (Xhc, TRBPtr, Urb)) {\r
a50f7c4c 1151 CheckedUrb = Urb;\r
d1102dba 1152 } else if (IsAsyncIntTrb (Xhc, TRBPtr, &AsyncUrb)) {\r
a50f7c4c 1153 CheckedUrb = AsyncUrb;\r
1154 } else {\r
1155 continue;\r
1156 }\r
d1102dba 1157\r
a50f7c4c 1158 switch (EvtTrb->Completecode) {\r
1159 case TRB_COMPLETION_STALL_ERROR:\r
1160 CheckedUrb->Result |= EFI_USB_ERR_STALL;\r
1161 CheckedUrb->Finished = TRUE;\r
87000d77 1162 DEBUG ((DEBUG_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
c3f44a77 1163 goto EXIT;\r
92870c98 1164\r
a50f7c4c 1165 case TRB_COMPLETION_BABBLE_ERROR:\r
1166 CheckedUrb->Result |= EFI_USB_ERR_BABBLE;\r
1167 CheckedUrb->Finished = TRUE;\r
87000d77 1168 DEBUG ((DEBUG_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
c3f44a77 1169 goto EXIT;\r
6b4483cd 1170\r
a50f7c4c 1171 case TRB_COMPLETION_DATA_BUFFER_ERROR:\r
1172 CheckedUrb->Result |= EFI_USB_ERR_BUFFER;\r
1173 CheckedUrb->Finished = TRUE;\r
87000d77 1174 DEBUG ((DEBUG_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));\r
c3f44a77 1175 goto EXIT;\r
a50f7c4c 1176\r
1177 case TRB_COMPLETION_USB_TRANSACTION_ERROR:\r
1178 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
1179 CheckedUrb->Finished = TRUE;\r
87000d77 1180 DEBUG ((DEBUG_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
c3f44a77 1181 goto EXIT;\r
a50f7c4c 1182\r
49be9c3c
RN
1183 case TRB_COMPLETION_STOPPED:\r
1184 case TRB_COMPLETION_STOPPED_LENGTH_INVALID:\r
1185 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
1186 CheckedUrb->Finished = TRUE;\r
1187 //\r
1188 // The pending URB is timeout and force stopped when stopping endpoint.\r
1189 // Continue the loop to receive the Command Complete Event for stopping endpoint.\r
1190 //\r
1191 continue;\r
1192\r
a50f7c4c 1193 case TRB_COMPLETION_SHORT_PACKET:\r
1194 case TRB_COMPLETION_SUCCESS:\r
1195 if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {\r
87000d77 1196 DEBUG ((DEBUG_VERBOSE, "XhcCheckUrbResult: short packet happens!\n"));\r
a50f7c4c 1197 }\r
1198\r
1199 TRBType = (UINT8) (TRBPtr->Type);\r
1200 if ((TRBType == TRB_TYPE_DATA_STAGE) ||\r
1201 (TRBType == TRB_TYPE_NORMAL) ||\r
1202 (TRBType == TRB_TYPE_ISOCH)) {\r
5956af2b 1203 CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL*)TRBPtr)->Length - EvtTrb->Length);\r
a50f7c4c 1204 }\r
1205\r
1206 break;\r
1207\r
1208 default:\r
87000d77 1209 DEBUG ((DEBUG_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));\r
a50f7c4c 1210 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
1211 CheckedUrb->Finished = TRUE;\r
c3f44a77 1212 goto EXIT;\r
a50f7c4c 1213 }\r
1214\r
1215 //\r
1216 // Only check first and end Trb event address\r
1217 //\r
1218 if (TRBPtr == CheckedUrb->TrbStart) {\r
1219 CheckedUrb->StartDone = TRUE;\r
1220 }\r
1221\r
1222 if (TRBPtr == CheckedUrb->TrbEnd) {\r
1223 CheckedUrb->EndDone = TRUE;\r
1224 }\r
1225\r
1226 if (CheckedUrb->StartDone && CheckedUrb->EndDone) {\r
1227 CheckedUrb->Finished = TRUE;\r
1228 CheckedUrb->EvtTrb = (TRB_TEMPLATE *)EvtTrb;\r
92870c98 1229 }\r
1230 }\r
1231\r
1232EXIT:\r
a50f7c4c 1233\r
1234 //\r
1235 // Advance event ring to last available entry\r
1236 //\r
1237 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
1238 // So divide it to two 32-bytes width register access.\r
1239 //\r
1240 Low = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);\r
1241 High = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);\r
1242 XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);\r
1243\r
1847ed0b
EL
1244 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE));\r
1245\r
1246 if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {\r
a50f7c4c 1247 //\r
1248 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
1249 // So divide it to two 32-bytes width register access.\r
1250 //\r
1847ed0b
EL
1251 XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);\r
1252 XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));\r
a50f7c4c 1253 }\r
1254\r
a40a5c08 1255 return Urb->Finished;\r
92870c98 1256}\r
1257\r
1258\r
1259/**\r
1260 Execute the transfer by polling the URB. This is a synchronous operation.\r
1261\r
71dd80f1
PH
1262 @param Xhc The XHCI Instance.\r
1263 @param CmdTransfer The executed URB is for cmd transfer or not.\r
1264 @param Urb The URB to execute.\r
1265 @param Timeout The time to wait before abort, in millisecond.\r
92870c98 1266\r
71dd80f1
PH
1267 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
1268 @return EFI_TIMEOUT The transfer failed due to time out.\r
1269 @return EFI_SUCCESS The transfer finished OK.\r
1270 @retval EFI_OUT_OF_RESOURCES Memory for the timer event could not be allocated.\r
92870c98 1271\r
1272**/\r
1273EFI_STATUS\r
1274XhcExecTransfer (\r
a9292c13 1275 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1276 IN BOOLEAN CmdTransfer,\r
1277 IN URB *Urb,\r
a9292c13 1278 IN UINTN Timeout\r
92870c98 1279 )\r
1280{\r
1281 EFI_STATUS Status;\r
92870c98 1282 UINT8 SlotId;\r
1283 UINT8 Dci;\r
a40a5c08 1284 BOOLEAN Finished;\r
71dd80f1
PH
1285 EFI_EVENT TimeoutEvent;\r
1286 BOOLEAN IndefiniteTimeout;\r
1287\r
1288 Status = EFI_SUCCESS;\r
1289 Finished = FALSE;\r
1290 TimeoutEvent = NULL;\r
1291 IndefiniteTimeout = FALSE;\r
92870c98 1292\r
1293 if (CmdTransfer) {\r
1294 SlotId = 0;\r
1295 Dci = 0;\r
1296 } else {\r
6b4483cd 1297 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
1298 if (SlotId == 0) {\r
1299 return EFI_DEVICE_ERROR;\r
1300 }\r
1301 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
1302 ASSERT (Dci < 32);\r
92870c98 1303 }\r
1304\r
a9292c13 1305 if (Timeout == 0) {\r
71dd80f1
PH
1306 IndefiniteTimeout = TRUE;\r
1307 goto RINGDOORBELL;\r
1308 }\r
1309\r
1310 Status = gBS->CreateEvent (\r
1311 EVT_TIMER,\r
1312 TPL_CALLBACK,\r
1313 NULL,\r
1314 NULL,\r
1315 &TimeoutEvent\r
1316 );\r
1317\r
1318 if (EFI_ERROR (Status)) {\r
1319 goto DONE;\r
92870c98 1320 }\r
1321\r
71dd80f1
PH
1322 Status = gBS->SetTimer (TimeoutEvent,\r
1323 TimerRelative,\r
1324 EFI_TIMER_PERIOD_MILLISECONDS(Timeout));\r
1325\r
1326 if (EFI_ERROR (Status)) {\r
1327 goto DONE;\r
1328 }\r
1329\r
1330RINGDOORBELL:\r
92870c98 1331 XhcRingDoorBell (Xhc, SlotId, Dci);\r
1332\r
71dd80f1 1333 do {\r
a40a5c08
FT
1334 Finished = XhcCheckUrbResult (Xhc, Urb);\r
1335 if (Finished) {\r
92870c98 1336 break;\r
1337 }\r
ca243131 1338 gBS->Stall (XHC_1_MICROSECOND);\r
71dd80f1 1339 } while (IndefiniteTimeout || EFI_ERROR(gBS->CheckEvent (TimeoutEvent)));\r
92870c98 1340\r
71dd80f1
PH
1341DONE:\r
1342 if (EFI_ERROR(Status)) {\r
1343 Urb->Result = EFI_USB_ERR_NOTEXECUTE;\r
1344 } else if (!Finished) {\r
a50f7c4c 1345 Urb->Result = EFI_USB_ERR_TIMEOUT;\r
a40a5c08
FT
1346 Status = EFI_TIMEOUT;\r
1347 } else if (Urb->Result != EFI_USB_NOERROR) {\r
1348 Status = EFI_DEVICE_ERROR;\r
a50f7c4c 1349 }\r
1350\r
71dd80f1
PH
1351 if (TimeoutEvent != NULL) {\r
1352 gBS->CloseEvent (TimeoutEvent);\r
1353 }\r
1354\r
92870c98 1355 return Status;\r
1356}\r
1357\r
1358/**\r
1359 Delete a single asynchronous interrupt transfer for\r
1360 the device and endpoint.\r
1361\r
a9292c13 1362 @param Xhc The XHCI Instance.\r
6b4483cd 1363 @param BusAddr The logical device address assigned by UsbBus driver.\r
92870c98 1364 @param EpNum The endpoint of the target.\r
1365\r
1366 @retval EFI_SUCCESS An asynchronous transfer is removed.\r
1367 @retval EFI_NOT_FOUND No transfer for the device is found.\r
1368\r
1369**/\r
1370EFI_STATUS\r
1371XhciDelAsyncIntTransfer (\r
a9292c13 1372 IN USB_XHCI_INSTANCE *Xhc,\r
6b4483cd 1373 IN UINT8 BusAddr,\r
92870c98 1374 IN UINT8 EpNum\r
1375 )\r
1376{\r
1377 LIST_ENTRY *Entry;\r
1378 LIST_ENTRY *Next;\r
1379 URB *Urb;\r
1380 EFI_USB_DATA_DIRECTION Direction;\r
b33b1055 1381 EFI_STATUS Status;\r
92870c98 1382\r
1383 Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
1384 EpNum &= 0x0F;\r
1385\r
6b4483cd 1386 Urb = NULL;\r
92870c98 1387\r
dc528558 1388 BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
92870c98 1389 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
6b4483cd 1390 if ((Urb->Ep.BusAddr == BusAddr) &&\r
92870c98 1391 (Urb->Ep.EpAddr == EpNum) &&\r
1392 (Urb->Ep.Direction == Direction)) {\r
b33b1055
RN
1393 //\r
1394 // Device doesn't finish the IntTransfer until real data comes\r
1395 // So the TRB should be removed as well.\r
1396 //\r
1397 Status = XhcDequeueTrbFromEndpoint (Xhc, Urb);\r
1398 if (EFI_ERROR (Status)) {\r
87000d77 1399 DEBUG ((DEBUG_ERROR, "XhciDelAsyncIntTransfer: XhcDequeueTrbFromEndpoint failed\n"));\r
b33b1055
RN
1400 }\r
1401\r
92870c98 1402 RemoveEntryList (&Urb->UrbList);\r
d98fc9ad 1403 FreePool (Urb->Data);\r
1847ed0b 1404 XhcFreeUrb (Xhc, Urb);\r
92870c98 1405 return EFI_SUCCESS;\r
1406 }\r
1407 }\r
1408\r
1409 return EFI_NOT_FOUND;\r
1410}\r
1411\r
1412/**\r
1413 Remove all the asynchronous interrutp transfers.\r
1414\r
a9292c13 1415 @param Xhc The XHCI Instance.\r
92870c98 1416\r
1417**/\r
1418VOID\r
1419XhciDelAllAsyncIntTransfers (\r
a9292c13 1420 IN USB_XHCI_INSTANCE *Xhc\r
92870c98 1421 )\r
1422{\r
1423 LIST_ENTRY *Entry;\r
1424 LIST_ENTRY *Next;\r
1425 URB *Urb;\r
b33b1055 1426 EFI_STATUS Status;\r
92870c98 1427\r
dc528558 1428 BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
92870c98 1429 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
b33b1055 1430\r
b0b626ea
RN
1431 //\r
1432 // Device doesn't finish the IntTransfer until real data comes\r
1433 // So the TRB should be removed as well.\r
1434 //\r
b33b1055
RN
1435 Status = XhcDequeueTrbFromEndpoint (Xhc, Urb);\r
1436 if (EFI_ERROR (Status)) {\r
87000d77 1437 DEBUG ((DEBUG_ERROR, "XhciDelAllAsyncIntTransfers: XhcDequeueTrbFromEndpoint failed\n"));\r
b33b1055
RN
1438 }\r
1439\r
92870c98 1440 RemoveEntryList (&Urb->UrbList);\r
d98fc9ad 1441 FreePool (Urb->Data);\r
1847ed0b 1442 XhcFreeUrb (Xhc, Urb);\r
92870c98 1443 }\r
1444}\r
1445\r
6681582d
SZ
1446/**\r
1447 Insert a single asynchronous interrupt transfer for\r
1448 the device and endpoint.\r
1449\r
1450 @param Xhc The XHCI Instance\r
1451 @param BusAddr The logical device address assigned by UsbBus driver\r
1452 @param EpAddr Endpoint addrress\r
1453 @param DevSpeed The device speed\r
1454 @param MaxPacket The max packet length of the endpoint\r
1455 @param DataLen The length of data buffer\r
1456 @param Callback The function to call when data is transferred\r
1457 @param Context The context to the callback\r
1458\r
1459 @return Created URB or NULL\r
1460\r
1461**/\r
1462URB *\r
1463XhciInsertAsyncIntTransfer (\r
1464 IN USB_XHCI_INSTANCE *Xhc,\r
1465 IN UINT8 BusAddr,\r
1466 IN UINT8 EpAddr,\r
1467 IN UINT8 DevSpeed,\r
1468 IN UINTN MaxPacket,\r
1469 IN UINTN DataLen,\r
1470 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
1471 IN VOID *Context\r
1472 )\r
1473{\r
d98fc9ad 1474 VOID *Data;\r
6681582d
SZ
1475 URB *Urb;\r
1476\r
d98fc9ad
SZ
1477 Data = AllocateZeroPool (DataLen);\r
1478 if (Data == NULL) {\r
1479 DEBUG ((DEBUG_ERROR, "%a: failed to allocate buffer\n", __FUNCTION__));\r
1480 return NULL;\r
1481 }\r
1482\r
6681582d
SZ
1483 Urb = XhcCreateUrb (\r
1484 Xhc,\r
1485 BusAddr,\r
1486 EpAddr,\r
1487 DevSpeed,\r
1488 MaxPacket,\r
1489 XHC_INT_TRANSFER_ASYNC,\r
1490 NULL,\r
d98fc9ad 1491 Data,\r
6681582d
SZ
1492 DataLen,\r
1493 Callback,\r
1494 Context\r
1495 );\r
1496 if (Urb == NULL) {\r
1497 DEBUG ((DEBUG_ERROR, "%a: failed to create URB\n", __FUNCTION__));\r
d98fc9ad 1498 FreePool (Data);\r
6681582d
SZ
1499 return NULL;\r
1500 }\r
1501\r
1502 //\r
1503 // New asynchronous transfer must inserted to the head.\r
1504 // Check the comments in XhcMoniteAsyncRequests\r
1505 //\r
1506 InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList);\r
1507\r
1508 return Urb;\r
1509}\r
1510\r
92870c98 1511/**\r
1512 Update the queue head for next round of asynchronous transfer\r
1513\r
a9292c13 1514 @param Xhc The XHCI Instance.\r
92870c98 1515 @param Urb The URB to update\r
1516\r
1517**/\r
1518VOID\r
1519XhcUpdateAsyncRequest (\r
a9292c13 1520 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1521 IN URB *Urb\r
1522 )\r
1523{\r
1524 EFI_STATUS Status;\r
1525\r
1526 if (Urb->Result == EFI_USB_NOERROR) {\r
1527 Status = XhcCreateTransferTrb (Xhc, Urb);\r
6b4483cd 1528 if (EFI_ERROR (Status)) {\r
1529 return;\r
1530 }\r
92870c98 1531 Status = RingIntTransferDoorBell (Xhc, Urb);\r
6b4483cd 1532 if (EFI_ERROR (Status)) {\r
1533 return;\r
1534 }\r
92870c98 1535 }\r
1536}\r
1537\r
d98fc9ad
SZ
1538/**\r
1539 Flush data from PCI controller specific address to mapped system\r
1540 memory address.\r
1541\r
1542 @param Xhc The XHCI device.\r
1543 @param Urb The URB to unmap.\r
1544\r
1545 @retval EFI_SUCCESS Success to flush data to mapped system memory.\r
1546 @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.\r
1547\r
1548**/\r
1549EFI_STATUS\r
1550XhcFlushAsyncIntMap (\r
1551 IN USB_XHCI_INSTANCE *Xhc,\r
1552 IN URB *Urb\r
1553 )\r
1554{\r
1555 EFI_STATUS Status;\r
1556 EFI_PHYSICAL_ADDRESS PhyAddr;\r
1557 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
1558 EFI_PCI_IO_PROTOCOL *PciIo;\r
1559 UINTN Len;\r
1560 VOID *Map;\r
1561\r
1562 PciIo = Xhc->PciIo;\r
1563 Len = Urb->DataLen;\r
1564\r
1565 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
1566 MapOp = EfiPciIoOperationBusMasterWrite;\r
1567 } else {\r
1568 MapOp = EfiPciIoOperationBusMasterRead;\r
1569 }\r
1570\r
1571 if (Urb->DataMap != NULL) {\r
1572 Status = PciIo->Unmap (PciIo, Urb->DataMap);\r
1573 if (EFI_ERROR (Status)) {\r
1574 goto ON_ERROR;\r
1575 }\r
1576 }\r
1577\r
1578 Urb->DataMap = NULL;\r
1579\r
1580 Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);\r
1581 if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {\r
1582 goto ON_ERROR;\r
1583 }\r
1584\r
1585 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);\r
1586 Urb->DataMap = Map;\r
1587 return EFI_SUCCESS;\r
1588\r
1589ON_ERROR:\r
1590 return EFI_DEVICE_ERROR;\r
1591}\r
1592\r
92870c98 1593/**\r
1594 Interrupt transfer periodic check handler.\r
1595\r
1596 @param Event Interrupt event.\r
a9292c13 1597 @param Context Pointer to USB_XHCI_INSTANCE.\r
92870c98 1598\r
1599**/\r
1600VOID\r
1601EFIAPI\r
1602XhcMonitorAsyncRequests (\r
1603 IN EFI_EVENT Event,\r
1604 IN VOID *Context\r
1605 )\r
1606{\r
a9292c13 1607 USB_XHCI_INSTANCE *Xhc;\r
92870c98 1608 LIST_ENTRY *Entry;\r
1609 LIST_ENTRY *Next;\r
1610 UINT8 *ProcBuf;\r
1611 URB *Urb;\r
1612 UINT8 SlotId;\r
d98fc9ad 1613 EFI_STATUS Status;\r
92870c98 1614 EFI_TPL OldTpl;\r
1615\r
1616 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1617\r
a9292c13 1618 Xhc = (USB_XHCI_INSTANCE*) Context;\r
92870c98 1619\r
dc528558 1620 BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
92870c98 1621 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1622\r
1623 //\r
1624 // Make sure that the device is available before every check.\r
1625 //\r
6b4483cd 1626 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
92870c98 1627 if (SlotId == 0) {\r
1628 continue;\r
1629 }\r
1630\r
1631 //\r
1632 // Check the result of URB execution. If it is still\r
1633 // active, check the next one.\r
1634 //\r
b6cb9c39 1635 XhcCheckUrbResult (Xhc, Urb);\r
92870c98 1636\r
a50f7c4c 1637 if (!Urb->Finished) {\r
92870c98 1638 continue;\r
1639 }\r
1640\r
d98fc9ad
SZ
1641 //\r
1642 // Flush any PCI posted write transactions from a PCI host\r
1643 // bridge to system memory.\r
1644 //\r
1645 Status = XhcFlushAsyncIntMap (Xhc, Urb);\r
1646 if (EFI_ERROR (Status)) {\r
87000d77 1647 DEBUG ((DEBUG_ERROR, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));\r
d98fc9ad
SZ
1648 }\r
1649\r
92870c98 1650 //\r
1651 // Allocate a buffer then copy the transferred data for user.\r
1652 // If failed to allocate the buffer, update the URB for next\r
1653 // round of transfer. Ignore the data of this round.\r
1654 //\r
1655 ProcBuf = NULL;\r
1656 if (Urb->Result == EFI_USB_NOERROR) {\r
7fb7259f
RN
1657 //\r
1658 // Make sure the data received from HW is no more than expected.\r
1659 //\r
1660 if (Urb->Completed <= Urb->DataLen) {\r
1661 ProcBuf = AllocateZeroPool (Urb->Completed);\r
1662 }\r
92870c98 1663\r
1664 if (ProcBuf == NULL) {\r
1665 XhcUpdateAsyncRequest (Xhc, Urb);\r
1666 continue;\r
1667 }\r
1668\r
1669 CopyMem (ProcBuf, Urb->Data, Urb->Completed);\r
1670 }\r
1671\r
92870c98 1672 //\r
1673 // Leave error recovery to its related device driver. A\r
1674 // common case of the error recovery is to re-submit the\r
1675 // interrupt transfer which is linked to the head of the\r
1676 // list. This function scans from head to tail. So the\r
1677 // re-submitted interrupt transfer's callback function\r
1678 // will not be called again in this round. Don't touch this\r
1679 // URB after the callback, it may have been removed by the\r
1680 // callback.\r
1681 //\r
1682 if (Urb->Callback != NULL) {\r
1683 //\r
1684 // Restore the old TPL, USB bus maybe connect device in\r
1685 // his callback. Some drivers may has a lower TPL restriction.\r
1686 //\r
1687 gBS->RestoreTPL (OldTpl);\r
1688 (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);\r
1689 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1690 }\r
1691\r
1692 if (ProcBuf != NULL) {\r
1693 gBS->FreePool (ProcBuf);\r
1694 }\r
a50f7c4c 1695\r
1696 XhcUpdateAsyncRequest (Xhc, Urb);\r
92870c98 1697 }\r
1698 gBS->RestoreTPL (OldTpl);\r
1699}\r
1700\r
1701/**\r
1702 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.\r
1703\r
a9292c13 1704 @param Xhc The XHCI Instance.\r
92870c98 1705 @param ParentRouteChart The route string pointed to the parent device if it exists.\r
1706 @param Port The port to be polled.\r
1707 @param PortState The port state.\r
1708\r
1709 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.\r
1710 @retval Others Should not appear.\r
1711\r
1712**/\r
1713EFI_STATUS\r
1714EFIAPI\r
1715XhcPollPortStatusChange (\r
a9292c13 1716 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1717 IN USB_DEV_ROUTE ParentRouteChart,\r
1718 IN UINT8 Port,\r
1719 IN EFI_USB_PORT_STATUS *PortState\r
1720 )\r
1721{\r
1722 EFI_STATUS Status;\r
1723 UINT8 Speed;\r
1724 UINT8 SlotId;\r
2363c692 1725 UINT8 Retries;\r
92870c98 1726 USB_DEV_ROUTE RouteChart;\r
1727\r
1728 Status = EFI_SUCCESS;\r
2363c692 1729 Retries = XHC_INIT_DEVICE_SLOT_RETRIES;\r
92870c98 1730\r
c3f44a77
FT
1731 if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {\r
1732 return EFI_SUCCESS;\r
1733 }\r
1734\r
92870c98 1735 if (ParentRouteChart.Dword == 0) {\r
a9292c13 1736 RouteChart.Route.RouteString = 0;\r
1737 RouteChart.Route.RootPortNum = Port + 1;\r
1738 RouteChart.Route.TierNum = 1;\r
92870c98 1739 } else {\r
1740 if(Port < 14) {\r
a9292c13 1741 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
92870c98 1742 } else {\r
a9292c13 1743 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
92870c98 1744 }\r
a9292c13 1745 RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;\r
1746 RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;\r
92870c98 1747 }\r
1748\r
c3f44a77
FT
1749 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
1750 if (SlotId != 0) {\r
1751 if (Xhc->HcCParams.Data.Csz == 0) {\r
1752 Status = XhcDisableSlotCmd (Xhc, SlotId);\r
1753 } else {\r
1754 Status = XhcDisableSlotCmd64 (Xhc, SlotId);\r
1755 }\r
1756 }\r
1757\r
92870c98 1758 if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&\r
1759 ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {\r
1760 //\r
1761 // Has a device attached, Identify device speed after port is enabled.\r
1762 //\r
1763 Speed = EFI_USB_SPEED_FULL;\r
1764 if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
1765 Speed = EFI_USB_SPEED_LOW;\r
1766 } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {\r
1767 Speed = EFI_USB_SPEED_HIGH;\r
1768 } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {\r
1769 Speed = EFI_USB_SPEED_SUPER;\r
1770 }\r
2363c692
JH
1771\r
1772 do {\r
1773 //\r
1774 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.\r
1775 //\r
1776 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
1777 if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {\r
1778 if (Xhc->HcCParams.Data.Csz == 0) {\r
1779 Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
1780 } else {\r
1781 Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
1782 }\r
6b4483cd 1783 }\r
2363c692
JH
1784\r
1785 //\r
1786 // According to the xHCI specification (section 4.6.5), "a USB Transaction\r
1787 // Error Completion Code for an Address Device Command may be due to a Stall\r
1788 // response from a device. Software should issue a Disable Slot Command for\r
1789 // the Device Slot then an Enable Slot Command to recover from this error."\r
1790 // Therefore, retry the device slot initialization if it fails due to a\r
1791 // device error.\r
1792 //\r
1793 } while ((Status == EFI_DEVICE_ERROR) && (Retries-- != 0));\r
d1102dba 1794 }\r
c3f44a77 1795\r
92870c98 1796 return Status;\r
1797}\r
1798\r
1799\r
1800/**\r
1801 Calculate the device context index by endpoint address and direction.\r
1802\r
1803 @param EpAddr The target endpoint number.\r
1804 @param Direction The direction of the target endpoint.\r
1805\r
1806 @return The device context index of endpoint.\r
1807\r
1808**/\r
1809UINT8\r
1810XhcEndpointToDci (\r
1811 IN UINT8 EpAddr,\r
1812 IN UINT8 Direction\r
1813 )\r
1814{\r
1815 UINT8 Index;\r
1816\r
1817 if (EpAddr == 0) {\r
1818 return 1;\r
1819 } else {\r
ce9b5900 1820 Index = (UINT8) (2 * EpAddr);\r
92870c98 1821 if (Direction == EfiUsbDataIn) {\r
1822 Index += 1;\r
1823 }\r
1824 return Index;\r
1825 }\r
1826}\r
1827\r
92870c98 1828/**\r
1829 Find out the actual device address according to the requested device address from UsbBus.\r
1830\r
a9292c13 1831 @param Xhc The XHCI Instance.\r
1832 @param BusDevAddr The requested device address by UsbBus upper driver.\r
92870c98 1833\r
1834 @return The actual device address assigned to the device.\r
1835\r
1836**/\r
1837UINT8\r
1838EFIAPI\r
1839XhcBusDevAddrToSlotId (\r
a9292c13 1840 IN USB_XHCI_INSTANCE *Xhc,\r
1841 IN UINT8 BusDevAddr\r
92870c98 1842 )\r
1843{\r
1844 UINT8 Index;\r
1845\r
1846 for (Index = 0; Index < 255; Index++) {\r
a9292c13 1847 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1848 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1849 (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {\r
92870c98 1850 break;\r
1851 }\r
1852 }\r
1853\r
1854 if (Index == 255) {\r
1855 return 0;\r
1856 }\r
1857\r
a9292c13 1858 return Xhc->UsbDevContext[Index + 1].SlotId;\r
92870c98 1859}\r
1860\r
1861/**\r
1862 Find out the slot id according to the device's route string.\r
1863\r
a9292c13 1864 @param Xhc The XHCI Instance.\r
1865 @param RouteString The route string described the device location.\r
92870c98 1866\r
1867 @return The slot id used by the device.\r
1868\r
1869**/\r
1870UINT8\r
1871EFIAPI\r
1872XhcRouteStringToSlotId (\r
a9292c13 1873 IN USB_XHCI_INSTANCE *Xhc,\r
1874 IN USB_DEV_ROUTE RouteString\r
92870c98 1875 )\r
1876{\r
1877 UINT8 Index;\r
1878\r
1879 for (Index = 0; Index < 255; Index++) {\r
a9292c13 1880 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1881 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1882 (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {\r
92870c98 1883 break;\r
1884 }\r
1885 }\r
1886\r
1887 if (Index == 255) {\r
1888 return 0;\r
1889 }\r
1890\r
a9292c13 1891 return Xhc->UsbDevContext[Index + 1].SlotId;\r
92870c98 1892}\r
1893\r
1894/**\r
1895 Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
1896\r
a9292c13 1897 @param Xhc The XHCI Instance.\r
92870c98 1898 @param EvtRing The event ring to sync.\r
1899\r
1900 @retval EFI_SUCCESS The event ring is synchronized successfully.\r
1901\r
1902**/\r
1903EFI_STATUS\r
1904EFIAPI\r
1905XhcSyncEventRing (\r
a9292c13 1906 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1907 IN EVENT_RING *EvtRing\r
1908 )\r
1909{\r
1910 UINTN Index;\r
a9292c13 1911 TRB_TEMPLATE *EvtTrb1;\r
92870c98 1912\r
1913 ASSERT (EvtRing != NULL);\r
1914\r
1915 //\r
1916 // Calculate the EventRingEnqueue and EventRingCCS.\r
1917 // Note: only support single Segment\r
1918 //\r
a50f7c4c 1919 EvtTrb1 = EvtRing->EventRingDequeue;\r
92870c98 1920\r
1921 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {\r
a50f7c4c 1922 if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {\r
92870c98 1923 break;\r
1924 }\r
a50f7c4c 1925\r
92870c98 1926 EvtTrb1++;\r
a50f7c4c 1927\r
1928 if ((UINTN)EvtTrb1 >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
1929 EvtTrb1 = EvtRing->EventRingSeg0;\r
1930 EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;\r
1931 }\r
92870c98 1932 }\r
1933\r
1934 if (Index < EvtRing->TrbNumber) {\r
1935 EvtRing->EventRingEnqueue = EvtTrb1;\r
92870c98 1936 } else {\r
a50f7c4c 1937 ASSERT (FALSE);\r
92870c98 1938 }\r
1939\r
1940 return EFI_SUCCESS;\r
1941}\r
1942\r
1943/**\r
1944 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
1945\r
a9292c13 1946 @param Xhc The XHCI Instance.\r
92870c98 1947 @param TrsRing The transfer ring to sync.\r
1948\r
1949 @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
1950\r
1951**/\r
1952EFI_STATUS\r
1953EFIAPI\r
1954XhcSyncTrsRing (\r
a9292c13 1955 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1956 IN TRANSFER_RING *TrsRing\r
1957 )\r
1958{\r
1959 UINTN Index;\r
a9292c13 1960 TRB_TEMPLATE *TrsTrb;\r
92870c98 1961\r
1962 ASSERT (TrsRing != NULL);\r
1963 //\r
1964 // Calculate the latest RingEnqueue and RingPCS\r
1965 //\r
1966 TrsTrb = TrsRing->RingEnqueue;\r
1967 ASSERT (TrsTrb != NULL);\r
1968\r
1969 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {\r
1970 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {\r
1971 break;\r
1972 }\r
1973 TrsTrb++;\r
1974 if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {\r
a9292c13 1975 ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);\r
92870c98 1976 //\r
1977 // set cycle bit in Link TRB as normal\r
1978 //\r
a9292c13 1979 ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;\r
92870c98 1980 //\r
1981 // Toggle PCS maintained by software\r
1982 //\r
1983 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;\r
1847ed0b 1984 TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0; // Use host address\r
92870c98 1985 }\r
1986 }\r
1987\r
1988 ASSERT (Index != TrsRing->TrbNumber);\r
1989\r
1990 if (TrsTrb != TrsRing->RingEnqueue) {\r
1991 TrsRing->RingEnqueue = TrsTrb;\r
1992 }\r
1993\r
1994 //\r
1995 // Clear the Trb context for enqueue, but reserve the PCS bit\r
1996 //\r
a9292c13 1997 TrsTrb->Parameter1 = 0;\r
1998 TrsTrb->Parameter2 = 0;\r
1999 TrsTrb->Status = 0;\r
2000 TrsTrb->RsvdZ1 = 0;\r
2001 TrsTrb->Type = 0;\r
2002 TrsTrb->Control = 0;\r
92870c98 2003\r
2004 return EFI_SUCCESS;\r
2005}\r
2006\r
2007/**\r
2008 Check if there is a new generated event.\r
2009\r
a9292c13 2010 @param Xhc The XHCI Instance.\r
92870c98 2011 @param EvtRing The event ring to check.\r
2012 @param NewEvtTrb The new event TRB found.\r
2013\r
2014 @retval EFI_SUCCESS Found a new event TRB at the event ring.\r
2015 @retval EFI_NOT_READY The event ring has no new event.\r
2016\r
2017**/\r
2018EFI_STATUS\r
2019EFIAPI\r
2020XhcCheckNewEvent (\r
a9292c13 2021 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 2022 IN EVENT_RING *EvtRing,\r
a9292c13 2023 OUT TRB_TEMPLATE **NewEvtTrb\r
92870c98 2024 )\r
2025{\r
92870c98 2026 ASSERT (EvtRing != NULL);\r
2027\r
92870c98 2028 *NewEvtTrb = EvtRing->EventRingDequeue;\r
2029\r
2030 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {\r
2031 return EFI_NOT_READY;\r
2032 }\r
2033\r
92870c98 2034 EvtRing->EventRingDequeue++;\r
2035 //\r
2036 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.\r
2037 //\r
a50f7c4c 2038 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
92870c98 2039 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;\r
2040 }\r
2041\r
b6cb9c39 2042 return EFI_SUCCESS;\r
92870c98 2043}\r
2044\r
2045/**\r
2046 Ring the door bell to notify XHCI there is a transaction to be executed.\r
2047\r
a9292c13 2048 @param Xhc The XHCI Instance.\r
92870c98 2049 @param SlotId The slot id of the target device.\r
2050 @param Dci The device context index of the target slot or endpoint.\r
2051\r
2052 @retval EFI_SUCCESS Successfully ring the door bell.\r
2053\r
2054**/\r
2055EFI_STATUS\r
2056EFIAPI\r
2057XhcRingDoorBell (\r
a9292c13 2058 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 2059 IN UINT8 SlotId,\r
2060 IN UINT8 Dci\r
2061 )\r
2062{\r
2063 if (SlotId == 0) {\r
2064 XhcWriteDoorBellReg (Xhc, 0, 0);\r
2065 } else {\r
2066 XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);\r
2067 }\r
2068\r
2069 return EFI_SUCCESS;\r
2070}\r
2071\r
2072/**\r
2073 Ring the door bell to notify XHCI there is a transaction to be executed through URB.\r
2074\r
a9292c13 2075 @param Xhc The XHCI Instance.\r
92870c98 2076 @param Urb The URB to be rung.\r
2077\r
2078 @retval EFI_SUCCESS Successfully ring the door bell.\r
2079\r
2080**/\r
2081EFI_STATUS\r
2082RingIntTransferDoorBell (\r
a9292c13 2083 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 2084 IN URB *Urb\r
2085 )\r
2086{\r
2087 UINT8 SlotId;\r
2088 UINT8 Dci;\r
2089\r
6b4483cd 2090 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
2091 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
92870c98 2092 XhcRingDoorBell (Xhc, SlotId, Dci);\r
2093 return EFI_SUCCESS;\r
2094}\r
2095\r
2096/**\r
2097 Assign and initialize the device slot for a new device.\r
2098\r
a9292c13 2099 @param Xhc The XHCI Instance.\r
92870c98 2100 @param ParentRouteChart The route string pointed to the parent device.\r
2101 @param ParentPort The port at which the device is located.\r
2102 @param RouteChart The route string pointed to the device.\r
2103 @param DeviceSpeed The device speed.\r
2104\r
2105 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
2106\r
2107**/\r
2108EFI_STATUS\r
2109EFIAPI\r
2110XhcInitializeDeviceSlot (\r
a9292c13 2111 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 2112 IN USB_DEV_ROUTE ParentRouteChart,\r
2113 IN UINT16 ParentPort,\r
2114 IN USB_DEV_ROUTE RouteChart,\r
2115 IN UINT8 DeviceSpeed\r
2116 )\r
2117{\r
a9292c13 2118 EFI_STATUS Status;\r
2119 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2120 INPUT_CONTEXT *InputContext;\r
2121 DEVICE_CONTEXT *OutputContext;\r
2122 TRANSFER_RING *EndpointTransferRing;\r
2123 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
2124 UINT8 DeviceAddress;\r
2125 CMD_TRB_ENABLE_SLOT CmdTrb;\r
2126 UINT8 SlotId;\r
2127 UINT8 ParentSlotId;\r
2128 DEVICE_CONTEXT *ParentDeviceContext;\r
1847ed0b 2129 EFI_PHYSICAL_ADDRESS PhyAddr;\r
a9292c13 2130\r
2131 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
92870c98 2132 CmdTrb.CycleBit = 1;\r
2133 CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
2134\r
2135 Status = XhcCmdTransfer (\r
2136 Xhc,\r
a9292c13 2137 (TRB_TEMPLATE *) (UINTN) &CmdTrb,\r
92870c98 2138 XHC_GENERIC_TIMEOUT,\r
a9292c13 2139 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 2140 );\r
260fbf53 2141 if (EFI_ERROR (Status)) {\r
87000d77 2142 DEBUG ((DEBUG_ERROR, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));\r
260fbf53
EL
2143 return Status;\r
2144 }\r
92870c98 2145 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
87000d77 2146 DEBUG ((DEBUG_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
92870c98 2147 SlotId = (UINT8)EvtTrb->SlotId;\r
2148 ASSERT (SlotId != 0);\r
2149\r
a9292c13 2150 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
2151 Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
2152 Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
2153 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
2154 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
92870c98 2155\r
2156 //\r
2157 // 4.3.3 Device Slot Initialization\r
2158 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
2159 //\r
1847ed0b 2160 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));\r
92870c98 2161 ASSERT (InputContext != NULL);\r
2162 ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
a9292c13 2163 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
92870c98 2164\r
a9292c13 2165 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
92870c98 2166\r
2167 //\r
2168 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
2169 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
2170 // Context are affected by the command.\r
2171 //\r
2172 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
2173\r
2174 //\r
2175 // 3) Initialize the Input Slot Context data structure\r
2176 //\r
a9292c13 2177 InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
92870c98 2178 InputContext->Slot.Speed = DeviceSpeed + 1;\r
2179 InputContext->Slot.ContextEntries = 1;\r
a9292c13 2180 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
92870c98 2181\r
a9292c13 2182 if (RouteChart.Route.RouteString) {\r
92870c98 2183 //\r
2184 // The device is behind of hub device.\r
2185 //\r
a9292c13 2186 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);\r
92870c98 2187 ASSERT (ParentSlotId != 0);\r
2188 //\r
2189 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
2190 //\r
a9292c13 2191 ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
92870c98 2192 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
2193 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
2194 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
2195 //\r
2196 // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
2197 // environment from Full/Low speed signaling environment for a device\r
2198 //\r
2199 InputContext->Slot.TTPortNum = ParentPort;\r
2200 InputContext->Slot.TTHubSlotId = ParentSlotId;\r
2201 }\r
2202 } else {\r
2203 //\r
2204 // Inherit the TT parameters from parent device.\r
2205 //\r
2206 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
2207 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
2208 //\r
2209 // If the device is a High speed device then down the speed to be the same as its parent Hub\r
2210 //\r
2211 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2212 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
2213 }\r
2214 }\r
2215 }\r
2216\r
2217 //\r
2218 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
2219 //\r
a9292c13 2220 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
2221 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
2222 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
92870c98 2223 //\r
2224 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
2225 //\r
2226 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
2227\r
2228 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2229 InputContext->EP[0].MaxPacketSize = 512;\r
2230 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2231 InputContext->EP[0].MaxPacketSize = 64;\r
2232 } else {\r
2233 InputContext->EP[0].MaxPacketSize = 8;\r
2234 }\r
2235 //\r
2236 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
2237 // 1KB, and Bulk and Isoch endpoints 3KB.\r
2238 //\r
2239 InputContext->EP[0].AverageTRBLength = 8;\r
2240 InputContext->EP[0].MaxBurstSize = 0;\r
2241 InputContext->EP[0].Interval = 0;\r
2242 InputContext->EP[0].MaxPStreams = 0;\r
2243 InputContext->EP[0].Mult = 0;\r
2244 InputContext->EP[0].CErr = 3;\r
2245\r
2246 //\r
2247 // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
2248 //\r
1847ed0b
EL
2249 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2250 Xhc->MemPool,\r
2251 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
2252 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2253 );\r
2254 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
2255 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 2256\r
2257 //\r
2258 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
2259 //\r
1847ed0b 2260 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));\r
a9292c13 2261 ASSERT (OutputContext != NULL);\r
2262 ASSERT (((UINTN) OutputContext & 0x3F) == 0);\r
2263 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));\r
92870c98 2264\r
a9292c13 2265 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
92870c98 2266 //\r
2267 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
2268 // a pointer to the Output Device Context data structure (6.2.1).\r
2269 //\r
1847ed0b
EL
2270 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));\r
2271 //\r
2272 // Fill DCBAA with PCI device address\r
2273 //\r
2274 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;\r
92870c98 2275\r
2276 //\r
2277 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
2278 // Context data structure described above.\r
2279 //\r
26b85012
FT
2280 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request\r
2281 // to device.\r
2282 //\r
2283 gBS->Stall (XHC_RESET_RECOVERY_DELAY);\r
92870c98 2284 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
1847ed0b
EL
2285 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
2286 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2287 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 2288 CmdTrbAddr.CycleBit = 1;\r
2289 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
a9292c13 2290 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
92870c98 2291 Status = XhcCmdTransfer (\r
2292 Xhc,\r
a9292c13 2293 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,\r
92870c98 2294 XHC_GENERIC_TIMEOUT,\r
a9292c13 2295 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 2296 );\r
260fbf53
EL
2297 if (!EFI_ERROR (Status)) {\r
2298 DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;\r
87000d77 2299 DEBUG ((DEBUG_INFO, " Address %d assigned successfully\n", DeviceAddress));\r
260fbf53 2300 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
a3212009 2301 } else {\r
b5d4a35d 2302 DEBUG ((DEBUG_ERROR, " Slot %d address not assigned successfully. Status = %r\n", SlotId, Status));\r
a3212009 2303 XhcDisableSlotCmd (Xhc, SlotId);\r
260fbf53 2304 }\r
92870c98 2305\r
2306 return Status;\r
2307}\r
2308\r
2309/**\r
6b4483cd 2310 Assign and initialize the device slot for a new device.\r
92870c98 2311\r
6b4483cd 2312 @param Xhc The XHCI Instance.\r
2313 @param ParentRouteChart The route string pointed to the parent device.\r
2314 @param ParentPort The port at which the device is located.\r
2315 @param RouteChart The route string pointed to the device.\r
2316 @param DeviceSpeed The device speed.\r
92870c98 2317\r
6b4483cd 2318 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
92870c98 2319\r
2320**/\r
2321EFI_STATUS\r
2322EFIAPI\r
6b4483cd 2323XhcInitializeDeviceSlot64 (\r
2324 IN USB_XHCI_INSTANCE *Xhc,\r
2325 IN USB_DEV_ROUTE ParentRouteChart,\r
2326 IN UINT16 ParentPort,\r
2327 IN USB_DEV_ROUTE RouteChart,\r
2328 IN UINT8 DeviceSpeed\r
92870c98 2329 )\r
2330{\r
6b4483cd 2331 EFI_STATUS Status;\r
2332 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2333 INPUT_CONTEXT_64 *InputContext;\r
2334 DEVICE_CONTEXT_64 *OutputContext;\r
2335 TRANSFER_RING *EndpointTransferRing;\r
2336 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
2337 UINT8 DeviceAddress;\r
2338 CMD_TRB_ENABLE_SLOT CmdTrb;\r
2339 UINT8 SlotId;\r
2340 UINT8 ParentSlotId;\r
2341 DEVICE_CONTEXT_64 *ParentDeviceContext;\r
1847ed0b 2342 EFI_PHYSICAL_ADDRESS PhyAddr;\r
92870c98 2343\r
6b4483cd 2344 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
2345 CmdTrb.CycleBit = 1;\r
2346 CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
92870c98 2347\r
6b4483cd 2348 Status = XhcCmdTransfer (\r
2349 Xhc,\r
2350 (TRB_TEMPLATE *) (UINTN) &CmdTrb,\r
2351 XHC_GENERIC_TIMEOUT,\r
2352 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2353 );\r
260fbf53 2354 if (EFI_ERROR (Status)) {\r
87000d77 2355 DEBUG ((DEBUG_ERROR, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));\r
260fbf53
EL
2356 return Status;\r
2357 }\r
6b4483cd 2358 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
87000d77 2359 DEBUG ((DEBUG_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
6b4483cd 2360 SlotId = (UINT8)EvtTrb->SlotId;\r
2361 ASSERT (SlotId != 0);\r
92870c98 2362\r
6b4483cd 2363 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
2364 Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
2365 Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
2366 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
2367 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
92870c98 2368\r
2369 //\r
6b4483cd 2370 // 4.3.3 Device Slot Initialization\r
2371 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
92870c98 2372 //\r
1847ed0b 2373 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));\r
6b4483cd 2374 ASSERT (InputContext != NULL);\r
2375 ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
2376 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
2377\r
2378 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
92870c98 2379\r
92870c98 2380 //\r
6b4483cd 2381 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
2382 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
2383 // Context are affected by the command.\r
92870c98 2384 //\r
6b4483cd 2385 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
92870c98 2386\r
2387 //\r
6b4483cd 2388 // 3) Initialize the Input Slot Context data structure\r
92870c98 2389 //\r
6b4483cd 2390 InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
2391 InputContext->Slot.Speed = DeviceSpeed + 1;\r
2392 InputContext->Slot.ContextEntries = 1;\r
2393 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
92870c98 2394\r
6b4483cd 2395 if (RouteChart.Route.RouteString) {\r
2396 //\r
2397 // The device is behind of hub device.\r
2398 //\r
2399 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);\r
2400 ASSERT (ParentSlotId != 0);\r
2401 //\r
2402 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
2403 //\r
2404 ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
2405 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
2406 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
2407 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
2408 //\r
2409 // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
2410 // environment from Full/Low speed signaling environment for a device\r
2411 //\r
2412 InputContext->Slot.TTPortNum = ParentPort;\r
2413 InputContext->Slot.TTHubSlotId = ParentSlotId;\r
2414 }\r
2415 } else {\r
2416 //\r
2417 // Inherit the TT parameters from parent device.\r
2418 //\r
2419 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
2420 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
2421 //\r
2422 // If the device is a High speed device then down the speed to be the same as its parent Hub\r
2423 //\r
2424 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2425 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
2426 }\r
92870c98 2427 }\r
2428 }\r
2429\r
92870c98 2430 //\r
6b4483cd 2431 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
92870c98 2432 //\r
6b4483cd 2433 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
2434 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
2435 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
2436 //\r
2437 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
2438 //\r
2439 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
2440\r
2441 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2442 InputContext->EP[0].MaxPacketSize = 512;\r
2443 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2444 InputContext->EP[0].MaxPacketSize = 64;\r
2445 } else {\r
2446 InputContext->EP[0].MaxPacketSize = 8;\r
2447 }\r
2448 //\r
2449 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
2450 // 1KB, and Bulk and Isoch endpoints 3KB.\r
2451 //\r
2452 InputContext->EP[0].AverageTRBLength = 8;\r
2453 InputContext->EP[0].MaxBurstSize = 0;\r
2454 InputContext->EP[0].Interval = 0;\r
2455 InputContext->EP[0].MaxPStreams = 0;\r
2456 InputContext->EP[0].Mult = 0;\r
2457 InputContext->EP[0].CErr = 3;\r
2458\r
2459 //\r
2460 // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
2461 //\r
1847ed0b
EL
2462 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2463 Xhc->MemPool,\r
2464 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
2465 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2466 );\r
2467 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
2468 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 2469\r
2470 //\r
2471 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
2472 //\r
1847ed0b 2473 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));\r
6b4483cd 2474 ASSERT (OutputContext != NULL);\r
2475 ASSERT (((UINTN) OutputContext & 0x3F) == 0);\r
2476 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));\r
2477\r
2478 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
2479 //\r
2480 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
2481 // a pointer to the Output Device Context data structure (6.2.1).\r
2482 //\r
1847ed0b
EL
2483 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));\r
2484 //\r
2485 // Fill DCBAA with PCI device address\r
2486 //\r
2487 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;\r
6b4483cd 2488\r
2489 //\r
2490 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
2491 // Context data structure described above.\r
2492 //\r
26b85012
FT
2493 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request\r
2494 // to device.\r
2495 //\r
2496 gBS->Stall (XHC_RESET_RECOVERY_DELAY);\r
6b4483cd 2497 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
1847ed0b
EL
2498 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
2499 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2500 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 2501 CmdTrbAddr.CycleBit = 1;\r
2502 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
2503 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
2504 Status = XhcCmdTransfer (\r
2505 Xhc,\r
2506 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,\r
2507 XHC_GENERIC_TIMEOUT,\r
2508 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2509 );\r
260fbf53
EL
2510 if (!EFI_ERROR (Status)) {\r
2511 DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress;\r
87000d77 2512 DEBUG ((DEBUG_INFO, " Address %d assigned successfully\n", DeviceAddress));\r
260fbf53 2513 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
a3212009 2514 } else {\r
b5d4a35d 2515 DEBUG ((DEBUG_ERROR, " Slot %d address not assigned successfully. Status = %r\n", SlotId, Status));\r
a3212009 2516 XhcDisableSlotCmd64 (Xhc, SlotId);\r
260fbf53 2517 }\r
a3212009 2518\r
6b4483cd 2519 return Status;\r
2520}\r
2521\r
2522\r
2523/**\r
2524 Disable the specified device slot.\r
2525\r
2526 @param Xhc The XHCI Instance.\r
2527 @param SlotId The slot id to be disabled.\r
2528\r
2529 @retval EFI_SUCCESS Successfully disable the device slot.\r
2530\r
2531**/\r
2532EFI_STATUS\r
2533EFIAPI\r
2534XhcDisableSlotCmd (\r
2535 IN USB_XHCI_INSTANCE *Xhc,\r
2536 IN UINT8 SlotId\r
2537 )\r
2538{\r
2539 EFI_STATUS Status;\r
2540 TRB_TEMPLATE *EvtTrb;\r
2541 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
2542 UINT8 Index;\r
2543 VOID *RingSeg;\r
2544\r
2545 //\r
2546 // Disable the device slots occupied by these devices on its downstream ports.\r
2547 // Entry 0 is reserved.\r
2548 //\r
2549 for (Index = 0; Index < 255; Index++) {\r
2550 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
2551 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
2552 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {\r
2553 continue;\r
2554 }\r
2555\r
2556 Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2557\r
2558 if (EFI_ERROR (Status)) {\r
87000d77 2559 DEBUG ((DEBUG_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));\r
6b4483cd 2560 Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
2561 }\r
2562 }\r
2563\r
2564 //\r
2565 // Construct the disable slot command\r
2566 //\r
87000d77 2567 DEBUG ((DEBUG_INFO, "Disable device slot %d!\n", SlotId));\r
6b4483cd 2568\r
2569 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
2570 CmdTrbDisSlot.CycleBit = 1;\r
2571 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
2572 CmdTrbDisSlot.SlotId = SlotId;\r
2573 Status = XhcCmdTransfer (\r
2574 Xhc,\r
2575 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,\r
2576 XHC_GENERIC_TIMEOUT,\r
2577 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2578 );\r
260fbf53 2579 if (EFI_ERROR (Status)) {\r
87000d77 2580 DEBUG ((DEBUG_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));\r
260fbf53
EL
2581 return Status;\r
2582 }\r
6b4483cd 2583 //\r
2584 // Free the slot's device context entry\r
2585 //\r
2586 Xhc->DCBAA[SlotId] = 0;\r
2587\r
2588 //\r
2589 // Free the slot related data structure\r
2590 //\r
2591 for (Index = 0; Index < 31; Index++) {\r
2592 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
2593 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
2594 if (RingSeg != NULL) {\r
1847ed0b 2595 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
6b4483cd 2596 }\r
2597 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
1847ed0b 2598 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
6b4483cd 2599 }\r
2600 }\r
2601\r
2602 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
2603 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
2604 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
2605 }\r
2606 }\r
2607\r
e1f2dfec
SZ
2608 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {\r
2609 FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);\r
2610 }\r
2611\r
6b4483cd 2612 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
1847ed0b 2613 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
6b4483cd 2614 }\r
2615\r
2616 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
1847ed0b 2617 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));\r
6b4483cd 2618 }\r
2619 //\r
2620 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
2621 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
2622 // remove urb from XHCI's asynchronous transfer list.\r
2623 //\r
2624 Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
2625 Xhc->UsbDevContext[SlotId].SlotId = 0;\r
2626\r
2627 return Status;\r
2628}\r
2629\r
2630/**\r
2631 Disable the specified device slot.\r
2632\r
2633 @param Xhc The XHCI Instance.\r
2634 @param SlotId The slot id to be disabled.\r
2635\r
2636 @retval EFI_SUCCESS Successfully disable the device slot.\r
2637\r
2638**/\r
2639EFI_STATUS\r
2640EFIAPI\r
2641XhcDisableSlotCmd64 (\r
2642 IN USB_XHCI_INSTANCE *Xhc,\r
2643 IN UINT8 SlotId\r
2644 )\r
2645{\r
2646 EFI_STATUS Status;\r
2647 TRB_TEMPLATE *EvtTrb;\r
2648 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
2649 UINT8 Index;\r
2650 VOID *RingSeg;\r
2651\r
2652 //\r
2653 // Disable the device slots occupied by these devices on its downstream ports.\r
2654 // Entry 0 is reserved.\r
2655 //\r
2656 for (Index = 0; Index < 255; Index++) {\r
2657 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
2658 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
2659 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {\r
2660 continue;\r
2661 }\r
2662\r
2663 Status = XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2664\r
2665 if (EFI_ERROR (Status)) {\r
87000d77 2666 DEBUG ((DEBUG_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));\r
6b4483cd 2667 Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
2668 }\r
2669 }\r
2670\r
2671 //\r
2672 // Construct the disable slot command\r
2673 //\r
87000d77 2674 DEBUG ((DEBUG_INFO, "Disable device slot %d!\n", SlotId));\r
6b4483cd 2675\r
2676 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
2677 CmdTrbDisSlot.CycleBit = 1;\r
2678 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
2679 CmdTrbDisSlot.SlotId = SlotId;\r
2680 Status = XhcCmdTransfer (\r
2681 Xhc,\r
2682 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,\r
2683 XHC_GENERIC_TIMEOUT,\r
2684 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2685 );\r
260fbf53 2686 if (EFI_ERROR (Status)) {\r
87000d77 2687 DEBUG ((DEBUG_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));\r
260fbf53
EL
2688 return Status;\r
2689 }\r
6b4483cd 2690 //\r
2691 // Free the slot's device context entry\r
2692 //\r
2693 Xhc->DCBAA[SlotId] = 0;\r
2694\r
2695 //\r
2696 // Free the slot related data structure\r
2697 //\r
2698 for (Index = 0; Index < 31; Index++) {\r
2699 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
2700 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
2701 if (RingSeg != NULL) {\r
1847ed0b 2702 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
6b4483cd 2703 }\r
2704 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
1847ed0b 2705 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
6b4483cd 2706 }\r
2707 }\r
2708\r
2709 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
2710 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
2711 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
2712 }\r
2713 }\r
2714\r
e1f2dfec
SZ
2715 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {\r
2716 FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);\r
2717 }\r
2718\r
6b4483cd 2719 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
1847ed0b 2720 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
6b4483cd 2721 }\r
2722\r
2723 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
1847ed0b 2724 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));\r
6b4483cd 2725 }\r
2726 //\r
2727 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
2728 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
2729 // remove urb from XHCI's asynchronous transfer list.\r
2730 //\r
2731 Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
2732 Xhc->UsbDevContext[SlotId].SlotId = 0;\r
2733\r
2734 return Status;\r
2735}\r
2736\r
e1f2dfec
SZ
2737/**\r
2738 Initialize endpoint context in input context.\r
2739\r
2740 @param Xhc The XHCI Instance.\r
2741 @param SlotId The slot id to be configured.\r
2742 @param DeviceSpeed The device's speed.\r
2743 @param InputContext The pointer to the input context.\r
2744 @param IfDesc The pointer to the usb device interface descriptor.\r
2745\r
2746 @return The maximum device context index of endpoint.\r
2747\r
2748**/\r
2749UINT8\r
2750EFIAPI\r
2751XhcInitializeEndpointContext (\r
2752 IN USB_XHCI_INSTANCE *Xhc,\r
2753 IN UINT8 SlotId,\r
2754 IN UINT8 DeviceSpeed,\r
2755 IN INPUT_CONTEXT *InputContext,\r
2756 IN USB_INTERFACE_DESCRIPTOR *IfDesc\r
2757 )\r
2758{\r
2759 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
2760 UINTN NumEp;\r
2761 UINTN EpIndex;\r
2762 UINT8 EpAddr;\r
2763 UINT8 Direction;\r
2764 UINT8 Dci;\r
2765 UINT8 MaxDci;\r
2766 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2767 UINT8 Interval;\r
2768 TRANSFER_RING *EndpointTransferRing;\r
2769\r
2770 MaxDci = 0;\r
2771\r
2772 NumEp = IfDesc->NumEndpoints;\r
2773\r
2774 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
2775 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
2776 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
2777 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2778 }\r
2779\r
fd5d2dd2
FT
2780 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
2781 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2782 continue;\r
2783 }\r
2784\r
e1f2dfec
SZ
2785 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
2786 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
2787\r
2788 Dci = XhcEndpointToDci (EpAddr, Direction);\r
2789 ASSERT (Dci < 32);\r
2790 if (Dci > MaxDci) {\r
2791 MaxDci = Dci;\r
2792 }\r
2793\r
2794 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
2795 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
2796\r
2797 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2798 //\r
2799 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
2800 //\r
2801 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2802 } else {\r
2803 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2804 }\r
2805\r
2806 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
2807 case USB_ENDPOINT_BULK:\r
2808 if (Direction == EfiUsbDataIn) {\r
2809 InputContext->EP[Dci-1].CErr = 3;\r
2810 InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
2811 } else {\r
2812 InputContext->EP[Dci-1].CErr = 3;\r
2813 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
2814 }\r
2815\r
2816 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2817 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2818 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2819 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2820 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
396ae94d
RN
2821 DEBUG ((DEBUG_INFO, "Endpoint[%x]: Created BULK ring [%p~%p)\n",\r
2822 EpDesc->EndpointAddress,\r
2823 EndpointTransferRing->RingSeg0,\r
2824 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
2825 ));\r
e1f2dfec
SZ
2826 }\r
2827\r
2828 break;\r
2829 case USB_ENDPOINT_ISO:\r
2830 if (Direction == EfiUsbDataIn) {\r
2831 InputContext->EP[Dci-1].CErr = 0;\r
2832 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
2833 } else {\r
2834 InputContext->EP[Dci-1].CErr = 0;\r
2835 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
2836 }\r
3719c2aa
HW
2837 //\r
2838 // Get the bInterval from descriptor and init the the interval field of endpoint context.\r
2839 // Refer to XHCI 1.1 spec section 6.2.3.6.\r
2840 //\r
2841 if (DeviceSpeed == EFI_USB_SPEED_FULL) {\r
2842 Interval = EpDesc->Interval;\r
2843 ASSERT (Interval >= 1 && Interval <= 16);\r
2844 InputContext->EP[Dci-1].Interval = Interval + 2;\r
2845 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2846 Interval = EpDesc->Interval;\r
2847 ASSERT (Interval >= 1 && Interval <= 16);\r
2848 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2849 }\r
2850\r
acedecdd
EL
2851 //\r
2852 // Do not support isochronous transfer now.\r
2853 //\r
87000d77 2854 DEBUG ((DEBUG_INFO, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));\r
acedecdd
EL
2855 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2856 continue;\r
e1f2dfec
SZ
2857 case USB_ENDPOINT_INTERRUPT:\r
2858 if (Direction == EfiUsbDataIn) {\r
2859 InputContext->EP[Dci-1].CErr = 3;\r
2860 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
2861 } else {\r
2862 InputContext->EP[Dci-1].CErr = 3;\r
2863 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
2864 }\r
2865 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2866 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
2867 //\r
2868 // Get the bInterval from descriptor and init the the interval field of endpoint context\r
2869 //\r
2870 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
2871 Interval = EpDesc->Interval;\r
2872 //\r
2873 // Calculate through the bInterval field of Endpoint descriptor.\r
2874 //\r
2875 ASSERT (Interval != 0);\r
2876 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;\r
2877 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2878 Interval = EpDesc->Interval;\r
2879 ASSERT (Interval >= 1 && Interval <= 16);\r
2880 //\r
2881 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
2882 //\r
2883 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2884 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2885 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;\r
2886 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2887 InputContext->EP[Dci-1].CErr = 3;\r
2888 }\r
2889\r
2890 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2891 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2892 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2893 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
396ae94d
RN
2894 DEBUG ((DEBUG_INFO, "Endpoint[%x]: Created INT ring [%p~%p)\n",\r
2895 EpDesc->EndpointAddress,\r
2896 EndpointTransferRing->RingSeg0,\r
2897 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
2898 ));\r
e1f2dfec
SZ
2899 }\r
2900 break;\r
2901\r
2902 case USB_ENDPOINT_CONTROL:\r
acedecdd
EL
2903 //\r
2904 // Do not support control transfer now.\r
2905 //\r
87000d77 2906 DEBUG ((DEBUG_INFO, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));\r
e1f2dfec 2907 default:\r
87000d77 2908 DEBUG ((DEBUG_INFO, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));\r
acedecdd
EL
2909 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2910 continue;\r
e1f2dfec
SZ
2911 }\r
2912\r
2913 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2914 Xhc->MemPool,\r
2915 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
2916 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2917 );\r
6e1e5405
FT
2918 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);\r
2919 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
e1f2dfec
SZ
2920 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2921 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2922\r
2923 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2924 }\r
2925\r
2926 return MaxDci;\r
2927}\r
2928\r
2929/**\r
2930 Initialize endpoint context in input context.\r
2931\r
2932 @param Xhc The XHCI Instance.\r
2933 @param SlotId The slot id to be configured.\r
2934 @param DeviceSpeed The device's speed.\r
2935 @param InputContext The pointer to the input context.\r
2936 @param IfDesc The pointer to the usb device interface descriptor.\r
2937\r
2938 @return The maximum device context index of endpoint.\r
2939\r
2940**/\r
2941UINT8\r
2942EFIAPI\r
2943XhcInitializeEndpointContext64 (\r
2944 IN USB_XHCI_INSTANCE *Xhc,\r
2945 IN UINT8 SlotId,\r
2946 IN UINT8 DeviceSpeed,\r
2947 IN INPUT_CONTEXT_64 *InputContext,\r
2948 IN USB_INTERFACE_DESCRIPTOR *IfDesc\r
2949 )\r
2950{\r
2951 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
2952 UINTN NumEp;\r
2953 UINTN EpIndex;\r
2954 UINT8 EpAddr;\r
2955 UINT8 Direction;\r
2956 UINT8 Dci;\r
2957 UINT8 MaxDci;\r
2958 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2959 UINT8 Interval;\r
2960 TRANSFER_RING *EndpointTransferRing;\r
2961\r
2962 MaxDci = 0;\r
2963\r
2964 NumEp = IfDesc->NumEndpoints;\r
2965\r
2966 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
2967 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
2968 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
2969 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2970 }\r
2971\r
fd5d2dd2
FT
2972 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
2973 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2974 continue;\r
2975 }\r
2976\r
e1f2dfec
SZ
2977 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
2978 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
2979\r
2980 Dci = XhcEndpointToDci (EpAddr, Direction);\r
2981 ASSERT (Dci < 32);\r
2982 if (Dci > MaxDci) {\r
2983 MaxDci = Dci;\r
2984 }\r
2985\r
2986 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
2987 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
2988\r
2989 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2990 //\r
2991 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
2992 //\r
2993 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2994 } else {\r
2995 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2996 }\r
2997\r
2998 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
2999 case USB_ENDPOINT_BULK:\r
3000 if (Direction == EfiUsbDataIn) {\r
3001 InputContext->EP[Dci-1].CErr = 3;\r
3002 InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
3003 } else {\r
3004 InputContext->EP[Dci-1].CErr = 3;\r
3005 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
3006 }\r
3007\r
3008 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
3009 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
3010 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
3011 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
3012 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
396ae94d
RN
3013 DEBUG ((DEBUG_INFO, "Endpoint64[%x]: Created BULK ring [%p~%p)\n",\r
3014 EpDesc->EndpointAddress,\r
3015 EndpointTransferRing->RingSeg0,\r
3016 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
3017 ));\r
e1f2dfec
SZ
3018 }\r
3019\r
3020 break;\r
3021 case USB_ENDPOINT_ISO:\r
3022 if (Direction == EfiUsbDataIn) {\r
3023 InputContext->EP[Dci-1].CErr = 0;\r
3024 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
3025 } else {\r
3026 InputContext->EP[Dci-1].CErr = 0;\r
3027 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
3028 }\r
3719c2aa
HW
3029 //\r
3030 // Get the bInterval from descriptor and init the the interval field of endpoint context.\r
3031 // Refer to XHCI 1.1 spec section 6.2.3.6.\r
3032 //\r
3033 if (DeviceSpeed == EFI_USB_SPEED_FULL) {\r
3034 Interval = EpDesc->Interval;\r
3035 ASSERT (Interval >= 1 && Interval <= 16);\r
3036 InputContext->EP[Dci-1].Interval = Interval + 2;\r
3037 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
3038 Interval = EpDesc->Interval;\r
3039 ASSERT (Interval >= 1 && Interval <= 16);\r
3040 InputContext->EP[Dci-1].Interval = Interval - 1;\r
3041 }\r
3042\r
acedecdd
EL
3043 //\r
3044 // Do not support isochronous transfer now.\r
3045 //\r
87000d77 3046 DEBUG ((DEBUG_INFO, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));\r
acedecdd
EL
3047 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3048 continue;\r
e1f2dfec
SZ
3049 case USB_ENDPOINT_INTERRUPT:\r
3050 if (Direction == EfiUsbDataIn) {\r
3051 InputContext->EP[Dci-1].CErr = 3;\r
3052 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
3053 } else {\r
3054 InputContext->EP[Dci-1].CErr = 3;\r
3055 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
3056 }\r
3057 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
3058 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
3059 //\r
3060 // Get the bInterval from descriptor and init the the interval field of endpoint context\r
3061 //\r
3062 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
3063 Interval = EpDesc->Interval;\r
3064 //\r
3065 // Calculate through the bInterval field of Endpoint descriptor.\r
3066 //\r
3067 ASSERT (Interval != 0);\r
3068 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;\r
3069 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
3070 Interval = EpDesc->Interval;\r
3071 ASSERT (Interval >= 1 && Interval <= 16);\r
3072 //\r
3073 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
3074 //\r
3075 InputContext->EP[Dci-1].Interval = Interval - 1;\r
3076 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
3077 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;\r
3078 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
3079 InputContext->EP[Dci-1].CErr = 3;\r
3080 }\r
3081\r
3082 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
3083 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
3084 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
3085 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
396ae94d
RN
3086 DEBUG ((DEBUG_INFO, "Endpoint64[%x]: Created INT ring [%p~%p)\n",\r
3087 EpDesc->EndpointAddress,\r
3088 EndpointTransferRing->RingSeg0,\r
3089 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
3090 ));\r
e1f2dfec
SZ
3091 }\r
3092 break;\r
3093\r
3094 case USB_ENDPOINT_CONTROL:\r
acedecdd
EL
3095 //\r
3096 // Do not support control transfer now.\r
3097 //\r
87000d77 3098 DEBUG ((DEBUG_INFO, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));\r
e1f2dfec 3099 default:\r
87000d77 3100 DEBUG ((DEBUG_INFO, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));\r
acedecdd
EL
3101 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3102 continue;\r
e1f2dfec
SZ
3103 }\r
3104\r
3105 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
3106 Xhc->MemPool,\r
3107 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
3108 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
3109 );\r
6e1e5405
FT
3110 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);\r
3111 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
e1f2dfec
SZ
3112 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3113 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3114\r
3115 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3116 }\r
3117\r
3118 return MaxDci;\r
3119}\r
6b4483cd 3120\r
3121/**\r
3122 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
3123\r
3124 @param Xhc The XHCI Instance.\r
3125 @param SlotId The slot id to be configured.\r
3126 @param DeviceSpeed The device's speed.\r
3127 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3128\r
3129 @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
3130\r
3131**/\r
3132EFI_STATUS\r
3133EFIAPI\r
3134XhcSetConfigCmd (\r
3135 IN USB_XHCI_INSTANCE *Xhc,\r
3136 IN UINT8 SlotId,\r
3137 IN UINT8 DeviceSpeed,\r
3138 IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
3139 )\r
3140{\r
3141 EFI_STATUS Status;\r
6b4483cd 3142 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
6b4483cd 3143 UINT8 Index;\r
6b4483cd 3144 UINT8 Dci;\r
3145 UINT8 MaxDci;\r
1847ed0b 3146 EFI_PHYSICAL_ADDRESS PhyAddr;\r
6b4483cd 3147\r
6b4483cd 3148 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3149 INPUT_CONTEXT *InputContext;\r
3150 DEVICE_CONTEXT *OutputContext;\r
3151 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3152 //\r
3153 // 4.6.6 Configure Endpoint\r
3154 //\r
3155 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3156 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3157 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
3158 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));\r
3159\r
3160 ASSERT (ConfigDesc != NULL);\r
3161\r
3162 MaxDci = 0;\r
3163\r
3164 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3165 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
e1f2dfec 3166 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {\r
6b4483cd 3167 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3168 }\r
3169\r
fd5d2dd2
FT
3170 if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {\r
3171 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3172 continue;\r
3173 }\r
3174\r
e1f2dfec
SZ
3175 Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);\r
3176 if (Dci > MaxDci) {\r
3177 MaxDci = Dci;\r
6b4483cd 3178 }\r
e1f2dfec 3179\r
6b4483cd 3180 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3181 }\r
3182\r
3183 InputContext->InputControlContext.Dword2 |= BIT0;\r
3184 InputContext->Slot.ContextEntries = MaxDci;\r
3185 //\r
3186 // configure endpoint\r
3187 //\r
3188 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1847ed0b
EL
3189 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3190 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3191 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 3192 CmdTrbCfgEP.CycleBit = 1;\r
3193 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3194 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
87000d77 3195 DEBUG ((DEBUG_INFO, "Configure Endpoint\n"));\r
6b4483cd 3196 Status = XhcCmdTransfer (\r
3197 Xhc,\r
3198 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
3199 XHC_GENERIC_TIMEOUT,\r
3200 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3201 );\r
260fbf53 3202 if (EFI_ERROR (Status)) {\r
87000d77 3203 DEBUG ((DEBUG_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));\r
e1f2dfec
SZ
3204 } else {\r
3205 Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;\r
260fbf53 3206 }\r
e1f2dfec 3207\r
92870c98 3208 return Status;\r
3209}\r
3210\r
3211/**\r
3212 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
3213\r
a9292c13 3214 @param Xhc The XHCI Instance.\r
92870c98 3215 @param SlotId The slot id to be configured.\r
3216 @param DeviceSpeed The device's speed.\r
3217 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3218\r
3219 @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
3220\r
3221**/\r
3222EFI_STATUS\r
3223EFIAPI\r
6b4483cd 3224XhcSetConfigCmd64 (\r
a9292c13 3225 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 3226 IN UINT8 SlotId,\r
a9292c13 3227 IN UINT8 DeviceSpeed,\r
92870c98 3228 IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
3229 )\r
3230{\r
a9292c13 3231 EFI_STATUS Status;\r
a9292c13 3232 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
a9292c13 3233 UINT8 Index;\r
a9292c13 3234 UINT8 Dci;\r
3235 UINT8 MaxDci;\r
1847ed0b 3236 EFI_PHYSICAL_ADDRESS PhyAddr;\r
a9292c13 3237\r
a9292c13 3238 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
6b4483cd 3239 INPUT_CONTEXT_64 *InputContext;\r
3240 DEVICE_CONTEXT_64 *OutputContext;\r
a9292c13 3241 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
92870c98 3242 //\r
3243 // 4.6.6 Configure Endpoint\r
3244 //\r
a9292c13 3245 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3246 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
6b4483cd 3247 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
3248 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));\r
92870c98 3249\r
3250 ASSERT (ConfigDesc != NULL);\r
3251\r
3252 MaxDci = 0;\r
3253\r
3254 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3255 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
e1f2dfec 3256 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {\r
92870c98 3257 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3258 }\r
3259\r
fd5d2dd2
FT
3260 if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {\r
3261 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3262 continue;\r
3263 }\r
3264\r
e1f2dfec
SZ
3265 Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);\r
3266 if (Dci > MaxDci) {\r
3267 MaxDci = Dci;\r
92870c98 3268 }\r
d1102dba 3269\r
92870c98 3270 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3271 }\r
3272\r
3273 InputContext->InputControlContext.Dword2 |= BIT0;\r
3274 InputContext->Slot.ContextEntries = MaxDci;\r
3275 //\r
3276 // configure endpoint\r
3277 //\r
3278 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1847ed0b
EL
3279 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
3280 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3281 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 3282 CmdTrbCfgEP.CycleBit = 1;\r
3283 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
a9292c13 3284 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
87000d77 3285 DEBUG ((DEBUG_INFO, "Configure Endpoint\n"));\r
92870c98 3286 Status = XhcCmdTransfer (\r
3287 Xhc,\r
a9292c13 3288 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
92870c98 3289 XHC_GENERIC_TIMEOUT,\r
a9292c13 3290 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 3291 );\r
260fbf53 3292 if (EFI_ERROR (Status)) {\r
87000d77 3293 DEBUG ((DEBUG_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));\r
e1f2dfec
SZ
3294 } else {\r
3295 Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;\r
3296 }\r
3297\r
3298 return Status;\r
3299}\r
3300\r
3301/**\r
3302 Stop endpoint through XHCI's Stop_Endpoint cmd.\r
3303\r
3304 @param Xhc The XHCI Instance.\r
3305 @param SlotId The slot id to be configured.\r
3306 @param Dci The device context index of endpoint.\r
49be9c3c 3307 @param PendingUrb The pending URB to check completion status when stopping the end point.\r
e1f2dfec
SZ
3308\r
3309 @retval EFI_SUCCESS Stop endpoint successfully.\r
3310 @retval Others Failed to stop endpoint.\r
3311\r
3312**/\r
3313EFI_STATUS\r
3314EFIAPI\r
3315XhcStopEndpoint (\r
3316 IN USB_XHCI_INSTANCE *Xhc,\r
3317 IN UINT8 SlotId,\r
49be9c3c
RN
3318 IN UINT8 Dci,\r
3319 IN URB *PendingUrb OPTIONAL\r
e1f2dfec
SZ
3320 )\r
3321{\r
3322 EFI_STATUS Status;\r
3323 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3324 CMD_TRB_STOP_ENDPOINT CmdTrbStopED;\r
3325\r
87000d77 3326 DEBUG ((DEBUG_INFO, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
e1f2dfec 3327\r
49be9c3c
RN
3328 //\r
3329 // When XhcCheckUrbResult waits for the Stop_Endpoint completion, it also checks\r
3330 // the PendingUrb completion status, because it's possible that the PendingUrb is\r
3331 // finished just before stopping the end point, but after the looping check.\r
3332 //\r
3333 // The PendingUrb could be passed to XhcCmdTransfer to XhcExecTransfer to XhcCheckUrbResult\r
3334 // through function parameter, but That will cause every consumer of XhcCmdTransfer,\r
3335 // XhcExecTransfer and XhcCheckUrbResult pass a NULL PendingUrb.\r
3336 // But actually only XhcCheckUrbResult is aware of the PendingUrb.\r
3337 // So we choose to save the PendingUrb into the USB_XHCI_INSTANCE and use it in XhcCheckUrbResult.\r
3338 //\r
3339 ASSERT (Xhc->PendingUrb == NULL);\r
3340 Xhc->PendingUrb = PendingUrb;\r
3341 //\r
3342 // Reset the URB result from Timeout to NoError.\r
3343 // The USB result will be:\r
3344 // changed to Timeout when Stop/StopInvalidLength Transfer Event is received, or\r
3345 // remain NoError when Success/ShortPacket Transfer Event is received.\r
3346 //\r
3347 if (PendingUrb != NULL) {\r
3348 PendingUrb->Result = EFI_USB_NOERROR;\r
3349 }\r
3350\r
e1f2dfec
SZ
3351 //\r
3352 // Send stop endpoint command to transit Endpoint from running to stop state\r
3353 //\r
3354 ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));\r
3355 CmdTrbStopED.CycleBit = 1;\r
3356 CmdTrbStopED.Type = TRB_TYPE_STOP_ENDPOINT;\r
3357 CmdTrbStopED.EDID = Dci;\r
3358 CmdTrbStopED.SlotId = SlotId;\r
3359 Status = XhcCmdTransfer (\r
3360 Xhc,\r
3361 (TRB_TEMPLATE *) (UINTN) &CmdTrbStopED,\r
3362 XHC_GENERIC_TIMEOUT,\r
3363 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3364 );\r
3365 if (EFI_ERROR(Status)) {\r
87000d77 3366 DEBUG ((DEBUG_ERROR, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));\r
e1f2dfec
SZ
3367 }\r
3368\r
49be9c3c
RN
3369 Xhc->PendingUrb = NULL;\r
3370\r
e1f2dfec
SZ
3371 return Status;\r
3372}\r
3373\r
12e6c738
FT
3374/**\r
3375 Reset endpoint through XHCI's Reset_Endpoint cmd.\r
3376\r
3377 @param Xhc The XHCI Instance.\r
3378 @param SlotId The slot id to be configured.\r
3379 @param Dci The device context index of endpoint.\r
3380\r
3381 @retval EFI_SUCCESS Reset endpoint successfully.\r
3382 @retval Others Failed to reset endpoint.\r
3383\r
3384**/\r
3385EFI_STATUS\r
3386EFIAPI\r
3387XhcResetEndpoint (\r
3388 IN USB_XHCI_INSTANCE *Xhc,\r
3389 IN UINT8 SlotId,\r
3390 IN UINT8 Dci\r
3391 )\r
3392{\r
3393 EFI_STATUS Status;\r
3394 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3395 CMD_TRB_RESET_ENDPOINT CmdTrbResetED;\r
3396\r
87000d77 3397 DEBUG ((DEBUG_INFO, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
12e6c738
FT
3398\r
3399 //\r
3400 // Send stop endpoint command to transit Endpoint from running to stop state\r
3401 //\r
3402 ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
3403 CmdTrbResetED.CycleBit = 1;\r
3404 CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;\r
3405 CmdTrbResetED.EDID = Dci;\r
3406 CmdTrbResetED.SlotId = SlotId;\r
3407 Status = XhcCmdTransfer (\r
3408 Xhc,\r
3409 (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,\r
3410 XHC_GENERIC_TIMEOUT,\r
3411 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3412 );\r
3413 if (EFI_ERROR(Status)) {\r
87000d77 3414 DEBUG ((DEBUG_ERROR, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
12e6c738
FT
3415 }\r
3416\r
3417 return Status;\r
3418}\r
3419\r
3420/**\r
3421 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.\r
3422\r
3423 @param Xhc The XHCI Instance.\r
3424 @param SlotId The slot id to be configured.\r
3425 @param Dci The device context index of endpoint.\r
3426 @param Urb The dequeue pointer of the transfer ring specified\r
3427 by the urb to be updated.\r
3428\r
3429 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.\r
3430 @retval Others Failed to set transfer ring dequeue pointer.\r
3431\r
3432**/\r
3433EFI_STATUS\r
3434EFIAPI\r
3435XhcSetTrDequeuePointer (\r
3436 IN USB_XHCI_INSTANCE *Xhc,\r
3437 IN UINT8 SlotId,\r
3438 IN UINT8 Dci,\r
3439 IN URB *Urb\r
3440 )\r
3441{\r
3442 EFI_STATUS Status;\r
3443 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3444 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;\r
3445 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3446\r
87000d77 3447 DEBUG ((DEBUG_INFO, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));\r
12e6c738
FT
3448\r
3449 //\r
3450 // Send stop endpoint command to transit Endpoint from running to stop state\r
3451 //\r
3452 ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
3453 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));\r
3454 CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;\r
3455 CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3456 CmdSetTRDeq.CycleBit = 1;\r
3457 CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;\r
3458 CmdSetTRDeq.Endpoint = Dci;\r
3459 CmdSetTRDeq.SlotId = SlotId;\r
3460 Status = XhcCmdTransfer (\r
3461 Xhc,\r
3462 (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,\r
3463 XHC_GENERIC_TIMEOUT,\r
3464 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3465 );\r
3466 if (EFI_ERROR(Status)) {\r
87000d77 3467 DEBUG ((DEBUG_ERROR, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));\r
12e6c738
FT
3468 }\r
3469\r
3470 return Status;\r
3471}\r
3472\r
e1f2dfec
SZ
3473/**\r
3474 Set interface through XHCI's Configure_Endpoint cmd.\r
3475\r
3476 @param Xhc The XHCI Instance.\r
3477 @param SlotId The slot id to be configured.\r
3478 @param DeviceSpeed The device's speed.\r
3479 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3480 @param Request USB device request to send.\r
3481\r
3482 @retval EFI_SUCCESS Successfully set interface.\r
3483\r
3484**/\r
3485EFI_STATUS\r
3486EFIAPI\r
3487XhcSetInterface (\r
3488 IN USB_XHCI_INSTANCE *Xhc,\r
3489 IN UINT8 SlotId,\r
3490 IN UINT8 DeviceSpeed,\r
3491 IN USB_CONFIG_DESCRIPTOR *ConfigDesc,\r
3492 IN EFI_USB_DEVICE_REQUEST *Request\r
3493 )\r
3494{\r
3495 EFI_STATUS Status;\r
3496 USB_INTERFACE_DESCRIPTOR *IfDescActive;\r
3497 USB_INTERFACE_DESCRIPTOR *IfDescSet;\r
3498 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
3499 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
3500 UINTN NumEp;\r
3501 UINTN EpIndex;\r
3502 UINT8 EpAddr;\r
3503 UINT8 Direction;\r
3504 UINT8 Dci;\r
3505 UINT8 MaxDci;\r
3506 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3507 VOID *RingSeg;\r
3508\r
3509 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3510 INPUT_CONTEXT *InputContext;\r
3511 DEVICE_CONTEXT *OutputContext;\r
3512 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3513\r
3514 Status = EFI_SUCCESS;\r
3515\r
3516 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3517 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3518 //\r
3519 // XHCI 4.6.6 Configure Endpoint\r
3520 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3521 // Context and Add Context flags as follows:\r
3522 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop\r
3523 // Context and Add Context flags to '0'.\r
3524 //\r
3525 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.\r
3526 // So the default Drop Context and Add Context flags can be '0' to cover 1).\r
3527 //\r
3528 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
3529 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));\r
3530\r
3531 ASSERT (ConfigDesc != NULL);\r
3532\r
3533 MaxDci = 0;\r
3534\r
3535 IfDescActive = NULL;\r
3536 IfDescSet = NULL;\r
3537\r
3538 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3539 while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {\r
fd5d2dd2 3540 if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {\r
e1f2dfec
SZ
3541 if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {\r
3542 if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {\r
3543 //\r
3544 // Find out the active interface descriptor.\r
3545 //\r
3546 IfDescActive = IfDesc;\r
3547 } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {\r
3548 //\r
3549 // Find out the interface descriptor to set.\r
3550 //\r
3551 IfDescSet = IfDesc;\r
3552 }\r
3553 }\r
3554 }\r
3555 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3556 }\r
3557\r
3558 //\r
3559 // XHCI 4.6.6 Configure Endpoint\r
3560 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3561 // Context and Add Context flags as follows:\r
3562 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set\r
3563 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.\r
3564 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set\r
3565 // the Drop Context flag to '1' and Add Context flag to '0'.\r
3566 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context\r
3567 // and Add Context flags shall be set to '1'.\r
3568 //\r
3569 // Below codes are to cover 2), 3) and 4).\r
3570 //\r
3571\r
3572 if ((IfDescActive != NULL) && (IfDescSet != NULL)) {\r
3573 NumEp = IfDescActive->NumEndpoints;\r
3574 EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);\r
3575 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
3576 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
3577 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3578 }\r
3579\r
fd5d2dd2
FT
3580 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
3581 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3582 continue;\r
3583 }\r
3584\r
e1f2dfec
SZ
3585 EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);\r
3586 Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
3587\r
3588 Dci = XhcEndpointToDci (EpAddr, Direction);\r
3589 ASSERT (Dci < 32);\r
3590 if (Dci > MaxDci) {\r
3591 MaxDci = Dci;\r
3592 }\r
3593 //\r
3594 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3595 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.\r
3596 //\r
49be9c3c 3597 Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);\r
e1f2dfec
SZ
3598 if (EFI_ERROR (Status)) {\r
3599 return Status;\r
3600 }\r
3601 //\r
3602 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3603 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.\r
3604 //\r
3605 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {\r
3606 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;\r
3607 if (RingSeg != NULL) {\r
3608 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
3609 }\r
3610 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);\r
3611 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;\r
3612 }\r
3613\r
3614 //\r
3615 // Set the Drop Context flag to '1'.\r
3616 //\r
3617 InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);\r
3618\r
3619 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3620 }\r
3621\r
3622 //\r
3623 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3624 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate\r
3625 // Interface setting, to '0'.\r
3626 //\r
3627 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.\r
3628 //\r
3629\r
3630 //\r
3631 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3632 // 4) For each endpoint enabled by the Configure Endpoint Command:\r
3633 // a. Allocate a Transfer Ring.\r
3634 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.\r
3635 // c. Initialize the Endpoint Context data structure.\r
3636 //\r
3637 Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);\r
3638 if (Dci > MaxDci) {\r
3639 MaxDci = Dci;\r
3640 }\r
3641\r
3642 InputContext->InputControlContext.Dword2 |= BIT0;\r
3643 InputContext->Slot.ContextEntries = MaxDci;\r
3644 //\r
3645 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3646 // 5) Issue and successfully complete a Configure Endpoint Command.\r
3647 //\r
3648 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
3649 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3650 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3651 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3652 CmdTrbCfgEP.CycleBit = 1;\r
3653 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3654 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
87000d77 3655 DEBUG ((DEBUG_INFO, "SetInterface: Configure Endpoint\n"));\r
e1f2dfec
SZ
3656 Status = XhcCmdTransfer (\r
3657 Xhc,\r
3658 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
3659 XHC_GENERIC_TIMEOUT,\r
3660 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3661 );\r
3662 if (EFI_ERROR (Status)) {\r
87000d77 3663 DEBUG ((DEBUG_ERROR, "SetInterface: Config Endpoint Failed, Status = %r\n", Status));\r
e1f2dfec
SZ
3664 } else {\r
3665 //\r
3666 // Update the active AlternateSetting.\r
3667 //\r
3668 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;\r
3669 }\r
260fbf53 3670 }\r
92870c98 3671\r
3672 return Status;\r
3673}\r
3674\r
e1f2dfec
SZ
3675/**\r
3676 Set interface through XHCI's Configure_Endpoint cmd.\r
3677\r
3678 @param Xhc The XHCI Instance.\r
3679 @param SlotId The slot id to be configured.\r
3680 @param DeviceSpeed The device's speed.\r
3681 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3682 @param Request USB device request to send.\r
3683\r
3684 @retval EFI_SUCCESS Successfully set interface.\r
3685\r
3686**/\r
3687EFI_STATUS\r
3688EFIAPI\r
3689XhcSetInterface64 (\r
3690 IN USB_XHCI_INSTANCE *Xhc,\r
3691 IN UINT8 SlotId,\r
3692 IN UINT8 DeviceSpeed,\r
3693 IN USB_CONFIG_DESCRIPTOR *ConfigDesc,\r
3694 IN EFI_USB_DEVICE_REQUEST *Request\r
3695 )\r
3696{\r
3697 EFI_STATUS Status;\r
3698 USB_INTERFACE_DESCRIPTOR *IfDescActive;\r
3699 USB_INTERFACE_DESCRIPTOR *IfDescSet;\r
3700 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
3701 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
3702 UINTN NumEp;\r
3703 UINTN EpIndex;\r
3704 UINT8 EpAddr;\r
3705 UINT8 Direction;\r
3706 UINT8 Dci;\r
3707 UINT8 MaxDci;\r
3708 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3709 VOID *RingSeg;\r
3710\r
3711 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3712 INPUT_CONTEXT_64 *InputContext;\r
3713 DEVICE_CONTEXT_64 *OutputContext;\r
3714 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3715\r
3716 Status = EFI_SUCCESS;\r
3717\r
3718 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3719 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3720 //\r
3721 // XHCI 4.6.6 Configure Endpoint\r
3722 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3723 // Context and Add Context flags as follows:\r
3724 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop\r
3725 // Context and Add Context flags to '0'.\r
3726 //\r
3727 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.\r
3728 // So the default Drop Context and Add Context flags can be '0' to cover 1).\r
3729 //\r
3730 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
3731 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));\r
3732\r
3733 ASSERT (ConfigDesc != NULL);\r
3734\r
3735 MaxDci = 0;\r
3736\r
3737 IfDescActive = NULL;\r
3738 IfDescSet = NULL;\r
3739\r
3740 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3741 while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {\r
fd5d2dd2 3742 if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {\r
e1f2dfec
SZ
3743 if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {\r
3744 if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {\r
3745 //\r
3746 // Find out the active interface descriptor.\r
3747 //\r
3748 IfDescActive = IfDesc;\r
3749 } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {\r
3750 //\r
3751 // Find out the interface descriptor to set.\r
3752 //\r
3753 IfDescSet = IfDesc;\r
3754 }\r
3755 }\r
3756 }\r
3757 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3758 }\r
3759\r
3760 //\r
3761 // XHCI 4.6.6 Configure Endpoint\r
3762 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3763 // Context and Add Context flags as follows:\r
3764 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set\r
3765 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.\r
3766 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set\r
3767 // the Drop Context flag to '1' and Add Context flag to '0'.\r
3768 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context\r
3769 // and Add Context flags shall be set to '1'.\r
3770 //\r
3771 // Below codes are to cover 2), 3) and 4).\r
3772 //\r
3773\r
3774 if ((IfDescActive != NULL) && (IfDescSet != NULL)) {\r
3775 NumEp = IfDescActive->NumEndpoints;\r
3776 EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);\r
3777 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
3778 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
3779 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3780 }\r
3781\r
fd5d2dd2
FT
3782 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
3783 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3784 continue;\r
3785 }\r
3786\r
e1f2dfec
SZ
3787 EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);\r
3788 Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
3789\r
3790 Dci = XhcEndpointToDci (EpAddr, Direction);\r
3791 ASSERT (Dci < 32);\r
3792 if (Dci > MaxDci) {\r
3793 MaxDci = Dci;\r
3794 }\r
3795 //\r
3796 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3797 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.\r
3798 //\r
49be9c3c 3799 Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);\r
e1f2dfec
SZ
3800 if (EFI_ERROR (Status)) {\r
3801 return Status;\r
3802 }\r
3803 //\r
3804 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3805 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.\r
3806 //\r
3807 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {\r
3808 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;\r
3809 if (RingSeg != NULL) {\r
3810 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
3811 }\r
3812 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);\r
3813 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;\r
3814 }\r
3815\r
3816 //\r
3817 // Set the Drop Context flag to '1'.\r
3818 //\r
3819 InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);\r
3820\r
3821 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3822 }\r
3823\r
3824 //\r
3825 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3826 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate\r
3827 // Interface setting, to '0'.\r
3828 //\r
3829 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.\r
3830 //\r
3831\r
3832 //\r
3833 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3834 // 4) For each endpoint enabled by the Configure Endpoint Command:\r
3835 // a. Allocate a Transfer Ring.\r
3836 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.\r
3837 // c. Initialize the Endpoint Context data structure.\r
3838 //\r
3839 Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);\r
3840 if (Dci > MaxDci) {\r
3841 MaxDci = Dci;\r
3842 }\r
3843\r
3844 InputContext->InputControlContext.Dword2 |= BIT0;\r
3845 InputContext->Slot.ContextEntries = MaxDci;\r
3846 //\r
3847 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3848 // 5) Issue and successfully complete a Configure Endpoint Command.\r
3849 //\r
3850 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
3851 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
3852 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3853 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3854 CmdTrbCfgEP.CycleBit = 1;\r
3855 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3856 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
87000d77 3857 DEBUG ((DEBUG_INFO, "SetInterface64: Configure Endpoint\n"));\r
e1f2dfec
SZ
3858 Status = XhcCmdTransfer (\r
3859 Xhc,\r
3860 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
3861 XHC_GENERIC_TIMEOUT,\r
3862 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3863 );\r
3864 if (EFI_ERROR (Status)) {\r
87000d77 3865 DEBUG ((DEBUG_ERROR, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status));\r
e1f2dfec
SZ
3866 } else {\r
3867 //\r
3868 // Update the active AlternateSetting.\r
3869 //\r
3870 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;\r
3871 }\r
3872 }\r
3873\r
3874 return Status;\r
3875}\r
6b4483cd 3876\r
92870c98 3877/**\r
3878 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
3879\r
a9292c13 3880 @param Xhc The XHCI Instance.\r
92870c98 3881 @param SlotId The slot id to be evaluated.\r
3882 @param MaxPacketSize The max packet size supported by the device control transfer.\r
3883\r
3884 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
3885\r
3886**/\r
3887EFI_STATUS\r
3888EFIAPI\r
3889XhcEvaluateContext (\r
a9292c13 3890 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 3891 IN UINT8 SlotId,\r
3892 IN UINT32 MaxPacketSize\r
3893 )\r
3894{\r
a9292c13 3895 EFI_STATUS Status;\r
3896 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
3897 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3898 INPUT_CONTEXT *InputContext;\r
1847ed0b 3899 EFI_PHYSICAL_ADDRESS PhyAddr;\r
92870c98 3900\r
a9292c13 3901 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
92870c98 3902\r
3903 //\r
3904 // 4.6.7 Evaluate Context\r
3905 //\r
a9292c13 3906 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
92870c98 3907 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
3908\r
3909 InputContext->InputControlContext.Dword2 |= BIT1;\r
3910 InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
3911\r
3912 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
1847ed0b
EL
3913 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3914 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3915 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 3916 CmdTrbEvalu.CycleBit = 1;\r
3917 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
a9292c13 3918 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
87000d77 3919 DEBUG ((DEBUG_INFO, "Evaluate context\n"));\r
92870c98 3920 Status = XhcCmdTransfer (\r
3921 Xhc,\r
a9292c13 3922 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,\r
92870c98 3923 XHC_GENERIC_TIMEOUT,\r
a9292c13 3924 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 3925 );\r
260fbf53 3926 if (EFI_ERROR (Status)) {\r
87000d77 3927 DEBUG ((DEBUG_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));\r
260fbf53 3928 }\r
92870c98 3929 return Status;\r
3930}\r
3931\r
6b4483cd 3932/**\r
3933 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
3934\r
3935 @param Xhc The XHCI Instance.\r
3936 @param SlotId The slot id to be evaluated.\r
3937 @param MaxPacketSize The max packet size supported by the device control transfer.\r
3938\r
3939 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
3940\r
3941**/\r
3942EFI_STATUS\r
3943EFIAPI\r
3944XhcEvaluateContext64 (\r
3945 IN USB_XHCI_INSTANCE *Xhc,\r
3946 IN UINT8 SlotId,\r
3947 IN UINT32 MaxPacketSize\r
3948 )\r
3949{\r
3950 EFI_STATUS Status;\r
3951 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
3952 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3953 INPUT_CONTEXT_64 *InputContext;\r
1847ed0b 3954 EFI_PHYSICAL_ADDRESS PhyAddr;\r
6b4483cd 3955\r
3956 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
3957\r
3958 //\r
3959 // 4.6.7 Evaluate Context\r
3960 //\r
3961 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3962 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
3963\r
3964 InputContext->InputControlContext.Dword2 |= BIT1;\r
3965 InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
3966\r
3967 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
1847ed0b
EL
3968 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
3969 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3970 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 3971 CmdTrbEvalu.CycleBit = 1;\r
3972 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
3973 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
87000d77 3974 DEBUG ((DEBUG_INFO, "Evaluate context\n"));\r
6b4483cd 3975 Status = XhcCmdTransfer (\r
3976 Xhc,\r
3977 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,\r
3978 XHC_GENERIC_TIMEOUT,\r
3979 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3980 );\r
260fbf53 3981 if (EFI_ERROR (Status)) {\r
87000d77 3982 DEBUG ((DEBUG_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));\r
260fbf53 3983 }\r
6b4483cd 3984 return Status;\r
3985}\r
3986\r
3987\r
92870c98 3988/**\r
3989 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
3990\r
a9292c13 3991 @param Xhc The XHCI Instance.\r
92870c98 3992 @param SlotId The slot id to be configured.\r
3993 @param PortNum The total number of downstream port supported by the hub.\r
3994 @param TTT The TT think time of the hub device.\r
3995 @param MTT The multi-TT of the hub device.\r
3996\r
3997 @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
3998\r
3999**/\r
4000EFI_STATUS\r
4001XhcConfigHubContext (\r
a9292c13 4002 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 4003 IN UINT8 SlotId,\r
4004 IN UINT8 PortNum,\r
4005 IN UINT8 TTT,\r
4006 IN UINT8 MTT\r
4007 )\r
4008{\r
a9292c13 4009 EFI_STATUS Status;\r
a9292c13 4010 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
4011 INPUT_CONTEXT *InputContext;\r
4012 DEVICE_CONTEXT *OutputContext;\r
4013 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
1847ed0b 4014 EFI_PHYSICAL_ADDRESS PhyAddr;\r
92870c98 4015\r
a9292c13 4016 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
4017 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
4018 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
92870c98 4019\r
4020 //\r
4021 // 4.6.7 Evaluate Context\r
4022 //\r
4023 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
4024\r
4025 InputContext->InputControlContext.Dword2 |= BIT0;\r
4026\r
4027 //\r
4028 // Copy the slot context from OutputContext to Input context\r
4029 //\r
a9292c13 4030 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));\r
92870c98 4031 InputContext->Slot.Hub = 1;\r
4032 InputContext->Slot.PortNum = PortNum;\r
4033 InputContext->Slot.TTT = TTT;\r
4034 InputContext->Slot.MTT = MTT;\r
4035\r
4036 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1847ed0b
EL
4037 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
4038 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
4039 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 4040 CmdTrbCfgEP.CycleBit = 1;\r
4041 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
a9292c13 4042 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
87000d77 4043 DEBUG ((DEBUG_INFO, "Configure Hub Slot Context\n"));\r
92870c98 4044 Status = XhcCmdTransfer (\r
4045 Xhc,\r
a9292c13 4046 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
92870c98 4047 XHC_GENERIC_TIMEOUT,\r
a9292c13 4048 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 4049 );\r
260fbf53 4050 if (EFI_ERROR (Status)) {\r
87000d77 4051 DEBUG ((DEBUG_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));\r
260fbf53 4052 }\r
92870c98 4053 return Status;\r
4054}\r
4055\r
6b4483cd 4056/**\r
4057 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
4058\r
4059 @param Xhc The XHCI Instance.\r
4060 @param SlotId The slot id to be configured.\r
4061 @param PortNum The total number of downstream port supported by the hub.\r
4062 @param TTT The TT think time of the hub device.\r
4063 @param MTT The multi-TT of the hub device.\r
4064\r
4065 @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
4066\r
4067**/\r
4068EFI_STATUS\r
4069XhcConfigHubContext64 (\r
4070 IN USB_XHCI_INSTANCE *Xhc,\r
4071 IN UINT8 SlotId,\r
4072 IN UINT8 PortNum,\r
4073 IN UINT8 TTT,\r
4074 IN UINT8 MTT\r
4075 )\r
4076{\r
4077 EFI_STATUS Status;\r
6b4483cd 4078 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
4079 INPUT_CONTEXT_64 *InputContext;\r
4080 DEVICE_CONTEXT_64 *OutputContext;\r
4081 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
1847ed0b 4082 EFI_PHYSICAL_ADDRESS PhyAddr;\r
6b4483cd 4083\r
4084 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
4085 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
4086 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
4087\r
4088 //\r
4089 // 4.6.7 Evaluate Context\r
4090 //\r
4091 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
4092\r
4093 InputContext->InputControlContext.Dword2 |= BIT0;\r
4094\r
4095 //\r
4096 // Copy the slot context from OutputContext to Input context\r
4097 //\r
4098 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));\r
4099 InputContext->Slot.Hub = 1;\r
4100 InputContext->Slot.PortNum = PortNum;\r
4101 InputContext->Slot.TTT = TTT;\r
4102 InputContext->Slot.MTT = MTT;\r
4103\r
4104 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1847ed0b
EL
4105 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
4106 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
4107 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 4108 CmdTrbCfgEP.CycleBit = 1;\r
4109 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
4110 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
87000d77 4111 DEBUG ((DEBUG_INFO, "Configure Hub Slot Context\n"));\r
6b4483cd 4112 Status = XhcCmdTransfer (\r
4113 Xhc,\r
4114 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
4115 XHC_GENERIC_TIMEOUT,\r
4116 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
4117 );\r
260fbf53 4118 if (EFI_ERROR (Status)) {\r
87000d77 4119 DEBUG ((DEBUG_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));\r
260fbf53 4120 }\r
6b4483cd 4121 return Status;\r
4122}\r