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