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