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