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