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