]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciPei / XhciSched.c
CommitLineData
d987459f
SZ
1/** @file\r
2PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
3which is used to enable recovery function from USB Drivers.\r
4\r
3719c2aa 5Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.<BR>\r
8147fe09 6Copyright (C) 2022 Advanced Micro Devices, Inc. All rights reserved.<BR>\r
d987459f 7\r
9d510e61 8SPDX-License-Identifier: BSD-2-Clause-Patent\r
d987459f
SZ
9\r
10**/\r
11\r
12#include "XhcPeim.h"\r
13\r
14/**\r
15 Create a command transfer TRB to support XHCI command interfaces.\r
16\r
17 @param Xhc The XHCI device.\r
18 @param CmdTrb The cmd TRB to be executed.\r
19\r
20 @return Created URB or NULL.\r
21\r
22**/\r
1436aea4 23URB *\r
d987459f 24XhcPeiCreateCmdTrb (\r
1436aea4
MK
25 IN PEI_XHC_DEV *Xhc,\r
26 IN TRB_TEMPLATE *CmdTrb\r
d987459f
SZ
27 )\r
28{\r
1436aea4 29 URB *Urb;\r
d987459f
SZ
30\r
31 Urb = AllocateZeroPool (sizeof (URB));\r
32 if (Urb == NULL) {\r
33 return NULL;\r
34 }\r
35\r
1436aea4 36 Urb->Signature = XHC_URB_SIG;\r
d987459f 37\r
1436aea4 38 Urb->Ring = &Xhc->CmdRing;\r
d987459f 39 XhcPeiSyncTrsRing (Xhc, Urb->Ring);\r
1436aea4
MK
40 Urb->TrbNum = 1;\r
41 Urb->TrbStart = Urb->Ring->RingEnqueue;\r
d987459f
SZ
42 CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));\r
43 Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;\r
44 Urb->TrbEnd = Urb->TrbStart;\r
45\r
46 return Urb;\r
47}\r
48\r
49/**\r
50 Execute a XHCI cmd TRB pointed by CmdTrb.\r
51\r
52 @param Xhc The XHCI device.\r
53 @param CmdTrb The cmd TRB to be executed.\r
54 @param Timeout Indicates the maximum time, in millisecond, which the\r
55 transfer is allowed to complete.\r
56 @param EvtTrb The event TRB corresponding to the cmd TRB.\r
57\r
58 @retval EFI_SUCCESS The transfer was completed successfully.\r
59 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
60 @retval EFI_TIMEOUT The transfer failed due to timeout.\r
61 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
62\r
63**/\r
64EFI_STATUS\r
65XhcPeiCmdTransfer (\r
1436aea4
MK
66 IN PEI_XHC_DEV *Xhc,\r
67 IN TRB_TEMPLATE *CmdTrb,\r
68 IN UINTN Timeout,\r
69 OUT TRB_TEMPLATE **EvtTrb\r
d987459f
SZ
70 )\r
71{\r
1436aea4
MK
72 EFI_STATUS Status;\r
73 URB *Urb;\r
d987459f
SZ
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 (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {\r
87000d77 85 DEBUG ((DEBUG_ERROR, "XhcPeiCmdTransfer: HC is halted or has system error\n"));\r
d987459f
SZ
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 = XhcPeiCreateCmdTrb (Xhc, CmdTrb);\r
93 if (Urb == NULL) {\r
87000d77 94 DEBUG ((DEBUG_ERROR, "XhcPeiCmdTransfer: failed to create URB\n"));\r
d987459f
SZ
95 Status = EFI_OUT_OF_RESOURCES;\r
96 goto ON_EXIT;\r
97 }\r
98\r
99 Status = XhcPeiExecTransfer (Xhc, TRUE, Urb, Timeout);\r
100 *EvtTrb = Urb->EvtTrb;\r
101\r
102 if (Urb->Result == EFI_USB_NOERROR) {\r
103 Status = EFI_SUCCESS;\r
104 }\r
105\r
106 XhcPeiFreeUrb (Xhc, Urb);\r
107\r
108ON_EXIT:\r
109 return Status;\r
110}\r
111\r
112/**\r
113 Create a new URB for a new transaction.\r
114\r
115 @param Xhc The XHCI device\r
116 @param BusAddr The logical device address assigned by UsbBus driver\r
117 @param EpAddr Endpoint addrress\r
118 @param DevSpeed The device speed\r
119 @param MaxPacket The max packet length of the endpoint\r
120 @param Type The transaction type\r
121 @param Request The standard USB request for control transfer\r
122 @param Data The user data to transfer\r
123 @param DataLen The length of data buffer\r
124 @param Callback The function to call when data is transferred\r
125 @param Context The context to the callback\r
126\r
127 @return Created URB or NULL\r
128\r
129**/\r
1436aea4 130URB *\r
d987459f 131XhcPeiCreateUrb (\r
1436aea4
MK
132 IN PEI_XHC_DEV *Xhc,\r
133 IN UINT8 BusAddr,\r
134 IN UINT8 EpAddr,\r
135 IN UINT8 DevSpeed,\r
136 IN UINTN MaxPacket,\r
137 IN UINTN Type,\r
138 IN EFI_USB_DEVICE_REQUEST *Request,\r
139 IN VOID *Data,\r
140 IN UINTN DataLen,\r
141 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
142 IN VOID *Context\r
d987459f
SZ
143 )\r
144{\r
1436aea4
MK
145 USB_ENDPOINT *Ep;\r
146 EFI_STATUS Status;\r
147 URB *Urb;\r
d987459f
SZ
148\r
149 Urb = AllocateZeroPool (sizeof (URB));\r
150 if (Urb == NULL) {\r
151 return NULL;\r
152 }\r
153\r
154 Urb->Signature = XHC_URB_SIG;\r
155\r
156 Ep = &Urb->Ep;\r
157 Ep->BusAddr = BusAddr;\r
1436aea4 158 Ep->EpAddr = (UINT8)(EpAddr & 0x0F);\r
d987459f
SZ
159 Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
160 Ep->DevSpeed = DevSpeed;\r
161 Ep->MaxPacket = MaxPacket;\r
162 Ep->Type = Type;\r
163\r
164 Urb->Request = Request;\r
165 Urb->Data = Data;\r
166 Urb->DataLen = DataLen;\r
167 Urb->Callback = Callback;\r
168 Urb->Context = Context;\r
169\r
170 Status = XhcPeiCreateTransferTrb (Xhc, Urb);\r
171 if (EFI_ERROR (Status)) {\r
87000d77 172 DEBUG ((DEBUG_ERROR, "XhcPeiCreateUrb: XhcPeiCreateTransferTrb Failed, Status = %r\n", Status));\r
d987459f
SZ
173 FreePool (Urb);\r
174 Urb = NULL;\r
175 }\r
176\r
177 return Urb;\r
178}\r
179\r
180/**\r
181 Free an allocated URB.\r
182\r
183 @param Xhc The XHCI device.\r
184 @param Urb The URB to free.\r
185\r
186**/\r
187VOID\r
188XhcPeiFreeUrb (\r
1436aea4
MK
189 IN PEI_XHC_DEV *Xhc,\r
190 IN URB *Urb\r
d987459f
SZ
191 )\r
192{\r
193 if ((Xhc == NULL) || (Urb == NULL)) {\r
194 return;\r
195 }\r
196\r
b575ca32
JY
197 IoMmuUnmap (Urb->DataMap);\r
198\r
d987459f
SZ
199 FreePool (Urb);\r
200}\r
201\r
202/**\r
203 Create a transfer TRB.\r
204\r
205 @param Xhc The XHCI device\r
206 @param Urb The urb used to construct the transfer TRB.\r
207\r
208 @return Created TRB or NULL\r
209\r
210**/\r
211EFI_STATUS\r
212XhcPeiCreateTransferTrb (\r
1436aea4
MK
213 IN PEI_XHC_DEV *Xhc,\r
214 IN URB *Urb\r
d987459f
SZ
215 )\r
216{\r
1436aea4
MK
217 VOID *OutputContext;\r
218 TRANSFER_RING *EPRing;\r
219 UINT8 EPType;\r
220 UINT8 SlotId;\r
221 UINT8 Dci;\r
222 TRB *TrbStart;\r
223 UINTN TotalLen;\r
224 UINTN Len;\r
225 UINTN TrbNum;\r
226 EDKII_IOMMU_OPERATION MapOp;\r
227 EFI_PHYSICAL_ADDRESS PhyAddr;\r
228 VOID *Map;\r
229 EFI_STATUS Status;\r
d987459f
SZ
230\r
231 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
232 if (SlotId == 0) {\r
233 return EFI_DEVICE_ERROR;\r
234 }\r
235\r
236 Urb->Finished = FALSE;\r
237 Urb->StartDone = FALSE;\r
238 Urb->EndDone = FALSE;\r
239 Urb->Completed = 0;\r
240 Urb->Result = EFI_USB_NOERROR;\r
241\r
1436aea4
MK
242 Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
243 EPRing = (TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];\r
244 Urb->Ring = EPRing;\r
d987459f
SZ
245 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
246 if (Xhc->HcCParams.Data.Csz == 0) {\r
1436aea4 247 EPType = (UINT8)((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType;\r
d987459f 248 } else {\r
1436aea4 249 EPType = (UINT8)((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;\r
d987459f
SZ
250 }\r
251\r
b575ca32
JY
252 //\r
253 // No need to remap.\r
254 //\r
255 if ((Urb->Data != NULL) && (Urb->DataMap == NULL)) {\r
1436aea4 256 if (((UINT8)(Urb->Ep.Direction)) == EfiUsbDataIn) {\r
b575ca32
JY
257 MapOp = EdkiiIoMmuOperationBusMasterWrite;\r
258 } else {\r
259 MapOp = EdkiiIoMmuOperationBusMasterRead;\r
260 }\r
261\r
1436aea4 262 Len = Urb->DataLen;\r
b575ca32
JY
263 Status = IoMmuMap (MapOp, Urb->Data, &Len, &PhyAddr, &Map);\r
264\r
265 if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {\r
266 DEBUG ((DEBUG_ERROR, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));\r
267 return EFI_OUT_OF_RESOURCES;\r
268 }\r
269\r
1436aea4
MK
270 Urb->DataPhy = (VOID *)((UINTN)PhyAddr);\r
271 Urb->DataMap = Map;\r
b575ca32 272 }\r
d987459f
SZ
273\r
274 //\r
275 // Construct the TRB\r
276 //\r
277 XhcPeiSyncTrsRing (Xhc, EPRing);\r
278 Urb->TrbStart = EPRing->RingEnqueue;\r
279 switch (EPType) {\r
280 case ED_CONTROL_BIDIR:\r
281 //\r
282 // For control transfer, create SETUP_STAGE_TRB first.\r
283 //\r
1436aea4 284 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
d987459f
SZ
285 TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;\r
286 TrbStart->TrbCtrSetup.bRequest = Urb->Request->Request;\r
287 TrbStart->TrbCtrSetup.wValue = Urb->Request->Value;\r
288 TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index;\r
289 TrbStart->TrbCtrSetup.wLength = Urb->Request->Length;\r
290 TrbStart->TrbCtrSetup.Length = 8;\r
291 TrbStart->TrbCtrSetup.IntTarget = 0;\r
292 TrbStart->TrbCtrSetup.IOC = 1;\r
293 TrbStart->TrbCtrSetup.IDT = 1;\r
294 TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE;\r
b5379899
WX
295 if (Urb->DataLen > 0) {\r
296 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
297 TrbStart->TrbCtrSetup.TRT = 3;\r
298 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
299 TrbStart->TrbCtrSetup.TRT = 2;\r
300 } else {\r
301 DEBUG ((DEBUG_ERROR, "XhcPeiCreateTransferTrb: Direction sholud be IN or OUT when Data exists!\n"));\r
302 ASSERT (FALSE);\r
303 }\r
d987459f
SZ
304 } else {\r
305 TrbStart->TrbCtrSetup.TRT = 0;\r
306 }\r
1436aea4 307\r
d987459f
SZ
308 //\r
309 // Update the cycle bit\r
310 //\r
311 TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;\r
312 Urb->TrbNum++;\r
313\r
314 //\r
315 // For control transfer, create DATA_STAGE_TRB.\r
316 //\r
317 if (Urb->DataLen > 0) {\r
318 XhcPeiSyncTrsRing (Xhc, EPRing);\r
1436aea4 319 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
d987459f
SZ
320 TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT (Urb->DataPhy);\r
321 TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT (Urb->DataPhy);\r
1436aea4 322 TrbStart->TrbCtrData.Length = (UINT32)Urb->DataLen;\r
d987459f
SZ
323 TrbStart->TrbCtrData.TDSize = 0;\r
324 TrbStart->TrbCtrData.IntTarget = 0;\r
325 TrbStart->TrbCtrData.ISP = 1;\r
326 TrbStart->TrbCtrData.IOC = 1;\r
327 TrbStart->TrbCtrData.IDT = 0;\r
328 TrbStart->TrbCtrData.CH = 0;\r
329 TrbStart->TrbCtrData.Type = TRB_TYPE_DATA_STAGE;\r
330 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
331 TrbStart->TrbCtrData.DIR = 1;\r
332 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
333 TrbStart->TrbCtrData.DIR = 0;\r
334 } else {\r
335 TrbStart->TrbCtrData.DIR = 0;\r
336 }\r
1436aea4 337\r
d987459f
SZ
338 //\r
339 // Update the cycle bit\r
340 //\r
341 TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;\r
342 Urb->TrbNum++;\r
343 }\r
1436aea4 344\r
d987459f
SZ
345 //\r
346 // For control transfer, create STATUS_STAGE_TRB.\r
347 // Get the pointer to next TRB for status stage use\r
348 //\r
349 XhcPeiSyncTrsRing (Xhc, EPRing);\r
1436aea4 350 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
d987459f
SZ
351 TrbStart->TrbCtrStatus.IntTarget = 0;\r
352 TrbStart->TrbCtrStatus.IOC = 1;\r
353 TrbStart->TrbCtrStatus.CH = 0;\r
354 TrbStart->TrbCtrStatus.Type = TRB_TYPE_STATUS_STAGE;\r
355 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
356 TrbStart->TrbCtrStatus.DIR = 0;\r
357 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
358 TrbStart->TrbCtrStatus.DIR = 1;\r
359 } else {\r
360 TrbStart->TrbCtrStatus.DIR = 0;\r
361 }\r
1436aea4 362\r
d987459f
SZ
363 //\r
364 // Update the cycle bit\r
365 //\r
366 TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;\r
367 //\r
368 // Update the enqueue pointer\r
369 //\r
370 XhcPeiSyncTrsRing (Xhc, EPRing);\r
371 Urb->TrbNum++;\r
1436aea4 372 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
d987459f
SZ
373\r
374 break;\r
375\r
376 case ED_BULK_OUT:\r
377 case ED_BULK_IN:\r
378 TotalLen = 0;\r
379 Len = 0;\r
380 TrbNum = 0;\r
1436aea4 381 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
d987459f
SZ
382 while (TotalLen < Urb->DataLen) {\r
383 if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
384 Len = Urb->DataLen - TotalLen;\r
385 } else {\r
386 Len = 0x10000;\r
387 }\r
1436aea4
MK
388\r
389 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
390 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT ((UINT8 *)Urb->DataPhy + TotalLen);\r
391 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT ((UINT8 *)Urb->DataPhy + TotalLen);\r
392 TrbStart->TrbNormal.Length = (UINT32)Len;\r
d987459f
SZ
393 TrbStart->TrbNormal.TDSize = 0;\r
394 TrbStart->TrbNormal.IntTarget = 0;\r
395 TrbStart->TrbNormal.ISP = 1;\r
396 TrbStart->TrbNormal.IOC = 1;\r
397 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;\r
398 //\r
399 // Update the cycle bit\r
400 //\r
401 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
402\r
403 XhcPeiSyncTrsRing (Xhc, EPRing);\r
404 TrbNum++;\r
405 TotalLen += Len;\r
406 }\r
407\r
408 Urb->TrbNum = TrbNum;\r
409 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
410 break;\r
411\r
412 case ED_INTERRUPT_OUT:\r
413 case ED_INTERRUPT_IN:\r
414 TotalLen = 0;\r
415 Len = 0;\r
416 TrbNum = 0;\r
1436aea4 417 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
d987459f
SZ
418 while (TotalLen < Urb->DataLen) {\r
419 if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
420 Len = Urb->DataLen - TotalLen;\r
421 } else {\r
422 Len = 0x10000;\r
423 }\r
1436aea4
MK
424\r
425 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
426 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT ((UINT8 *)Urb->DataPhy + TotalLen);\r
427 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT ((UINT8 *)Urb->DataPhy + TotalLen);\r
428 TrbStart->TrbNormal.Length = (UINT32)Len;\r
d987459f
SZ
429 TrbStart->TrbNormal.TDSize = 0;\r
430 TrbStart->TrbNormal.IntTarget = 0;\r
431 TrbStart->TrbNormal.ISP = 1;\r
432 TrbStart->TrbNormal.IOC = 1;\r
433 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;\r
434 //\r
435 // Update the cycle bit\r
436 //\r
437 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
438\r
439 XhcPeiSyncTrsRing (Xhc, EPRing);\r
440 TrbNum++;\r
441 TotalLen += Len;\r
442 }\r
443\r
444 Urb->TrbNum = TrbNum;\r
445 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
446 break;\r
447\r
448 default:\r
1436aea4 449 DEBUG ((DEBUG_INFO, "Not supported EPType 0x%x!\n", EPType));\r
d987459f
SZ
450 ASSERT (FALSE);\r
451 break;\r
452 }\r
453\r
454 return EFI_SUCCESS;\r
455}\r
456\r
457/**\r
458 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted\r
459 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint\r
460 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is\r
461 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the\r
462 Stopped to the Running state.\r
463\r
464 @param Xhc The XHCI device.\r
465 @param Urb The urb which makes the endpoint halted.\r
466\r
467 @retval EFI_SUCCESS The recovery is successful.\r
468 @retval Others Failed to recovery halted endpoint.\r
469\r
470**/\r
471EFI_STATUS\r
472XhcPeiRecoverHaltedEndpoint (\r
1436aea4
MK
473 IN PEI_XHC_DEV *Xhc,\r
474 IN URB *Urb\r
d987459f
SZ
475 )\r
476{\r
1436aea4
MK
477 EFI_STATUS Status;\r
478 UINT8 Dci;\r
479 UINT8 SlotId;\r
d987459f
SZ
480\r
481 Status = EFI_SUCCESS;\r
482 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
483 if (SlotId == 0) {\r
484 return EFI_DEVICE_ERROR;\r
485 }\r
1436aea4
MK
486\r
487 Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
d987459f 488\r
87000d77 489 DEBUG ((DEBUG_INFO, "XhcPeiRecoverHaltedEndpoint: Recovery Halted Slot = %x, Dci = %x\n", SlotId, Dci));\r
d987459f
SZ
490\r
491 //\r
492 // 1) Send Reset endpoint command to transit from halt to stop state\r
493 //\r
12e6c738 494 Status = XhcPeiResetEndpoint (Xhc, SlotId, Dci);\r
1436aea4 495 if (EFI_ERROR (Status)) {\r
87000d77 496 DEBUG ((DEBUG_ERROR, "XhcPeiRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
d987459f
SZ
497 goto Done;\r
498 }\r
499\r
500 //\r
501 // 2) Set dequeue pointer\r
502 //\r
12e6c738 503 Status = XhcPeiSetTrDequeuePointer (Xhc, SlotId, Dci, Urb);\r
1436aea4 504 if (EFI_ERROR (Status)) {\r
87000d77 505 DEBUG ((DEBUG_ERROR, "XhcPeiRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));\r
d987459f
SZ
506 goto Done;\r
507 }\r
508\r
509 //\r
510 // 3) Ring the doorbell to transit from stop to active\r
511 //\r
512 XhcPeiRingDoorBell (Xhc, SlotId, Dci);\r
513\r
514Done:\r
515 return Status;\r
516}\r
517\r
12e6c738
FT
518/**\r
519 System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer\r
520 Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to\r
521 the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running\r
522 state.\r
523\r
524 @param Xhc The XHCI device.\r
525 @param Urb The urb which doesn't get completed in a specified timeout range.\r
526\r
527 @retval EFI_SUCCESS The dequeuing of the TDs is successful.\r
528 @retval Others Failed to stop the endpoint and dequeue the TDs.\r
529\r
530**/\r
531EFI_STATUS\r
532XhcPeiDequeueTrbFromEndpoint (\r
1436aea4
MK
533 IN PEI_XHC_DEV *Xhc,\r
534 IN URB *Urb\r
12e6c738
FT
535 )\r
536{\r
1436aea4
MK
537 EFI_STATUS Status;\r
538 UINT8 Dci;\r
539 UINT8 SlotId;\r
12e6c738
FT
540\r
541 Status = EFI_SUCCESS;\r
542 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
543 if (SlotId == 0) {\r
544 return EFI_DEVICE_ERROR;\r
545 }\r
1436aea4
MK
546\r
547 Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
12e6c738 548\r
87000d77 549 DEBUG ((DEBUG_INFO, "XhcPeiDequeueTrbFromEndpoint: Stop Slot = %x, Dci = %x\n", SlotId, Dci));\r
12e6c738
FT
550\r
551 //\r
552 // 1) Send Stop endpoint command to stop endpoint.\r
553 //\r
554 Status = XhcPeiStopEndpoint (Xhc, SlotId, Dci);\r
1436aea4 555 if (EFI_ERROR (Status)) {\r
87000d77 556 DEBUG ((DEBUG_ERROR, "XhcPeiDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status));\r
12e6c738
FT
557 goto Done;\r
558 }\r
559\r
560 //\r
561 // 2) Set dequeue pointer\r
562 //\r
563 Status = XhcPeiSetTrDequeuePointer (Xhc, SlotId, Dci, Urb);\r
1436aea4 564 if (EFI_ERROR (Status)) {\r
87000d77 565 DEBUG ((DEBUG_ERROR, "XhcPeiDequeueTrbFromEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));\r
12e6c738
FT
566 goto Done;\r
567 }\r
568\r
569 //\r
570 // 3) Ring the doorbell to transit from stop to active\r
571 //\r
572 XhcPeiRingDoorBell (Xhc, SlotId, Dci);\r
573\r
574Done:\r
575 return Status;\r
576}\r
577\r
d987459f
SZ
578/**\r
579 Check if the Trb is a transaction of the URB.\r
580\r
581 @param Trb The TRB to be checked\r
582 @param Urb The transfer ring to be checked.\r
583\r
584 @retval TRUE It is a transaction of the URB.\r
585 @retval FALSE It is not any transaction of the URB.\r
586\r
587**/\r
588BOOLEAN\r
589XhcPeiIsTransferRingTrb (\r
1436aea4
MK
590 IN TRB_TEMPLATE *Trb,\r
591 IN URB *Urb\r
d987459f
SZ
592 )\r
593{\r
594 TRB_TEMPLATE *CheckedTrb;\r
595 UINTN Index;\r
596\r
597 CheckedTrb = Urb->Ring->RingSeg0;\r
598\r
599 ASSERT (Urb->Ring->TrbNumber == CMD_RING_TRB_NUMBER || Urb->Ring->TrbNumber == TR_RING_TRB_NUMBER);\r
600\r
601 for (Index = 0; Index < Urb->Ring->TrbNumber; Index++) {\r
602 if (Trb == CheckedTrb) {\r
603 return TRUE;\r
604 }\r
1436aea4 605\r
d987459f
SZ
606 CheckedTrb++;\r
607 }\r
608\r
609 return FALSE;\r
610}\r
611\r
612/**\r
613 Check the URB's execution result and update the URB's\r
614 result accordingly.\r
615\r
616 @param Xhc The XHCI device.\r
617 @param Urb The URB to check result.\r
618\r
619 @return Whether the result of URB transfer is finialized.\r
620\r
621**/\r
56b1927a 622BOOLEAN\r
d987459f 623XhcPeiCheckUrbResult (\r
1436aea4
MK
624 IN PEI_XHC_DEV *Xhc,\r
625 IN URB *Urb\r
d987459f
SZ
626 )\r
627{\r
1436aea4
MK
628 EVT_TRB_TRANSFER *EvtTrb;\r
629 TRB_TEMPLATE *TRBPtr;\r
630 UINTN Index;\r
631 UINT8 TRBType;\r
632 EFI_STATUS Status;\r
633 URB *CheckedUrb;\r
634 UINT64 XhcDequeue;\r
635 UINT32 High;\r
636 UINT32 Low;\r
637 EFI_PHYSICAL_ADDRESS PhyAddr;\r
d987459f
SZ
638\r
639 ASSERT ((Xhc != NULL) && (Urb != NULL));\r
640\r
641 Status = EFI_SUCCESS;\r
642\r
643 if (Urb->Finished) {\r
644 goto EXIT;\r
645 }\r
646\r
647 EvtTrb = NULL;\r
648\r
649 if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {\r
650 Urb->Result |= EFI_USB_ERR_SYSTEM;\r
d987459f
SZ
651 goto EXIT;\r
652 }\r
653\r
654 //\r
655 // Traverse the event ring to find out all new events from the previous check.\r
656 //\r
657 XhcPeiSyncEventRing (Xhc, &Xhc->EventRing);\r
658 for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {\r
1436aea4 659 Status = XhcPeiCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **)&EvtTrb));\r
d987459f
SZ
660 if (Status == EFI_NOT_READY) {\r
661 //\r
662 // All new events are handled, return directly.\r
663 //\r
664 goto EXIT;\r
665 }\r
666\r
667 //\r
668 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.\r
669 //\r
670 if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {\r
671 continue;\r
672 }\r
673\r
674 //\r
675 // Need convert pci device address to host address\r
676 //\r
1436aea4
MK
677 PhyAddr = (EFI_PHYSICAL_ADDRESS)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64)EvtTrb->TRBPtrHi, 32));\r
678 TRBPtr = (TRB_TEMPLATE *)(UINTN)UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN)PhyAddr, sizeof (TRB_TEMPLATE));\r
d987459f
SZ
679\r
680 //\r
681 // Update the status of Urb according to the finished event regardless of whether\r
682 // the urb is current checked one or in the XHCI's async transfer list.\r
683 // This way is used to avoid that those completed async transfer events don't get\r
684 // handled in time and are flushed by newer coming events.\r
685 //\r
686 if (XhcPeiIsTransferRingTrb (TRBPtr, Urb)) {\r
687 CheckedUrb = Urb;\r
688 } else {\r
689 continue;\r
690 }\r
691\r
692 switch (EvtTrb->Completecode) {\r
693 case TRB_COMPLETION_STALL_ERROR:\r
694 CheckedUrb->Result |= EFI_USB_ERR_STALL;\r
695 CheckedUrb->Finished = TRUE;\r
87000d77 696 DEBUG ((DEBUG_ERROR, "XhcPeiCheckUrbResult: STALL_ERROR! Completecode = %x\n", EvtTrb->Completecode));\r
d987459f
SZ
697 goto EXIT;\r
698\r
699 case TRB_COMPLETION_BABBLE_ERROR:\r
700 CheckedUrb->Result |= EFI_USB_ERR_BABBLE;\r
701 CheckedUrb->Finished = TRUE;\r
87000d77 702 DEBUG ((DEBUG_ERROR, "XhcPeiCheckUrbResult: BABBLE_ERROR! Completecode = %x\n", EvtTrb->Completecode));\r
d987459f
SZ
703 goto EXIT;\r
704\r
705 case TRB_COMPLETION_DATA_BUFFER_ERROR:\r
706 CheckedUrb->Result |= EFI_USB_ERR_BUFFER;\r
707 CheckedUrb->Finished = TRUE;\r
87000d77 708 DEBUG ((DEBUG_ERROR, "XhcPeiCheckUrbResult: ERR_BUFFER! Completecode = %x\n", EvtTrb->Completecode));\r
d987459f
SZ
709 goto EXIT;\r
710\r
711 case TRB_COMPLETION_USB_TRANSACTION_ERROR:\r
712 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
713 CheckedUrb->Finished = TRUE;\r
87000d77 714 DEBUG ((DEBUG_ERROR, "XhcPeiCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n", EvtTrb->Completecode));\r
d987459f
SZ
715 goto EXIT;\r
716\r
717 case TRB_COMPLETION_SHORT_PACKET:\r
718 case TRB_COMPLETION_SUCCESS:\r
719 if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {\r
87000d77 720 DEBUG ((DEBUG_VERBOSE, "XhcPeiCheckUrbResult: short packet happens!\n"));\r
d987459f
SZ
721 }\r
722\r
1436aea4 723 TRBType = (UINT8)(TRBPtr->Type);\r
d987459f
SZ
724 if ((TRBType == TRB_TYPE_DATA_STAGE) ||\r
725 (TRBType == TRB_TYPE_NORMAL) ||\r
1436aea4
MK
726 (TRBType == TRB_TYPE_ISOCH))\r
727 {\r
728 CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL *)TRBPtr)->Length - EvtTrb->Length);\r
d987459f
SZ
729 }\r
730\r
731 break;\r
732\r
733 default:\r
87000d77 734 DEBUG ((DEBUG_ERROR, "XhcPeiCheckUrbResult: Transfer Default Error Occur! Completecode = 0x%x!\n", EvtTrb->Completecode));\r
d987459f
SZ
735 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
736 CheckedUrb->Finished = TRUE;\r
737 goto EXIT;\r
738 }\r
739\r
740 //\r
741 // Only check first and end Trb event address\r
742 //\r
743 if (TRBPtr == CheckedUrb->TrbStart) {\r
744 CheckedUrb->StartDone = TRUE;\r
745 }\r
746\r
747 if (TRBPtr == CheckedUrb->TrbEnd) {\r
748 CheckedUrb->EndDone = TRUE;\r
749 }\r
750\r
751 if (CheckedUrb->StartDone && CheckedUrb->EndDone) {\r
752 CheckedUrb->Finished = TRUE;\r
1436aea4 753 CheckedUrb->EvtTrb = (TRB_TEMPLATE *)EvtTrb;\r
d987459f
SZ
754 }\r
755 }\r
756\r
757EXIT:\r
758\r
759 //\r
760 // Advance event ring to last available entry\r
761 //\r
762 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
763 // So divide it to two 32-bytes width register access.\r
764 //\r
1436aea4
MK
765 Low = XhcPeiReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);\r
766 High = XhcPeiReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);\r
767 XhcDequeue = (UINT64)(LShiftU64 ((UINT64)High, 32) | Low);\r
d987459f
SZ
768\r
769 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE));\r
770\r
771 if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {\r
772 //\r
773 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
774 // So divide it to two 32-bytes width register access.\r
775 //\r
776 XhcPeiWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);\r
777 XhcPeiWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));\r
778 }\r
779\r
56b1927a 780 return Urb->Finished;\r
d987459f
SZ
781}\r
782\r
783/**\r
784 Execute the transfer by polling the URB. This is a synchronous operation.\r
785\r
786 @param Xhc The XHCI device.\r
787 @param CmdTransfer The executed URB is for cmd transfer or not.\r
788 @param Urb The URB to execute.\r
789 @param Timeout The time to wait before abort, in millisecond.\r
790\r
791 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
792 @return EFI_TIMEOUT The transfer failed due to time out.\r
793 @return EFI_SUCCESS The transfer finished OK.\r
794\r
795**/\r
796EFI_STATUS\r
797XhcPeiExecTransfer (\r
1436aea4
MK
798 IN PEI_XHC_DEV *Xhc,\r
799 IN BOOLEAN CmdTransfer,\r
800 IN URB *Urb,\r
801 IN UINTN Timeout\r
d987459f
SZ
802 )\r
803{\r
1436aea4
MK
804 EFI_STATUS Status;\r
805 UINTN Index;\r
806 UINT64 Loop;\r
807 UINT8 SlotId;\r
808 UINT8 Dci;\r
809 BOOLEAN Finished;\r
d987459f
SZ
810\r
811 if (CmdTransfer) {\r
812 SlotId = 0;\r
813 Dci = 0;\r
814 } else {\r
815 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
816 if (SlotId == 0) {\r
817 return EFI_DEVICE_ERROR;\r
818 }\r
1436aea4
MK
819\r
820 Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
d987459f
SZ
821 }\r
822\r
823 Status = EFI_SUCCESS;\r
824 Loop = Timeout * XHC_1_MILLISECOND;\r
825 if (Timeout == 0) {\r
826 Loop = 0xFFFFFFFF;\r
827 }\r
828\r
829 XhcPeiRingDoorBell (Xhc, SlotId, Dci);\r
830\r
831 for (Index = 0; Index < Loop; Index++) {\r
56b1927a
FT
832 Finished = XhcPeiCheckUrbResult (Xhc, Urb);\r
833 if (Finished) {\r
d987459f
SZ
834 break;\r
835 }\r
1436aea4 836\r
d987459f
SZ
837 MicroSecondDelay (XHC_1_MICROSECOND);\r
838 }\r
839\r
840 if (Index == Loop) {\r
841 Urb->Result = EFI_USB_ERR_TIMEOUT;\r
56b1927a
FT
842 Status = EFI_TIMEOUT;\r
843 } else if (Urb->Result != EFI_USB_NOERROR) {\r
1436aea4 844 Status = EFI_DEVICE_ERROR;\r
d987459f
SZ
845 }\r
846\r
847 return Status;\r
848}\r
849\r
850/**\r
851 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.\r
852\r
853 @param Xhc The XHCI device.\r
854 @param ParentRouteChart The route string pointed to the parent device if it exists.\r
855 @param Port The port to be polled.\r
856 @param PortState The port state.\r
857\r
858 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.\r
859 @retval Others Should not appear.\r
860\r
861**/\r
862EFI_STATUS\r
863XhcPeiPollPortStatusChange (\r
1436aea4
MK
864 IN PEI_XHC_DEV *Xhc,\r
865 IN USB_DEV_ROUTE ParentRouteChart,\r
866 IN UINT8 Port,\r
867 IN EFI_USB_PORT_STATUS *PortState\r
d987459f
SZ
868 )\r
869{\r
1436aea4
MK
870 EFI_STATUS Status;\r
871 UINT8 Speed;\r
872 UINT8 SlotId;\r
873 USB_DEV_ROUTE RouteChart;\r
d987459f 874\r
87000d77 875 DEBUG ((DEBUG_INFO, "XhcPeiPollPortStatusChange: PortChangeStatus: %x PortStatus: %x\n", PortState->PortChangeStatus, PortState->PortStatus));\r
d987459f
SZ
876\r
877 Status = EFI_SUCCESS;\r
878\r
879 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
880 return EFI_SUCCESS;\r
881 }\r
882\r
883 if (ParentRouteChart.Dword == 0) {\r
884 RouteChart.Route.RouteString = 0;\r
885 RouteChart.Route.RootPortNum = Port + 1;\r
886 RouteChart.Route.TierNum = 1;\r
887 } else {\r
1436aea4 888 if (Port < 14) {\r
d987459f
SZ
889 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
890 } else {\r
891 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
892 }\r
1436aea4
MK
893\r
894 RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;\r
895 RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;\r
d987459f
SZ
896 }\r
897\r
898 SlotId = XhcPeiRouteStringToSlotId (Xhc, RouteChart);\r
899 if (SlotId != 0) {\r
900 if (Xhc->HcCParams.Data.Csz == 0) {\r
901 Status = XhcPeiDisableSlotCmd (Xhc, SlotId);\r
902 } else {\r
903 Status = XhcPeiDisableSlotCmd64 (Xhc, SlotId);\r
904 }\r
905 }\r
906\r
907 if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&\r
1436aea4
MK
908 ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0))\r
909 {\r
d987459f
SZ
910 //\r
911 // Has a device attached, Identify device speed after port is enabled.\r
912 //\r
913 Speed = EFI_USB_SPEED_FULL;\r
914 if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
915 Speed = EFI_USB_SPEED_LOW;\r
916 } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {\r
917 Speed = EFI_USB_SPEED_HIGH;\r
918 } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {\r
919 Speed = EFI_USB_SPEED_SUPER;\r
920 }\r
1436aea4 921\r
d987459f
SZ
922 //\r
923 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.\r
924 //\r
925 SlotId = XhcPeiRouteStringToSlotId (Xhc, RouteChart);\r
926 if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {\r
927 if (Xhc->HcCParams.Data.Csz == 0) {\r
928 Status = XhcPeiInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
929 } else {\r
930 Status = XhcPeiInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
931 }\r
932 }\r
933 }\r
934\r
935 return Status;\r
936}\r
937\r
938/**\r
939 Calculate the device context index by endpoint address and direction.\r
940\r
941 @param EpAddr The target endpoint number.\r
942 @param Direction The direction of the target endpoint.\r
943\r
944 @return The device context index of endpoint.\r
945\r
946**/\r
947UINT8\r
948XhcPeiEndpointToDci (\r
1436aea4
MK
949 IN UINT8 EpAddr,\r
950 IN EFI_USB_DATA_DIRECTION Direction\r
d987459f
SZ
951 )\r
952{\r
1436aea4 953 UINT8 Index;\r
d987459f
SZ
954\r
955 ASSERT (EpAddr <= 15);\r
956\r
957 if (EpAddr == 0) {\r
958 return 1;\r
959 } else {\r
1436aea4 960 Index = (UINT8)(2 * EpAddr);\r
d987459f
SZ
961 if (Direction == EfiUsbDataIn) {\r
962 Index += 1;\r
963 }\r
1436aea4 964\r
d987459f
SZ
965 return Index;\r
966 }\r
967}\r
968\r
969/**\r
970 Find out the actual device address according to the requested device address from UsbBus.\r
971\r
972 @param Xhc The XHCI device.\r
973 @param BusDevAddr The requested device address by UsbBus upper driver.\r
974\r
975 @return The actual device address assigned to the device.\r
976\r
977**/\r
978UINT8\r
979XhcPeiBusDevAddrToSlotId (\r
1436aea4
MK
980 IN PEI_XHC_DEV *Xhc,\r
981 IN UINT8 BusDevAddr\r
d987459f
SZ
982 )\r
983{\r
1436aea4 984 UINT8 Index;\r
d987459f
SZ
985\r
986 for (Index = 0; Index < 255; Index++) {\r
987 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
988 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1436aea4
MK
989 (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr))\r
990 {\r
d987459f
SZ
991 break;\r
992 }\r
993 }\r
994\r
995 if (Index == 255) {\r
996 return 0;\r
997 }\r
998\r
999 return Xhc->UsbDevContext[Index + 1].SlotId;\r
1000}\r
1001\r
1002/**\r
1003 Find out the slot id according to the device's route string.\r
1004\r
1005 @param Xhc The XHCI device.\r
1006 @param RouteString The route string described the device location.\r
1007\r
1008 @return The slot id used by the device.\r
1009\r
1010**/\r
1011UINT8\r
1012XhcPeiRouteStringToSlotId (\r
1436aea4
MK
1013 IN PEI_XHC_DEV *Xhc,\r
1014 IN USB_DEV_ROUTE RouteString\r
d987459f
SZ
1015 )\r
1016{\r
1436aea4 1017 UINT8 Index;\r
d987459f
SZ
1018\r
1019 for (Index = 0; Index < 255; Index++) {\r
1020 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1021 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1436aea4
MK
1022 (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword))\r
1023 {\r
d987459f
SZ
1024 break;\r
1025 }\r
1026 }\r
1027\r
1028 if (Index == 255) {\r
1029 return 0;\r
1030 }\r
1031\r
1032 return Xhc->UsbDevContext[Index + 1].SlotId;\r
1033}\r
1034\r
1035/**\r
1036 Ring the door bell to notify XHCI there is a transaction to be executed.\r
1037\r
1038 @param Xhc The XHCI device.\r
1039 @param SlotId The slot id of the target device.\r
1040 @param Dci The device context index of the target slot or endpoint.\r
1041\r
1042**/\r
1043VOID\r
1044XhcPeiRingDoorBell (\r
1436aea4
MK
1045 IN PEI_XHC_DEV *Xhc,\r
1046 IN UINT8 SlotId,\r
1047 IN UINT8 Dci\r
d987459f
SZ
1048 )\r
1049{\r
1050 if (SlotId == 0) {\r
1051 XhcPeiWriteDoorBellReg (Xhc, 0, 0);\r
1052 } else {\r
1053 XhcPeiWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);\r
1054 }\r
1055}\r
1056\r
1057/**\r
1058 Assign and initialize the device slot for a new device.\r
1059\r
1060 @param Xhc The XHCI device.\r
1061 @param ParentRouteChart The route string pointed to the parent device.\r
1062 @param ParentPort The port at which the device is located.\r
1063 @param RouteChart The route string pointed to the device.\r
1064 @param DeviceSpeed The device speed.\r
1065\r
1066 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
1067 @retval Others Fail to initialize device slot.\r
1068\r
1069**/\r
1070EFI_STATUS\r
1071XhcPeiInitializeDeviceSlot (\r
1436aea4
MK
1072 IN PEI_XHC_DEV *Xhc,\r
1073 IN USB_DEV_ROUTE ParentRouteChart,\r
1074 IN UINT16 ParentPort,\r
1075 IN USB_DEV_ROUTE RouteChart,\r
1076 IN UINT8 DeviceSpeed\r
d987459f
SZ
1077 )\r
1078{\r
1436aea4
MK
1079 EFI_STATUS Status;\r
1080 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
1081 INPUT_CONTEXT *InputContext;\r
1082 DEVICE_CONTEXT *OutputContext;\r
1083 TRANSFER_RING *EndpointTransferRing;\r
1084 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
1085 UINT8 DeviceAddress;\r
1086 CMD_TRB_ENABLE_SLOT CmdTrb;\r
1087 UINT8 SlotId;\r
1088 UINT8 ParentSlotId;\r
1089 DEVICE_CONTEXT *ParentDeviceContext;\r
1090 EFI_PHYSICAL_ADDRESS PhyAddr;\r
d987459f
SZ
1091\r
1092 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
1093 CmdTrb.CycleBit = 1;\r
1094 CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
1095\r
1096 Status = XhcPeiCmdTransfer (\r
1097 Xhc,\r
1436aea4 1098 (TRB_TEMPLATE *)(UINTN)&CmdTrb,\r
d987459f 1099 XHC_GENERIC_TIMEOUT,\r
1436aea4 1100 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
d987459f
SZ
1101 );\r
1102 if (EFI_ERROR (Status)) {\r
87000d77 1103 DEBUG ((DEBUG_ERROR, "XhcPeiInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));\r
d987459f
SZ
1104 return Status;\r
1105 }\r
1436aea4 1106\r
d987459f 1107 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
87000d77 1108 DEBUG ((DEBUG_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
1436aea4 1109 SlotId = (UINT8)EvtTrb->SlotId;\r
d987459f
SZ
1110 ASSERT (SlotId != 0);\r
1111\r
1112 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
1113 Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
1114 Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
1115 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
1116 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
1117\r
1118 //\r
1119 // 4.3.3 Device Slot Initialization\r
1120 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
1121 //\r
1122 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));\r
1123 ASSERT (InputContext != NULL);\r
1436aea4 1124 ASSERT (((UINTN)InputContext & 0x3F) == 0);\r
d987459f
SZ
1125 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
1126\r
1436aea4 1127 Xhc->UsbDevContext[SlotId].InputContext = (VOID *)InputContext;\r
d987459f
SZ
1128\r
1129 //\r
1130 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
1131 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
1132 // Context are affected by the command.\r
1133 //\r
1134 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
1135\r
1136 //\r
1137 // 3) Initialize the Input Slot Context data structure\r
1138 //\r
1139 InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
1140 InputContext->Slot.Speed = DeviceSpeed + 1;\r
1141 InputContext->Slot.ContextEntries = 1;\r
1142 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
1143\r
1144 if (RouteChart.Route.RouteString != 0) {\r
1145 //\r
1146 // The device is behind of hub device.\r
1147 //\r
1148 ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);\r
1149 ASSERT (ParentSlotId != 0);\r
1150 //\r
1151 // If the Full/Low device attached to a High Speed Hub, init the TTPortNum and TTHubSlotId field of slot context\r
1152 //\r
1436aea4 1153 ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
d987459f 1154 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
1436aea4
MK
1155 (ParentDeviceContext->Slot.TTHubSlotId == 0))\r
1156 {\r
d987459f
SZ
1157 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
1158 //\r
1159 // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
1160 // environment from Full/Low speed signaling environment for a device\r
1161 //\r
1162 InputContext->Slot.TTPortNum = ParentPort;\r
1163 InputContext->Slot.TTHubSlotId = ParentSlotId;\r
1164 }\r
1165 } else {\r
1166 //\r
1167 // Inherit the TT parameters from parent device.\r
1168 //\r
1169 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
1170 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
1171 //\r
1172 // If the device is a High speed device then down the speed to be the same as its parent Hub\r
1173 //\r
1174 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
1175 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
1176 }\r
1177 }\r
1178 }\r
1179\r
1180 //\r
1181 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
1182 //\r
1436aea4 1183 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
d987459f 1184 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
1436aea4 1185 XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
d987459f
SZ
1186 //\r
1187 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
1188 //\r
1189 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
1190\r
1191 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
1192 InputContext->EP[0].MaxPacketSize = 512;\r
1193 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
1194 InputContext->EP[0].MaxPacketSize = 64;\r
1195 } else {\r
1196 InputContext->EP[0].MaxPacketSize = 8;\r
1197 }\r
1436aea4 1198\r
d987459f
SZ
1199 //\r
1200 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
1201 // 1KB, and Bulk and Isoch endpoints 3KB.\r
1202 //\r
1203 InputContext->EP[0].AverageTRBLength = 8;\r
1204 InputContext->EP[0].MaxBurstSize = 0;\r
1205 InputContext->EP[0].Interval = 0;\r
1206 InputContext->EP[0].MaxPStreams = 0;\r
1207 InputContext->EP[0].Mult = 0;\r
1208 InputContext->EP[0].CErr = 3;\r
1209\r
1210 //\r
1211 // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
1212 //\r
1213 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
1214 Xhc->MemPool,\r
1436aea4 1215 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
d987459f
SZ
1216 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
1217 );\r
1218 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
1219 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
1220\r
1221 //\r
1222 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
1223 //\r
1224 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));\r
1225 ASSERT (OutputContext != NULL);\r
1436aea4 1226 ASSERT (((UINTN)OutputContext & 0x3F) == 0);\r
d987459f
SZ
1227 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));\r
1228\r
1229 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
1230 //\r
1231 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
1232 // a pointer to the Output Device Context data structure (6.2.1).\r
1233 //\r
1234 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));\r
1235 //\r
1236 // Fill DCBAA with PCI device address\r
1237 //\r
1436aea4 1238 Xhc->DCBAA[SlotId] = (UINT64)(UINTN)PhyAddr;\r
d987459f
SZ
1239\r
1240 //\r
1241 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
1242 // Context data structure described above.\r
1243 //\r
26b85012
FT
1244 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request\r
1245 // to device.\r
1246 //\r
1247 MicroSecondDelay (XHC_RESET_RECOVERY_DELAY);\r
d987459f 1248 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
1436aea4 1249 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
d987459f
SZ
1250 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
1251 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
1252 CmdTrbAddr.CycleBit = 1;\r
1253 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
1254 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
1436aea4
MK
1255 Status = XhcPeiCmdTransfer (\r
1256 Xhc,\r
1257 (TRB_TEMPLATE *)(UINTN)&CmdTrbAddr,\r
1258 XHC_GENERIC_TIMEOUT,\r
1259 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
1260 );\r
d987459f 1261 if (!EFI_ERROR (Status)) {\r
1436aea4 1262 DeviceAddress = (UINT8)OutputContext->Slot.DeviceAddress;\r
87000d77 1263 DEBUG ((DEBUG_INFO, "XhcPeiInitializeDeviceSlot: Address %d assigned successfully\n", DeviceAddress));\r
d987459f
SZ
1264 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
1265 }\r
1266\r
87000d77 1267 DEBUG ((DEBUG_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot, Status = %r\n", Status));\r
d987459f
SZ
1268 return Status;\r
1269}\r
1270\r
1271/**\r
1272 Assign and initialize the device slot for a new device.\r
1273\r
1274 @param Xhc The XHCI device.\r
1275 @param ParentRouteChart The route string pointed to the parent device.\r
1276 @param ParentPort The port at which the device is located.\r
1277 @param RouteChart The route string pointed to the device.\r
1278 @param DeviceSpeed The device speed.\r
1279\r
1280 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
1281 @retval Others Fail to initialize device slot.\r
1282\r
1283**/\r
1284EFI_STATUS\r
1285XhcPeiInitializeDeviceSlot64 (\r
1436aea4
MK
1286 IN PEI_XHC_DEV *Xhc,\r
1287 IN USB_DEV_ROUTE ParentRouteChart,\r
1288 IN UINT16 ParentPort,\r
1289 IN USB_DEV_ROUTE RouteChart,\r
1290 IN UINT8 DeviceSpeed\r
d987459f
SZ
1291 )\r
1292{\r
1436aea4
MK
1293 EFI_STATUS Status;\r
1294 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
1295 INPUT_CONTEXT_64 *InputContext;\r
1296 DEVICE_CONTEXT_64 *OutputContext;\r
1297 TRANSFER_RING *EndpointTransferRing;\r
1298 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
1299 UINT8 DeviceAddress;\r
1300 CMD_TRB_ENABLE_SLOT CmdTrb;\r
1301 UINT8 SlotId;\r
1302 UINT8 ParentSlotId;\r
1303 DEVICE_CONTEXT_64 *ParentDeviceContext;\r
1304 EFI_PHYSICAL_ADDRESS PhyAddr;\r
d987459f
SZ
1305\r
1306 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
1307 CmdTrb.CycleBit = 1;\r
1308 CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
1309\r
1310 Status = XhcPeiCmdTransfer (\r
1311 Xhc,\r
1436aea4 1312 (TRB_TEMPLATE *)(UINTN)&CmdTrb,\r
d987459f 1313 XHC_GENERIC_TIMEOUT,\r
1436aea4 1314 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
d987459f
SZ
1315 );\r
1316 if (EFI_ERROR (Status)) {\r
87000d77 1317 DEBUG ((DEBUG_ERROR, "XhcPeiInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));\r
d987459f
SZ
1318 return Status;\r
1319 }\r
1436aea4 1320\r
d987459f 1321 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
87000d77 1322 DEBUG ((DEBUG_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
d987459f
SZ
1323 SlotId = (UINT8)EvtTrb->SlotId;\r
1324 ASSERT (SlotId != 0);\r
1325\r
1326 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
1327 Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
1328 Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
1329 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
1330 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
1331\r
1332 //\r
1333 // 4.3.3 Device Slot Initialization\r
1334 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
1335 //\r
1336 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));\r
1337 ASSERT (InputContext != NULL);\r
1436aea4 1338 ASSERT (((UINTN)InputContext & 0x3F) == 0);\r
d987459f
SZ
1339 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
1340\r
1436aea4 1341 Xhc->UsbDevContext[SlotId].InputContext = (VOID *)InputContext;\r
d987459f
SZ
1342\r
1343 //\r
1344 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
1345 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
1346 // Context are affected by the command.\r
1347 //\r
1348 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
1349\r
1350 //\r
1351 // 3) Initialize the Input Slot Context data structure\r
1352 //\r
1353 InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
1354 InputContext->Slot.Speed = DeviceSpeed + 1;\r
1355 InputContext->Slot.ContextEntries = 1;\r
1356 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
1357\r
1358 if (RouteChart.Route.RouteString != 0) {\r
1359 //\r
1360 // The device is behind of hub device.\r
1361 //\r
1362 ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);\r
1363 ASSERT (ParentSlotId != 0);\r
1364 //\r
1436aea4 1365 // if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
d987459f 1366 //\r
1436aea4 1367 ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
d987459f 1368 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
1436aea4
MK
1369 (ParentDeviceContext->Slot.TTHubSlotId == 0))\r
1370 {\r
d987459f
SZ
1371 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
1372 //\r
1373 // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
1374 // environment from Full/Low speed signaling environment for a device\r
1375 //\r
1376 InputContext->Slot.TTPortNum = ParentPort;\r
1377 InputContext->Slot.TTHubSlotId = ParentSlotId;\r
1378 }\r
1379 } else {\r
1380 //\r
1381 // Inherit the TT parameters from parent device.\r
1382 //\r
1383 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
1384 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
1385 //\r
1386 // If the device is a High speed device then down the speed to be the same as its parent Hub\r
1387 //\r
1388 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
1389 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
1390 }\r
1391 }\r
1392 }\r
1393\r
1394 //\r
1395 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
1396 //\r
1436aea4 1397 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
d987459f 1398 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
1436aea4 1399 XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
d987459f
SZ
1400 //\r
1401 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
1402 //\r
1403 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
1404\r
1405 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
1406 InputContext->EP[0].MaxPacketSize = 512;\r
1407 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
1408 InputContext->EP[0].MaxPacketSize = 64;\r
1409 } else {\r
1410 InputContext->EP[0].MaxPacketSize = 8;\r
1411 }\r
1436aea4 1412\r
d987459f
SZ
1413 //\r
1414 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
1415 // 1KB, and Bulk and Isoch endpoints 3KB.\r
1416 //\r
1417 InputContext->EP[0].AverageTRBLength = 8;\r
1418 InputContext->EP[0].MaxBurstSize = 0;\r
1419 InputContext->EP[0].Interval = 0;\r
1420 InputContext->EP[0].MaxPStreams = 0;\r
1421 InputContext->EP[0].Mult = 0;\r
1422 InputContext->EP[0].CErr = 3;\r
1423\r
1424 //\r
1425 // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
1426 //\r
1427 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
1428 Xhc->MemPool,\r
1436aea4 1429 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
d987459f
SZ
1430 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
1431 );\r
1432 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
1433 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
1434\r
1435 //\r
1436 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
1437 //\r
1438 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));\r
1439 ASSERT (OutputContext != NULL);\r
1436aea4 1440 ASSERT (((UINTN)OutputContext & 0x3F) == 0);\r
d987459f
SZ
1441 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));\r
1442\r
1443 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
1444 //\r
1445 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
1446 // a pointer to the Output Device Context data structure (6.2.1).\r
1447 //\r
1448 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));\r
1449 //\r
1450 // Fill DCBAA with PCI device address\r
1451 //\r
1436aea4 1452 Xhc->DCBAA[SlotId] = (UINT64)(UINTN)PhyAddr;\r
d987459f
SZ
1453\r
1454 //\r
1455 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
1456 // Context data structure described above.\r
1457 //\r
26b85012
FT
1458 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request\r
1459 // to device.\r
1460 //\r
1461 MicroSecondDelay (XHC_RESET_RECOVERY_DELAY);\r
d987459f 1462 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
1436aea4 1463 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
d987459f
SZ
1464 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
1465 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
1466 CmdTrbAddr.CycleBit = 1;\r
1467 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
1468 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
1436aea4
MK
1469 Status = XhcPeiCmdTransfer (\r
1470 Xhc,\r
1471 (TRB_TEMPLATE *)(UINTN)&CmdTrbAddr,\r
1472 XHC_GENERIC_TIMEOUT,\r
1473 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
1474 );\r
d987459f 1475 if (!EFI_ERROR (Status)) {\r
1436aea4 1476 DeviceAddress = (UINT8)OutputContext->Slot.DeviceAddress;\r
87000d77 1477 DEBUG ((DEBUG_INFO, "XhcPeiInitializeDeviceSlot64: Address %d assigned successfully\n", DeviceAddress));\r
d987459f
SZ
1478 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
1479 }\r
1480\r
87000d77 1481 DEBUG ((DEBUG_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot, Status = %r\n", Status));\r
d987459f
SZ
1482 return Status;\r
1483}\r
1484\r
d987459f
SZ
1485/**\r
1486 Disable the specified device slot.\r
1487\r
1488 @param Xhc The XHCI device.\r
1489 @param SlotId The slot id to be disabled.\r
1490\r
1491 @retval EFI_SUCCESS Successfully disable the device slot.\r
1492\r
1493**/\r
1494EFI_STATUS\r
1495XhcPeiDisableSlotCmd (\r
1436aea4
MK
1496 IN PEI_XHC_DEV *Xhc,\r
1497 IN UINT8 SlotId\r
d987459f
SZ
1498 )\r
1499{\r
1500 EFI_STATUS Status;\r
1501 TRB_TEMPLATE *EvtTrb;\r
1502 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
1503 UINT8 Index;\r
1504 VOID *RingSeg;\r
1505\r
1506 //\r
1507 // Disable the device slots occupied by these devices on its downstream ports.\r
1508 // Entry 0 is reserved.\r
1509 //\r
1510 for (Index = 0; Index < 255; Index++) {\r
1511 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
1512 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
1436aea4
MK
1513 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword))\r
1514 {\r
d987459f
SZ
1515 continue;\r
1516 }\r
1517\r
1518 Status = XhcPeiDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
1519\r
1520 if (EFI_ERROR (Status)) {\r
87000d77 1521 DEBUG ((DEBUG_ERROR, "XhcPeiDisableSlotCmd: failed to disable child, ignore error\n"));\r
d987459f
SZ
1522 Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
1523 }\r
1524 }\r
1525\r
1526 //\r
1527 // Construct the disable slot command\r
1528 //\r
87000d77 1529 DEBUG ((DEBUG_INFO, "XhcPeiDisableSlotCmd: Disable device slot %d!\n", SlotId));\r
d987459f
SZ
1530\r
1531 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
1532 CmdTrbDisSlot.CycleBit = 1;\r
1533 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
1534 CmdTrbDisSlot.SlotId = SlotId;\r
1436aea4
MK
1535 Status = XhcPeiCmdTransfer (\r
1536 Xhc,\r
1537 (TRB_TEMPLATE *)(UINTN)&CmdTrbDisSlot,\r
1538 XHC_GENERIC_TIMEOUT,\r
1539 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
1540 );\r
d987459f 1541 if (EFI_ERROR (Status)) {\r
87000d77 1542 DEBUG ((DEBUG_ERROR, "XhcPeiDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));\r
d987459f
SZ
1543 return Status;\r
1544 }\r
1436aea4 1545\r
d987459f
SZ
1546 //\r
1547 // Free the slot's device context entry\r
1548 //\r
1549 Xhc->DCBAA[SlotId] = 0;\r
1550\r
1551 //\r
1552 // Free the slot related data structure\r
1553 //\r
1554 for (Index = 0; Index < 31; Index++) {\r
1555 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
1436aea4 1556 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
d987459f
SZ
1557 if (RingSeg != NULL) {\r
1558 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
1559 }\r
1436aea4 1560\r
d987459f
SZ
1561 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
1562 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
1563 }\r
1564 }\r
1565\r
1566 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
1567 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
1568 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
1569 }\r
1570 }\r
1571\r
1572 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
1573 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
1574 }\r
1575\r
1576 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
1577 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));\r
1578 }\r
1436aea4 1579\r
d987459f
SZ
1580 //\r
1581 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
1582 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
1583 // remove urb from XHCI's asynchronous transfer list.\r
1584 //\r
1585 Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
1586 Xhc->UsbDevContext[SlotId].SlotId = 0;\r
1587\r
87000d77 1588 DEBUG ((DEBUG_INFO, "XhcPeiDisableSlotCmd: Disable Slot Command, Status = %r\n", Status));\r
d987459f
SZ
1589 return Status;\r
1590}\r
1591\r
1592/**\r
1593 Disable the specified device slot.\r
1594\r
1595 @param Xhc The XHCI device.\r
1596 @param SlotId The slot id to be disabled.\r
1597\r
1598 @retval EFI_SUCCESS Successfully disable the device slot.\r
1599\r
1600**/\r
1601EFI_STATUS\r
1602XhcPeiDisableSlotCmd64 (\r
1436aea4
MK
1603 IN PEI_XHC_DEV *Xhc,\r
1604 IN UINT8 SlotId\r
d987459f
SZ
1605 )\r
1606{\r
1607 EFI_STATUS Status;\r
1608 TRB_TEMPLATE *EvtTrb;\r
1609 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
1610 UINT8 Index;\r
1611 VOID *RingSeg;\r
1612\r
1613 //\r
1614 // Disable the device slots occupied by these devices on its downstream ports.\r
1615 // Entry 0 is reserved.\r
1616 //\r
1617 for (Index = 0; Index < 255; Index++) {\r
1618 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
1619 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
1436aea4
MK
1620 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword))\r
1621 {\r
d987459f
SZ
1622 continue;\r
1623 }\r
1624\r
1625 Status = XhcPeiDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
1626\r
1627 if (EFI_ERROR (Status)) {\r
87000d77 1628 DEBUG ((DEBUG_ERROR, "XhcPeiDisableSlotCmd64: failed to disable child, ignore error\n"));\r
d987459f
SZ
1629 Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
1630 }\r
1631 }\r
1632\r
1633 //\r
1634 // Construct the disable slot command\r
1635 //\r
87000d77 1636 DEBUG ((DEBUG_INFO, "XhcPeiDisableSlotCmd64: Disable device slot %d!\n", SlotId));\r
d987459f
SZ
1637\r
1638 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
1639 CmdTrbDisSlot.CycleBit = 1;\r
1640 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
1641 CmdTrbDisSlot.SlotId = SlotId;\r
1436aea4
MK
1642 Status = XhcPeiCmdTransfer (\r
1643 Xhc,\r
1644 (TRB_TEMPLATE *)(UINTN)&CmdTrbDisSlot,\r
1645 XHC_GENERIC_TIMEOUT,\r
1646 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
1647 );\r
d987459f 1648 if (EFI_ERROR (Status)) {\r
87000d77 1649 DEBUG ((DEBUG_ERROR, "XhcPeiDisableSlotCmd64: Disable Slot Command Failed, Status = %r\n", Status));\r
d987459f
SZ
1650 return Status;\r
1651 }\r
1436aea4 1652\r
d987459f
SZ
1653 //\r
1654 // Free the slot's device context entry\r
1655 //\r
1656 Xhc->DCBAA[SlotId] = 0;\r
1657\r
1658 //\r
1659 // Free the slot related data structure\r
1660 //\r
1661 for (Index = 0; Index < 31; Index++) {\r
1662 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
1436aea4 1663 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
d987459f
SZ
1664 if (RingSeg != NULL) {\r
1665 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
1666 }\r
1436aea4 1667\r
d987459f
SZ
1668 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
1669 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
1670 }\r
1671 }\r
1672\r
1673 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
1674 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
1675 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
1676 }\r
1677 }\r
1678\r
1679 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
1680 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
1681 }\r
1682\r
1683 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
1436aea4 1684 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));\r
d987459f 1685 }\r
1436aea4 1686\r
d987459f
SZ
1687 //\r
1688 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
1689 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
1690 // remove urb from XHCI's asynchronous transfer list.\r
1691 //\r
1692 Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
1693 Xhc->UsbDevContext[SlotId].SlotId = 0;\r
1694\r
87000d77 1695 DEBUG ((DEBUG_INFO, "XhcPeiDisableSlotCmd64: Disable Slot Command, Status = %r\n", Status));\r
d987459f
SZ
1696 return Status;\r
1697}\r
1698\r
1699/**\r
1700 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
1701\r
1702 @param Xhc The XHCI device.\r
1703 @param SlotId The slot id to be configured.\r
1704 @param DeviceSpeed The device's speed.\r
1705 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
1706\r
1707 @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
1708\r
1709**/\r
1710EFI_STATUS\r
1711XhcPeiSetConfigCmd (\r
1436aea4
MK
1712 IN PEI_XHC_DEV *Xhc,\r
1713 IN UINT8 SlotId,\r
1714 IN UINT8 DeviceSpeed,\r
1715 IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
d987459f
SZ
1716 )\r
1717{\r
1436aea4
MK
1718 EFI_STATUS Status;\r
1719 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
1720 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
1721 UINT8 Index;\r
1722 UINTN NumEp;\r
1723 UINTN EpIndex;\r
1724 UINT8 EpAddr;\r
1725 EFI_USB_DATA_DIRECTION Direction;\r
1726 UINT8 Dci;\r
1727 UINT8 MaxDci;\r
1728 EFI_PHYSICAL_ADDRESS PhyAddr;\r
1729 UINT8 Interval;\r
1730\r
1731 TRANSFER_RING *EndpointTransferRing;\r
1732 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
1733 INPUT_CONTEXT *InputContext;\r
1734 DEVICE_CONTEXT *OutputContext;\r
1735 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
1736\r
d987459f
SZ
1737 //\r
1738 // 4.6.6 Configure Endpoint\r
1739 //\r
1740 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
1741 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
1742 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
1743 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));\r
1744\r
1745 ASSERT (ConfigDesc != NULL);\r
1746\r
1747 MaxDci = 0;\r
1748\r
1436aea4 1749 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
d987459f
SZ
1750 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
1751 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {\r
1436aea4 1752 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
d987459f
SZ
1753 }\r
1754\r
1755 NumEp = IfDesc->NumEndpoints;\r
8147fe09
AC
1756 if ((NumEp == 0) && (MaxDci == 0)) {\r
1757 MaxDci = 1;\r
1758 }\r
d987459f 1759\r
1436aea4 1760 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
d987459f
SZ
1761 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
1762 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
1436aea4 1763 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
d987459f
SZ
1764 }\r
1765\r
1436aea4
MK
1766 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
1767 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
d987459f
SZ
1768\r
1769 Dci = XhcPeiEndpointToDci (EpAddr, Direction);\r
1770 if (Dci > MaxDci) {\r
1771 MaxDci = Dci;\r
1772 }\r
1773\r
1774 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
1775 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
1776\r
1777 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
1778 //\r
1779 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
1780 //\r
1781 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
1782 } else {\r
1783 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
1784 }\r
1785\r
1786 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
1787 case USB_ENDPOINT_BULK:\r
1788 if (Direction == EfiUsbDataIn) {\r
1789 InputContext->EP[Dci-1].CErr = 3;\r
1790 InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
1791 } else {\r
1792 InputContext->EP[Dci-1].CErr = 3;\r
1793 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
1794 }\r
1795\r
1796 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
1797 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
1436aea4
MK
1798 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
1799 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *)EndpointTransferRing;\r
1800 XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
d987459f
SZ
1801 }\r
1802\r
1803 break;\r
1804 case USB_ENDPOINT_ISO:\r
1805 if (Direction == EfiUsbDataIn) {\r
1806 InputContext->EP[Dci-1].CErr = 0;\r
1807 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
1808 } else {\r
1809 InputContext->EP[Dci-1].CErr = 0;\r
1810 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
1811 }\r
1436aea4 1812\r
3719c2aa
HW
1813 //\r
1814 // Get the bInterval from descriptor and init the the interval field of endpoint context.\r
1815 // Refer to XHCI 1.1 spec section 6.2.3.6.\r
1816 //\r
1817 if (DeviceSpeed == EFI_USB_SPEED_FULL) {\r
1818 Interval = EpDesc->Interval;\r
1819 ASSERT (Interval >= 1 && Interval <= 16);\r
1820 InputContext->EP[Dci-1].Interval = Interval + 2;\r
1821 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
1822 Interval = EpDesc->Interval;\r
1823 ASSERT (Interval >= 1 && Interval <= 16);\r
1824 InputContext->EP[Dci-1].Interval = Interval - 1;\r
1825 }\r
1826\r
04910ceb
SZ
1827 //\r
1828 // Do not support isochronous transfer now.\r
1829 //\r
87000d77 1830 DEBUG ((DEBUG_INFO, "XhcPeiSetConfigCmd: Unsupport ISO EP found, Transfer ring is not allocated.\n"));\r
04910ceb
SZ
1831 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
1832 continue;\r
d987459f
SZ
1833 case USB_ENDPOINT_INTERRUPT:\r
1834 if (Direction == EfiUsbDataIn) {\r
1835 InputContext->EP[Dci-1].CErr = 3;\r
1836 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
1837 } else {\r
1838 InputContext->EP[Dci-1].CErr = 3;\r
1839 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
1840 }\r
1436aea4 1841\r
d987459f
SZ
1842 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
1843 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
1844 //\r
1845 // Get the bInterval from descriptor and init the interval field of endpoint context\r
1846 //\r
1847 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
1848 Interval = EpDesc->Interval;\r
1849 //\r
1850 // Calculate through the bInterval field of Endpoint descriptor.\r
1851 //\r
1852 ASSERT (Interval != 0);\r
1436aea4 1853 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32 ((UINT32)Interval) + 3;\r
d987459f
SZ
1854 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
1855 Interval = EpDesc->Interval;\r
1856 ASSERT (Interval >= 1 && Interval <= 16);\r
1857 //\r
1858 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
1859 //\r
1860 InputContext->EP[Dci-1].Interval = Interval - 1;\r
1861 }\r
1862\r
1863 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
1436aea4
MK
1864 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
1865 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *)EndpointTransferRing;\r
1866 XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
d987459f 1867 }\r
1436aea4 1868\r
d987459f
SZ
1869 break;\r
1870\r
1871 case USB_ENDPOINT_CONTROL:\r
04910ceb
SZ
1872 //\r
1873 // Do not support control transfer now.\r
1874 //\r
87000d77 1875 DEBUG ((DEBUG_INFO, "XhcPeiSetConfigCmd: Unsupport Control EP found, Transfer ring is not allocated.\n"));\r
d987459f 1876 default:\r
87000d77 1877 DEBUG ((DEBUG_INFO, "XhcPeiSetConfigCmd: Unknown EP found, Transfer ring is not allocated.\n"));\r
04910ceb
SZ
1878 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
1879 continue;\r
d987459f
SZ
1880 }\r
1881\r
1882 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
1883 Xhc->MemPool,\r
1436aea4 1884 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
d987459f
SZ
1885 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
1886 );\r
1436aea4
MK
1887 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);\r
1888 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
d987459f
SZ
1889 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
1890 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
1891\r
1436aea4 1892 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
d987459f 1893 }\r
1436aea4
MK
1894\r
1895 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
d987459f
SZ
1896 }\r
1897\r
1898 InputContext->InputControlContext.Dword2 |= BIT0;\r
1899 InputContext->Slot.ContextEntries = MaxDci;\r
1900 //\r
1901 // configure endpoint\r
1902 //\r
1903 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1436aea4 1904 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
d987459f
SZ
1905 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
1906 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
1907 CmdTrbCfgEP.CycleBit = 1;\r
1908 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
1909 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
87000d77 1910 DEBUG ((DEBUG_INFO, "XhcSetConfigCmd: Configure Endpoint\n"));\r
d987459f
SZ
1911 Status = XhcPeiCmdTransfer (\r
1912 Xhc,\r
1436aea4 1913 (TRB_TEMPLATE *)(UINTN)&CmdTrbCfgEP,\r
d987459f 1914 XHC_GENERIC_TIMEOUT,\r
1436aea4 1915 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
d987459f
SZ
1916 );\r
1917 if (EFI_ERROR (Status)) {\r
87000d77 1918 DEBUG ((DEBUG_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));\r
d987459f 1919 }\r
1436aea4 1920\r
d987459f
SZ
1921 return Status;\r
1922}\r
1923\r
1924/**\r
1925 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
1926\r
1927 @param Xhc The XHCI device.\r
1928 @param SlotId The slot id to be configured.\r
1929 @param DeviceSpeed The device's speed.\r
1930 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
1931\r
1932 @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
1933\r
1934**/\r
1935EFI_STATUS\r
1936XhcPeiSetConfigCmd64 (\r
1436aea4
MK
1937 IN PEI_XHC_DEV *Xhc,\r
1938 IN UINT8 SlotId,\r
1939 IN UINT8 DeviceSpeed,\r
1940 IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
d987459f
SZ
1941 )\r
1942{\r
1436aea4
MK
1943 EFI_STATUS Status;\r
1944 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
1945 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
1946 UINT8 Index;\r
1947 UINTN NumEp;\r
1948 UINTN EpIndex;\r
1949 UINT8 EpAddr;\r
1950 EFI_USB_DATA_DIRECTION Direction;\r
1951 UINT8 Dci;\r
1952 UINT8 MaxDci;\r
1953 EFI_PHYSICAL_ADDRESS PhyAddr;\r
1954 UINT8 Interval;\r
1955\r
1956 TRANSFER_RING *EndpointTransferRing;\r
1957 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
1958 INPUT_CONTEXT_64 *InputContext;\r
1959 DEVICE_CONTEXT_64 *OutputContext;\r
1960 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
1961\r
d987459f
SZ
1962 //\r
1963 // 4.6.6 Configure Endpoint\r
1964 //\r
1965 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
1966 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
1967 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
1968 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));\r
1969\r
1970 ASSERT (ConfigDesc != NULL);\r
1971\r
1972 MaxDci = 0;\r
1973\r
1436aea4 1974 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
d987459f
SZ
1975 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
1976 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {\r
1436aea4 1977 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
d987459f
SZ
1978 }\r
1979\r
1980 NumEp = IfDesc->NumEndpoints;\r
8147fe09
AC
1981 if ((NumEp == 0) && (MaxDci == 0)) {\r
1982 MaxDci = 1;\r
1983 }\r
d987459f 1984\r
1436aea4 1985 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
d987459f
SZ
1986 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
1987 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
1436aea4 1988 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
d987459f
SZ
1989 }\r
1990\r
1436aea4
MK
1991 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
1992 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
d987459f
SZ
1993\r
1994 Dci = XhcPeiEndpointToDci (EpAddr, Direction);\r
1995 ASSERT (Dci < 32);\r
1996 if (Dci > MaxDci) {\r
1997 MaxDci = Dci;\r
1998 }\r
1999\r
2000 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
2001 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
2002\r
2003 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2004 //\r
2005 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
2006 //\r
2007 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2008 } else {\r
2009 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2010 }\r
2011\r
2012 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
2013 case USB_ENDPOINT_BULK:\r
2014 if (Direction == EfiUsbDataIn) {\r
2015 InputContext->EP[Dci-1].CErr = 3;\r
2016 InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
2017 } else {\r
2018 InputContext->EP[Dci-1].CErr = 3;\r
2019 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
2020 }\r
2021\r
2022 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2023 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
1436aea4
MK
2024 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
2025 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *)EndpointTransferRing;\r
2026 XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
d987459f
SZ
2027 }\r
2028\r
2029 break;\r
2030 case USB_ENDPOINT_ISO:\r
2031 if (Direction == EfiUsbDataIn) {\r
2032 InputContext->EP[Dci-1].CErr = 0;\r
2033 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
2034 } else {\r
2035 InputContext->EP[Dci-1].CErr = 0;\r
2036 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
2037 }\r
1436aea4 2038\r
3719c2aa
HW
2039 //\r
2040 // Get the bInterval from descriptor and init the the interval field of endpoint context.\r
2041 // Refer to XHCI 1.1 spec section 6.2.3.6.\r
2042 //\r
2043 if (DeviceSpeed == EFI_USB_SPEED_FULL) {\r
2044 Interval = EpDesc->Interval;\r
2045 ASSERT (Interval >= 1 && Interval <= 16);\r
2046 InputContext->EP[Dci-1].Interval = Interval + 2;\r
2047 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2048 Interval = EpDesc->Interval;\r
2049 ASSERT (Interval >= 1 && Interval <= 16);\r
2050 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2051 }\r
2052\r
04910ceb
SZ
2053 //\r
2054 // Do not support isochronous transfer now.\r
2055 //\r
87000d77 2056 DEBUG ((DEBUG_INFO, "XhcPeiSetConfigCmd64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));\r
04910ceb
SZ
2057 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2058 continue;\r
d987459f
SZ
2059 case USB_ENDPOINT_INTERRUPT:\r
2060 if (Direction == EfiUsbDataIn) {\r
2061 InputContext->EP[Dci-1].CErr = 3;\r
2062 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
2063 } else {\r
2064 InputContext->EP[Dci-1].CErr = 3;\r
2065 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
2066 }\r
1436aea4 2067\r
d987459f
SZ
2068 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2069 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
2070 //\r
2071 // Get the bInterval from descriptor and init the the interval field of endpoint context\r
2072 //\r
2073 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
2074 Interval = EpDesc->Interval;\r
2075 //\r
2076 // Calculate through the bInterval field of Endpoint descriptor.\r
2077 //\r
2078 ASSERT (Interval != 0);\r
1436aea4 2079 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32 ((UINT32)Interval) + 3;\r
d987459f
SZ
2080 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2081 Interval = EpDesc->Interval;\r
2082 ASSERT (Interval >= 1 && Interval <= 16);\r
2083 //\r
2084 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
2085 //\r
2086 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2087 }\r
2088\r
2089 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
1436aea4
MK
2090 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
2091 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *)EndpointTransferRing;\r
2092 XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
d987459f 2093 }\r
1436aea4 2094\r
d987459f
SZ
2095 break;\r
2096\r
2097 case USB_ENDPOINT_CONTROL:\r
04910ceb
SZ
2098 //\r
2099 // Do not support control transfer now.\r
2100 //\r
87000d77 2101 DEBUG ((DEBUG_INFO, "XhcPeiSetConfigCmd64: Unsupport Control EP found, Transfer ring is not allocated.\n"));\r
d987459f 2102 default:\r
87000d77 2103 DEBUG ((DEBUG_INFO, "XhcPeiSetConfigCmd64: Unknown EP found, Transfer ring is not allocated.\n"));\r
04910ceb
SZ
2104 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2105 continue;\r
d987459f
SZ
2106 }\r
2107\r
2108 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2109 Xhc->MemPool,\r
1436aea4 2110 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
d987459f
SZ
2111 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2112 );\r
2113\r
6e1e5405 2114 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);\r
1436aea4 2115 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
d987459f
SZ
2116\r
2117 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2118 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2119\r
1436aea4 2120 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
d987459f 2121 }\r
1436aea4
MK
2122\r
2123 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
d987459f
SZ
2124 }\r
2125\r
2126 InputContext->InputControlContext.Dword2 |= BIT0;\r
2127 InputContext->Slot.ContextEntries = MaxDci;\r
2128 //\r
2129 // configure endpoint\r
2130 //\r
2131 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1436aea4 2132 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
d987459f
SZ
2133 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2134 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2135 CmdTrbCfgEP.CycleBit = 1;\r
2136 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
2137 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
87000d77 2138 DEBUG ((DEBUG_INFO, "XhcSetConfigCmd64: Configure Endpoint\n"));\r
d987459f
SZ
2139 Status = XhcPeiCmdTransfer (\r
2140 Xhc,\r
1436aea4 2141 (TRB_TEMPLATE *)(UINTN)&CmdTrbCfgEP,\r
d987459f 2142 XHC_GENERIC_TIMEOUT,\r
1436aea4 2143 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
d987459f
SZ
2144 );\r
2145 if (EFI_ERROR (Status)) {\r
87000d77 2146 DEBUG ((DEBUG_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));\r
d987459f
SZ
2147 }\r
2148\r
2149 return Status;\r
2150}\r
2151\r
d987459f
SZ
2152/**\r
2153 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
2154\r
2155 @param Xhc The XHCI device.\r
2156 @param SlotId The slot id to be evaluated.\r
2157 @param MaxPacketSize The max packet size supported by the device control transfer.\r
2158\r
2159 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
2160\r
2161**/\r
2162EFI_STATUS\r
2163XhcPeiEvaluateContext (\r
1436aea4
MK
2164 IN PEI_XHC_DEV *Xhc,\r
2165 IN UINT8 SlotId,\r
2166 IN UINT32 MaxPacketSize\r
d987459f
SZ
2167 )\r
2168{\r
1436aea4
MK
2169 EFI_STATUS Status;\r
2170 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
2171 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2172 INPUT_CONTEXT *InputContext;\r
2173 EFI_PHYSICAL_ADDRESS PhyAddr;\r
d987459f
SZ
2174\r
2175 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
2176\r
2177 //\r
2178 // 4.6.7 Evaluate Context\r
2179 //\r
2180 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
2181 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
2182\r
2183 InputContext->InputControlContext.Dword2 |= BIT1;\r
2184 InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
2185\r
2186 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
1436aea4 2187 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
d987459f
SZ
2188 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2189 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2190 CmdTrbEvalu.CycleBit = 1;\r
2191 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
2192 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
87000d77 2193 DEBUG ((DEBUG_INFO, "XhcEvaluateContext: Evaluate context\n"));\r
d987459f
SZ
2194 Status = XhcPeiCmdTransfer (\r
2195 Xhc,\r
1436aea4 2196 (TRB_TEMPLATE *)(UINTN)&CmdTrbEvalu,\r
d987459f 2197 XHC_GENERIC_TIMEOUT,\r
1436aea4 2198 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
d987459f
SZ
2199 );\r
2200 if (EFI_ERROR (Status)) {\r
87000d77 2201 DEBUG ((DEBUG_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));\r
d987459f 2202 }\r
1436aea4 2203\r
d987459f
SZ
2204 return Status;\r
2205}\r
2206\r
2207/**\r
2208 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
2209\r
2210 @param Xhc The XHCI device.\r
2211 @param SlotId The slot id to be evaluated.\r
2212 @param MaxPacketSize The max packet size supported by the device control transfer.\r
2213\r
2214 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
2215\r
2216**/\r
2217EFI_STATUS\r
2218XhcPeiEvaluateContext64 (\r
1436aea4
MK
2219 IN PEI_XHC_DEV *Xhc,\r
2220 IN UINT8 SlotId,\r
2221 IN UINT32 MaxPacketSize\r
d987459f
SZ
2222 )\r
2223{\r
1436aea4
MK
2224 EFI_STATUS Status;\r
2225 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
2226 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2227 INPUT_CONTEXT_64 *InputContext;\r
2228 EFI_PHYSICAL_ADDRESS PhyAddr;\r
d987459f
SZ
2229\r
2230 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
2231\r
2232 //\r
2233 // 4.6.7 Evaluate Context\r
2234 //\r
2235 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
2236 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
2237\r
2238 InputContext->InputControlContext.Dword2 |= BIT1;\r
2239 InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
2240\r
2241 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
1436aea4 2242 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
d987459f
SZ
2243 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2244 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2245 CmdTrbEvalu.CycleBit = 1;\r
2246 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
2247 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
87000d77 2248 DEBUG ((DEBUG_INFO, "XhcEvaluateContext64: Evaluate context 64\n"));\r
d987459f
SZ
2249 Status = XhcPeiCmdTransfer (\r
2250 Xhc,\r
1436aea4 2251 (TRB_TEMPLATE *)(UINTN)&CmdTrbEvalu,\r
d987459f 2252 XHC_GENERIC_TIMEOUT,\r
1436aea4 2253 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
d987459f
SZ
2254 );\r
2255 if (EFI_ERROR (Status)) {\r
87000d77 2256 DEBUG ((DEBUG_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));\r
d987459f 2257 }\r
1436aea4 2258\r
d987459f
SZ
2259 return Status;\r
2260}\r
2261\r
2262/**\r
2263 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
2264\r
2265 @param Xhc The XHCI device.\r
2266 @param SlotId The slot id to be configured.\r
2267 @param PortNum The total number of downstream port supported by the hub.\r
2268 @param TTT The TT think time of the hub device.\r
2269 @param MTT The multi-TT of the hub device.\r
2270\r
2271 @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
2272\r
2273**/\r
2274EFI_STATUS\r
2275XhcPeiConfigHubContext (\r
1436aea4
MK
2276 IN PEI_XHC_DEV *Xhc,\r
2277 IN UINT8 SlotId,\r
2278 IN UINT8 PortNum,\r
2279 IN UINT8 TTT,\r
2280 IN UINT8 MTT\r
d987459f
SZ
2281 )\r
2282{\r
1436aea4
MK
2283 EFI_STATUS Status;\r
2284 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2285 INPUT_CONTEXT *InputContext;\r
2286 DEVICE_CONTEXT *OutputContext;\r
2287 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
2288 EFI_PHYSICAL_ADDRESS PhyAddr;\r
d987459f
SZ
2289\r
2290 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
2291 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
2292 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
2293\r
2294 //\r
2295 // 4.6.7 Evaluate Context\r
2296 //\r
2297 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
2298\r
2299 InputContext->InputControlContext.Dword2 |= BIT0;\r
2300\r
2301 //\r
2302 // Copy the slot context from OutputContext to Input context\r
2303 //\r
1436aea4 2304 CopyMem (&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));\r
d987459f
SZ
2305 InputContext->Slot.Hub = 1;\r
2306 InputContext->Slot.PortNum = PortNum;\r
2307 InputContext->Slot.TTT = TTT;\r
2308 InputContext->Slot.MTT = MTT;\r
2309\r
2310 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1436aea4 2311 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
d987459f
SZ
2312 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2313 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2314 CmdTrbCfgEP.CycleBit = 1;\r
2315 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
2316 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
87000d77 2317 DEBUG ((DEBUG_INFO, "Configure Hub Slot Context\n"));\r
d987459f
SZ
2318 Status = XhcPeiCmdTransfer (\r
2319 Xhc,\r
1436aea4 2320 (TRB_TEMPLATE *)(UINTN)&CmdTrbCfgEP,\r
d987459f 2321 XHC_GENERIC_TIMEOUT,\r
1436aea4 2322 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
d987459f
SZ
2323 );\r
2324 if (EFI_ERROR (Status)) {\r
87000d77 2325 DEBUG ((DEBUG_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));\r
d987459f 2326 }\r
1436aea4 2327\r
d987459f
SZ
2328 return Status;\r
2329}\r
2330\r
2331/**\r
2332 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
2333\r
2334 @param Xhc The XHCI device.\r
2335 @param SlotId The slot id to be configured.\r
2336 @param PortNum The total number of downstream port supported by the hub.\r
2337 @param TTT The TT think time of the hub device.\r
2338 @param MTT The multi-TT of the hub device.\r
2339\r
2340 @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
2341\r
2342**/\r
2343EFI_STATUS\r
2344XhcPeiConfigHubContext64 (\r
1436aea4
MK
2345 IN PEI_XHC_DEV *Xhc,\r
2346 IN UINT8 SlotId,\r
2347 IN UINT8 PortNum,\r
2348 IN UINT8 TTT,\r
2349 IN UINT8 MTT\r
d987459f
SZ
2350 )\r
2351{\r
1436aea4
MK
2352 EFI_STATUS Status;\r
2353 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2354 INPUT_CONTEXT_64 *InputContext;\r
2355 DEVICE_CONTEXT_64 *OutputContext;\r
2356 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
2357 EFI_PHYSICAL_ADDRESS PhyAddr;\r
d987459f
SZ
2358\r
2359 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
2360 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
2361 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
2362\r
2363 //\r
2364 // 4.6.7 Evaluate Context\r
2365 //\r
2366 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
2367\r
2368 InputContext->InputControlContext.Dword2 |= BIT0;\r
2369\r
2370 //\r
2371 // Copy the slot context from OutputContext to Input context\r
2372 //\r
1436aea4 2373 CopyMem (&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));\r
d987459f
SZ
2374 InputContext->Slot.Hub = 1;\r
2375 InputContext->Slot.PortNum = PortNum;\r
2376 InputContext->Slot.TTT = TTT;\r
2377 InputContext->Slot.MTT = MTT;\r
2378\r
2379 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1436aea4 2380 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
d987459f
SZ
2381 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2382 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2383 CmdTrbCfgEP.CycleBit = 1;\r
2384 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
2385 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
87000d77 2386 DEBUG ((DEBUG_INFO, "Configure Hub Slot Context 64\n"));\r
d987459f
SZ
2387 Status = XhcPeiCmdTransfer (\r
2388 Xhc,\r
1436aea4 2389 (TRB_TEMPLATE *)(UINTN)&CmdTrbCfgEP,\r
d987459f 2390 XHC_GENERIC_TIMEOUT,\r
1436aea4 2391 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
d987459f
SZ
2392 );\r
2393 if (EFI_ERROR (Status)) {\r
87000d77 2394 DEBUG ((DEBUG_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));\r
d987459f 2395 }\r
1436aea4 2396\r
d987459f
SZ
2397 return Status;\r
2398}\r
2399\r
12e6c738
FT
2400/**\r
2401 Stop endpoint through XHCI's Stop_Endpoint cmd.\r
2402\r
2403 @param Xhc The XHCI device.\r
2404 @param SlotId The slot id of the target device.\r
2405 @param Dci The device context index of the target slot or endpoint.\r
2406\r
2407 @retval EFI_SUCCESS Stop endpoint successfully.\r
2408 @retval Others Failed to stop endpoint.\r
2409\r
2410**/\r
2411EFI_STATUS\r
2412EFIAPI\r
2413XhcPeiStopEndpoint (\r
1436aea4
MK
2414 IN PEI_XHC_DEV *Xhc,\r
2415 IN UINT8 SlotId,\r
2416 IN UINT8 Dci\r
12e6c738
FT
2417 )\r
2418{\r
1436aea4
MK
2419 EFI_STATUS Status;\r
2420 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2421 CMD_TRB_STOP_ENDPOINT CmdTrbStopED;\r
12e6c738 2422\r
87000d77 2423 DEBUG ((DEBUG_INFO, "XhcPeiStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
12e6c738
FT
2424\r
2425 //\r
2426 // Send stop endpoint command to transit Endpoint from running to stop state\r
2427 //\r
2428 ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));\r
2429 CmdTrbStopED.CycleBit = 1;\r
2430 CmdTrbStopED.Type = TRB_TYPE_STOP_ENDPOINT;\r
2431 CmdTrbStopED.EDID = Dci;\r
2432 CmdTrbStopED.SlotId = SlotId;\r
1436aea4
MK
2433 Status = XhcPeiCmdTransfer (\r
2434 Xhc,\r
2435 (TRB_TEMPLATE *)(UINTN)&CmdTrbStopED,\r
2436 XHC_GENERIC_TIMEOUT,\r
2437 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
2438 );\r
2439 if (EFI_ERROR (Status)) {\r
87000d77 2440 DEBUG ((DEBUG_ERROR, "XhcPeiStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));\r
12e6c738
FT
2441 }\r
2442\r
2443 return Status;\r
2444}\r
2445\r
2446/**\r
2447 Reset endpoint through XHCI's Reset_Endpoint cmd.\r
2448\r
2449 @param Xhc The XHCI device.\r
2450 @param SlotId The slot id of the target device.\r
2451 @param Dci The device context index of the target slot or endpoint.\r
2452\r
2453 @retval EFI_SUCCESS Reset endpoint successfully.\r
2454 @retval Others Failed to reset endpoint.\r
2455\r
2456**/\r
2457EFI_STATUS\r
2458EFIAPI\r
2459XhcPeiResetEndpoint (\r
1436aea4
MK
2460 IN PEI_XHC_DEV *Xhc,\r
2461 IN UINT8 SlotId,\r
2462 IN UINT8 Dci\r
12e6c738
FT
2463 )\r
2464{\r
2465 EFI_STATUS Status;\r
2466 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2467 CMD_TRB_RESET_ENDPOINT CmdTrbResetED;\r
2468\r
87000d77 2469 DEBUG ((DEBUG_INFO, "XhcPeiResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
12e6c738
FT
2470\r
2471 //\r
2472 // Send stop endpoint command to transit Endpoint from running to stop state\r
2473 //\r
2474 ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
2475 CmdTrbResetED.CycleBit = 1;\r
2476 CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;\r
2477 CmdTrbResetED.EDID = Dci;\r
2478 CmdTrbResetED.SlotId = SlotId;\r
1436aea4
MK
2479 Status = XhcPeiCmdTransfer (\r
2480 Xhc,\r
2481 (TRB_TEMPLATE *)(UINTN)&CmdTrbResetED,\r
2482 XHC_GENERIC_TIMEOUT,\r
2483 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
2484 );\r
2485 if (EFI_ERROR (Status)) {\r
87000d77 2486 DEBUG ((DEBUG_ERROR, "XhcPeiResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
12e6c738
FT
2487 }\r
2488\r
2489 return Status;\r
2490}\r
2491\r
2492/**\r
2493 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.\r
2494\r
2495 @param Xhc The XHCI device.\r
2496 @param SlotId The slot id of the target device.\r
2497 @param Dci The device context index of the target slot or endpoint.\r
2498 @param Urb The dequeue pointer of the transfer ring specified\r
2499 by the urb to be updated.\r
2500\r
2501 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.\r
2502 @retval Others Failed to set transfer ring dequeue pointer.\r
2503\r
2504**/\r
2505EFI_STATUS\r
2506EFIAPI\r
2507XhcPeiSetTrDequeuePointer (\r
1436aea4
MK
2508 IN PEI_XHC_DEV *Xhc,\r
2509 IN UINT8 SlotId,\r
2510 IN UINT8 Dci,\r
2511 IN URB *Urb\r
12e6c738
FT
2512 )\r
2513{\r
2514 EFI_STATUS Status;\r
2515 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2516 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;\r
2517 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2518\r
87000d77 2519 DEBUG ((DEBUG_INFO, "XhcPeiSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));\r
12e6c738
FT
2520\r
2521 //\r
2522 // Send stop endpoint command to transit Endpoint from running to stop state\r
2523 //\r
2524 ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
1436aea4 2525 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));\r
12e6c738
FT
2526 CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;\r
2527 CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2528 CmdSetTRDeq.CycleBit = 1;\r
2529 CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;\r
2530 CmdSetTRDeq.Endpoint = Dci;\r
2531 CmdSetTRDeq.SlotId = SlotId;\r
1436aea4
MK
2532 Status = XhcPeiCmdTransfer (\r
2533 Xhc,\r
2534 (TRB_TEMPLATE *)(UINTN)&CmdSetTRDeq,\r
2535 XHC_GENERIC_TIMEOUT,\r
2536 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
2537 );\r
2538 if (EFI_ERROR (Status)) {\r
87000d77 2539 DEBUG ((DEBUG_ERROR, "XhcPeiSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));\r
12e6c738
FT
2540 }\r
2541\r
2542 return Status;\r
2543}\r
2544\r
d987459f
SZ
2545/**\r
2546 Check if there is a new generated event.\r
2547\r
2548 @param Xhc The XHCI device.\r
2549 @param EvtRing The event ring to check.\r
2550 @param NewEvtTrb The new event TRB found.\r
2551\r
2552 @retval EFI_SUCCESS Found a new event TRB at the event ring.\r
2553 @retval EFI_NOT_READY The event ring has no new event.\r
2554\r
2555**/\r
2556EFI_STATUS\r
2557XhcPeiCheckNewEvent (\r
1436aea4
MK
2558 IN PEI_XHC_DEV *Xhc,\r
2559 IN EVENT_RING *EvtRing,\r
2560 OUT TRB_TEMPLATE **NewEvtTrb\r
d987459f
SZ
2561 )\r
2562{\r
2563 ASSERT (EvtRing != NULL);\r
2564\r
2565 *NewEvtTrb = EvtRing->EventRingDequeue;\r
2566\r
2567 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {\r
2568 return EFI_NOT_READY;\r
2569 }\r
2570\r
2571 EvtRing->EventRingDequeue++;\r
2572 //\r
2573 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.\r
2574 //\r
1436aea4 2575 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
d987459f
SZ
2576 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;\r
2577 }\r
2578\r
2579 return EFI_SUCCESS;\r
2580}\r
2581\r
2582/**\r
2583 Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
2584\r
2585 @param Xhc The XHCI device.\r
2586 @param EvtRing The event ring to sync.\r
2587\r
2588 @retval EFI_SUCCESS The event ring is synchronized successfully.\r
2589\r
2590**/\r
2591EFI_STATUS\r
2592XhcPeiSyncEventRing (\r
1436aea4
MK
2593 IN PEI_XHC_DEV *Xhc,\r
2594 IN EVENT_RING *EvtRing\r
d987459f
SZ
2595 )\r
2596{\r
1436aea4
MK
2597 UINTN Index;\r
2598 TRB_TEMPLATE *EvtTrb;\r
d987459f
SZ
2599\r
2600 ASSERT (EvtRing != NULL);\r
2601\r
2602 //\r
2603 // Calculate the EventRingEnqueue and EventRingCCS.\r
2604 // Note: only support single Segment\r
2605 //\r
2606 EvtTrb = EvtRing->EventRingDequeue;\r
2607\r
2608 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {\r
2609 if (EvtTrb->CycleBit != EvtRing->EventRingCCS) {\r
2610 break;\r
2611 }\r
2612\r
2613 EvtTrb++;\r
2614\r
1436aea4
MK
2615 if ((UINTN)EvtTrb >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
2616 EvtTrb = EvtRing->EventRingSeg0;\r
d987459f
SZ
2617 EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;\r
2618 }\r
2619 }\r
2620\r
2621 if (Index < EvtRing->TrbNumber) {\r
2622 EvtRing->EventRingEnqueue = EvtTrb;\r
2623 } else {\r
2624 ASSERT (FALSE);\r
2625 }\r
2626\r
2627 return EFI_SUCCESS;\r
2628}\r
2629\r
2630/**\r
2631 Free XHCI event ring.\r
2632\r
2633 @param Xhc The XHCI device.\r
2634 @param EventRing The event ring to be freed.\r
2635\r
2636**/\r
2637VOID\r
2638XhcPeiFreeEventRing (\r
1436aea4
MK
2639 IN PEI_XHC_DEV *Xhc,\r
2640 IN EVENT_RING *EventRing\r
d987459f
SZ
2641 )\r
2642{\r
1436aea4 2643 if (EventRing->EventRingSeg0 == NULL) {\r
d987459f
SZ
2644 return;\r
2645 }\r
2646\r
2647 //\r
2648 // Free EventRing Segment 0\r
2649 //\r
2650 UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
2651\r
2652 //\r
2653 // Free ERST table\r
2654 //\r
2655 UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
2656}\r
2657\r
2658/**\r
2659 Create XHCI event ring.\r
2660\r
2661 @param Xhc The XHCI device.\r
2662 @param EventRing The created event ring.\r
2663\r
2664**/\r
2665VOID\r
2666XhcPeiCreateEventRing (\r
1436aea4
MK
2667 IN PEI_XHC_DEV *Xhc,\r
2668 OUT EVENT_RING *EventRing\r
d987459f
SZ
2669 )\r
2670{\r
1436aea4
MK
2671 VOID *Buf;\r
2672 EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;\r
2673 UINTN Size;\r
2674 EFI_PHYSICAL_ADDRESS ERSTPhy;\r
2675 EFI_PHYSICAL_ADDRESS DequeuePhy;\r
d987459f
SZ
2676\r
2677 ASSERT (EventRing != NULL);\r
2678\r
2679 Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;\r
1436aea4 2680 Buf = UsbHcAllocateMem (Xhc->MemPool, Size);\r
d987459f 2681 ASSERT (Buf != NULL);\r
1436aea4 2682 ASSERT (((UINTN)Buf & 0x3F) == 0);\r
d987459f
SZ
2683 ZeroMem (Buf, Size);\r
2684\r
2685 DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);\r
2686\r
1436aea4
MK
2687 EventRing->EventRingSeg0 = Buf;\r
2688 EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;\r
2689 EventRing->EventRingDequeue = (TRB_TEMPLATE *)EventRing->EventRingSeg0;\r
2690 EventRing->EventRingEnqueue = (TRB_TEMPLATE *)EventRing->EventRingSeg0;\r
d987459f
SZ
2691\r
2692 //\r
2693 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'\r
2694 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.\r
2695 //\r
2696 EventRing->EventRingCCS = 1;\r
2697\r
2698 Size = sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER;\r
1436aea4 2699 Buf = UsbHcAllocateMem (Xhc->MemPool, Size);\r
d987459f 2700 ASSERT (Buf != NULL);\r
1436aea4 2701 ASSERT (((UINTN)Buf & 0x3F) == 0);\r
d987459f
SZ
2702 ZeroMem (Buf, Size);\r
2703\r
1436aea4 2704 ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *)Buf;\r
d987459f
SZ
2705 EventRing->ERSTBase = ERSTBase;\r
2706 ERSTBase->PtrLo = XHC_LOW_32BIT (DequeuePhy);\r
2707 ERSTBase->PtrHi = XHC_HIGH_32BIT (DequeuePhy);\r
2708 ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;\r
2709\r
2710 ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);\r
2711\r
2712 //\r
2713 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)\r
2714 //\r
2715 XhcPeiWriteRuntimeReg (\r
2716 Xhc,\r
2717 XHC_ERSTSZ_OFFSET,\r
2718 ERST_NUMBER\r
2719 );\r
2720 //\r
2721 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)\r
2722 //\r
2723 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
2724 // So divide it to two 32-bytes width register access.\r
2725 //\r
2726 XhcPeiWriteRuntimeReg (\r
2727 Xhc,\r
2728 XHC_ERDP_OFFSET,\r
1436aea4 2729 XHC_LOW_32BIT ((UINT64)(UINTN)DequeuePhy)\r
d987459f
SZ
2730 );\r
2731 XhcPeiWriteRuntimeReg (\r
2732 Xhc,\r
2733 XHC_ERDP_OFFSET + 4,\r
1436aea4 2734 XHC_HIGH_32BIT ((UINT64)(UINTN)DequeuePhy)\r
d987459f
SZ
2735 );\r
2736 //\r
2737 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register (5.5.2.3.2)\r
2738 //\r
2739 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
2740 // So divide it to two 32-bytes width register access.\r
2741 //\r
2742 XhcPeiWriteRuntimeReg (\r
2743 Xhc,\r
2744 XHC_ERSTBA_OFFSET,\r
1436aea4 2745 XHC_LOW_32BIT ((UINT64)(UINTN)ERSTPhy)\r
d987459f
SZ
2746 );\r
2747 XhcPeiWriteRuntimeReg (\r
2748 Xhc,\r
2749 XHC_ERSTBA_OFFSET + 4,\r
1436aea4 2750 XHC_HIGH_32BIT ((UINT64)(UINTN)ERSTPhy)\r
d987459f
SZ
2751 );\r
2752 //\r
2753 // Need set IMAN IE bit to enable the ring interrupt\r
2754 //\r
2755 XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);\r
2756}\r
2757\r
2758/**\r
2759 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
2760\r
2761 @param Xhc The XHCI device.\r
2762 @param TrsRing The transfer ring to sync.\r
2763\r
2764 @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
2765\r
2766**/\r
2767EFI_STATUS\r
2768XhcPeiSyncTrsRing (\r
2769 IN PEI_XHC_DEV *Xhc,\r
2770 IN TRANSFER_RING *TrsRing\r
2771 )\r
2772{\r
1436aea4
MK
2773 UINTN Index;\r
2774 TRB_TEMPLATE *TrsTrb;\r
d987459f
SZ
2775\r
2776 ASSERT (TrsRing != NULL);\r
2777 //\r
2778 // Calculate the latest RingEnqueue and RingPCS\r
2779 //\r
2780 TrsTrb = TrsRing->RingEnqueue;\r
2781 ASSERT (TrsTrb != NULL);\r
2782\r
2783 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {\r
2784 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {\r
2785 break;\r
2786 }\r
1436aea4 2787\r
d987459f 2788 TrsTrb++;\r
1436aea4
MK
2789 if ((UINT8)TrsTrb->Type == TRB_TYPE_LINK) {\r
2790 ASSERT (((LINK_TRB *)TrsTrb)->TC != 0);\r
d987459f
SZ
2791 //\r
2792 // set cycle bit in Link TRB as normal\r
2793 //\r
1436aea4 2794 ((LINK_TRB *)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;\r
d987459f
SZ
2795 //\r
2796 // Toggle PCS maintained by software\r
2797 //\r
2798 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;\r
1436aea4 2799 TrsTrb = (TRB_TEMPLATE *)TrsRing->RingSeg0; // Use host address\r
d987459f
SZ
2800 }\r
2801 }\r
2802\r
2803 ASSERT (Index != TrsRing->TrbNumber);\r
2804\r
2805 if (TrsTrb != TrsRing->RingEnqueue) {\r
2806 TrsRing->RingEnqueue = TrsTrb;\r
2807 }\r
2808\r
2809 //\r
2810 // Clear the Trb context for enqueue, but reserve the PCS bit\r
2811 //\r
2812 TrsTrb->Parameter1 = 0;\r
2813 TrsTrb->Parameter2 = 0;\r
2814 TrsTrb->Status = 0;\r
2815 TrsTrb->RsvdZ1 = 0;\r
2816 TrsTrb->Type = 0;\r
2817 TrsTrb->Control = 0;\r
2818\r
2819 return EFI_SUCCESS;\r
2820}\r
2821\r
2822/**\r
2823 Create XHCI transfer ring.\r
2824\r
2825 @param Xhc The XHCI Device.\r
2826 @param TrbNum The number of TRB in the ring.\r
2827 @param TransferRing The created transfer ring.\r
2828\r
2829**/\r
2830VOID\r
2831XhcPeiCreateTransferRing (\r
1436aea4
MK
2832 IN PEI_XHC_DEV *Xhc,\r
2833 IN UINTN TrbNum,\r
2834 OUT TRANSFER_RING *TransferRing\r
d987459f
SZ
2835 )\r
2836{\r
2837 VOID *Buf;\r
2838 LINK_TRB *EndTrb;\r
2839 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2840\r
2841 Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);\r
2842 ASSERT (Buf != NULL);\r
1436aea4 2843 ASSERT (((UINTN)Buf & 0x3F) == 0);\r
d987459f
SZ
2844 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
2845\r
1436aea4
MK
2846 TransferRing->RingSeg0 = Buf;\r
2847 TransferRing->TrbNumber = TrbNum;\r
2848 TransferRing->RingEnqueue = (TRB_TEMPLATE *)TransferRing->RingSeg0;\r
2849 TransferRing->RingDequeue = (TRB_TEMPLATE *)TransferRing->RingSeg0;\r
2850 TransferRing->RingPCS = 1;\r
d987459f
SZ
2851 //\r
2852 // 4.9.2 Transfer Ring Management\r
2853 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to\r
2854 // point to the first TRB in the ring.\r
2855 //\r
1436aea4 2856 EndTrb = (LINK_TRB *)((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));\r
d987459f 2857 EndTrb->Type = TRB_TYPE_LINK;\r
1436aea4 2858 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
d987459f
SZ
2859 EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2860 EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2861 //\r
2862 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.\r
2863 //\r
1436aea4 2864 EndTrb->TC = 1;\r
d987459f
SZ
2865 //\r
2866 // Set Cycle bit as other TRB PCS init value\r
2867 //\r
2868 EndTrb->CycleBit = 0;\r
2869}\r
2870\r
2871/**\r
2872 Initialize the XHCI host controller for schedule.\r
2873\r
2874 @param Xhc The XHCI device to be initialized.\r
2875\r
2876**/\r
2877VOID\r
2878XhcPeiInitSched (\r
1436aea4 2879 IN PEI_XHC_DEV *Xhc\r
d987459f
SZ
2880 )\r
2881{\r
2882 VOID *Dcbaa;\r
2883 EFI_PHYSICAL_ADDRESS DcbaaPhy;\r
2884 UINTN Size;\r
2885 EFI_PHYSICAL_ADDRESS CmdRingPhy;\r
2886 UINT32 MaxScratchpadBufs;\r
2887 UINT64 *ScratchBuf;\r
2888 EFI_PHYSICAL_ADDRESS ScratchPhy;\r
2889 UINT64 *ScratchEntry;\r
2890 EFI_PHYSICAL_ADDRESS ScratchEntryPhy;\r
2891 UINT32 Index;\r
b575ca32 2892 UINTN *ScratchEntryMap;\r
d987459f
SZ
2893 EFI_STATUS Status;\r
2894\r
2895 //\r
2896 // Initialize memory management.\r
2897 //\r
2898 Xhc->MemPool = UsbHcInitMemPool ();\r
2899 ASSERT (Xhc->MemPool != NULL);\r
2900\r
2901 //\r
2902 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)\r
2903 // to enable the device slots that system software is going to use.\r
2904 //\r
2905 Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;\r
2906 ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);\r
2907 XhcPeiWriteOpReg (Xhc, XHC_CONFIG_OFFSET, (XhcPeiReadOpReg (Xhc, XHC_CONFIG_OFFSET) & ~XHC_CONFIG_MASK) | Xhc->MaxSlotsEn);\r
2908\r
2909 //\r
2910 // The Device Context Base Address Array entry associated with each allocated Device Slot\r
2911 // shall contain a 64-bit pointer to the base of the associated Device Context.\r
2912 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.\r
2913 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.\r
2914 //\r
1436aea4 2915 Size = (Xhc->MaxSlotsEn + 1) * sizeof (UINT64);\r
d987459f
SZ
2916 Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Size);\r
2917 ASSERT (Dcbaa != NULL);\r
2918\r
2919 //\r
2920 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.\r
2921 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run\r
2922 // mode (Run/Stop(R/S) ='1').\r
2923 //\r
2924 MaxScratchpadBufs = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);\r
2925 Xhc->MaxScratchpadBufs = MaxScratchpadBufs;\r
2926 ASSERT (MaxScratchpadBufs <= 1023);\r
2927 if (MaxScratchpadBufs != 0) {\r
b575ca32
JY
2928 //\r
2929 // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them\r
2930 //\r
2931 ScratchEntryMap = AllocateZeroPool (sizeof (UINTN) * MaxScratchpadBufs);\r
2932 ASSERT (ScratchEntryMap != NULL);\r
2933 Xhc->ScratchEntryMap = ScratchEntryMap;\r
2934\r
d987459f
SZ
2935 //\r
2936 // Allocate the buffer to record the host address for each entry\r
2937 //\r
2938 ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);\r
2939 ASSERT (ScratchEntry != NULL);\r
2940 Xhc->ScratchEntry = ScratchEntry;\r
2941\r
60050b31 2942 ScratchPhy = 0;\r
1436aea4
MK
2943 Status = UsbHcAllocateAlignedPages (\r
2944 EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),\r
2945 Xhc->PageSize,\r
2946 (VOID **)&ScratchBuf,\r
2947 &ScratchPhy,\r
2948 &Xhc->ScratchMap\r
2949 );\r
d987459f
SZ
2950 ASSERT_EFI_ERROR (Status);\r
2951\r
2952 ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));\r
2953 Xhc->ScratchBuf = ScratchBuf;\r
2954\r
2955 //\r
2956 // Allocate each scratch buffer\r
2957 //\r
2958 for (Index = 0; Index < MaxScratchpadBufs; Index++) {\r
60050b31 2959 ScratchEntryPhy = 0;\r
1436aea4
MK
2960 Status = UsbHcAllocateAlignedPages (\r
2961 EFI_SIZE_TO_PAGES (Xhc->PageSize),\r
2962 Xhc->PageSize,\r
2963 (VOID **)&ScratchEntry[Index],\r
2964 &ScratchEntryPhy,\r
2965 (VOID **)&ScratchEntryMap[Index]\r
2966 );\r
d987459f 2967 ASSERT_EFI_ERROR (Status);\r
1436aea4 2968 ZeroMem ((VOID *)(UINTN)ScratchEntry[Index], Xhc->PageSize);\r
d987459f
SZ
2969 //\r
2970 // Fill with the PCI device address\r
2971 //\r
2972 *ScratchBuf++ = ScratchEntryPhy;\r
2973 }\r
1436aea4 2974\r
d987459f
SZ
2975 //\r
2976 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the\r
2977 // Device Context Base Address Array points to the Scratchpad Buffer Array.\r
2978 //\r
1436aea4 2979 *(UINT64 *)Dcbaa = (UINT64)(UINTN)ScratchPhy;\r
d987459f
SZ
2980 }\r
2981\r
2982 //\r
2983 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with\r
2984 // a 64-bit address pointing to where the Device Context Base Address Array is located.\r
2985 //\r
1436aea4 2986 Xhc->DCBAA = (UINT64 *)(UINTN)Dcbaa;\r
d987459f
SZ
2987 //\r
2988 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
2989 // So divide it to two 32-bytes width register access.\r
2990 //\r
2991 DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Size);\r
2992 XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT (DcbaaPhy));\r
2993 XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));\r
2994\r
87000d77 2995 DEBUG ((DEBUG_INFO, "XhcPeiInitSched:DCBAA=0x%x\n", Xhc->DCBAA));\r
d987459f
SZ
2996\r
2997 //\r
2998 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register\r
2999 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.\r
3000 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall\r
3001 // always be '0'.\r
3002 //\r
3003 XhcPeiCreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);\r
3004 //\r
3005 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a\r
3006 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.\r
3007 // So we set RCS as inverted PCS init value to let Command Ring empty\r
3008 //\r
3009 CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
3010 ASSERT ((CmdRingPhy & 0x3F) == 0);\r
3011 CmdRingPhy |= XHC_CRCR_RCS;\r
3012 //\r
3013 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
3014 // So divide it to two 32-bytes width register access.\r
3015 //\r
3016 XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT (CmdRingPhy));\r
3017 XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));\r
3018\r
87000d77 3019 DEBUG ((DEBUG_INFO, "XhcPeiInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));\r
d987459f
SZ
3020\r
3021 //\r
3022 // Disable the 'interrupter enable' bit in USB_CMD\r
3023 // and clear IE & IP bit in all Interrupter X Management Registers.\r
3024 //\r
3025 XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);\r
3026 for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {\r
3027 XhcPeiClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);\r
3028 XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);\r
3029 }\r
3030\r
3031 //\r
3032 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer\r
3033 //\r
3034 XhcPeiCreateEventRing (Xhc, &Xhc->EventRing);\r
87000d77 3035 DEBUG ((DEBUG_INFO, "XhcPeiInitSched:XHC_EVENTRING=0x%x\n", Xhc->EventRing.EventRingSeg0));\r
d987459f
SZ
3036}\r
3037\r
3038/**\r
3039 Free the resouce allocated at initializing schedule.\r
3040\r
3041 @param Xhc The XHCI device.\r
3042\r
3043**/\r
3044VOID\r
3045XhcPeiFreeSched (\r
1436aea4 3046 IN PEI_XHC_DEV *Xhc\r
d987459f
SZ
3047 )\r
3048{\r
1436aea4
MK
3049 UINT32 Index;\r
3050 UINT64 *ScratchEntry;\r
d987459f
SZ
3051\r
3052 if (Xhc->ScratchBuf != NULL) {\r
3053 ScratchEntry = Xhc->ScratchEntry;\r
3054 for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {\r
3055 //\r
3056 // Free Scratchpad Buffers\r
3057 //\r
1436aea4 3058 UsbHcFreeAlignedPages ((VOID *)(UINTN)ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize), (VOID *)Xhc->ScratchEntryMap[Index]);\r
d987459f 3059 }\r
1436aea4 3060\r
d987459f
SZ
3061 //\r
3062 // Free Scratchpad Buffer Array\r
3063 //\r
b575ca32
JY
3064 UsbHcFreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)), Xhc->ScratchMap);\r
3065 FreePool (Xhc->ScratchEntryMap);\r
d987459f
SZ
3066 FreePool (Xhc->ScratchEntry);\r
3067 }\r
3068\r
3069 if (Xhc->CmdRing.RingSeg0 != NULL) {\r
3070 UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
3071 Xhc->CmdRing.RingSeg0 = NULL;\r
3072 }\r
3073\r
1436aea4 3074 XhcPeiFreeEventRing (Xhc, &Xhc->EventRing);\r
d987459f
SZ
3075\r
3076 if (Xhc->DCBAA != NULL) {\r
3077 UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof (UINT64));\r
3078 Xhc->DCBAA = NULL;\r
3079 }\r
3080\r
3081 //\r
3082 // Free memory pool at last\r
3083 //\r
3084 if (Xhc->MemPool != NULL) {\r
3085 UsbHcFreeMemPool (Xhc->MemPool);\r
3086 Xhc->MemPool = NULL;\r
3087 }\r
3088}\r