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