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