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