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